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:
Julien Panis 2024-01-22 19:57:38 +02:00 committed by Alberto Escolar
parent 62e7b788aa
commit 30b6cd2647
3 changed files with 74 additions and 65 deletions

View file

@ -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)), \

View file

@ -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... */

View file

@ -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
}