drivers: spi: add Data Fusion Subsystem SPI driver

Introduce DesignWare ARC Data Fusion IP Subsystem(DFSS) SPI
driver for ARC boards, i.e. EMSDP, which uses DW SPI to controll
SPI-Flash and DFSS SPI to connect external devices. Both drivers
share most source code, but DFSS uses ARC auxiliary registers.
Move FIFO depth setting to device tree.

Signed-off-by: Siyuan Cheng <siyuanc@synopsys.com>
This commit is contained in:
Siyuan Cheng 2023-04-24 16:30:35 +08:00 committed by Carles Cufí
parent 37aad05883
commit cbdd2f38da
16 changed files with 332 additions and 153 deletions

View file

@ -19,14 +19,4 @@ config I2C_DW_CLOCK_SPEED
endif # I2C_DW
if SPI_DW
config SPI_DW_FIFO_DEPTH
default 32
config SPI_DW_ARC_AUX_REGS
default n
endif # SPI_DW
endif # BOARD_EM_STARTERKIT

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_ARC_MPU_ENABLE arc_mpu_regions.c)
zephyr_sources(platform.c)

View file

@ -21,16 +21,6 @@ if SPI
config SPI_DW
default y
if SPI_DW
config SPI_DW_FIFO_DEPTH
default 32
config SPI_DW_ARC_AUX_REGS
default n
endif # SPI_DW
endif # SPI
endif # BOARD_EMSDP

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2023 Synopsys
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/arch/cpu.h>
#include <zephyr/init.h>
#define DFSS_SPI0_BASE 0x80010000
#define DFSS_SPI1_BASE 0x80010100
#define REG_CLK_ENA_OFFSET (0x16) /* DFSS only */
/* Enable clock for DFSS SPI0 controller & DFSS SPI1 controller */
static int emsdp_dfss_clock_init(void)
{
sys_out32(1, DFSS_SPI0_BASE + REG_CLK_ENA_OFFSET);
sys_out32(1, DFSS_SPI1_BASE + REG_CLK_ENA_OFFSET);
return 0;
}
SYS_INIT(emsdp_dfss_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

View file

@ -18,12 +18,6 @@ endif # GPIO
if SPI_DW
config SPI_DW_FIFO_DEPTH
default 32
config SPI_DW_ARC_AUX_REGS
default n
config SPI_DW_ACCESS_WORD_ONLY
default y

View file

@ -21,11 +21,6 @@ config USB_DEVICE_DRIVER
default y
endif # USB_DEVICE_STACK
if SPI_DW
config SPI_DW_FIFO_DEPTH
default 256
endif # SPI_DW
if NETWORKING
config NET_L2_ETHERNET

View file

@ -18,22 +18,6 @@ menuconfig SPI_DW
if SPI_DW
config SPI_DW_ARC_AUX_REGS
bool "Registers are part of ARC auxiliary registers"
depends on ARC
default y
help
SPI IP block registers are part of user extended auxiliary
registers and thus their access is different than memory
mapped registers.
config SPI_DW_FIFO_DEPTH
int "RX and TX FIFO Depth"
help
Corresponds to the SSI_TX_FIFO_DEPTH and
SSI_RX_FIFO_DEPTH of the DesignWare Synchronous
Serial Interface. Depth ranges from 2-256.
config SPI_DW_ACCESS_WORD_ONLY
bool "DesignWare SPI only allows word access"
help

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2015 Intel Corporation.
* Copyright (c) 2023 Synopsys, Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -47,6 +48,10 @@ LOG_MODULE_REGISTER(spi_dw);
#include "spi_dw.h"
#include "spi_context.h"
#ifdef CONFIG_PINCTRL
#include <zephyr/drivers/pinctrl.h>
#endif
static inline bool spi_dw_is_slave(struct spi_dw_data *spi)
{
return (IS_ENABLED(CONFIG_SPI_SLAVE) &&
@ -69,13 +74,13 @@ 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->regs)) {
while (test_bit_sr_busy(info)) {
}
/* Disabling interrupts */
write_imr(DW_SPI_IMR_MASK, info->regs);
write_imr(info, DW_SPI_IMR_MASK);
/* Disabling the controller */
clear_bit_ssienr(info->regs);
clear_bit_ssienr(info);
spi_context_cs_control(&spi->ctx, false);
@ -95,13 +100,13 @@ static void push_data(const struct device *dev)
DBG_COUNTER_INIT();
if (spi_context_rx_on(&spi->ctx)) {
f_tx = DW_SPI_FIFO_DEPTH - read_txflr(info->regs) -
read_rxflr(info->regs);
f_tx = info->fifo_depth - read_txflr(info) -
read_rxflr(info);
if ((int)f_tx < 0) {
f_tx = 0U; /* if rx-fifo is full, hold off tx */
}
} else {
f_tx = DW_SPI_FIFO_DEPTH - read_txflr(info->regs);
f_tx = info->fifo_depth - read_txflr(info);
}
while (f_tx) {
@ -136,7 +141,7 @@ static void push_data(const struct device *dev)
break;
}
write_dr(data, info->regs);
write_dr(info, data);
spi_context_update_tx(&spi->ctx, spi->dfs, 1);
spi->fifo_diff++;
@ -148,7 +153,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(0, info->regs);
write_txftlr(info, 0);
}
LOG_DBG("Pushed: %d", DBG_COUNTER_RESULT());
@ -161,8 +166,8 @@ static void pull_data(const struct device *dev)
DBG_COUNTER_INIT();
while (read_rxflr(info->regs)) {
uint32_t data = read_dr(info->regs);
while (read_rxflr(info)) {
uint32_t data = read_dr(info);
DBG_COUNTER_INC();
@ -186,10 +191,10 @@ static void pull_data(const struct device *dev)
spi->fifo_diff--;
}
if (!spi->ctx.rx_len && spi->ctx.tx_len < DW_SPI_FIFO_DEPTH) {
write_rxftlr(spi->ctx.tx_len - 1, info->regs);
} else if (read_rxftlr(info->regs) >= spi->ctx.rx_len) {
write_rxftlr(spi->ctx.rx_len - 1, info->regs);
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);
}
LOG_DBG("Pulled: %d", DBG_COUNTER_RESULT());
@ -254,16 +259,16 @@ static int spi_dw_configure(const struct spi_dw_config *info,
}
/* Installing the configuration */
write_ctrlr0(ctrlr0, info->regs);
write_ctrlr0(info, 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(SPI_DW_CLK_DIVIDER(info->clock_frequency,
config->frequency), info->regs);
write_ser(1 << config->slave, info->regs);
write_baudr(info, SPI_DW_CLK_DIVIDER(info->clock_frequency,
config->frequency));
write_ser(info, 1 << config->slave);
}
if (spi_dw_is_slave(spi)) {
@ -319,19 +324,20 @@ error:
static void spi_dw_update_txftlr(const struct spi_dw_config *info,
struct spi_dw_data *spi)
{
uint32_t reg_data = DW_SPI_TXFTLR_DFLT;
uint32_t dw_spi_txftlr_dflt = (info->fifo_depth * 1) / 2;
uint32_t reg_data = dw_spi_txftlr_dflt;
if (spi_dw_is_slave(spi)) {
if (!spi->ctx.tx_len) {
reg_data = 0U;
} else if (spi->ctx.tx_len < DW_SPI_TXFTLR_DFLT) {
} else if (spi->ctx.tx_len < dw_spi_txftlr_dflt) {
reg_data = spi->ctx.tx_len - 1;
}
}
LOG_DBG("TxFTLR: %u", reg_data);
write_txftlr(reg_data, info->regs);
write_txftlr(info, reg_data);
}
static int transceive(const struct device *dev,
@ -345,6 +351,7 @@ static int transceive(const struct device *dev,
const struct spi_dw_config *info = dev->config;
struct spi_dw_data *spi = dev->data;
uint32_t tmod = DW_SPI_CTRLR0_TMOD_TX_RX;
uint32_t dw_spi_rxftlr_dflt = (info->fifo_depth * 5) / 8;
uint32_t reg_data;
int ret;
@ -380,9 +387,9 @@ static int transceive(const struct device *dev,
goto out;
}
write_ctrlr1(reg_data, info->regs);
write_ctrlr1(info, reg_data);
} else {
write_ctrlr1(0, info->regs);
write_ctrlr1(info, 0);
}
if (spi_dw_is_slave(spi)) {
@ -395,11 +402,11 @@ static int transceive(const struct device *dev,
}
/* Updating TMOD in CTRLR0 register */
reg_data = read_ctrlr0(info->regs);
reg_data = read_ctrlr0(info);
reg_data &= ~DW_SPI_CTRLR0_TMOD_RESET;
reg_data |= tmod;
write_ctrlr0(reg_data, info->regs);
write_ctrlr0(info, reg_data);
/* Set buffers info */
spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, spi->dfs);
@ -410,32 +417,32 @@ static int transceive(const struct device *dev,
spi_dw_update_txftlr(info, spi);
/* Does Rx thresholds needs to be lower? */
reg_data = DW_SPI_RXFTLR_DFLT;
reg_data = dw_spi_rxftlr_dflt;
if (spi_dw_is_slave(spi)) {
if (spi->ctx.rx_len &&
spi->ctx.rx_len < DW_SPI_RXFTLR_DFLT) {
spi->ctx.rx_len < dw_spi_rxftlr_dflt) {
reg_data = spi->ctx.rx_len - 1;
}
} else {
if (spi->ctx.rx_len && spi->ctx.rx_len < DW_SPI_FIFO_DEPTH) {
if (spi->ctx.rx_len && spi->ctx.rx_len < info->fifo_depth) {
reg_data = spi->ctx.rx_len - 1;
}
}
/* Rx Threshold */
write_rxftlr(reg_data, info->regs);
write_rxftlr(info, reg_data);
/* Enable interrupts */
reg_data = !rx_bufs ?
DW_SPI_IMR_UNMASK & DW_SPI_IMR_MASK_RX :
DW_SPI_IMR_UNMASK;
write_imr(reg_data, info->regs);
DW_SPI_IMR_UNMASK & DW_SPI_IMR_MASK_TX;
write_imr(info, reg_data);
spi_context_cs_control(&spi->ctx, true);
LOG_DBG("Enabling controller");
set_bit_ssienr(info->regs);
set_bit_ssienr(info);
ret = spi_context_wait_for_completion(&spi->ctx);
out:
@ -490,10 +497,10 @@ void spi_dw_isr(const struct device *dev)
uint32_t int_status;
int error;
int_status = read_isr(info->regs);
int_status = read_isr(info);
LOG_DBG("SPI %p int_status 0x%x - (tx: %d, rx: %d)", dev,
int_status, read_txflr(info->regs), read_rxflr(info->regs));
LOG_DBG("SPI %p int_status 0x%x - (tx: %d, rx: %d)", dev, int_status,
read_txflr(info), read_rxflr(info));
if (int_status & DW_SPI_ISR_ERRORS_MASK) {
error = -EIO;
@ -511,7 +518,7 @@ void spi_dw_isr(const struct device *dev)
}
out:
clear_interrupts(info->regs);
clear_interrupts(info);
completed(dev, error);
}
@ -529,11 +536,15 @@ int spi_dw_init(const struct device *dev)
const struct spi_dw_config *info = dev->config;
struct spi_dw_data *spi = dev->data;
#ifdef CONFIG_PINCTRL
pinctrl_apply_state(info->pcfg, PINCTRL_STATE_DEFAULT);
#endif
info->config_func();
/* Masking interrupt and making sure controller is disabled */
write_imr(DW_SPI_IMR_MASK, info->regs);
clear_bit_ssienr(info->regs);
write_imr(info, DW_SPI_IMR_MASK);
clear_bit_ssienr(info);
LOG_DBG("Designware SPI driver initialized on device: %p", dev);
@ -565,11 +576,31 @@ struct spi_dw_data spi_dw_data_port_0 = {
DT_INST_PROP(0, clock_frequency)
#endif
#ifdef CONFIG_PINCTRL
PINCTRL_DT_INST_DEFINE(0);
#endif
const struct spi_dw_config spi_dw_config_0 = {
.regs = DT_INST_REG_ADDR(0),
.clock_frequency = INST_0_SNPS_DESIGNWARE_SPI_CLOCK_FREQ,
.config_func = spi_config_0_irq,
.op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER
.op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER,
.fifo_depth = DT_INST_PROP(0, fifo_depth),
#ifdef CONFIG_PINCTRL
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
#endif
#if DT_INST_PROP(0, aux_reg)
.read_func = aux_reg_read,
.write_func = aux_reg_write,
.set_bit_func = aux_reg_set_bit,
.clear_bit_func = aux_reg_clear_bit,
.test_bit_func = aux_reg_test_bit
#else
.read_func = reg_read,
.write_func = reg_write,
.set_bit_func = reg_set_bit,
.clear_bit_func = reg_clear_bit,
.test_bit_func = reg_test_bit
#endif
};
DEVICE_DT_INST_DEFINE(0, spi_dw_init, NULL,
@ -592,17 +623,17 @@ void spi_config_0_irq(void)
irq_enable(DT_INST_IRQN(0));
#else
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, rx_avail, irq),
DT_INST_IRQ_BY_NAME(0, rx_avail_pri, irq),
DT_INST_IRQ_BY_NAME(0, rx_avail, priority),
spi_dw_isr, DEVICE_DT_INST_GET(0),
DT_INST_IRQ_BY_NAME(0, rx_avail, flags));
0);
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, tx_req, irq),
DT_INST_IRQ_BY_NAME(0, tx_req_pri, irq),
DT_INST_IRQ_BY_NAME(0, tx_req, priority),
spi_dw_isr, DEVICE_DT_INST_GET(0),
DT_INST_IRQ_BY_NAME(0, tx_req, flags));
0);
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, err_int, irq),
DT_INST_IRQ_BY_NAME(0, err_int_pri, irq),
DT_INST_IRQ_BY_NAME(0, err_int, priority),
spi_dw_isr, DEVICE_DT_INST_GET(0),
DT_INST_IRQ_BY_NAME(0, err_int, flags));
0);
irq_enable(DT_INST_IRQ_BY_NAME(0, rx_avail, irq));
irq_enable(DT_INST_IRQ_BY_NAME(0, tx_req, irq));
@ -629,11 +660,31 @@ struct spi_dw_data spi_dw_data_port_1 = {
DT_INST_PROP(1, clock_frequency)
#endif
#ifdef CONFIG_PINCTRL
PINCTRL_DT_INST_DEFINE(1);
#endif
static const struct spi_dw_config spi_dw_config_1 = {
.regs = DT_INST_REG_ADDR(1),
.clock_frequency = INST_1_SNPS_DESIGNWARE_SPI_CLOCK_FREQ,
.config_func = spi_config_1_irq,
.op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER
.op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER,
.fifo_depth = DT_INST_PROP(1, fifo_depth),
#ifdef CONFIG_PINCTRL
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(1),
#endif
#if DT_INST_PROP(1, aux_reg)
.read_func = aux_reg_read,
.write_func = aux_reg_write,
.set_bit_func = aux_reg_set_bit,
.clear_bit_func = aux_reg_clear_bit,
.test_bit_func = aux_reg_test_bit
#else
.read_func = reg_read,
.write_func = reg_write,
.set_bit_func = reg_set_bit,
.clear_bit_func = reg_clear_bit,
.test_bit_func = reg_test_bit
#endif
};
DEVICE_DT_INST_DEFINE(1, spi_dw_init, NULL,
@ -656,17 +707,17 @@ void spi_config_1_irq(void)
irq_enable(DT_INST_IRQN(1));
#else
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, rx_avail, irq),
DT_INST_IRQ_BY_NAME(1, rx_avail_pri, irq),
DT_INST_IRQ_BY_NAME(1, rx_avail, priority),
spi_dw_isr, DEVICE_DT_INST_GET(1),
DT_INST_IRQ_BY_NAME(1, rx_avail, flags));
0);
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, tx_req, irq),
DT_INST_IRQ_BY_NAME(1, tx_req_pri, irq),
DT_INST_IRQ_BY_NAME(1, tx_req, priority),
spi_dw_isr, DEVICE_DT_INST_GET(1),
DT_INST_IRQ_BY_NAME(1, tx_req, flags));
0);
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, err_int, irq),
DT_INST_IRQ_BY_NAME(1, err_int_pri, irq),
DT_INST_IRQ_BY_NAME(1, err_int, priority),
spi_dw_isr, DEVICE_DT_INST_GET(1),
DT_INST_IRQ_BY_NAME(1, err_int, flags));
0);
irq_enable(DT_INST_IRQ_BY_NAME(1, rx_avail, irq));
irq_enable(DT_INST_IRQ_BY_NAME(1, tx_req, irq));
@ -693,11 +744,31 @@ struct spi_dw_data spi_dw_data_port_2 = {
DT_INST_PROP(2, clock_frequency)
#endif
#ifdef CONFIG_PINCTRL
PINCTRL_DT_INST_DEFINE(2);
#endif
static const struct spi_dw_config spi_dw_config_2 = {
.regs = DT_INST_REG_ADDR(2),
.clock_frequency = INST_2_SNPS_DESIGNWARE_SPI_CLOCK_FREQ,
.config_func = spi_config_2_irq,
.op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER
.op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER,
.fifo_depth = DT_INST_PROP(2, fifo_depth),
#ifdef CONFIG_PINCTRL
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(2),
#endif
#if DT_INST_PROP(2, aux_reg)
.read_func = aux_reg_read,
.write_func = aux_reg_write,
.set_bit_func = aux_reg_set_bit,
.clear_bit_func = aux_reg_clear_bit,
.test_bit_func = aux_reg_test_bit
#else
.read_func = reg_read,
.write_func = reg_write,
.set_bit_func = reg_set_bit,
.clear_bit_func = reg_clear_bit,
.test_bit_func = reg_test_bit
#endif
};
DEVICE_DT_INST_DEFINE(2, spi_dw_init, NULL,
@ -720,17 +791,17 @@ void spi_config_2_irq(void)
irq_enable(DT_INST_IRQN(2));
#else
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, rx_avail, irq),
DT_INST_IRQ_BY_NAME(2, rx_avail_pri, irq),
DT_INST_IRQ_BY_NAME(2, rx_avail, priority),
spi_dw_isr, DEVICE_DT_INST_GET(2),
DT_INST_IRQ_BY_NAME(2, rx_avail, flags));
0);
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, tx_req, irq),
DT_INST_IRQ_BY_NAME(2, tx_req_pri, irq),
DT_INST_IRQ_BY_NAME(2, tx_req, priority),
spi_dw_isr, DEVICE_DT_INST_GET(2),
DT_INST_IRQ_BY_NAME(2, tx_req, flags));
0);
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, err_int, irq),
DT_INST_IRQ_BY_NAME(2, err_int_pri, irq),
DT_INST_IRQ_BY_NAME(2, err_int, priority),
spi_dw_isr, DEVICE_DT_INST_GET(2),
DT_INST_IRQ_BY_NAME(2, err_int, flags));
0);
irq_enable(DT_INST_IRQ_BY_NAME(2, rx_avail, irq));
irq_enable(DT_INST_IRQ_BY_NAME(2, tx_req, irq));
@ -757,11 +828,31 @@ struct spi_dw_data spi_dw_data_port_3 = {
DT_INST_PROP(3, clock_frequency)
#endif
#ifdef CONFIG_PINCTRL
PINCTRL_DT_INST_DEFINE(3);
#endif
static const struct spi_dw_config spi_dw_config_3 = {
.regs = DT_INST_REG_ADDR(3),
.clock_frequency = INST_3_SNPS_DESIGNWARE_SPI_CLOCK_FREQ,
.config_func = spi_config_3_irq,
.op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER
.op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER,
.fifo_depth = DT_INST_PROP(3, fifo_depth),
#ifdef CONFIG_PINCTRL
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(3),
#endif
#if DT_INST_PROP(3, aux_reg)
.read_func = aux_reg_read,
.write_func = aux_reg_write,
.set_bit_func = aux_reg_set_bit,
.clear_bit_func = aux_reg_clear_bit,
.test_bit_func = aux_reg_test_bit
#else
.read_func = reg_read,
.write_func = reg_write,
.set_bit_func = reg_set_bit,
.clear_bit_func = reg_clear_bit,
.test_bit_func = reg_test_bit
#endif
};
DEVICE_DT_INST_DEFINE(3, spi_dw_init, NULL,
@ -784,17 +875,17 @@ void spi_config_3_irq(void)
irq_enable(DT_INST_IRQN(3));
#else
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, rx_avail, irq),
DT_INST_IRQ_BY_NAME(3, rx_avail_pri, irq),
DT_INST_IRQ_BY_NAME(3, rx_avail, priority),
spi_dw_isr, DEVICE_DT_INST_GET(3),
DT_INST_IRQ_BY_NAME(3, rx_avail, flags));
0);
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, tx_req, irq),
DT_INST_IRQ_BY_NAME(3, tx_req_pri, irq),
DT_INST_IRQ_BY_NAME(3, tx_req, priority),
spi_dw_isr, DEVICE_DT_INST_GET(3),
DT_INST_IRQ_BY_NAME(3, tx_req, flags));
0);
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, err_int, irq),
DT_INST_IRQ_BY_NAME(3, err_int_pri, irq),
DT_INST_IRQ_BY_NAME(3, err_int, priority),
spi_dw_isr, DEVICE_DT_INST_GET(3),
DT_INST_IRQ_BY_NAME(3, err_int, flags));
0);
irq_enable(DT_INST_IRQ_BY_NAME(3, rx_avail, irq));
irq_enable(DT_INST_IRQ_BY_NAME(3, tx_req, irq));

View file

@ -2,6 +2,7 @@
/*
* Copyright (c) 2015 Intel Corporation.
* Copyright (c) 2023 Synopsys, Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -19,6 +20,11 @@ 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);
/* Private structures */
struct spi_dw_config {
@ -26,6 +32,15 @@ struct spi_dw_config {
uint32_t clock_frequency;
spi_dw_config_t config_func;
uint8_t op_modes;
uint8_t fifo_depth;
#ifdef CONFIG_PINCTRL
const struct pinctrl_dev_config *pcfg;
#endif
spi_dw_read_t read_func;
spi_dw_write_t write_func;
spi_dw_set_bit_t set_bit_func;
spi_dw_clear_bit_t clear_bit_func;
spi_dw_test_bit_t test_bit_func;
};
struct spi_dw_data {
@ -35,52 +50,123 @@ struct spi_dw_data {
uint16_t _unused;
};
/* Register operation functions */
#define DT_INST_NODE_PROP_NOT_OR(inst, prop) \
!DT_INST_PROP(inst, prop) ||
#define DT_ANY_INST_NOT_PROP_STATUS_OKAY(prop) \
(DT_INST_FOREACH_STATUS_OKAY_VARGS(DT_INST_NODE_PROP_NOT_OR, prop) 0)
#define DT_INST_NODE_PROP_AND_OR(inst, prop) \
DT_INST_PROP(inst, prop) ||
#define DT_ANY_INST_PROP_STATUS_OKAY(prop) \
(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)
{
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)
{
ARG_UNUSED(size);
sys_out32(data, addr + off/4);
}
static void aux_reg_set_bit(uint8_t bit, uint32_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)
{
sys_io_clear_bit(addr + off/4, bit);
}
static int aux_reg_test_bit(uint8_t bit, uint32_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)
{
switch (size) {
case 8:
return sys_read8(addr + off);
case 16:
return sys_read16(addr + off);
case 32:
return sys_read32(addr + off);
default:
return -EINVAL;
}
}
static void reg_write(uint8_t size, uint32_t data, uint32_t addr, uint32_t off)
{
switch (size) {
case 8:
sys_write8(data, addr + off); break;
case 16:
sys_write16(data, addr + off); break;
case 32:
sys_write32(data, addr + off); break;
default:
break;
}
}
static void reg_set_bit(uint8_t bit, uint32_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)
{
sys_clear_bit(addr + off, bit);
}
static int reg_test_bit(uint8_t bit, uint32_t addr, uint32_t off)
{
return sys_test_bit(addr + off, bit);
}
#endif
/* Helper macros */
#define SPI_DW_CLK_DIVIDER(clock_freq, ssi_clk_hz) \
((clock_freq / ssi_clk_hz) & 0xFFFF)
#ifdef CONFIG_SPI_DW_ARC_AUX_REGS
#define Z_REG_READ(__sz) sys_in##__sz
#define Z_REG_WRITE(__sz) sys_out##__sz
#define Z_REG_SET_BIT sys_io_set_bit
#define Z_REG_CLEAR_BIT sys_io_clear_bit
#define Z_REG_TEST_BIT sys_io_test_bit
#else
#define Z_REG_READ(__sz) sys_read##__sz
#define Z_REG_WRITE(__sz) sys_write##__sz
#define Z_REG_SET_BIT sys_set_bit
#define Z_REG_CLEAR_BIT sys_clear_bit
#define Z_REG_TEST_BIT sys_test_bit
#endif /* CONFIG_SPI_DW_ARC_AUX_REGS */
#define DEFINE_MM_REG_READ(__reg, __off, __sz) \
static inline uint32_t read_##__reg(uint32_t addr) \
static inline uint32_t read_##__reg(const struct spi_dw_config *info) \
{ \
return Z_REG_READ(__sz)(addr + __off); \
return info->read_func(__sz, info->regs, __off); \
}
#define DEFINE_MM_REG_WRITE(__reg, __off, __sz) \
static inline void write_##__reg(uint32_t data, uint32_t addr) \
static inline void write_##__reg(const struct spi_dw_config *info, uint32_t data)\
{ \
Z_REG_WRITE(__sz)(data, addr + __off); \
info->write_func(__sz, data, info->regs, __off); \
}
#define DEFINE_SET_BIT_OP(__reg_bit, __reg_off, __bit) \
static inline void set_bit_##__reg_bit(uint32_t addr) \
static inline void set_bit_##__reg_bit(const struct spi_dw_config *info) \
{ \
Z_REG_SET_BIT(addr + __reg_off, __bit); \
info->set_bit_func(__bit, info->regs, __reg_off); \
}
#define DEFINE_CLEAR_BIT_OP(__reg_bit, __reg_off, __bit) \
static inline void clear_bit_##__reg_bit(uint32_t addr) \
static inline void clear_bit_##__reg_bit(const struct spi_dw_config *info)\
{ \
Z_REG_CLEAR_BIT(addr + __reg_off, __bit); \
info->clear_bit_func(__bit, info->regs, __reg_off); \
}
#define DEFINE_TEST_BIT_OP(__reg_bit, __reg_off, __bit) \
static inline int test_bit_##__reg_bit(uint32_t addr) \
static inline int test_bit_##__reg_bit(const struct spi_dw_config *info)\
{ \
return Z_REG_TEST_BIT(addr + __reg_off, __bit); \
return info->test_bit_func(__bit, info->regs, __reg_off); \
}
/* Common registers settings, bits etc... */
@ -126,6 +212,9 @@ struct spi_dw_data {
/* SSIENR bits */
#define DW_SPI_SSIENR_SSIEN_BIT (0)
/* CLK_ENA bits */
#define DW_SPI_CLK_ENA_BIT (0)
/* SR bits and values */
#define DW_SPI_SR_BUSY_BIT (0)
#define DW_SPI_SR_TFNF_BIT (1)
@ -163,23 +252,23 @@ struct spi_dw_data {
/* ICR Bit */
#define DW_SPI_SR_ICR_BIT (0)
/* Threshold defaults */
#define DW_SPI_FIFO_DEPTH CONFIG_SPI_DW_FIFO_DEPTH
#define DW_SPI_TXFTLR_DFLT ((DW_SPI_FIFO_DEPTH * 1) / 2) /* 50% */
#define DW_SPI_RXFTLR_DFLT ((DW_SPI_FIFO_DEPTH * 5) / 8)
/* Interrupt mask (IMR) */
#define DW_SPI_IMR_MASK (0x0)
#define DW_SPI_IMR_UNMASK (DW_SPI_IMR_TXEIM | \
DW_SPI_IMR_TXOIM | \
DW_SPI_IMR_RXUIM | \
DW_SPI_IMR_RXOIM | \
DW_SPI_IMR_RXFIM)
#define DW_SPI_IMR_MASK_TX (~(DW_SPI_IMR_TXEIM | \
DW_SPI_IMR_TXOIM))
#define DW_SPI_IMR_MASK_RX (~(DW_SPI_IMR_RXUIM | \
DW_SPI_IMR_RXFIM | \
DW_SPI_IMR_MSTIM)
#define DW_SPI_IMR_MASK_TX (~(DW_SPI_IMR_RXUIM | \
DW_SPI_IMR_TXOIM | \
DW_SPI_IMR_RXOIM | \
DW_SPI_IMR_RXFIM))
DW_SPI_IMR_MSTIM))
#define DW_SPI_IMR_MASK_RX (~(DW_SPI_IMR_TXEIM |\
DW_SPI_IMR_RXUIM | \
DW_SPI_IMR_TXOIM | \
DW_SPI_IMR_RXOIM | \
DW_SPI_IMR_MSTIM))
/*
* Including the right register definition file

View file

@ -2,6 +2,7 @@
/*
* Copyright (c) 2015 Intel Corporation.
* Copyright (c) 2023 Synopsys, Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -63,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(addr) test_bit_icr(addr)
#define clear_interrupts(info) test_bit_icr(info)
#ifdef __cplusplus
}

View file

@ -184,7 +184,7 @@
#size-cells = <0>;
reg = <0xf0020000 0x100>;
interrupts = <40 1>;
fifo-depth = <32>;
status = "disabled";
};
@ -194,6 +194,7 @@
#size-cells = <0>;
reg = <0xf0021000 0x100>;
interrupts = <41 1>;
fifo-depth = <32>;
status = "disabled";
};
@ -203,6 +204,7 @@
#size-cells = <0>;
reg = <0xf0022000 0x100>;
interrupts = <42 1>;
fifo-depth = <32>;
status = "disabled";
};
};

View file

@ -184,7 +184,7 @@
#size-cells = <0>;
reg = <0xf0020000 0x1000>;
interrupts = <40 1>;
fifo-depth = <32>;
status = "disabled";
};
@ -194,6 +194,7 @@
#size-cells = <0>;
reg = <0xf0021000 0x1000>;
interrupts = <41 1>;
fifo-depth = <32>;
status = "disabled";
};
@ -203,6 +204,7 @@
#size-cells = <0>;
reg = <0xf0022000 0x1000>;
interrupts = <42 1>;
fifo-depth = <32>;
status = "disabled";
};

View file

@ -94,6 +94,7 @@
compatible = "snps,designware-spi";
reg = <0xf0008000 0x1000>;
clocks = <&spiclk>;
fifo-depth = <32>;
interrupt-parent = <&intc>;
#address-cells = <1>;
#size-cells = <0>;
@ -105,6 +106,7 @@
compatible = "snps,designware-spi";
reg = <0xf1000000 0x1000>;
clocks = <&spiclk>;
fifo-depth = <32>;
interrupt-parent = <&intc>;
#address-cells = <1>;
#size-cells = <0>;

View file

@ -147,7 +147,7 @@
reg = <0xf0006000 0x1000>;
clocks = <&sysclk>;
interrupt-parent = <&intc>;
fifo-depth = <32>;
#address-cells = <1>;
#size-cells = <0>;
@ -158,7 +158,7 @@
reg = <0xf0007000 0x1000>;
clocks = <&sysclk>;
interrupt-parent = <&intc>;
fifo-depth = <32>;
#address-cells = <1>;
#size-cells = <0>;

View file

@ -243,6 +243,7 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfff00000 0x1000>;
fifo-depth = <256>;
interrupts = <0 154 4 IRQ_DEFAULT_PRIORITY>;
clock-frequency = <200000000>;
status = "okay";
@ -253,6 +254,7 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfff01000 0x1000>;
fifo-depth = <256>;
interrupts = <0 155 4 IRQ_DEFAULT_PRIORITY>;
clock-frequency = <200000000>;
status = "disabled";

View file

@ -5,7 +5,7 @@ description: Synopsys DesignWare SPI node
compatible: "snps,designware-spi"
include: spi-controller.yaml
include: [spi-controller.yaml, pinctrl-device.yaml]
properties:
reg:
@ -13,3 +13,16 @@ properties:
interrupts:
required: true
aux_reg:
description: |
This value is used for auxiliary register access. For
other platform, this value should be default 0.
type: boolean
fifo-depth:
type: int
description: |
RX/TX FIFO depth. Corresponds to the SSI_TX_FIFO_DEPTH
and SSI_RX_FIFO_DEPTH of the DesignWare Synchronous
Serial Interface. Depth ranges from 2-256.