Commit 3e7a6262 authored by Federico Vaga's avatar Federico Vaga

Merge branch 'feature/spiflash' into develop

parents 02eb8c61 94d7d1c2
......@@ -13,6 +13,33 @@
#include "spec-compat.h"
#include "gn412x.h"
#define FCL_CTRL_START_FSM BIT(0)
#define FCL_CTRL_SPRI_EN BIT(1)
#define FCL_CTRL_FSM_EN BIT(2)
#define FCL_CTRL_SEND_CFG_DATA BIT(3)
#define FCL_CTRL_LAST_BYTE_CNT_1 (0x3 << 4)
#define FCL_CTRL_LAST_BYTE_CNT_2 (0x2 << 4)
#define FCL_CTRL_LAST_BYTE_CNT_3 (0x1 << 4)
#define FCL_CTRL_LAST_BYTE_CNT_4 (0x0 << 4)
#define FCL_CTRL_RESET BIT(6)
#define FCL_CTRL_DATA_PUSH_COMP BIT(7)
#define FCL_CTRL_SPRI_CLK_STOP_EN BIT(8)
#define FCL_SPRI_CLKOUT BIT(0)
#define FCL_SPRI_DATAOUT BIT(1)
#define FCL_SPRI_CONFIG BIT(2)
#define FCL_SPRI_DONE BIT(3)
#define FCL_SPRI_XI_SWAP BIT(4)
#define FCL_SPRI_STATUS BIT(5)
#define FCL_IRQ_SPRI_STATUS BIT(0)
#define FCL_IRQ_TIMER BIT(1)
#define FCL_IRQ_CONFIG_ERROR BIT(2)
#define FCL_IRQ_CONFIG_DONE BIT(3)
#define FCL_IRQ_FIFO_UNDRFL BIT(4)
#define FCL_IRQ_FIFO_HALFFULL BIT(5)
/* Compatibility layer */
static int gn412x_fcl_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
......@@ -122,8 +149,75 @@ struct gn412x_fcl_dev {
void __iomem *mem;
struct fpga_manager *mgr;
struct dentry *dbg_dir;
#define GN412X_DBG_REG_NAME "regs"
struct dentry *dbg_reg;
struct debugfs_regset32 dbg_reg32;
};
#define REG32(_name, _offset) {.name = _name, .offset = _offset}
static const struct debugfs_reg32 gn412x_debugfs_reg32[] = {
REG32("FCL_CTRL", FCL_CTRL),
REG32("FCL_STATUS", FCL_STATUS),
REG32("FCL_IODATA_IN", FCL_IODATA_IN),
REG32("FCL_IODATA_OUT", FCL_IODATA_OUT),
REG32("FCL_EN", FCL_EN),
REG32("FCL_TIMER0", FCL_TIMER_0),
REG32("FCL_TIMER1", FCL_TIMER_1),
REG32("FCL_CLK_DIV", FCL_CLK_DIV),
REG32("FCL_IRQ", FCL_IRQ),
REG32("FCL_TIMER_CTRL", FCL_TIMER_CTRL),
REG32("FCL_IM", FCL_IM),
REG32("FCL_TIMER2_0", FCL_TIMER2_0),
REG32("FCL_TIMER2_1", FCL_TIMER2_1),
REG32("FCL_DBG_STS", FCL_DBG_STS),
};
static int gn4124_dbg_init(struct platform_device *pdev)
{
struct gn412x_fcl_dev *gn412x = platform_get_drvdata(pdev);
struct dentry *dir, *file;
int err;
dir = debugfs_create_dir(dev_name(&pdev->dev), NULL);
if (IS_ERR_OR_NULL(dir)) {
err = PTR_ERR(dir);
dev_warn(&pdev->dev,
"Cannot create debugfs directory \"%s\" (%d)\n",
dev_name(&pdev->dev), err);
goto err_dir;
}
gn412x->dbg_reg32.regs = gn412x_debugfs_reg32;
gn412x->dbg_reg32.nregs = ARRAY_SIZE(gn412x_debugfs_reg32);
gn412x->dbg_reg32.base = gn412x->mem;
file = debugfs_create_regset32(GN412X_DBG_REG_NAME, 0200,
dir, &gn412x->dbg_reg32);
if (IS_ERR_OR_NULL(file)) {
err = PTR_ERR(file);
dev_warn(&pdev->dev,
"Cannot create debugfs file \"%s\" (%d)\n",
GN412X_DBG_REG_NAME, err);
goto err_reg32;
}
gn412x->dbg_dir = dir;
gn412x->dbg_reg = file;
return 0;
err_reg32:
debugfs_remove_recursive(dir);
err_dir:
return err;
}
static void gn4124_dbg_exit(struct platform_device *pdev)
{
struct gn412x_fcl_dev *gn412x = platform_get_drvdata(pdev);
debugfs_remove_recursive(gn412x->dbg_dir);
}
static uint32_t gn412x_ioread32(struct gn412x_fcl_dev *gn412x,
int reg)
{
......@@ -182,7 +276,6 @@ static void gn4124_fpga_reset(struct gn412x_fcl_dev *gn412x)
GNPCI_SYS_CFG_SYSTEM);
}
/**
* Initialize the gennum
* @gn412x: gn412x device instance
......@@ -193,31 +286,35 @@ static void gn4124_fpga_reset(struct gn412x_fcl_dev *gn412x)
static int gn4124_fpga_fcl_init(struct gn412x_fcl_dev *gn412x,
int last_word_size)
{
uint32_t ctrl;
uint32_t ctrl, en;
int i;
gn412x_iowrite32(gn412x, 0x00, FCL_CLK_DIV);
gn412x_iowrite32(gn412x, 0x40, FCL_CTRL); /* Reset */
gn412x_iowrite32(gn412x, FCL_CTRL_RESET, FCL_CTRL);
i = gn412x_ioread32(gn412x, FCL_CTRL);
if (i != 0x40) {
if (i != FCL_CTRL_RESET) {
pr_err("%s: %i: error\n", __func__, __LINE__);
return -EIO;
}
gn412x_iowrite32(gn412x, 0x00, FCL_CTRL);
gn412x_iowrite32(gn412x, 0x00, FCL_IRQ); /* clear pending irq */
ctrl = 0;
ctrl |= FCL_CTRL_SPRI_EN;
ctrl |= FCL_CTRL_FSM_EN;
ctrl |= FCL_CTRL_SPRI_CLK_STOP_EN;
switch (last_word_size) {
case 3:
ctrl = 0x116;
ctrl |= FCL_CTRL_LAST_BYTE_CNT_3;
break;
case 2:
ctrl = 0x126;
ctrl |= FCL_CTRL_LAST_BYTE_CNT_2;
break;
case 1:
ctrl = 0x136;
ctrl |= FCL_CTRL_LAST_BYTE_CNT_1;
break;
case 0:
ctrl = 0x106;
ctrl |= FCL_CTRL_LAST_BYTE_CNT_4;
break;
default: return -EINVAL;
}
......@@ -233,9 +330,14 @@ static int gn4124_fpga_fcl_init(struct gn412x_fcl_dev *gn412x,
*/
gn412x_iowrite32(gn412x, 0x08, FCL_TIMER2_0);
gn412x_iowrite32(gn412x, 0x00, FCL_TIMER2_1);
gn412x_iowrite32(gn412x, 0x17, FCL_EN);
ctrl |= 0x01; /* "start FSM configuration" */
en = 0;
en |= FCL_SPRI_CLKOUT;
en |= FCL_SPRI_DATAOUT;
en |= FCL_SPRI_CONFIG;
en |= FCL_SPRI_XI_SWAP;
gn412x_iowrite32(gn412x, en, FCL_EN);
ctrl |= FCL_CTRL_START_FSM;
gn412x_iowrite32(gn412x, ctrl, FCL_CTRL);
return 0;
......@@ -292,12 +394,12 @@ static int gn4124_fpga_load(struct gn412x_fcl_dev *gn412x,
/* Check to see if FPGA configuation has error */
int i = gn412x_ioread32(gn412x, FCL_IRQ);
if ((i & 8) && wrote) {
if ((i & FCL_IRQ_CONFIG_DONE) && wrote) {
done = 1;
pr_err("%s: %i: done after %i%i\n",
__func__, __LINE__,
wrote, ((len + 3) >> 2));
} else if ((i & 0x4) && !done) {
} else if ((i & FCL_IRQ_CONFIG_ERROR) && !done) {
pr_err("%s: %i: error after %i/%i\n",
__func__, __LINE__,
wrote, ((len + 3) >> 2));
......@@ -305,7 +407,7 @@ static int gn4124_fpga_load(struct gn412x_fcl_dev *gn412x,
}
/* Wait until at least 1/2 of the fifo is empty */
while (gn412x_ioread32(gn412x, FCL_IRQ) & (1<<5))
while (gn412x_ioread32(gn412x, FCL_IRQ) & FCL_IRQ_FIFO_HALFFULL)
;
/* Write a few dwords into FIFO at a time. */
......@@ -326,7 +428,13 @@ static int gn4124_fpga_load(struct gn412x_fcl_dev *gn412x,
*/
static void gn4124_fpga_fcl_complete(struct gn412x_fcl_dev *gn412x)
{
gn412x_iowrite32(gn412x, 0x186, FCL_CTRL); /* "last data written" */
uint32_t ctrl = 0;
ctrl |= FCL_CTRL_SPRI_EN;
ctrl |= FCL_CTRL_FSM_EN;
ctrl |= FCL_CTRL_DATA_PUSH_COMP;
ctrl |= FCL_CTRL_SPRI_CLK_STOP_EN;
gn412x_iowrite32(gn412x, ctrl, FCL_CTRL);
}
......@@ -363,6 +471,12 @@ static int gn412x_fcl_write(struct fpga_manager *mgr,
}
static void gn4124_fcl_reset(struct gn412x_fcl_dev *gn412x)
{
gn412x_iowrite32(gn412x, 0x00, FCL_CTRL);
gn412x_iowrite32(gn412x, 0x00, FCL_EN);
}
static int gn412x_fcl_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info)
{
......@@ -375,6 +489,7 @@ static int gn412x_fcl_write_complete(struct fpga_manager *mgr,
if (err < 0)
return err;
gn4124_fcl_reset(gn412x);
gn4124_fpga_reset(gn412x);
return 0;
......@@ -421,6 +536,9 @@ static int gn412x_fcl_probe(struct platform_device *pdev)
goto err_map;
}
gn4124_fcl_reset(gn412x);
gn4124_dbg_init(pdev);
gn412x->mgr = compat_fpga_mgr_create(&pdev->dev,
dev_name(&pdev->dev),
......@@ -439,6 +557,7 @@ static int gn412x_fcl_probe(struct platform_device *pdev)
err_fpga_reg:
compat_fpga_mgr_free(gn412x->mgr);
err_fpga_create:
gn4124_dbg_exit(pdev);
devm_iounmap(&pdev->dev, gn412x->mem);
err_map:
err_res_mem:
......@@ -450,6 +569,8 @@ static int gn412x_fcl_remove(struct platform_device *pdev)
{
struct gn412x_fcl_dev *gn412x = platform_get_drvdata(pdev);
gn4124_dbg_exit(pdev);
if (!gn412x->mgr)
return -ENODEV;
......
......@@ -323,10 +323,12 @@ static struct resource spec_fpga_fmc_i2c_res[] = {
},
};
#define SPEC_FPGA_WB_CLK_HZ 62500000
#define SPEC_FPGA_WB_CLK_KHZ (SPEC_FPGA_WB_CLK_HZ / 1000)
static struct ocores_i2c_platform_data spec_fpga_fmc_i2c_pdata = {
.reg_shift = 2, /* 32bit aligned */
.reg_io_width = 4,
.clock_khz = 62500,
.clock_khz = SPEC_FPGA_WB_CLK_KHZ,
.big_endian = 0,
.num_devices = 0,
.devices = NULL,
......@@ -356,7 +358,7 @@ struct flash_platform_data spec_flash_pdata = {
static struct spi_board_info spec_fpga_spi_devices_info[] = {
{
.modalias = "m25p32",
.max_speed_hz = 75000000,
.max_speed_hz = SPEC_FPGA_WB_CLK_HZ / 128,
.chip_select = 0,
.platform_data = &spec_flash_pdata,
}
......@@ -364,7 +366,7 @@ static struct spi_board_info spec_fpga_spi_devices_info[] = {
static struct spi_ocores_platform_data spec_fpga_spi_pdata = {
.big_endian = 0,
.clock_hz = 65200000,
.clock_hz = SPEC_FPGA_WB_CLK_HZ,
.num_devices = ARRAY_SIZE(spec_fpga_spi_devices_info),
.devices = spec_fpga_spi_devices_info,
};
......
......@@ -48,16 +48,15 @@ struct spi_ocores {
/* Current transfer */
struct spi_transfer *cur_xfer;
uint32_t cur_ctrl;
uint32_t cur_divider;
const void *cur_tx_buf;
unsigned int cur_tx_len;
void *cur_rx_buf;
unsigned int cur_rx_len;
unsigned int cur_len;
size_t (*cur_tx_push)(struct spi_ocores *sp);
size_t (*cur_rx_pop)(struct spi_ocores *sp);
/* Register Access functions */
uint32_t (*read)(struct spi_ocores *sp, unsigned int reg);
void (*write)(struct spi_ocores *sp, unsigned int reg, uint32_t val);
void (*write)(struct spi_ocores *sp, uint32_t val, unsigned int reg);
};
enum spi_ocores_type {
......@@ -71,7 +70,7 @@ static inline uint32_t spi_ocores_ioread32(struct spi_ocores *sp,
}
static inline void spi_ocores_iowrite32(struct spi_ocores *sp,
unsigned int reg, uint32_t val)
uint32_t val, unsigned int reg)
{
iowrite32(val, sp->mem + reg);
}
......@@ -83,7 +82,7 @@ static inline uint32_t spi_ocores_ioread32be(struct spi_ocores *sp,
}
static inline void spi_ocores_iowrite32be(struct spi_ocores *sp,
unsigned int reg, uint32_t val)
uint32_t val, unsigned int reg)
{
iowrite32be(val, sp->mem + reg);
}
......@@ -167,11 +166,15 @@ static void spi_ocores_tx_set(struct spi_ocores *sp,
*/
static uint32_t spi_ocores_rx_get(struct spi_ocores *sp, unsigned int idx)
{
uint32_t val;
if (WARN(idx > 3, "Invalid RX register index %d (min:0, max: 3)\n",
idx))
return 0;
return sp->read(sp, SPI_OCORES_RX(idx));
val = sp->read(sp, SPI_OCORES_RX(idx));
return val;
}
/**
......@@ -191,172 +194,158 @@ static uint8_t spi_ocores_hw_xfer_bits_per_word(struct spi_ocores *sp)
return nbits;
}
static void spi_ocores_hw_xfer_tx_push8(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_tx_push8(struct spi_ocores *sp)
{
uint32_t data;
uint8_t data;
data = *((uint8_t *)sp->cur_tx_buf);
sp->cur_tx_buf += 1;
data = ((uint8_t *)sp->cur_tx_buf)[0];
spi_ocores_tx_set(sp, 0, data);
sp->cur_tx_len -= 1;
return sizeof(data);
}
static void spi_ocores_hw_xfer_tx_push16(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_tx_push16(struct spi_ocores *sp)
{
uint32_t data;
uint16_t data;
data = *((uint16_t *)sp->cur_tx_buf);
sp->cur_tx_buf += 2;
spi_ocores_tx_set(sp, 0, data);
sp->cur_tx_len -= 2;
data = ((uint16_t *)sp->cur_tx_buf)[0];
spi_ocores_tx_set(sp, 0, __cpu_to_be16(data));
return sizeof(data);
}
static void spi_ocores_hw_xfer_tx_push32(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_tx_push32(struct spi_ocores *sp)
{
uint32_t data;
data = *((uint32_t *)sp->cur_tx_buf);
sp->cur_tx_buf += 4;
spi_ocores_tx_set(sp, 0, data);
sp->cur_tx_len -= 4;
data = ((uint32_t *)sp->cur_tx_buf)[0];
spi_ocores_tx_set(sp, 0, __cpu_to_be32(data));
return sizeof(data);
}
static void spi_ocores_hw_xfer_tx_push64(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_tx_push64(struct spi_ocores *sp)
{
int i;
uint64_t data;
for (i = 0; i < 2; ++i) {
uint32_t data;
data = __cpu_to_be64(*((uint64_t *)sp->cur_tx_buf));
spi_ocores_tx_set(sp, 0, data & 0xFFFFFFFF);
data >>= 32;
spi_ocores_tx_set(sp, 1, data & 0xFFFFFFFF);
data = *((uint32_t *)sp->cur_tx_buf);
sp->cur_tx_buf += 4;
spi_ocores_tx_set(sp, i, data);
sp->cur_tx_len -= 4;
}
return sizeof(data);
}
static void spi_ocores_hw_xfer_tx_push128(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_tx_push128(struct spi_ocores *sp)
{
int i;
uint64_t data;
for (i = 0; i < 4; ++i) {
uint32_t data;
data = __cpu_to_be64(((uint64_t *)sp->cur_tx_buf)[0]);
spi_ocores_tx_set(sp, 2, data & 0xFFFFFFFF);
data >>= 32;
spi_ocores_tx_set(sp, 3, data & 0xFFFFFFFF);
data = *((uint32_t *)sp->cur_tx_buf);
sp->cur_tx_buf += 4;
spi_ocores_tx_set(sp, i, data);
sp->cur_tx_len -= 4;
}
data = __cpu_to_be64(((uint64_t *)sp->cur_tx_buf)[1]);
spi_ocores_tx_set(sp, 0, data & 0xFFFFFFFF);
data >>= 32;
spi_ocores_tx_set(sp, 1, data & 0xFFFFFFFF);
return sizeof(data) * 2;
}
static void spi_ocores_hw_xfer_rx_push8(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_tx_push(struct spi_ocores *sp)
{
uint32_t data;
size_t len = 0;
if (sp->cur_tx_buf)
len = sp->cur_tx_push(sp);
sp->cur_tx_buf += len;
return len;
}
static size_t spi_ocores_hw_xfer_rx_pop8(struct spi_ocores *sp)
{
uint8_t data;
data = spi_ocores_rx_get(sp, 0) & 0x000000FF;
*((uint8_t *)sp->cur_rx_buf) = data;
sp->cur_rx_buf += 1;
sp->cur_rx_len -= 1;
((uint8_t *)sp->cur_rx_buf)[0] = data;
return sizeof(data);
}
static void spi_ocores_hw_xfer_rx_push16(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_rx_pop16(struct spi_ocores *sp)
{
uint32_t data;
uint16_t data;
data = spi_ocores_rx_get(sp, 0) & 0x0000FFFF;
*((uint16_t *)sp->cur_rx_buf) = data;
sp->cur_rx_buf += 2;
sp->cur_rx_len -= 2;
((uint16_t *)sp->cur_rx_buf)[0] = __be16_to_cpu(data);
return sizeof(data);
}
static void spi_ocores_hw_xfer_rx_push32(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_rx_pop32(struct spi_ocores *sp)
{
uint32_t data;
data = spi_ocores_rx_get(sp, 0) & 0xFFFFFFFF;
*((uint32_t *)sp->cur_rx_buf) = data;
sp->cur_rx_buf += 4;
sp->cur_rx_len -= 4;
((uint32_t *)sp->cur_rx_buf)[0] = __be32_to_cpu(data);
return sizeof(data);
}
static void spi_ocores_hw_xfer_rx_push64(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_rx_pop64(struct spi_ocores *sp)
{
int i;
uint64_t data;
for (i = 0; i < 2; ++i) {
uint32_t data;
data = spi_ocores_rx_get(sp, 1) & 0xFFFFFFFF;
data <<= 32;
data |= spi_ocores_rx_get(sp, 0) & 0xFFFFFFFF;
((uint64_t *)sp->cur_rx_buf)[0] = __be64_to_cpu(data);
data = spi_ocores_rx_get(sp, i) & 0xFFFFFFFF;
*((uint32_t *)sp->cur_rx_buf) = data;
sp->cur_rx_buf += 4;
sp->cur_rx_len -= 4;
}
return sizeof(data);
}
static void spi_ocores_hw_xfer_rx_push128(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_rx_pop128(struct spi_ocores *sp)
{
int i;
uint64_t data;
for (i = 0; i < 4; ++i) {
uint32_t data;
data = spi_ocores_rx_get(sp, 3) & 0xFFFFFFFF;
data <<= 32;
data |= spi_ocores_rx_get(sp, 2) & 0xFFFFFFFF;
((uint64_t *)sp->cur_rx_buf)[1] = __be64_to_cpu(data);
data = spi_ocores_rx_get(sp, i) & 0xFFFFFFFF;
*((uint32_t *)sp->cur_rx_buf) = data;
sp->cur_rx_buf += 4;
sp->cur_rx_len -= 4;
}
data = spi_ocores_rx_get(sp, 1) & 0xFFFFFFFF;
data <<= 32;
data |= spi_ocores_rx_get(sp, 0) & 0xFFFFFFFF;
((uint64_t *)sp->cur_rx_buf)[0] = __be64_to_cpu(data);
return sizeof(data) * 2;
}
/**
* Write pending data in RX registers
* @sp: SPI OCORE controller
*/
static void spi_ocores_hw_xfer_tx_push(struct spi_ocores *sp)
static size_t spi_ocores_hw_xfer_rx_pop(struct spi_ocores *sp)
{
size_t len = 0;
uint8_t nbits;
/*
* When we read is because a complete HW transfer is over, so we
* can safely decrease the counter of pending bytes
*/
nbits = spi_ocores_hw_xfer_bits_per_word(sp);
if (nbits >= 8)
spi_ocores_hw_xfer_tx_push8(sp);
else if (nbits >= 16)
spi_ocores_hw_xfer_tx_push16(sp);
else if (nbits >= 32)
spi_ocores_hw_xfer_tx_push32(sp);
else if (nbits >= 64)
spi_ocores_hw_xfer_tx_push64(sp);
else if (nbits >= 128)
spi_ocores_hw_xfer_tx_push128(sp);
}
sp->cur_len -= (nbits / 8); /* FIXME not working for !pow2 */
/**
* Read received data from TX registers
* @sp: SPI OCORE controller
*/
static void spi_ocores_hw_xfer_rx_pop(struct spi_ocores *sp)
{
uint8_t nbits;
if (sp->cur_rx_buf)
len = sp->cur_rx_pop(sp);
sp->cur_rx_buf += len;
nbits = spi_ocores_hw_xfer_bits_per_word(sp);
if (nbits >= 8)
spi_ocores_hw_xfer_rx_push8(sp);
else if (nbits >= 16)
spi_ocores_hw_xfer_rx_push16(sp);
else if (nbits >= 32)
spi_ocores_hw_xfer_rx_push32(sp);
else if (nbits >= 64)
spi_ocores_hw_xfer_rx_push64(sp);
else if (nbits >= 128)
spi_ocores_hw_xfer_rx_push128(sp);
return len;
}
static void spi_ocores_hw_xfer_start(struct spi_ocores *sp)
{
unsigned int cs = sp->master->cur_msg->spi->chip_select;
/* Optimize:
* Probably we can avoid to write CTRL DIVIDER and CS everytime
*/
spi_ocores_hw_xfer_config(sp, sp->cur_ctrl, sp->cur_divider);
spi_ocores_hw_xfer_cs(sp, cs, 1);
spi_ocores_hw_xfer_go(sp);
}
......@@ -425,13 +414,9 @@ static int spi_ocores_sw_xfer_finish(struct spi_ocores *sp)
spi_ocores_hw_xfer_cs(sp, cs, 0);
}
spi_ocores_hw_xfer_config(sp, 0, 0);
sp->cur_xfer = NULL;
sp->cur_tx_buf = NULL;
sp->cur_tx_len = 0;
sp->cur_rx_buf = NULL;
sp->cur_rx_len = 0;
sp->cur_len = 0;
return 0;
}
......@@ -447,17 +432,14 @@ static int spi_ocores_sw_xfer_finish(struct spi_ocores *sp)
static int spi_ocores_sw_xfer_next_init(struct spi_ocores *sp)
{
struct list_head *head = &sp->master->cur_msg->transfers;
uint32_t hz;
if (spi_ocores_hw_xfer_bits_per_word(sp) > 128)
return -EINVAL;
uint8_t nbits;
uint16_t divider;
uint32_t hz, ctrl;
if (!sp->cur_xfer) {
sp->cur_xfer = list_first_entry_or_null(head,
struct spi_transfer,
transfer_list);
if (!sp->cur_xfer)
return -ENODATA;
} else {
if (list_is_last(&sp->cur_xfer->transfer_list, head))
return -ENODATA;
......@@ -465,17 +447,62 @@ static int spi_ocores_sw_xfer_next_init(struct spi_ocores *sp)
sp->cur_xfer = list_next_entry(sp->cur_xfer, transfer_list);
}
sp->cur_ctrl = sp->ctrl_base;
sp->cur_ctrl |= spi_ocores_hw_xfer_bits_per_word(sp);
if (WARN(!sp->cur_xfer, "Invalid SPI transfer")) {
sp->master->cur_msg->status = -EINVAL;
return sp->master->cur_msg->status;
}
nbits = spi_ocores_hw_xfer_bits_per_word(sp);
if ((nbits - 1) & (~SPI_OCORES_CTRL_CHAR_LEN)) {
sp->master->cur_msg->status = -EINVAL;
return sp->master->cur_msg->status;
}
if ((sp->cur_xfer->len << 3) < nbits) {
dev_err(&sp->master->dev,
"Invalid transfer length %d (bits_per_word %d)\n",
sp->cur_xfer->len, nbits);
sp->master->cur_msg->status = -EINVAL;
return sp->master->cur_msg->status;
}
ctrl = sp->ctrl_base;
if (sp->master->cur_msg->spi->mode & SPI_CPHA) {
ctrl |= SPI_OCORES_CTRL_Tx_NEG;
ctrl |= SPI_OCORES_CTRL_Rx_NEG;
}
if (sp->master->cur_msg->spi->mode & SPI_LSB_FIRST)
ctrl |= SPI_OCORES_CTRL_LSB;
ctrl |= nbits;
if (sp->cur_xfer->speed_hz)
hz = sp->cur_xfer->speed_hz;
else
hz = sp->master->cur_msg->spi->max_speed_hz;
sp->cur_divider = 1 + (sp->clock_hz / (hz * 2));
divider = (sp->clock_hz / (hz * 2)) - 1;
spi_ocores_hw_xfer_config(sp, ctrl, divider);
sp->cur_tx_buf = sp->cur_xfer->tx_buf;
sp->cur_tx_len = sp->cur_xfer->len;
sp->cur_rx_buf = sp->cur_xfer->rx_buf;
sp->cur_rx_len = sp->cur_xfer->len;
sp->cur_len = sp->cur_xfer->len;
/* set operations */
if (nbits <= 8) {
sp->cur_tx_push = spi_ocores_hw_xfer_tx_push8;
sp->cur_rx_pop = spi_ocores_hw_xfer_rx_pop8;
} else if (nbits <= 16) {
sp->cur_tx_push = spi_ocores_hw_xfer_tx_push16;
sp->cur_rx_pop = spi_ocores_hw_xfer_rx_pop16;
} else if (nbits <= 32) {
sp->cur_tx_push = spi_ocores_hw_xfer_tx_push32;
sp->cur_rx_pop = spi_ocores_hw_xfer_rx_pop32;
} else if (nbits <= 64) {
sp->cur_tx_push = spi_ocores_hw_xfer_tx_push64;
sp->cur_rx_pop = spi_ocores_hw_xfer_rx_pop64;
} else if (nbits <= 128) {
sp->cur_tx_push = spi_ocores_hw_xfer_tx_push128;
sp->cur_rx_pop = spi_ocores_hw_xfer_rx_pop128;
}
return 0;
}
......@@ -491,10 +518,8 @@ static int spi_ocores_sw_xfer_next_start(struct spi_ocores *sp)
int err;
err = spi_ocores_sw_xfer_next_init(sp);
if (err) {
spi_finalize_current_message(sp->master);
if (err)
return err;
}
spi_ocores_hw_xfer_tx_push(sp);
spi_ocores_hw_xfer_start(sp);
......@@ -506,9 +531,49 @@ static int spi_ocores_sw_xfer_next_start(struct spi_ocores *sp)
* @sp: SPI OCORE controller
* Return: True is there are still pending data in the current transfer
*/
static bool spi_ocores_sw_xfer_tx_pending(struct spi_ocores *sp)
static bool spi_ocores_sw_xfer_has_pending(struct spi_ocores *sp)
{
return sp->cur_tx_len;
return sp->cur_len > 0;
}
/**
* Finalize message transmission
* @sp: SPI OCORE controller
*/
static void spi_ocores_finalize_current_message(struct spi_ocores *sp)
{
unsigned int cs = sp->master->cur_msg->spi->chip_select;
spi_ocores_hw_xfer_cs(sp, cs, 0);
sp->cur_xfer = NULL;
sp->master->cur_msg->status = 0;
spi_finalize_current_message(sp->master);
}
static bool spi_ocores_is_busy(struct spi_ocores *sp)
{
uint32_t ctrl = sp->read(sp, SPI_OCORES_CTRL);
return (ctrl & SPI_OCORES_CTRL_BUSY);
}
/**
* Pop RX word and push next TX from current transfer
* @sp: SPI OCORE controller
*
* Return: 0 on success, -ENODATA when there is nothing to process
*/
static int spi_ocores_hw_xfer_rxtx(struct spi_ocores *sp)
{
spi_ocores_hw_xfer_rx_pop(sp);
if (spi_ocores_sw_xfer_has_pending(sp))
return -ENODATA;
spi_ocores_hw_xfer_tx_push(sp);
spi_ocores_hw_xfer_start(sp);
return 0;
}
/**
......@@ -519,18 +584,17 @@ static bool spi_ocores_sw_xfer_tx_pending(struct spi_ocores *sp)
*/
static int spi_ocores_process(struct spi_ocores *sp)
{
uint32_t ctrl = sp->read(sp, SPI_OCORES_CTRL);
int err;
if (ctrl & SPI_OCORES_CTRL_BUSY)
return -ENODATA;
if (spi_ocores_is_busy(sp))
return -EBUSY;
spi_ocores_hw_xfer_rx_pop(sp);
if (spi_ocores_sw_xfer_tx_pending(sp)) {
spi_ocores_hw_xfer_tx_push(sp);
spi_ocores_hw_xfer_start(sp);
} else {
err = spi_ocores_hw_xfer_rxtx(sp);
if (err == -ENODATA) {
spi_ocores_sw_xfer_finish(sp);
spi_ocores_sw_xfer_next_start(sp);
err = spi_ocores_sw_xfer_next_start(sp);
if (err)
spi_ocores_finalize_current_message(sp);
}
return 0;
......@@ -563,7 +627,7 @@ static irqreturn_t spi_ocores_irq_handler(int irq, void *arg)
int err;
err = spi_ocores_process(sp);
if (err)
if (err && err != -ENODATA)
return IRQ_NONE;
return IRQ_HANDLED;
......@@ -588,6 +652,20 @@ static int spi_ocores_transfer_one_message(struct spi_master *master,
return 0;
}
/**
* Unprepare hardware
*
* Mainly it disables interrupts
*/
static int spi_ocores_unprepare_transfer_hardware(struct spi_master *master)
{
struct spi_ocores *sp = spi_master_get_devdata(master);
spi_ocores_hw_xfer_config(sp, 0, 0);
return 0;
}
static int spi_ocores_probe(struct platform_device *pdev)
{
struct spi_master *master;
......@@ -598,7 +676,6 @@ static int spi_ocores_probe(struct platform_device *pdev)
int irq;
int i;
pr_info("%s:%d\n", __func__, __LINE__);
master = spi_alloc_master(&pdev->dev, sizeof(*sp));
if (!master) {
dev_err(&pdev->dev, "failed to allocate spi master\n");
......@@ -621,8 +698,9 @@ static int spi_ocores_probe(struct platform_device *pdev)
master->setup = spi_ocores_setup;
master->cleanup = spi_ocores_cleanup;
master->transfer_one_message = spi_ocores_transfer_one_message;
master->unprepare_transfer_hardware = spi_ocores_unprepare_transfer_hardware;
master->num_chipselect = SPI_OCORES_CS_MAX_N;
master->bits_per_word_mask = BIT(32 - 1);
master->mode_bits = SPI_LSB_FIRST | SPI_CPHA;
if (pdata->big_endian) {
sp->read = spi_ocores_ioread32be;
sp->write = spi_ocores_iowrite32be;
......@@ -676,16 +754,13 @@ static int spi_ocores_probe(struct platform_device *pdev)
return 0;
err_reg_spi:
pr_info("%s:%d\n", __func__, __LINE__);
if (!(sp->flags & SPI_OCORES_FLAG_POLL))
free_irq(irq, sp);
err_irq:
err_get_irq:
pr_info("%s:%d\n", __func__, __LINE__);
devm_iounmap(&pdev->dev, sp->mem);
err_get_mem:
err_get_pdata:
pr_info("%s:%d\n", __func__, __LINE__);
spi_master_put(master);
return err;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment