summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernard Xiong <[email protected]>2024-07-17 22:25:26 +0800
committerGitHub <[email protected]>2024-07-17 22:25:26 +0800
commita2f4e120c3c30a7d0497749811bd5fe7aa4b4b47 (patch)
treea9b4068895e9abf808700aea8eb37ff91f694bc4
parent4e630fed08250a3f92c4d463b4adf6a16bdb0cae (diff)
parent1ef2afbc932d1ad4dd8f1841ae96522233bf53f9 (diff)
Merge pull request #9200 from unicornx/dev-spi-new
bsp: cvitek: re-wrote spi driver
-rwxr-xr-xbsp/cvitek/drivers/SConscript2
-rw-r--r--bsp/cvitek/drivers/drv_spi.c353
-rw-r--r--bsp/cvitek/drivers/drv_spi.h151
-rw-r--r--bsp/cvitek/drivers/libraries/spi/dw_spi.c375
-rw-r--r--bsp/cvitek/drivers/libraries/spi/dw_spi.h246
5 files changed, 816 insertions, 311 deletions
diff --git a/bsp/cvitek/drivers/SConscript b/bsp/cvitek/drivers/SConscript
index d67ffc5e39..91961af61a 100755
--- a/bsp/cvitek/drivers/SConscript
+++ b/bsp/cvitek/drivers/SConscript
@@ -31,6 +31,8 @@ if GetDepend('BSP_USING_WDT'):
if GetDepend(['BSP_USING_SPI']):
src += ['drv_spi.c']
+ src += ['libraries/spi/dw_spi.c']
+ CPPPATH += [cwd + r'/libraries/spi']
if GetDepend('BSP_USING_PWM'):
src += ['drv_pwm.c']
diff --git a/bsp/cvitek/drivers/drv_spi.c b/bsp/cvitek/drivers/drv_spi.c
index 3e88af06f6..e268fa89d0 100644
--- a/bsp/cvitek/drivers/drv_spi.c
+++ b/bsp/cvitek/drivers/drv_spi.c
@@ -1,217 +1,231 @@
/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
+ * Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
- * 2024-03-28 qiujingbao first version
+ * 2024-03-28 qiujingbao first version
+ * 2024/06/08 flyingcys fix transmission failure
*/
+#include <rtthread.h>
+#include <rthw.h>
+#include <rtdevice.h>
+
+#include "board.h"
#include "drv_spi.h"
+
#include "drv_pinmux.h"
-#define DBG_TAG "drv.spi"
-#define DBG_LVL DBG_INFO
+#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
+#define LOG_TAG "drv.spi"
+
+struct _device_spi
+{
+ struct rt_spi_bus spi_bus;
+ struct dw_spi dws;
+ char *device_name;
+};
-static struct cv1800_spi cv1800_spi_obj[] =
+static struct _device_spi _spi_obj[] =
{
-#ifdef BSP_USING_SPI
+#ifdef BSP_USING_SPI0
{
- .spi_id = SPI2,
+ .dws.regs = (void *)DW_SPI0_BASE,
+ .dws.irq = DW_SPI0_IRQn,
+ .dws.index = 0,
+ .device_name = "spi0",
+ },
+#endif /* BSP_USING_SPI0 */
+#ifdef BSP_USING_SPI1
+ {
+ .dws.regs = (void *)DW_SPI1_BASE,
+ .dws.irq = DW_SPI1_IRQn,
+ .dws.index = 0,
+ .device_name = "spi1",
+ },
+#endif /* BSP_USING_SPI1 */
+#ifdef BSP_USING_SPI2
+ {
+ .dws.regs = (void *)DW_SPI2_BASE,
+ .dws.irq = DW_SPI2_IRQn,
+ .dws.index = 0,
.device_name = "spi2",
- .fifo_len = SPI_TXFTLR,
},
-#endif
+#endif /* BSP_USING_SPI2 */
+#ifdef BSP_USING_SPI3
+ {
+ .dws.regs = (void *)DW_SPI3_BASE,
+ .dws.irq = DW_SPI3_IRQn,
+ .dws.index = 0,
+ .device_name = "spi3",
+ },
+#endif /* BSP_USING_SPI3 */
};
-static struct spi_regs *get_spi_base(uint8_t spi_id)
+static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
{
- struct spi_regs *spi_base = NULL;
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(device->bus != RT_NULL);
+ RT_ASSERT(device->bus->parent.user_data != RT_NULL);
+ RT_ASSERT(cfg != RT_NULL);
+
+ rt_err_t ret = RT_EOK;
+ struct _device_spi *spi = (struct _device_spi *)device->bus->parent.user_data;
+ struct dw_spi *dws = &spi->dws;
+
+ rt_uint8_t mode;
- switch (spi_id)
+ LOG_D("spi_configure input");
+
+ /* set cs low when spi idle */
+ writel(0, (void *)0x030001d0);
+
+ if (cfg->mode & RT_SPI_SLAVE)
{
- case SPI0:
- spi_base = (struct spi_regs *)SPI0_BASE;
- break;
- case SPI1:
- spi_base = (struct spi_regs *)SPI1_BASE;
- break;
- case SPI2:
- spi_base = (struct spi_regs *)SPI2_BASE;
- break;
- case SPI3:
- spi_base = (struct spi_regs *)SPI3_BASE;
- break;
+ LOG_E("invalid mode: %d", cfg->mode);
+ return -RT_EINVAL;
}
- return spi_base;
-}
-
-static rt_err_t drv_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
-{
- rt_err_t ret = RT_EOK;
- struct cv1800_spi *spi_dev = RT_NULL;
- uint32_t mode;
+ spi_reset_chip(dws);
+ spi_hw_init(dws);
+ spi_enable_chip(dws, 0);
- spi_dev = (struct cv1800_spi *)(device->bus->parent.user_data);
+ LOG_D("cfg->max_hz: %d", cfg->max_hz);
+ dw_spi_set_clock(dws, SPI_REF_CLK, cfg->max_hz);
- spi_dev->data_width = configuration->data_width;
+ LOG_D("cfg->data_width: %d", cfg->data_width);
+ if (dw_spi_set_data_frame_len(dws, (uint32_t)cfg->data_width) < 0)
+ {
+ LOG_E("dw_spi_set_data_frame_len failed...\n");
+ return -RT_ERROR;
+ }
- /* disable spi */
- spi_enable(spi_dev->reg, 0);
+ LOG_D("cfg->mode: %08x", cfg->mode);
+ switch (cfg->mode & RT_SPI_MODE_3)
+ {
+ case RT_SPI_MODE_0:
+ mode = SPI_FORMAT_CPOL0_CPHA0;
+ break;
- /* clear irq */
- spi_clear_irq(spi_dev->reg, SPI_IRQ_MSAK);
+ case RT_SPI_MODE_1:
+ mode = SPI_FORMAT_CPOL0_CPHA1;
+ break;
- /* set clk */
- ret = spi_set_frequency(spi_dev->reg, configuration->max_hz);
- if (ret)
- return ret;
+ case RT_SPI_MODE_2:
+ mode = SPI_FORMAT_CPOL1_CPHA0;
+ break;
- /* set mode */
- ret = gen_spi_mode(configuration, &mode);
- if (ret)
- return ret;
+ case RT_SPI_MODE_3:
+ mode = SPI_FORMAT_CPOL1_CPHA1;
+ break;
- spi_set_mode(spi_dev->reg, mode);
+ default:
+ LOG_E("spi configure mode error %x\n", cfg->mode);
+ break;
+ }
- /* set cs */
- spi_enable_cs(spi_dev->reg, 0x1);
+ dw_spi_set_polarity_and_phase(dws, mode);
- spi_enable(spi_dev->reg, 0x1);
+ dw_spi_set_cs(dws, 1, 0);
- mode = mmio_read_32((uintptr_t)&spi_dev->reg->spi_ctrl0);
- LOG_D("mode: %x", mode);
- mode = mmio_read_32((uintptr_t)&spi_dev->reg->spi_baudr);
- LOG_D("spi_baudr: %x", mode);
+ spi_enable_chip(dws, 1);
- return ret;
+ return RT_EOK;
}
-int hw_spi_recv(struct cv1800_spi *dev) {
- uint32_t rever;
- uint32_t tem;
- int ret;
+static rt_err_t dw_spi_transfer_one(struct dw_spi *dws, const void *tx_buf, void *rx_buf, uint32_t len, enum transfer_type tran_type)
+{
+ uint8_t imask = 0;
+ uint16_t txlevel = 0;
- rever = mmio_read_32((uintptr_t)&dev->reg->spi_rxflr);
- ret = (int)rever;
+ dws->tx = NULL;
+ dws->tx_end = NULL;
+ dws->rx = NULL;
+ dws->rx_end = NULL;
- while (rever)
- {
- tem = mmio_read_32((uintptr_t)&dev->reg->spi_dr);
-
- if (dev->recv_buf < dev->recv_end)
- {
- if (dev->data_width == 8)
- *(uint8_t *)(dev->recv_buf) = tem;
- else
- *(uint16_t *)(dev->recv_buf) = tem;
- }
- else
- {
- return 0;
- }
+ if (tx_buf != NULL) {
+ dws->tx = tx_buf;
+ dws->tx_end = dws->tx + len;
+ }
- rever--;
- dev->recv_buf += dev->data_width >> 3;
+ if (rx_buf != NULL) {
+ dws->rx = rx_buf;
+ dws->rx_end = dws->rx + len;
}
- return ret;
-}
-int hw_spi_send(struct cv1800_spi *dev) {
- uint32_t txflr;
- uint32_t max;
- uint16_t value;
+ dws->rx_len = len / dws->n_bytes;
+ dws->tx_len = len / dws->n_bytes;
- txflr = mmio_read_32((uintptr_t)&dev->reg->spi_txflr);
- max = dev->fifo_len - txflr;
+ spi_enable_chip(dws, 0);
- while (max)
- {
- if (dev->send_end - dev->send_buf)
- {
- if (dev->data_width == 8)
- value = *(uint8_t *)(dev->send_buf);
- else
- value = *(uint16_t *)(dev->send_buf);
- }
- else
- {
- return 0;
- }
+ /* For poll mode just disable all interrupts */
+ spi_mask_intr(dws, 0xff);
+
+ /* set tran mode */
+ set_tran_mode(dws);
+
+ /* cs0 */
+ dw_spi_set_cs(dws, true, 0);
+
+ /* enable spi */
+ spi_enable_chip(dws, 1);
- mmio_write_32((uintptr_t)&dev->reg->spi_dr, value);
- dev->send_buf += dev->data_width >> 3;
- max--;
+ rt_hw_us_delay(10);
+
+ if (tran_type == POLL_TRAN)
+ {
+ if (poll_transfer(dws) < 0)
+ return -RT_ERROR;
+ }
+ else
+ {
+ return -RT_ENOSYS;
}
- return 0;
+ return RT_EOK;
}
-static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message) {
- int ret = 0;
- struct cv1800_spi *spi_dev;
+static rt_ssize_t spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
+{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
+ RT_ASSERT(device->bus->parent.user_data != RT_NULL);
RT_ASSERT(message != RT_NULL);
- spi_dev = (struct cv1800_spi *)(device->bus->parent.user_data);
+ struct _device_spi *spi = (struct _device_spi *)device->bus->parent.user_data;
+ struct dw_spi *dws = &spi->dws;
+ int32_t ret = 0;
- if (message->send_buf != RT_NULL)
+ if (message->send_buf && message->recv_buf)
{
- spi_dev->send_buf = message->send_buf;
- spi_dev->send_end = (void *)((uint8_t *)spi_dev->send_buf + message->length);
- }
+ ret = dw_spi_transfer_one(dws, message->send_buf, message->recv_buf, message->length, POLL_TRAN);
- if (message->recv_buf != RT_NULL)
- {
- spi_dev->recv_buf = message->recv_buf;
- spi_dev->recv_end = (void *)((uint8_t *)spi_dev->recv_buf + message->length);
}
-
- /* if user use their cs */
- if (message->cs_take && device->cs_pin != PIN_NONE)
- rt_pin_write(device->cs_pin, PIN_LOW);
-
- if (message->send_buf)
+ else if (message->send_buf)
{
- while (spi_dev->send_buf != spi_dev->send_end)
- {
- hw_spi_send(spi_dev);
- }
+ ret = dw_spi_transfer_one(dws, message->send_buf, RT_NULL, message->length, POLL_TRAN);
- /* wait for complete */
- while (mmio_read_32((uintptr_t)&spi_dev->reg->spi_txflr)) {}
-
- ret = message->length;
}
-
- if (message->recv_buf)
+ else if (message->recv_buf)
{
- while (spi_dev->recv_buf != spi_dev->recv_end)
- {
- hw_spi_recv(spi_dev);
- }
+ ret = dw_spi_transfer_one(dws, RT_NULL, message->recv_buf, message->length, POLL_TRAN);
- ret = message->length;
}
- if (message->cs_release && device->cs_pin != PIN_NONE)
- rt_pin_write(device->cs_pin, PIN_HIGH);
-
- return ret;
+ return message->length;
}
-const static struct rt_spi_ops drv_spi_ops =
+static const struct rt_spi_ops _spi_ops =
{
- drv_spi_configure,
- spixfer,
+ .configure = spi_configure,
+ .xfer = spi_xfer,
};
#if defined(BOARD_TYPE_MILKV_DUO) || defined(BOARD_TYPE_MILKV_DUO_SPINOR) || defined(BOARD_TYPE_MILKV_DUO256M) || defined(BOARD_TYPE_MILKV_DUO256M_SPINOR)
-
+// For Duo / Duo 256m, only SPI2 are exported on board.
#ifdef BSP_USING_SPI0
static const char *pinname_whitelist_spi0_sck[] = {
NULL,
@@ -283,54 +297,49 @@ static const char *pinname_whitelist_spi3_cs[] = {
static void rt_hw_spi_pinmux_config()
{
#ifdef BSP_USING_SPI0
- pinmux_config(BSP_SPI0_SCK_PINNAME, SPI0_SCK, pinname_whitelist_spi0_sck);
- pinmux_config(BSP_SPI0_SDO_PINNAME, SPI0_SDO, pinname_whitelist_spi0_sdo);
- pinmux_config(BSP_SPI0_SDI_PINNAME, SPI0_SDI, pinname_whitelist_spi0_sdi);
- pinmux_config(BSP_SPI0_CS_PINNAME, SPI0_CS_X, pinname_whitelist_spi0_cs);
+ pinmux_config(BSP_SPI0_SCK_PINNAME, SPI0_SCK, pinname_whitelist_spi0_sck);
+ pinmux_config(BSP_SPI0_SDO_PINNAME, SPI0_SDO, pinname_whitelist_spi0_sdo);
+ pinmux_config(BSP_SPI0_SDI_PINNAME, SPI0_SDI, pinname_whitelist_spi0_sdi);
+ pinmux_config(BSP_SPI0_CS_PINNAME, SPI0_CS_X, pinname_whitelist_spi0_cs);
#endif /* BSP_USING_SPI0 */
#ifdef BSP_USING_SPI1
- pinmux_config(BSP_SPI1_SCK_PINNAME, SPI1_SCK, pinname_whitelist_spi1_sck);
- pinmux_config(BSP_SPI1_SDO_PINNAME, SPI1_SDO, pinname_whitelist_spi1_sdo);
- pinmux_config(BSP_SPI1_SDI_PINNAME, SPI1_SDI, pinname_whitelist_spi1_sdi);
- pinmux_config(BSP_SPI1_CS_PINNAME, SPI1_CS_X, pinname_whitelist_spi1_cs);
+ pinmux_config(BSP_SPI1_SCK_PINNAME, SPI1_SCK, pinname_whitelist_spi1_sck);
+ pinmux_config(BSP_SPI1_SDO_PINNAME, SPI1_SDO, pinname_whitelist_spi1_sdo);
+ pinmux_config(BSP_SPI1_SDI_PINNAME, SPI1_SDI, pinname_whitelist_spi1_sdi);
+ pinmux_config(BSP_SPI1_CS_PINNAME, SPI1_CS_X, pinname_whitelist_spi1_cs);
#endif /* BSP_USING_SPI1 */
#ifdef BSP_USING_SPI2
- pinmux_config(BSP_SPI2_SCK_PINNAME, SPI2_SCK, pinname_whitelist_spi2_sck);
- pinmux_config(BSP_SPI2_SDO_PINNAME, SPI2_SDO, pinname_whitelist_spi2_sdo);
- pinmux_config(BSP_SPI2_SDI_PINNAME, SPI2_SDI, pinname_whitelist_spi2_sdi);
- pinmux_config(BSP_SPI2_CS_PINNAME, SPI2_CS_X, pinname_whitelist_spi2_cs);
+ pinmux_config(BSP_SPI2_SCK_PINNAME, SPI2_SCK, pinname_whitelist_spi2_sck);
+ pinmux_config(BSP_SPI2_SDO_PINNAME, SPI2_SDO, pinname_whitelist_spi2_sdo);
+ pinmux_config(BSP_SPI2_SDI_PINNAME, SPI2_SDI, pinname_whitelist_spi2_sdi);
+ pinmux_config(BSP_SPI2_CS_PINNAME, SPI2_CS_X, pinname_whitelist_spi2_cs);
#endif /* BSP_USING_SPI2 */
#ifdef BSP_USING_SPI3
- pinmux_config(BSP_SPI3_SCK_PINNAME, SPI3_SCK, pinname_whitelist_spi3_sck);
- pinmux_config(BSP_SPI3_SDO_PINNAME, SPI3_SDO, pinname_whitelist_spi3_sdo);
- pinmux_config(BSP_SPI3_SDI_PINNAME, SPI3_SDI, pinname_whitelist_spi3_sdi);
- pinmux_config(BSP_SPI3_CS_PINNAME, SPI3_CS_X, pinname_whitelist_spi3_cs);
+ pinmux_config(BSP_SPI3_SCK_PINNAME, SPI3_SCK, pinname_whitelist_spi3_sck);
+ pinmux_config(BSP_SPI3_SDO_PINNAME, SPI3_SDO, pinname_whitelist_spi3_sdo);
+ pinmux_config(BSP_SPI3_SDI_PINNAME, SPI3_SDI, pinname_whitelist_spi3_sdi);
+ pinmux_config(BSP_SPI3_CS_PINNAME, SPI3_CS_X, pinname_whitelist_spi3_cs);
#endif /* BSP_USING_SPI3 */
}
int rt_hw_spi_init(void)
{
rt_err_t ret = RT_EOK;
- struct spi_regs *reg = NULL;
+ struct dw_spi *dws;
rt_hw_spi_pinmux_config();
- for (rt_size_t i = 0; i < sizeof(cv1800_spi_obj) / sizeof(struct cv1800_spi); i++) {
- /* set reg base addr */
- reg = get_spi_base(cv1800_spi_obj[i].spi_id);
- if (!reg)
- return -RT_ERROR;
-
- cv1800_spi_obj[i].reg = reg;
- cv1800_spi_obj[i].spi_bus.parent.user_data = &cv1800_spi_obj[i];
-
- /* register spix bus */
- ret = rt_spi_bus_register(&cv1800_spi_obj[i].spi_bus, cv1800_spi_obj[i].device_name, &drv_spi_ops);
+ for (rt_size_t i = 0; i < sizeof(_spi_obj) / sizeof(struct _device_spi); i++)
+ {
+ _spi_obj[i].spi_bus.parent.user_data = (void *)&_spi_obj[i];
+ ret = rt_spi_bus_register(&_spi_obj[i].spi_bus, _spi_obj[i].device_name, &_spi_ops);
}
+ RT_ASSERT(ret == RT_EOK);
+
return ret;
}
INIT_BOARD_EXPORT(rt_hw_spi_init);
diff --git a/bsp/cvitek/drivers/drv_spi.h b/bsp/cvitek/drivers/drv_spi.h
index 2e20b15b2e..9ee398371d 100644
--- a/bsp/cvitek/drivers/drv_spi.h
+++ b/bsp/cvitek/drivers/drv_spi.h
@@ -5,151 +5,24 @@
*
* Change Logs:
* Date Author Notes
- * 2024-03-28 qiujingbao first version
+ * 2024-03-28 qiujingbao first version
+ * 2024/06/08 flyingcys fix transmission failure
*/
#ifndef __DRV_SPI_H__
#define __DRV_SPI_H__
-#include "rtdevice.h"
-#include <rthw.h>
-#include <rtthread.h>
-
#include "mmio.h"
-#include "pinctrl.h"
-
-#define SPI0 0x0
-#define SPI1 0x1
-#define SPI2 0x2
-#define SPI3 0x3
-
-#define SPI0_BASE 0x04180000
-#define SPI1_BASE 0x04190000
-#define SPI2_BASE 0x041A0000
-#define SPI3_BASE 0x041B0000
-
-#define SPI_IRQ_MSAK 0x3e
-#define SPI_FREQUENCY 187500000
-
-/* Transmit FiFO Threshold Level */
-#define SPI_TXFTLR 0xf
-
-#define SPI_CTRL0_DATA_FREAM_SHIFT 0
-#define SPI_CTRL0_FREAM_FORMAT_SHIFT 4
-#define SPI_CTRL0_CPHA_SHIFT 6
-#define SPI_CTRL0_CPOL_SHIFT 7
-#define SPI_CTRL0_TRANS_MODE 8
-#define SPI_CTRL0_LOOP_SHIFT 11
-#define SPI_CTRL0_CTRL_FREAM_SHIFT 12
-
-struct cv1800_spi {
- uint8_t spi_id;
- char *device_name;
-
- uint8_t fifo_len;
- uint8_t data_width;
-
- const void *send_buf;
- void *recv_buf;
-
- const void *send_end;
- void *recv_end;
-
- struct rt_spi_bus spi_bus;
- struct spi_regs *reg;
-};
-
-struct spi_regs {
- uint32_t spi_ctrl0; // 0x00
- uint32_t spi_ctrl1; // 0x04
- uint32_t spi_ssienr; // 0x08
- uint32_t spi_mwcr; // 0x0c
- uint32_t spi_ser; // 0x10
- uint32_t spi_baudr; // 0x14
- uint32_t spi_txftlr; // 0x18
- uint32_t spi_rxftlr; // 0x1c
- uint32_t spi_txflr; // 0x20
- uint32_t spi_rxflr; // 0x24
- uint32_t spi_sr; // 0x28
- uint32_t spi_imr; // 0x2c
- uint32_t spi_isr; // 0x30
- uint32_t spi_risr; // 0x34
- uint32_t spi_txoicr; // 0x38
- uint32_t spi_rxoicr; // 0x3c
- uint32_t spi_rxuicr; // 0x40
- uint32_t spi_msticr; // 0x44
- uint32_t spi_icr; // 0x48
- uint32_t spi_dmacr; // 0x4c
- uint32_t spi_dmatdlr; // 0x50
- uint32_t spi_dmardlr; // 0x54
- uint32_t spi_idr; // 0x58
- uint32_t spi_version; // 0x5c
- uint32_t spi_dr; // 0x60
- uint32_t spi_rx_sample_dly; // 0xf0
- uint32_t spi_cs_override; // 0xf4
-};
-
-uint32_t gen_spi_mode(struct rt_spi_configuration *cfg, uint32_t *mode)
-{
- uint32_t value = 0;
-
- if (cfg->data_width != 8 && cfg->data_width != 16)
- return -1;
-
- value |= (cfg->data_width - 1) >> SPI_CTRL0_DATA_FREAM_SHIFT;
- value |= cfg->mode >> SPI_CTRL0_CPHA_SHIFT;
-
- *mode = value;
- return 0;
-}
-
-/* set spi mode */
-static inline void spi_set_mode(struct spi_regs *reg, uint32_t mode)
-{
- mmio_write_32((uintptr_t)&reg->spi_ctrl0, mode);
-}
-
-/* clear irq */
-static inline void spi_clear_irq(struct spi_regs *reg, uint32_t mode)
-{
- mmio_write_32((uintptr_t)&reg->spi_imr, mode);
-}
-
-static inline void spi_enable_cs(struct spi_regs *reg, uint32_t enable)
-{
- if (enable)
- enable = 0x1;
- else
- enable = 0x0;
-
- mmio_write_32((uintptr_t)&reg->spi_ser, enable);
-}
-
-/* set spi frequency*/
-static inline rt_err_t spi_set_frequency(struct spi_regs *reg, uint32_t speed)
-{
- uint16_t value;
-
- /* The value of the BAUDR register must be an even number between 2-65534 */
- value = SPI_FREQUENCY / speed;
- if (value % 2 != 0)
- value++;
-
- if (value < 4 || value > 65534)
- value = 4;
-
- mmio_write_32((uintptr_t)&reg->spi_baudr, value);
-
- return RT_EOK;
-}
+#include "dw_spi.h"
-static inline void spi_enable(struct spi_regs *reg, uint32_t enable)
-{
- if (enable)
- enable = 0x1;
- else
- enable = 0x0;
+#define DW_SPI_REG_SIZE (0x10000UL)
+#define DW_SPI0_BASE (0x04180000UL)
+#define DW_SPI1_BASE (DW_SPI0_BASE + 1 * DW_SPI_REG_SIZE)
+#define DW_SPI2_BASE (DW_SPI0_BASE + 2 * DW_SPI_REG_SIZE)
+#define DW_SPI3_BASE (DW_SPI0_BASE + 3 * DW_SPI_REG_SIZE)
- mmio_write_32((uintptr_t)&reg->spi_ssienr, enable);
-}
+#define DW_SPI0_IRQn 54
+#define DW_SPI1_IRQn 55
+#define DW_SPI2_IRQn 56
+#define DW_SPI3_IRQn 56
#endif /* __DRV_SPI_H__ */
diff --git a/bsp/cvitek/drivers/libraries/spi/dw_spi.c b/bsp/cvitek/drivers/libraries/spi/dw_spi.c
new file mode 100644
index 0000000000..1c098e15ba
--- /dev/null
+++ b/bsp/cvitek/drivers/libraries/spi/dw_spi.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "mmio.h"
+#include "dw_spi.h"
+
+#include <rthw.h>
+
+#ifdef SPI_DEBUG
+#define SP_DEBUG_LOG printf
+#else
+#define SP_DEBUG_LOG
+#endif
+
+/* Restart the controller, disable all interrupts, clean rx fifo */
+void spi_hw_init(struct dw_spi *dws)
+{
+ /*
+ * Try to detect the FIFO depth if not set by interface driver,
+ * the depth could be from 2 to 256 from HW spec
+ */
+ if (!dws->fifo_len) {
+ uint32_t fifo;
+
+ for (fifo = 1; fifo < 256; fifo++) {
+ dw_writel(dws, CVI_DW_SPI_TXFTLR, fifo);
+ if (fifo != dw_readl(dws, CVI_DW_SPI_TXFTLR))
+ break;
+ }
+ dw_writel(dws, CVI_DW_SPI_TXFTLR, 0);
+
+ dws->fifo_len = (fifo == 1) ? 0 : fifo;
+
+ SP_DEBUG_LOG("Detected FIFO size: %u bytes\n", dws->fifo_len);
+ }
+}
+
+uint32_t min3(uint32_t a, uint32_t b, uint32_t c)
+{
+ uint32_t tmp;
+
+ tmp = (a < b) ? a : b;
+ return (tmp < c) ? tmp : c;
+}
+
+static inline void cpu_relax(void)
+{
+ //asm volatile("" ::: "memory");
+}
+
+static inline uint32_t tx_max(struct dw_spi *dws)
+{
+ uint32_t tx_left, tx_room, rxtx_gap, temp;
+ cpu_relax();
+ tx_left = dws->tx_len;
+ tx_room = dws->fifo_len - dw_readl(dws, CVI_DW_SPI_TXFLR);
+
+ /*
+ * Another concern is about the tx/rx mismatch, we
+ * though to use (dws->fifo_len - rxflr - txflr) as
+ * one maximum value for tx, but it doesn't cover the
+ * data which is out of tx/rx fifo and inside the
+ * shift registers. So a control from sw point of
+ * view is taken.
+ */
+
+ SP_DEBUG_LOG("tx left: %#x, tx room: %#x\n", tx_left, tx_room);
+ if (dws->rx != NULL && dws->tx != NULL) {
+ cpu_relax();
+ rxtx_gap = dws->fifo_len - (dws->rx_len - dws->tx_len);
+ temp = min3(tx_left, tx_room, (uint32_t)(rxtx_gap));
+ } else {
+ temp = tx_left < tx_room ? tx_left : tx_room;
+ }
+
+ SP_DEBUG_LOG("temp: %#x\n", temp);
+ return temp;
+}
+
+void dw_writer(struct dw_spi *dws)
+{
+ uint32_t max;
+ uint16_t txw = 0;
+
+ max = tx_max(dws);
+ SP_DEBUG_LOG("max: %#x \n", max);
+ while (max--) {
+ if (dws->tx) {
+ if (dws->n_bytes == 1)
+ txw = *(uint8_t *)(dws->tx);
+ else
+ txw = *(uint16_t *)(dws->tx);
+ }
+ dw_writel(dws, CVI_DW_SPI_DR, txw);
+ dws->tx += dws->n_bytes;
+ --dws->tx_len;
+ }
+}
+
+static inline uint32_t rx_max(struct dw_spi *dws)
+{
+ uint32_t temp;
+ uint32_t rx_left = dws->rx_len;
+ uint32_t data_in_fifo = dw_readl(dws, CVI_DW_SPI_RXFLR);
+
+ temp = (rx_left < data_in_fifo ? rx_left : data_in_fifo);
+ SP_DEBUG_LOG("data_in_fifo:%u temp: %u\n", data_in_fifo, temp);
+ return temp;
+}
+
+int dw_spi_check_status(struct dw_spi *dws, bool raw)
+{
+ uint32_t irq_status;
+ int ret = 0;
+
+ if (raw)
+ irq_status = dw_readl(dws, CVI_DW_SPI_RISR);
+ else
+ irq_status = dw_readl(dws, CVI_DW_SPI_ISR);
+
+ if (irq_status & CVI_SPI_INT_RXOI) {
+ SP_DEBUG_LOG("RX FIFO overflow detected\n");
+ ret = -1;
+ }
+
+ if (irq_status & CVI_SPI_INT_RXUI) {
+ SP_DEBUG_LOG("RX FIFO underflow detected\n");
+ ret = -1;
+ }
+
+ if (irq_status & CVI_SPI_INT_TXOI) {
+ SP_DEBUG_LOG("TX FIFO overflow detected\n");
+ ret = -1;
+ }
+
+ if (ret)
+ spi_reset_chip(dws);
+
+ return ret;
+}
+
+void dw_reader(struct dw_spi *dws)
+{
+ uint32_t max;
+ uint16_t rxw;
+
+ max = rx_max(dws);
+ SP_DEBUG_LOG("max: %#x \n", max);
+ while (max--) {
+ rxw = dw_readl(dws, CVI_DW_SPI_DR);
+ if (dws->rx) {
+ if (dws->n_bytes == 1)
+ *(uint8_t *)(dws->rx) = rxw;
+ else
+ *(uint16_t *)(dws->rx) = rxw;
+ dws->rx += dws->n_bytes;
+ }
+ --dws->rx_len;
+ }
+}
+
+int spi_delay_to_ns(struct spi_delay *_delay, struct dw_spi *dws)
+{
+ uint32_t delay = _delay->value;
+ uint32_t unit = _delay->unit;
+ uint32_t hz;
+
+ if (!delay)
+ return 0;
+
+ switch (unit) {
+ case SPI_DELAY_UNIT_USECS:
+ delay *= 1000;
+ break;
+ case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
+ break;
+ case SPI_DELAY_UNIT_SCK:
+ /* clock cycles need to be obtained from spi_transfer */
+ if (!dws)
+ return -1;
+ /* if there is no effective speed know, then approximate
+ * by underestimating with half the requested hz
+ */
+ hz = dws->speed_hz / 2;
+ if (!hz)
+ return -1;
+ delay *= DIV_ROUND_UP(1000000000, hz);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return delay;
+}
+
+static void _spi_transfer_delay_ns(uint32_t ns)
+{
+ if (!ns)
+ return;
+ if (ns <= 1000) {
+ rt_hw_us_delay(1);
+ } else {
+ uint32_t us = DIV_ROUND_UP(ns, 1000);
+ rt_hw_us_delay(us);
+ }
+}
+
+int spi_delay_exec(struct spi_delay *_delay, struct dw_spi *dws)
+{
+ int delay;
+
+ if (!_delay)
+ return -1;
+
+ delay = spi_delay_to_ns(_delay, dws);
+ if (delay < 0)
+ return delay;
+
+ _spi_transfer_delay_ns(delay);
+
+ return 0;
+}
+
+int poll_transfer(struct dw_spi *dws)
+{
+ struct spi_delay delay;
+ uint16_t nbits;
+ delay.unit = SPI_DELAY_UNIT_SCK;
+ nbits = dws->n_bytes * BITS_PER_BYTE;
+ int ret = 0;
+
+ do
+ {
+ dw_writer(dws);
+ cpu_relax();
+
+ delay.value = nbits * (dws->rx_len - dws->tx_len);
+ spi_delay_exec(&delay, dws);
+ dw_reader(dws);
+ cpu_relax();
+ ret = dw_spi_check_status(dws, true);
+ if (ret)
+ return ret;
+ } while (dws->rx_len && dws->tx_len);
+
+ return 0;
+}
+
+void set_tran_mode(struct dw_spi *dws)
+{
+ uint32_t reg = dw_readl(dws, CVI_DW_SPI_CTRLR0);
+ uint8_t tmode;
+
+ if (dws->rx && dws->tx) {
+ tmode = CVI_SPI_TMOD_TR;
+ } else if (dws->rx) {
+ tmode = CVI_SPI_TMOD_RO;
+ } else {
+ tmode = CVI_SPI_TMOD_TO;
+ }
+ reg &= ~CVI_SPI_TMOD_MASK;
+ reg |= (tmode << CVI_SPI_TMOD_OFFSET);
+
+ dw_writel(dws, CVI_DW_SPI_CTRLR0, reg);
+}
+
+void dw_spi_set_controller_mode(struct dw_spi *dws, uint8_t enable_master)
+{
+ /* do not support to switch controller mode, it is default master mode */
+}
+
+void dw_spi_set_cs(struct dw_spi *dws, bool enable, uint32_t index)
+{
+ uint32_t reg = dw_readl(dws, CVI_DW_SPI_SER);
+
+ if (enable)
+ dw_writel(dws, CVI_DW_SPI_SER, reg | BIT(index));
+ else
+ dw_writel(dws, CVI_DW_SPI_SER, reg & ~BIT(index));
+}
+
+void dw_spi_set_polarity_and_phase(struct dw_spi *dws, uint8_t format)
+{
+ uint32_t reg = dw_readl(dws, CVI_DW_SPI_CTRLR0);
+ reg &= ~(0x3 << 6);
+
+ switch (format) {
+ case SPI_FORMAT_CPOL0_CPHA0:
+ reg |= (SPI_MODE_0 << 6);
+ break;
+
+ case SPI_FORMAT_CPOL0_CPHA1:
+ reg |= (SPI_MODE_1 << 6);
+ break;
+
+ case SPI_FORMAT_CPOL1_CPHA0:
+ reg |= (SPI_MODE_2 << 6);
+ break;
+
+ case SPI_FORMAT_CPOL1_CPHA1:
+ reg |= (SPI_MODE_3 << 6);
+ break;
+
+ default:
+ reg = dw_readl(dws, CVI_DW_SPI_CTRLR0);
+ break;
+ }
+ SP_DEBUG_LOG("set phase and polarity: %#x\n", reg);
+ dw_writel(dws, CVI_DW_SPI_CTRLR0, reg);
+}
+
+uint32_t dw_spi_set_clock(struct dw_spi *dws, uint32_t clock_in, uint32_t clock_out)
+{
+ uint16_t div;
+
+ div = (DIV_ROUND_UP(clock_in, clock_out) + 1) & 0xfffe;
+ dws->speed_hz = clock_in / div;
+ SP_DEBUG_LOG("clk div value is: %u, hz:%u\n", div, dws->speed_hz);
+ spi_set_clk(dws, div);
+ return dws->speed_hz;
+}
+
+int dw_spi_set_data_frame_len(struct dw_spi *dws, uint32_t size)
+{
+ uint32_t temp = dw_readl(dws, CVI_DW_SPI_CTRLR0);
+ temp &= ~0xf;
+
+ if (size == 8) {
+ dws->n_bytes = 1;
+ } else if (size == 16) {
+ dws->n_bytes = 2;
+ } else {
+ SP_DEBUG_LOG("do not support %u bit data!\n", size);
+ return -1;
+ }
+ temp |= (size - 1);
+ dw_writel(dws, CVI_DW_SPI_CTRLR0, temp);
+ SP_DEBUG_LOG("set data frame len: %#x\n", temp);
+ return 0;
+}
+
+void dw_spi_show_regs(struct dw_spi *dws)
+{
+ SP_DEBUG_LOG("CTRLR0: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_CTRLR0));
+ SP_DEBUG_LOG("CTRLR1: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_CTRLR1));
+ SP_DEBUG_LOG("SSIENR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_SSIENR));
+ SP_DEBUG_LOG("SER: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_SER));
+ SP_DEBUG_LOG("BAUDR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_BAUDR));
+ SP_DEBUG_LOG("TXFTLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_TXFTLR));
+ SP_DEBUG_LOG("RXFTLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_RXFTLR));
+ SP_DEBUG_LOG("TXFLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_TXFLR));
+ SP_DEBUG_LOG("RXFLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_RXFLR));
+ SP_DEBUG_LOG("SR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_SR));
+ SP_DEBUG_LOG("IMR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_IMR));
+ SP_DEBUG_LOG("ISR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_ISR));
+ SP_DEBUG_LOG("DMACR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_DMACR));
+ SP_DEBUG_LOG("DMATDLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_DMATDLR));
+ SP_DEBUG_LOG("DMARDLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_DMARDLR));
+}
diff --git a/bsp/cvitek/drivers/libraries/spi/dw_spi.h b/bsp/cvitek/drivers/libraries/spi/dw_spi.h
new file mode 100644
index 0000000000..b5b6e6bc60
--- /dev/null
+++ b/bsp/cvitek/drivers/libraries/spi/dw_spi.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __DW_SPI_HEADER_H__
+#define __DW_SPI_HEADER_H__
+
+#include "stdint.h"
+#include "stdbool.h"
+
+#define SPI_REGBASE 0x04180000
+#define SPI_REF_CLK 187500000
+#define MAX_SPI_NUM 4
+
+#define CVI_DW_SPI_CTRLR0 0x00
+#define CVI_DW_SPI_CTRLR1 0x04
+#define CVI_DW_SPI_SSIENR 0x08
+#define CVI_DW_SPI_MWCR 0x0c
+#define CVI_DW_SPI_SER 0x10
+#define CVI_DW_SPI_BAUDR 0x14
+#define CVI_DW_SPI_TXFTLR 0x18
+#define CVI_DW_SPI_RXFTLR 0x1c
+#define CVI_DW_SPI_TXFLR 0x20
+#define CVI_DW_SPI_RXFLR 0x24
+#define CVI_DW_SPI_SR 0x28
+#define CVI_DW_SPI_IMR 0x2c
+#define CVI_DW_SPI_ISR 0x30
+#define CVI_DW_SPI_RISR 0x34
+#define CVI_DW_SPI_TXOICR 0x38
+#define CVI_DW_SPI_RXOICR 0x3c
+#define CVI_DW_SPI_RXUICR 0x40
+#define CVI_DW_SPI_MSTICR 0x44
+#define CVI_DW_SPI_ICR 0x48
+#define CVI_DW_SPI_DMACR 0x4c
+#define CVI_DW_SPI_DMATDLR 0x50
+#define CVI_DW_SPI_DMARDLR 0x54
+#define CVI_DW_SPI_IDR 0x58
+#define CVI_DW_SPI_VERSION 0x5c
+#define CVI_DW_SPI_DR 0x60
+
+/* Bit fields in CTRLR0 */
+#define CVI_SPI_DFS_OFFSET 0
+
+#define CVI_SPI_FRF_OFFSET 4
+#define CVI_SPI_FRF_SPI 0x0
+#define CVI_SPI_FRF_SSP 0x1
+#define CVI_SPI_FRF_MICROWIRE 0x2
+#define CVI_SPI_FRF_RESV 0x3
+
+#define CVI_SPI_MODE_OFFSET 6
+#define CVI_SPI_SCPH_OFFSET 6
+#define CVI_SPI_SCOL_OFFSET 7
+
+#define CVI_SPI_TMOD_OFFSET 8
+#define CVI_SPI_TMOD_MASK (0x3 << CVI_SPI_TMOD_OFFSET)
+#define CVI_SPI_TMOD_TR 0x0 /* xmit & recv */
+#define CVI_SPI_TMOD_TO 0x1 /* xmit only */
+#define CVI_SPI_TMOD_RO 0x2 /* recv only */
+#define CVI_SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
+
+#define CVI_SPI_SLVOE_OFFSET 10
+#define CVI_SPI_SRL_OFFSET 11
+#define CVI_SPI_CFS_OFFSET 12
+
+/* Bit fields in SR, 7 bits */
+#define CVI_SR_MASK 0x7f
+#define CVI_SR_BUSY (1 << 0)
+#define CVI_SR_TF_NOT_FULL (1 << 1)
+#define CVI_SR_TF_EMPT (1 << 2)
+#define CVI_SR_RF_NOT_EMPT (1 << 3)
+#define CVI_SR_RF_FULL (1 << 4)
+#define CVI_SR_TX_ERR (1 << 5)
+#define SR_DCOL (1 << 6)
+
+/* Bit fields in ISR, IMR, RISR, 7 bits */
+#define CVI_SPI_INT_TXEI (1 << 0)
+#define CVI_SPI_INT_TXOI (1 << 1)
+#define CVI_SPI_INT_RXUI (1 << 2)
+#define CVI_SPI_INT_RXOI (1 << 3)
+#define CVI_SPI_INT_RXFI (1 << 4)
+#define CVI_SPI_INT_MSTI (1 << 5)
+
+/* Bit fields in DMACR */
+#define CVI_SPI_DMA_RDMAE (1 << 0)
+#define CVI_SPI_DMA_TDMAE (1 << 1)
+
+/* TX RX interrupt level threshold, max can be 256 */
+#define CVI_SPI_INT_THRESHOLD 32
+#define BITS_PER_BYTE 8
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
+struct dw_spi {
+ void *regs;
+ int irq;
+ int index;
+ uint32_t fifo_len; /* depth of the FIFO buffer */
+ uint16_t num_cs; /* supported slave numbers */
+ uint32_t speed_hz;
+ /* Current message transfer state info */
+ size_t len;
+ const void *tx;
+ const void *tx_end;
+ void *rx;
+ void *rx_end;
+ uint32_t rx_len;
+ uint32_t tx_len;
+ uint8_t n_bytes; /* current is a 1/2 bytes op */
+ uint32_t dma_width;
+ int (*transfer_handler)(struct dw_spi *dws);
+
+ /* Bus interface info */
+ void *priv;
+};
+
+struct spi_delay {
+#define SPI_DELAY_UNIT_USECS 0
+#define SPI_DELAY_UNIT_NSECS 1
+#define SPI_DELAY_UNIT_SCK 2
+ uint16_t value;
+ uint8_t unit;
+};
+
+#define SPI_CPHA 0x01
+#define SPI_CPOL 0x02
+
+#define SPI_MODE_0 (0|0)
+#define SPI_MODE_1 (0|SPI_CPHA)
+#define SPI_MODE_2 (SPI_CPOL|0)
+#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
+
+enum transfer_type {
+ POLL_TRAN = 0,
+ IRQ_TRAN,
+ DMA_TRAN,
+};
+
+enum dw_ssi_type {
+ SSI_MOTO_SPI = 0,
+ SSI_TI_SSP,
+ SSI_NS_MICROWIRE,
+};
+
+#define SPI_FORMAT_CPOL0_CPHA0 0
+#define SPI_FORMAT_CPOL0_CPHA1 1
+#define SPI_FORMAT_CPOL1_CPHA0 2
+#define SPI_FORMAT_CPOL1_CPHA1 3
+
+#ifndef BIT
+#define BIT(_n) ( 1 << (_n))
+#endif
+
+static void dw_writel(struct dw_spi *dws, uint32_t off, uint32_t val)
+{
+ writel(val, (dws->regs + off));
+}
+
+static uint32_t dw_readl(struct dw_spi *dws, uint32_t off)
+{
+ return readl(dws->regs + off);
+}
+
+static inline void spi_enable_chip(struct dw_spi *dws, int enable)
+{
+ dw_writel(dws, CVI_DW_SPI_SSIENR, (enable ? 1 : 0));
+}
+
+static inline void spi_set_clk(struct dw_spi *dws, uint16_t div)
+{
+ dw_writel(dws, CVI_DW_SPI_BAUDR, div);
+}
+
+/* Disable IRQ bits */
+static inline void spi_mask_intr(struct dw_spi *dws, uint32_t mask)
+{
+ uint32_t new_mask;
+
+ new_mask = dw_readl(dws, CVI_DW_SPI_IMR) & ~mask;
+ dw_writel(dws, CVI_DW_SPI_IMR, new_mask);
+}
+
+static inline uint32_t spi_get_status(struct dw_spi *dws)
+{
+ return dw_readl(dws, CVI_DW_SPI_SR);
+}
+
+/* Enable IRQ bits */
+static inline void spi_umask_intr(struct dw_spi *dws, uint32_t mask)
+{
+ uint32_t new_mask;
+
+ new_mask = dw_readl(dws, CVI_DW_SPI_IMR) | mask;
+ dw_writel(dws, CVI_DW_SPI_IMR, new_mask);
+}
+
+static inline void spi_reset_chip(struct dw_spi *dws)
+{
+ spi_enable_chip(dws, 0);
+ spi_mask_intr(dws, 0xff);
+ dw_readl(dws, CVI_DW_SPI_ICR);
+ dw_writel(dws, CVI_DW_SPI_SER, 0);
+ spi_enable_chip(dws, 1);
+}
+
+static inline void spi_enable_dma(struct dw_spi *dws, uint8_t is_tx, uint8_t op)
+{
+ /* 1: TDMAE, 0: RDMAE */
+ uint32_t val = dw_readl(dws, CVI_DW_SPI_DMACR);
+
+ if (op)
+ val |= 1 << (!!is_tx);
+ else
+ val &= ~(1 << (!!is_tx));
+
+ dw_writel(dws, CVI_DW_SPI_DMACR, val);
+}
+
+static inline void spi_shutdown_chip(struct dw_spi *dws)
+{
+ spi_enable_chip(dws, 0);
+ spi_set_clk(dws, 0);
+}
+
+void spi_hw_init(struct dw_spi *dws);
+void dw_spi_set_controller_mode(struct dw_spi *dws, uint8_t enable_master);
+void dw_spi_set_polarity_and_phase(struct dw_spi *dws, uint8_t format);
+uint32_t dw_spi_set_clock(struct dw_spi *dws, uint32_t clock_in, uint32_t clock_out);
+int dw_spi_set_data_frame_len(struct dw_spi *dws, uint32_t size);
+void dw_spi_set_cs(struct dw_spi *dws, bool enable, uint32_t index);
+void dw_reader(struct dw_spi *dws);
+void dw_writer(struct dw_spi *dws);
+void set_tran_mode(struct dw_spi *dws);
+void dw_spi_show_regs(struct dw_spi *dws);
+int poll_transfer(struct dw_spi *dws);
+int dw_spi_check_status(struct dw_spi *dws, bool raw);
+#endif