drivers: spi_dw: Manage MMIO and 64 bit platforms
This patch manages DW SPI driver MMIO region. As a result, the driver now runs properly on 64 bit platforms. Signed-off-by: Julien Panis <jpanis@baylibre.com>
This commit is contained in:
parent
62e7b788aa
commit
30b6cd2647
3 changed files with 74 additions and 65 deletions
|
|
@ -48,7 +48,6 @@ static inline bool spi_dw_is_slave(struct spi_dw_data *spi)
|
|||
|
||||
static void completed(const struct device *dev, int error)
|
||||
{
|
||||
const struct spi_dw_config *info = dev->config;
|
||||
struct spi_dw_data *spi = dev->data;
|
||||
struct spi_context *ctx = &spi->ctx;
|
||||
|
||||
|
|
@ -63,19 +62,19 @@ static void completed(const struct device *dev, int error)
|
|||
|
||||
out:
|
||||
/* need to give time for FIFOs to drain before issuing more commands */
|
||||
while (test_bit_sr_busy(info)) {
|
||||
while (test_bit_sr_busy(dev)) {
|
||||
}
|
||||
|
||||
/* Disabling interrupts */
|
||||
write_imr(info, DW_SPI_IMR_MASK);
|
||||
write_imr(dev, DW_SPI_IMR_MASK);
|
||||
/* Disabling the controller */
|
||||
clear_bit_ssienr(info);
|
||||
clear_bit_ssienr(dev);
|
||||
|
||||
if (!spi_dw_is_slave(spi)) {
|
||||
if (spi_cs_is_gpio(ctx->config)) {
|
||||
spi_context_cs_control(ctx, false);
|
||||
} else {
|
||||
write_ser(info, 0);
|
||||
write_ser(dev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,13 +92,13 @@ static void push_data(const struct device *dev)
|
|||
uint32_t f_tx;
|
||||
|
||||
if (spi_context_rx_on(&spi->ctx)) {
|
||||
f_tx = info->fifo_depth - read_txflr(info) -
|
||||
read_rxflr(info);
|
||||
f_tx = info->fifo_depth - read_txflr(dev) -
|
||||
read_rxflr(dev);
|
||||
if ((int)f_tx < 0) {
|
||||
f_tx = 0U; /* if rx-fifo is full, hold off tx */
|
||||
}
|
||||
} else {
|
||||
f_tx = info->fifo_depth - read_txflr(info);
|
||||
f_tx = info->fifo_depth - read_txflr(dev);
|
||||
}
|
||||
|
||||
while (f_tx) {
|
||||
|
|
@ -132,7 +131,7 @@ static void push_data(const struct device *dev)
|
|||
break;
|
||||
}
|
||||
|
||||
write_dr(info, data);
|
||||
write_dr(dev, data);
|
||||
|
||||
spi_context_update_tx(&spi->ctx, spi->dfs, 1);
|
||||
spi->fifo_diff++;
|
||||
|
|
@ -142,7 +141,7 @@ static void push_data(const struct device *dev)
|
|||
|
||||
if (!spi_context_tx_on(&spi->ctx)) {
|
||||
/* prevents any further interrupts demanding TX fifo fill */
|
||||
write_txftlr(info, 0);
|
||||
write_txftlr(dev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,8 +150,8 @@ static void pull_data(const struct device *dev)
|
|||
const struct spi_dw_config *info = dev->config;
|
||||
struct spi_dw_data *spi = dev->data;
|
||||
|
||||
while (read_rxflr(info)) {
|
||||
uint32_t data = read_dr(info);
|
||||
while (read_rxflr(dev)) {
|
||||
uint32_t data = read_dr(dev);
|
||||
|
||||
if (spi_context_rx_buf_on(&spi->ctx)) {
|
||||
switch (spi->dfs) {
|
||||
|
|
@ -173,16 +172,17 @@ static void pull_data(const struct device *dev)
|
|||
}
|
||||
|
||||
if (!spi->ctx.rx_len && spi->ctx.tx_len < info->fifo_depth) {
|
||||
write_rxftlr(info, spi->ctx.tx_len - 1);
|
||||
} else if (read_rxftlr(info) >= spi->ctx.rx_len) {
|
||||
write_rxftlr(info, spi->ctx.rx_len - 1);
|
||||
write_rxftlr(dev, spi->ctx.tx_len - 1);
|
||||
} else if (read_rxftlr(dev) >= spi->ctx.rx_len) {
|
||||
write_rxftlr(dev, spi->ctx.rx_len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int spi_dw_configure(const struct spi_dw_config *info,
|
||||
static int spi_dw_configure(const struct device *dev,
|
||||
struct spi_dw_data *spi,
|
||||
const struct spi_config *config)
|
||||
{
|
||||
const struct spi_dw_config *info = dev->config;
|
||||
uint32_t ctrlr0 = 0U;
|
||||
|
||||
LOG_DBG("%p (prev %p)", config, spi->ctx.config);
|
||||
|
|
@ -248,15 +248,15 @@ static int spi_dw_configure(const struct spi_dw_config *info,
|
|||
}
|
||||
|
||||
/* Installing the configuration */
|
||||
write_ctrlr0(info, ctrlr0);
|
||||
write_ctrlr0(dev, ctrlr0);
|
||||
|
||||
/* At this point, it's mandatory to set this on the context! */
|
||||
spi->ctx.config = config;
|
||||
|
||||
if (!spi_dw_is_slave(spi)) {
|
||||
/* Baud rate and Slave select, for master only */
|
||||
write_baudr(info, SPI_DW_CLK_DIVIDER(info->clock_frequency,
|
||||
config->frequency));
|
||||
write_baudr(dev, SPI_DW_CLK_DIVIDER(info->clock_frequency,
|
||||
config->frequency));
|
||||
}
|
||||
|
||||
if (spi_dw_is_slave(spi)) {
|
||||
|
|
@ -309,9 +309,10 @@ error:
|
|||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
static void spi_dw_update_txftlr(const struct spi_dw_config *info,
|
||||
static void spi_dw_update_txftlr(const struct device *dev,
|
||||
struct spi_dw_data *spi)
|
||||
{
|
||||
const struct spi_dw_config *info = dev->config;
|
||||
uint32_t dw_spi_txftlr_dflt = (info->fifo_depth * 1) / 2;
|
||||
uint32_t reg_data = dw_spi_txftlr_dflt;
|
||||
|
||||
|
|
@ -325,7 +326,7 @@ static void spi_dw_update_txftlr(const struct spi_dw_config *info,
|
|||
|
||||
LOG_DBG("TxFTLR: %u", reg_data);
|
||||
|
||||
write_txftlr(info, reg_data);
|
||||
write_txftlr(dev, reg_data);
|
||||
}
|
||||
|
||||
static int transceive(const struct device *dev,
|
||||
|
|
@ -352,7 +353,7 @@ static int transceive(const struct device *dev,
|
|||
#endif /* CONFIG_PM_DEVICE */
|
||||
|
||||
/* Configure */
|
||||
ret = spi_dw_configure(info, spi, config);
|
||||
ret = spi_dw_configure(dev, spi, config);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -375,9 +376,9 @@ static int transceive(const struct device *dev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
write_ctrlr1(info, reg_data);
|
||||
write_ctrlr1(dev, reg_data);
|
||||
} else {
|
||||
write_ctrlr1(info, 0);
|
||||
write_ctrlr1(dev, 0);
|
||||
}
|
||||
|
||||
if (spi_dw_is_slave(spi)) {
|
||||
|
|
@ -390,11 +391,11 @@ static int transceive(const struct device *dev,
|
|||
}
|
||||
|
||||
/* Updating TMOD in CTRLR0 register */
|
||||
reg_data = read_ctrlr0(info);
|
||||
reg_data = read_ctrlr0(dev);
|
||||
reg_data &= ~DW_SPI_CTRLR0_TMOD_RESET;
|
||||
reg_data |= tmod;
|
||||
|
||||
write_ctrlr0(info, reg_data);
|
||||
write_ctrlr0(dev, reg_data);
|
||||
|
||||
/* Set buffers info */
|
||||
spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, spi->dfs);
|
||||
|
|
@ -402,7 +403,7 @@ static int transceive(const struct device *dev,
|
|||
spi->fifo_diff = 0U;
|
||||
|
||||
/* Tx Threshold */
|
||||
spi_dw_update_txftlr(info, spi);
|
||||
spi_dw_update_txftlr(dev, spi);
|
||||
|
||||
/* Does Rx thresholds needs to be lower? */
|
||||
reg_data = dw_spi_rxftlr_dflt;
|
||||
|
|
@ -419,25 +420,25 @@ static int transceive(const struct device *dev,
|
|||
}
|
||||
|
||||
/* Rx Threshold */
|
||||
write_rxftlr(info, reg_data);
|
||||
write_rxftlr(dev, reg_data);
|
||||
|
||||
/* Enable interrupts */
|
||||
reg_data = !rx_bufs ?
|
||||
DW_SPI_IMR_UNMASK & DW_SPI_IMR_MASK_RX :
|
||||
DW_SPI_IMR_UNMASK;
|
||||
write_imr(info, reg_data);
|
||||
write_imr(dev, reg_data);
|
||||
|
||||
if (!spi_dw_is_slave(spi)) {
|
||||
/* if cs is not defined as gpio, use hw cs */
|
||||
if (spi_cs_is_gpio(config)) {
|
||||
spi_context_cs_control(&spi->ctx, true);
|
||||
} else {
|
||||
write_ser(info, BIT(config->slave));
|
||||
write_ser(dev, BIT(config->slave));
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DBG("Enabling controller");
|
||||
set_bit_ssienr(info);
|
||||
set_bit_ssienr(dev);
|
||||
|
||||
ret = spi_context_wait_for_completion(&spi->ctx);
|
||||
|
||||
|
|
@ -495,14 +496,13 @@ static int spi_dw_release(const struct device *dev,
|
|||
|
||||
void spi_dw_isr(const struct device *dev)
|
||||
{
|
||||
const struct spi_dw_config *info = dev->config;
|
||||
uint32_t int_status;
|
||||
int error;
|
||||
|
||||
int_status = read_isr(info);
|
||||
int_status = read_isr(dev);
|
||||
|
||||
LOG_DBG("SPI %p int_status 0x%x - (tx: %d, rx: %d)", dev, int_status,
|
||||
read_txflr(info), read_rxflr(info));
|
||||
read_txflr(dev), read_rxflr(dev));
|
||||
|
||||
if (int_status & DW_SPI_ISR_ERRORS_MASK) {
|
||||
error = -EIO;
|
||||
|
|
@ -520,7 +520,7 @@ void spi_dw_isr(const struct device *dev)
|
|||
}
|
||||
|
||||
out:
|
||||
clear_interrupts(info);
|
||||
clear_interrupts(dev);
|
||||
completed(dev, error);
|
||||
}
|
||||
|
||||
|
|
@ -542,11 +542,13 @@ int spi_dw_init(const struct device *dev)
|
|||
pinctrl_apply_state(info->pcfg, PINCTRL_STATE_DEFAULT);
|
||||
#endif
|
||||
|
||||
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
|
||||
|
||||
info->config_func();
|
||||
|
||||
/* Masking interrupt and making sure controller is disabled */
|
||||
write_imr(info, DW_SPI_IMR_MASK);
|
||||
clear_bit_ssienr(info);
|
||||
write_imr(dev, DW_SPI_IMR_MASK);
|
||||
clear_bit_ssienr(dev);
|
||||
|
||||
LOG_DBG("Designware SPI driver initialized on device: %p", dev);
|
||||
|
||||
|
|
@ -595,7 +597,7 @@ COND_CODE_1(IS_EQ(DT_NUM_IRQS(DT_DRV_INST(inst)), 1), \
|
|||
SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(inst), ctx) \
|
||||
}; \
|
||||
static const struct spi_dw_config spi_dw_config_##inst = { \
|
||||
.regs = DT_INST_REG_ADDR(inst), \
|
||||
DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \
|
||||
.clock_frequency = COND_CODE_1( \
|
||||
DT_NODE_HAS_PROP(DT_INST_PHANDLE(inst, clocks), clock_frequency), \
|
||||
(DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency)), \
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#define ZEPHYR_DRIVERS_SPI_SPI_DW_H_
|
||||
|
||||
#include <string.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
|
||||
#include "spi_context.h"
|
||||
|
|
@ -20,15 +21,15 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
typedef void (*spi_dw_config_t)(void);
|
||||
typedef uint32_t (*spi_dw_read_t)(uint8_t size, uint32_t addr, uint32_t off);
|
||||
typedef void (*spi_dw_write_t)(uint8_t size, uint32_t data, uint32_t addr, uint32_t off);
|
||||
typedef void (*spi_dw_set_bit_t)(uint8_t bit, uint32_t addr, uint32_t off);
|
||||
typedef void (*spi_dw_clear_bit_t)(uint8_t bit, uint32_t addr, uint32_t off);
|
||||
typedef int (*spi_dw_test_bit_t)(uint8_t bit, uint32_t addr, uint32_t off);
|
||||
typedef uint32_t (*spi_dw_read_t)(uint8_t size, mm_reg_t addr, uint32_t off);
|
||||
typedef void (*spi_dw_write_t)(uint8_t size, uint32_t data, mm_reg_t addr, uint32_t off);
|
||||
typedef void (*spi_dw_set_bit_t)(uint8_t bit, mm_reg_t addr, uint32_t off);
|
||||
typedef void (*spi_dw_clear_bit_t)(uint8_t bit, mm_reg_t addr, uint32_t off);
|
||||
typedef int (*spi_dw_test_bit_t)(uint8_t bit, mm_reg_t addr, uint32_t off);
|
||||
|
||||
/* Private structures */
|
||||
struct spi_dw_config {
|
||||
uint32_t regs;
|
||||
DEVICE_MMIO_ROM;
|
||||
uint32_t clock_frequency;
|
||||
spi_dw_config_t config_func;
|
||||
bool serial_target;
|
||||
|
|
@ -45,6 +46,7 @@ struct spi_dw_config {
|
|||
};
|
||||
|
||||
struct spi_dw_data {
|
||||
DEVICE_MMIO_RAM;
|
||||
struct spi_context ctx;
|
||||
uint8_t dfs; /* dfs in bytes: 1,2 or 4 */
|
||||
uint8_t fifo_diff; /* cannot be bigger than FIFO depth */
|
||||
|
|
@ -62,36 +64,36 @@ struct spi_dw_data {
|
|||
(DT_INST_FOREACH_STATUS_OKAY_VARGS(DT_INST_NODE_PROP_AND_OR, prop) 0)
|
||||
|
||||
#if DT_ANY_INST_PROP_STATUS_OKAY(aux_reg)
|
||||
static uint32_t aux_reg_read(uint8_t size, uint32_t addr, uint32_t off)
|
||||
static uint32_t aux_reg_read(uint8_t size, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
ARG_UNUSED(size);
|
||||
return sys_in32(addr + off/4);
|
||||
}
|
||||
|
||||
static void aux_reg_write(uint8_t size, uint32_t data, uint32_t addr, uint32_t off)
|
||||
static void aux_reg_write(uint8_t size, uint32_t data, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
ARG_UNUSED(size);
|
||||
sys_out32(data, addr + off/4);
|
||||
}
|
||||
|
||||
static void aux_reg_set_bit(uint8_t bit, uint32_t addr, uint32_t off)
|
||||
static void aux_reg_set_bit(uint8_t bit, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
sys_io_set_bit(addr + off/4, bit);
|
||||
}
|
||||
|
||||
static void aux_reg_clear_bit(uint8_t bit, uint32_t addr, uint32_t off)
|
||||
static void aux_reg_clear_bit(uint8_t bit, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
sys_io_clear_bit(addr + off/4, bit);
|
||||
}
|
||||
|
||||
static int aux_reg_test_bit(uint8_t bit, uint32_t addr, uint32_t off)
|
||||
static int aux_reg_test_bit(uint8_t bit, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
return sys_io_test_bit(addr + off/4, bit);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DT_ANY_INST_NOT_PROP_STATUS_OKAY(aux_reg)
|
||||
static uint32_t reg_read(uint8_t size, uint32_t addr, uint32_t off)
|
||||
static uint32_t reg_read(uint8_t size, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
switch (size) {
|
||||
case 8:
|
||||
|
|
@ -105,7 +107,7 @@ static uint32_t reg_read(uint8_t size, uint32_t addr, uint32_t off)
|
|||
}
|
||||
}
|
||||
|
||||
static void reg_write(uint8_t size, uint32_t data, uint32_t addr, uint32_t off)
|
||||
static void reg_write(uint8_t size, uint32_t data, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
switch (size) {
|
||||
case 8:
|
||||
|
|
@ -119,17 +121,17 @@ static void reg_write(uint8_t size, uint32_t data, uint32_t addr, uint32_t off)
|
|||
}
|
||||
}
|
||||
|
||||
static void reg_set_bit(uint8_t bit, uint32_t addr, uint32_t off)
|
||||
static void reg_set_bit(uint8_t bit, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
sys_set_bit(addr + off, bit);
|
||||
}
|
||||
|
||||
static void reg_clear_bit(uint8_t bit, uint32_t addr, uint32_t off)
|
||||
static void reg_clear_bit(uint8_t bit, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
sys_clear_bit(addr + off, bit);
|
||||
}
|
||||
|
||||
static int reg_test_bit(uint8_t bit, uint32_t addr, uint32_t off)
|
||||
static int reg_test_bit(uint8_t bit, mm_reg_t addr, uint32_t off)
|
||||
{
|
||||
return sys_test_bit(addr + off, bit);
|
||||
}
|
||||
|
|
@ -141,32 +143,37 @@ static int reg_test_bit(uint8_t bit, uint32_t addr, uint32_t off)
|
|||
((clock_freq / ssi_clk_hz) & 0xFFFF)
|
||||
|
||||
#define DEFINE_MM_REG_READ(__reg, __off, __sz) \
|
||||
static inline uint32_t read_##__reg(const struct spi_dw_config *info) \
|
||||
static inline uint32_t read_##__reg(const struct device *dev) \
|
||||
{ \
|
||||
return info->read_func(__sz, info->regs, __off); \
|
||||
const struct spi_dw_config *info = dev->config; \
|
||||
return info->read_func(__sz, (mm_reg_t)DEVICE_MMIO_GET(dev), __off); \
|
||||
}
|
||||
#define DEFINE_MM_REG_WRITE(__reg, __off, __sz) \
|
||||
static inline void write_##__reg(const struct spi_dw_config *info, uint32_t data)\
|
||||
static inline void write_##__reg(const struct device *dev, uint32_t data)\
|
||||
{ \
|
||||
info->write_func(__sz, data, info->regs, __off); \
|
||||
const struct spi_dw_config *info = dev->config; \
|
||||
info->write_func(__sz, data, (mm_reg_t)DEVICE_MMIO_GET(dev), __off); \
|
||||
}
|
||||
|
||||
#define DEFINE_SET_BIT_OP(__reg_bit, __reg_off, __bit) \
|
||||
static inline void set_bit_##__reg_bit(const struct spi_dw_config *info) \
|
||||
static inline void set_bit_##__reg_bit(const struct device *dev) \
|
||||
{ \
|
||||
info->set_bit_func(__bit, info->regs, __reg_off); \
|
||||
const struct spi_dw_config *info = dev->config; \
|
||||
info->set_bit_func(__bit, (mm_reg_t)DEVICE_MMIO_GET(dev), __reg_off); \
|
||||
}
|
||||
|
||||
#define DEFINE_CLEAR_BIT_OP(__reg_bit, __reg_off, __bit) \
|
||||
static inline void clear_bit_##__reg_bit(const struct spi_dw_config *info)\
|
||||
static inline void clear_bit_##__reg_bit(const struct device *dev)\
|
||||
{ \
|
||||
info->clear_bit_func(__bit, info->regs, __reg_off); \
|
||||
const struct spi_dw_config *info = dev->config; \
|
||||
info->clear_bit_func(__bit, (mm_reg_t)DEVICE_MMIO_GET(dev), __reg_off); \
|
||||
}
|
||||
|
||||
#define DEFINE_TEST_BIT_OP(__reg_bit, __reg_off, __bit) \
|
||||
static inline int test_bit_##__reg_bit(const struct spi_dw_config *info)\
|
||||
static inline int test_bit_##__reg_bit(const struct device *dev)\
|
||||
{ \
|
||||
return info->test_bit_func(__bit, info->regs, __reg_off); \
|
||||
const struct spi_dw_config *info = dev->config; \
|
||||
return info->test_bit_func(__bit, (mm_reg_t)DEVICE_MMIO_GET(dev), __reg_off); \
|
||||
}
|
||||
|
||||
/* Common registers settings, bits etc... */
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ DEFINE_MM_REG_WRITE(ser, DW_SPI_REG_SER, 8)
|
|||
|
||||
/* ICR is on a unique bit */
|
||||
DEFINE_TEST_BIT_OP(icr, DW_SPI_REG_ICR, DW_SPI_SR_ICR_BIT)
|
||||
#define clear_interrupts(info) test_bit_icr(info)
|
||||
#define clear_interrupts(dev) test_bit_icr(dev)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue