Merge branch 'master' of git://git.denx.de/u-boot-spi

This commit is contained in:
Tom Rini 2014-11-03 12:42:58 -05:00
commit 130aec779a
3 changed files with 101 additions and 77 deletions

View file

@ -0,0 +1,6 @@
SoCFPGA EPCS/EPCQx1 mini howto:
- Instantiate EPCS/EPCQx1 Serial flash controller in QSys and rebuild
- The controller base address is the "Base" in QSys + 0x400
- Set MSEL[4:0]=10010 (AS Standard)
- Load the bitstream into FPGA, enable bridges
- Only then will the driver work

View file

@ -12,58 +12,62 @@
#include <malloc.h> #include <malloc.h>
#include <spi.h> #include <spi.h>
#define ALTERA_SPI_RXDATA 0 #ifndef CONFIG_ALTERA_SPI_IDLE_VAL
#define ALTERA_SPI_TXDATA 4 #define CONFIG_ALTERA_SPI_IDLE_VAL 0xff
#define ALTERA_SPI_STATUS 8 #endif
#define ALTERA_SPI_CONTROL 12
#define ALTERA_SPI_SLAVE_SEL 20
#define ALTERA_SPI_STATUS_ROE_MSK (0x8)
#define ALTERA_SPI_STATUS_TOE_MSK (0x10)
#define ALTERA_SPI_STATUS_TMT_MSK (0x20)
#define ALTERA_SPI_STATUS_TRDY_MSK (0x40)
#define ALTERA_SPI_STATUS_RRDY_MSK (0x80)
#define ALTERA_SPI_STATUS_E_MSK (0x100)
#define ALTERA_SPI_CONTROL_IROE_MSK (0x8)
#define ALTERA_SPI_CONTROL_ITOE_MSK (0x10)
#define ALTERA_SPI_CONTROL_ITRDY_MSK (0x40)
#define ALTERA_SPI_CONTROL_IRRDY_MSK (0x80)
#define ALTERA_SPI_CONTROL_IE_MSK (0x100)
#define ALTERA_SPI_CONTROL_SSO_MSK (0x400)
#ifndef CONFIG_SYS_ALTERA_SPI_LIST #ifndef CONFIG_SYS_ALTERA_SPI_LIST
#define CONFIG_SYS_ALTERA_SPI_LIST { CONFIG_SYS_SPI_BASE } #define CONFIG_SYS_ALTERA_SPI_LIST { CONFIG_SYS_SPI_BASE }
#endif #endif
struct altera_spi_regs {
u32 rxdata;
u32 txdata;
u32 status;
u32 control;
u32 _reserved;
u32 slave_sel;
};
#define ALTERA_SPI_STATUS_ROE_MSK (1 << 3)
#define ALTERA_SPI_STATUS_TOE_MSK (1 << 4)
#define ALTERA_SPI_STATUS_TMT_MSK (1 << 5)
#define ALTERA_SPI_STATUS_TRDY_MSK (1 << 6)
#define ALTERA_SPI_STATUS_RRDY_MSK (1 << 7)
#define ALTERA_SPI_STATUS_E_MSK (1 << 8)
#define ALTERA_SPI_CONTROL_IROE_MSK (1 << 3)
#define ALTERA_SPI_CONTROL_ITOE_MSK (1 << 4)
#define ALTERA_SPI_CONTROL_ITRDY_MSK (1 << 6)
#define ALTERA_SPI_CONTROL_IRRDY_MSK (1 << 7)
#define ALTERA_SPI_CONTROL_IE_MSK (1 << 8)
#define ALTERA_SPI_CONTROL_SSO_MSK (1 << 10)
static ulong altera_spi_base_list[] = CONFIG_SYS_ALTERA_SPI_LIST; static ulong altera_spi_base_list[] = CONFIG_SYS_ALTERA_SPI_LIST;
struct altera_spi_slave { struct altera_spi_slave {
struct spi_slave slave; struct spi_slave slave;
ulong base; struct altera_spi_regs *regs;
}; };
#define to_altera_spi_slave(s) container_of(s, struct altera_spi_slave, slave) #define to_altera_spi_slave(s) container_of(s, struct altera_spi_slave, slave)
__attribute__((weak)) __weak int spi_cs_is_valid(unsigned int bus, unsigned int cs)
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{ {
return bus < ARRAY_SIZE(altera_spi_base_list) && cs < 32; return bus < ARRAY_SIZE(altera_spi_base_list) && cs < 32;
} }
__attribute__((weak)) __weak void spi_cs_activate(struct spi_slave *slave)
void spi_cs_activate(struct spi_slave *slave)
{ {
struct altera_spi_slave *altspi = to_altera_spi_slave(slave); struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
writel(1 << slave->cs, altspi->base + ALTERA_SPI_SLAVE_SEL); writel(1 << slave->cs, &altspi->regs->slave_sel);
writel(ALTERA_SPI_CONTROL_SSO_MSK, altspi->base + ALTERA_SPI_CONTROL); writel(ALTERA_SPI_CONTROL_SSO_MSK, &altspi->regs->control);
} }
__attribute__((weak)) __weak void spi_cs_deactivate(struct spi_slave *slave)
void spi_cs_deactivate(struct spi_slave *slave)
{ {
struct altera_spi_slave *altspi = to_altera_spi_slave(slave); struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
writel(0, altspi->base + ALTERA_SPI_CONTROL); writel(0, &altspi->regs->control);
writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL); writel(0, &altspi->regs->slave_sel);
} }
void spi_init(void) void spi_init(void)
@ -87,9 +91,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!altspi) if (!altspi)
return NULL; return NULL;
altspi->base = altera_spi_base_list[bus]; altspi->regs = (struct altera_spi_regs *)altera_spi_base_list[bus];
debug("%s: bus:%i cs:%i base:%lx\n", __func__, debug("%s: bus:%i cs:%i base:%p\n", __func__, bus, cs, altspi->regs);
bus, cs, altspi->base);
return &altspi->slave; return &altspi->slave;
} }
@ -105,8 +108,8 @@ int spi_claim_bus(struct spi_slave *slave)
struct altera_spi_slave *altspi = to_altera_spi_slave(slave); struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
writel(0, altspi->base + ALTERA_SPI_CONTROL); writel(0, &altspi->regs->control);
writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL); writel(0, &altspi->regs->slave_sel);
return 0; return 0;
} }
@ -115,24 +118,22 @@ void spi_release_bus(struct spi_slave *slave)
struct altera_spi_slave *altspi = to_altera_spi_slave(slave); struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL); writel(0, &altspi->regs->slave_sel);
} }
#ifndef CONFIG_ALTERA_SPI_IDLE_VAL
# define CONFIG_ALTERA_SPI_IDLE_VAL 0xff
#endif
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags) void *din, unsigned long flags)
{ {
struct altera_spi_slave *altspi = to_altera_spi_slave(slave); struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
/* assume spi core configured to do 8 bit transfers */ /* assume spi core configured to do 8 bit transfers */
uint bytes = bitlen / 8; unsigned int bytes = bitlen / 8;
const uchar *txp = dout; const unsigned char *txp = dout;
uchar *rxp = din; unsigned char *rxp = din;
uint32_t reg, data, start;
debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__, debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
slave->bus, slave->cs, bitlen, bytes, flags); slave->bus, slave->cs, bitlen, bytes, flags);
if (bitlen == 0) if (bitlen == 0)
goto done; goto done;
@ -142,25 +143,40 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
} }
/* empty read buffer */ /* empty read buffer */
if (readl(altspi->base + ALTERA_SPI_STATUS) & if (readl(&altspi->regs->status) & ALTERA_SPI_STATUS_RRDY_MSK)
ALTERA_SPI_STATUS_RRDY_MSK) readl(&altspi->regs->rxdata);
readl(altspi->base + ALTERA_SPI_RXDATA);
if (flags & SPI_XFER_BEGIN) if (flags & SPI_XFER_BEGIN)
spi_cs_activate(slave); spi_cs_activate(slave);
while (bytes--) { while (bytes--) {
uchar d = txp ? *txp++ : CONFIG_ALTERA_SPI_IDLE_VAL; if (txp)
debug("%s: tx:%x ", __func__, d); data = *txp++;
writel(d, altspi->base + ALTERA_SPI_TXDATA); else
while (!(readl(altspi->base + ALTERA_SPI_STATUS) & data = CONFIG_ALTERA_SPI_IDLE_VAL;
ALTERA_SPI_STATUS_RRDY_MSK))
; debug("%s: tx:%x ", __func__, data);
d = readl(altspi->base + ALTERA_SPI_RXDATA); writel(data, &altspi->regs->txdata);
start = get_timer(0);
while (1) {
reg = readl(&altspi->regs->status);
if (reg & ALTERA_SPI_STATUS_RRDY_MSK)
break;
if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
printf("%s: Transmission timed out!\n", __func__);
goto done;
}
}
data = readl(&altspi->regs->rxdata);
if (rxp) if (rxp)
*rxp++ = d; *rxp++ = data & 0xff;
debug("rx:%x\n", d);
debug("rx:%x\n", data);
} }
done:
done:
if (flags & SPI_XFER_END) if (flags & SPI_XFER_END)
spi_cs_deactivate(slave); spi_cs_deactivate(slave);

View file

@ -49,6 +49,8 @@ struct mxc_spi_slave {
#endif #endif
int gpio; int gpio;
int ss_pol; int ss_pol;
unsigned int max_hz;
unsigned int mode;
}; };
static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave)
@ -83,12 +85,13 @@ u32 get_cspi_div(u32 div)
} }
#ifdef MXC_CSPI #ifdef MXC_CSPI
static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs)
unsigned int max_hz, unsigned int mode)
{ {
unsigned int ctrl_reg; unsigned int ctrl_reg;
u32 clk_src; u32 clk_src;
u32 div; u32 div;
unsigned int max_hz = mxcs->max_hz;
unsigned int mode = mxcs->mode;
clk_src = mxc_get_clock(MXC_CSPI_CLK); clk_src = mxc_get_clock(MXC_CSPI_CLK);
@ -120,19 +123,15 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs,
#endif #endif
#ifdef MXC_ECSPI #ifdef MXC_ECSPI
static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs)
unsigned int max_hz, unsigned int mode)
{ {
u32 clk_src = mxc_get_clock(MXC_CSPI_CLK); u32 clk_src = mxc_get_clock(MXC_CSPI_CLK);
s32 reg_ctrl, reg_config; s32 reg_ctrl, reg_config;
u32 ss_pol = 0, sclkpol = 0, sclkpha = 0, sclkctl = 0; u32 ss_pol = 0, sclkpol = 0, sclkpha = 0, sclkctl = 0;
u32 pre_div = 0, post_div = 0; u32 pre_div = 0, post_div = 0;
struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
unsigned int max_hz = mxcs->max_hz;
if (max_hz == 0) { unsigned int mode = mxcs->mode;
printf("Error: desired clock is 0\n");
return -1;
}
/* /*
* Reset SPI and set all CSs to master mode, if toggling * Reset SPI and set all CSs to master mode, if toggling
@ -169,9 +168,6 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs,
reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_POSTDIV(0x0F)) | reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_POSTDIV(0x0F)) |
MXC_CSPICTRL_POSTDIV(post_div); MXC_CSPICTRL_POSTDIV(post_div);
/* We need to disable SPI before changing registers */
reg_ctrl &= ~MXC_CSPICTRL_EN;
if (mode & SPI_CS_HIGH) if (mode & SPI_CS_HIGH)
ss_pol = 1; ss_pol = 1;
@ -412,6 +408,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (bus >= ARRAY_SIZE(spi_bases)) if (bus >= ARRAY_SIZE(spi_bases))
return NULL; return NULL;
if (max_hz == 0) {
printf("Error: desired clock is 0\n");
return NULL;
}
mxcs = spi_alloc_slave(struct mxc_spi_slave, bus, cs); mxcs = spi_alloc_slave(struct mxc_spi_slave, bus, cs);
if (!mxcs) { if (!mxcs) {
puts("mxc_spi: SPI Slave not allocated !\n"); puts("mxc_spi: SPI Slave not allocated !\n");
@ -427,13 +428,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
} }
mxcs->base = spi_bases[bus]; mxcs->base = spi_bases[bus];
mxcs->max_hz = max_hz;
mxcs->mode = mode;
ret = spi_cfg_mxc(mxcs, cs, max_hz, mode);
if (ret) {
printf("mxc_spi: cannot setup SPI controller\n");
free(mxcs);
return NULL;
}
return &mxcs->slave; return &mxcs->slave;
} }
@ -446,12 +443,17 @@ void spi_free_slave(struct spi_slave *slave)
int spi_claim_bus(struct spi_slave *slave) int spi_claim_bus(struct spi_slave *slave)
{ {
int ret;
struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
reg_write(&regs->rxdata, 1); reg_write(&regs->rxdata, 1);
udelay(1); udelay(1);
reg_write(&regs->ctrl, mxcs->ctrl_reg); ret = spi_cfg_mxc(mxcs, slave->cs);
if (ret) {
printf("mxc_spi: cannot setup SPI controller\n");
return ret;
}
reg_write(&regs->period, MXC_CSPIPERIOD_32KHZ); reg_write(&regs->period, MXC_CSPIPERIOD_32KHZ);
reg_write(&regs->intr, 0); reg_write(&regs->intr, 0);