This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 091372069c risc-v/bl808: Add SPI driver
091372069c is described below
commit 091372069c831ed63ddf2ec0ef7a998f9fc9a639
Author: Henry Rovner <[email protected]>
AuthorDate: Sat Jul 6 15:23:51 2024 -0700
risc-v/bl808: Add SPI driver
This commit implements a driver for SPI0 and SPI1 on the BL808 and
introduces an accompanying example configuration.
---
.../platforms/risc-v/bl808/boards/ox64/index.rst | 7 +
Documentation/platforms/risc-v/bl808/index.rst | 2 +-
arch/risc-v/include/bl808/irq.h | 2 +
arch/risc-v/src/bl808/Kconfig | 94 ++
arch/risc-v/src/bl808/Make.defs | 2 +-
arch/risc-v/src/bl808/bl808_gpio.h | 37 +-
arch/risc-v/src/bl808/bl808_spi.c | 1337 ++++++++++++++++++++
arch/risc-v/src/bl808/bl808_spi.h | 72 ++
arch/risc-v/src/bl808/hardware/bl808_glb.h | 19 +
arch/risc-v/src/bl808/hardware/bl808_memorymap.h | 3 +
.../bl808/hardware/{bl808_glb.h => bl808_mm_glb.h} | 45 +-
arch/risc-v/src/bl808/hardware/bl808_spi.h | 144 +++
boards/risc-v/bl808/ox64/configs/spi/defconfig | 100 ++
boards/risc-v/bl808/ox64/src/bl808_appinit.c | 13 +
14 files changed, 1829 insertions(+), 48 deletions(-)
diff --git a/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
b/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
index 9313dd2cbf..85d245ce7d 100644
--- a/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
+++ b/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
@@ -143,3 +143,10 @@ adc
This configuration enables support for the general purpose ADC and the adc
example app.
By default, the ADC will scan external channels 3, 4, 6, 7 and 9 (GPIO pins
11, 6, 12,
13 and 18). Serial Console is enabled on UART3 at 2 Mbps.
+
+spi
+---
+
+This configuration enables support for SPI0 and spitool.
+By default, GPIO14 is MISO, 13 is MOSI, 15 is SCLK and 12 is SS.
+Serial Console is enabled on UART3 at 2 Mbps.
diff --git a/Documentation/platforms/risc-v/bl808/index.rst
b/Documentation/platforms/risc-v/bl808/index.rst
index a91742fe22..f8f9d95d44 100644
--- a/Documentation/platforms/risc-v/bl808/index.rst
+++ b/Documentation/platforms/risc-v/bl808/index.rst
@@ -51,7 +51,7 @@ GPIO Yes
I2C No
I2S No
PWM No
-SPI No
+SPI Yes
Timers No
UART Yes
USB No
diff --git a/arch/risc-v/include/bl808/irq.h b/arch/risc-v/include/bl808/irq.h
index 4de1636b05..0b743f1063 100644
--- a/arch/risc-v/include/bl808/irq.h
+++ b/arch/risc-v/include/bl808/irq.h
@@ -52,12 +52,14 @@
/* D0 IRQs ******************************************************************/
#define BL808_IRQ_UART3 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 4)
+#define BL808_IRQ_SPI1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 7)
#define BL808_IRQ_D0_IPC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 38)
#define BL808_IRQ_M0IC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 65)
/* M0 IRQs ******************************************************************/
#define BL808_IRQ_GPADC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE +
BL808_M0_IRQ_OFFSET + 25)
+#define BL808_IRQ_SPI0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE +
BL808_M0_IRQ_OFFSET + 27)
#define BL808_IRQ_UART0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE +
BL808_M0_IRQ_OFFSET + 28)
#define BL808_IRQ_UART1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE +
BL808_M0_IRQ_OFFSET + 29)
#define BL808_IRQ_UART2 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE +
BL808_M0_IRQ_OFFSET + 30)
diff --git a/arch/risc-v/src/bl808/Kconfig b/arch/risc-v/src/bl808/Kconfig
index 0766d0dd5b..0156783813 100644
--- a/arch/risc-v/src/bl808/Kconfig
+++ b/arch/risc-v/src/bl808/Kconfig
@@ -130,4 +130,98 @@ config BL808_UART3
select UART3_SERIALDRIVER
select ARCH_HAVE_SERIAL_TERMIOS
+menuconfig BL808_SPI0
+ bool "SPI 0"
+ default n
+ select SPI
+
+if BL808_SPI0
+
+config BL808_SPI0_DEG_ENABLE
+ bool "Deglitch enable"
+ default y
+
+config BL808_SPI0_CONT_ENABLE
+ bool "Continuous transfer mode"
+ default y
+
+config BL808_SPI0_BYTE_INV
+ bool "Invert byte transfer order"
+ default n
+
+config BL808_SPI0_BIT_INV
+ bool "Invert bit transfer order"
+ default n
+
+comment "Refer to datasheet for valid pin assignments"
+
+config BL808_SPI0_MISO
+ int "MISO Pin"
+ default 14
+ range 0 45
+
+config BL808_SPI0_MOSI
+ int "MOSI Pin"
+ default 13
+ range 0 45
+
+config BL808_SPI0_SCLK
+ int "SCLK Pin"
+ default 15
+ range 0 45
+
+config BL808_SPI0_SS
+ int "SS Pin"
+ default 12
+ range 0 45
+
+endif
+
+menuconfig BL808_SPI1
+ bool "SPI 1"
+ default n
+ select SPI
+
+if BL808_SPI1
+
+config BL808_SPI1_DEG_ENABLE
+ bool "Deglitch enable"
+ default y
+
+config BL808_SPI1_CONT_ENABLE
+ bool "Continuous transfer mode"
+ default y
+
+config BL808_SPI1_BYTE_INV
+ bool "Invert byte transfer order"
+ default n
+
+config BL808_SPI1_BIT_INV
+ bool "Invert bit transfer order"
+ default n
+
+comment "Refer to datasheet for valid pin assignments"
+
+config BL808_SPI1_MISO
+ int "MISO Pin"
+ default 14
+ range 0 45
+
+config BL808_SPI1_MOSI
+ int "MOSI Pin"
+ default 13
+ range 0 45
+
+config BL808_SPI1_SCLK
+ int "SCLK Pin"
+ default 15
+ range 0 45
+
+config BL808_SPI1_SS
+ int "SS Pin"
+ default 12
+ range 0 45
+
+endif
+
endmenu
diff --git a/arch/risc-v/src/bl808/Make.defs b/arch/risc-v/src/bl808/Make.defs
index 89e9abe62c..ffb276ace9 100644
--- a/arch/risc-v/src/bl808/Make.defs
+++ b/arch/risc-v/src/bl808/Make.defs
@@ -28,4 +28,4 @@ HEAD_ASRC = bl808_head.S
CHIP_CSRCS = bl808_start.c bl808_irq_dispatch.c bl808_irq.c
CHIP_CSRCS += bl808_timerisr.c bl808_allocateheap.c
CHIP_CSRCS += bl808_gpio.c bl808_mm_init.c bl808_pgalloc.c bl808_serial.c
-CHIP_CSRCS += bl808_gpadc.c
+CHIP_CSRCS += bl808_gpadc.c bl808_spi.c
diff --git a/arch/risc-v/src/bl808/bl808_gpio.h
b/arch/risc-v/src/bl808/bl808_gpio.h
index f9b25c88bd..d51bdea699 100644
--- a/arch/risc-v/src/bl808/bl808_gpio.h
+++ b/arch/risc-v/src/bl808/bl808_gpio.h
@@ -43,7 +43,7 @@
* 1111 1100 0000 0000
* 5432 1098 7654 3210
* ---- ---- ---- ----
- * .... ..MU UDDS FFFF
+ * .... .MUU DDSF FFFF
*/
/* Mode:
@@ -51,10 +51,10 @@
* 1111 1100 0000 0000
* 5432 1098 7654 3210
* ---- ---- ---- ----
- * .... ..M. .... ....
+ * .... .M.. .... ....
*/
-#define GPIO_MODE_SHIFT (9) /* Bit 9: Port Mode */
+#define GPIO_MODE_SHIFT (10) /* Bit 10: Port Mode */
#define GPIO_MODE_MASK (1 << GPIO_MODE_SHIFT)
# define GPIO_INPUT (1 << GPIO_MODE_SHIFT) /* Input Enable */
# define GPIO_OUTPUT (0 << GPIO_MODE_SHIFT) /* Output Enable */
@@ -64,10 +64,10 @@
* 1111 1100 0000 0000
* 5432 1098 7654 3210
* ---- ---- ---- ----
- * .... ...U U... ....
+ * .... ..UU .... ....
*/
-#define GPIO_PUPD_SHIFT (7) /* Bits 7-8: Pull-up/down */
+#define GPIO_PUPD_SHIFT (8) /* Bits 8-9: Pull-up/down */
#define GPIO_PUPD_MASK (3 << GPIO_PUPD_SHIFT)
#define GPIO_FLOAT (0 << GPIO_PUPD_SHIFT) /* No pull-up, pull-down */
#define GPIO_PULLUP (1 << GPIO_PUPD_SHIFT) /* Pull-up */
@@ -78,10 +78,10 @@
* 1111 1100 0000 0000
* 5432 1098 7654 3210
* ---- ---- ---- ----
- * .... .... .DD. ....
+ * .... .... DD.. ....
*/
-#define GPIO_DRV_SHIFT (5) /* Bits 5-6: Drive */
+#define GPIO_DRV_SHIFT (6) /* Bits 6-7: Drive */
#define GPIO_DRV_MASK (3 << GPIO_DRV_SHIFT)
#define GPIO_DRV_0 (0 << GPIO_DRV_SHIFT)
#define GPIO_DRV_1 (1 << GPIO_DRV_SHIFT)
@@ -93,10 +93,10 @@
* 1111 1100 0000 0000
* 5432 1098 7654 3210
* ---- ---- ---- ----
- * .... .... ...S ....
+ * .... .... ..S. ....
*/
-#define GPIO_SMT_SHIFT (4) /* Bit 4: SMT Enable */
+#define GPIO_SMT_SHIFT (5) /* Bit 5: SMT Enable */
#define GPIO_SMT_MASK (3 << GPIO_SMT_SHIFT)
#define GPIO_SMT_DIS (0 << GPIO_SMT_SHIFT)
#define GPIO_SMT_EN (1 << GPIO_SMT_SHIFT)
@@ -106,21 +106,22 @@
* 1111 1100 0000 0000
* 5432 1098 7654 3210
* ---- ---- ---- ----
- * .... .... .... FFFF
+ * .... .... ...F FFFF
*/
-#define GPIO_FUNC_SHIFT (0) /* Bits 0-3: GPIO Type */
-#define GPIO_FUNC_MASK (15 << GPIO_FUNC_SHIFT)
-#define GPIO_FUNC_SDIO (1 << GPIO_FUNC_SHIFT) /* SDIO */
+#define GPIO_FUNC_SHIFT (0) /* Bits 0-4: GPIO Type */
+#define GPIO_FUNC_MASK (0x1f << GPIO_FUNC_SHIFT)
+#define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) /* SDH */
+#define GPIO_FUNC_SPI0 (1 << GPIO_FUNC_SHIFT) /* SPI0 */
#define GPIO_FUNC_FLASH (2 << GPIO_FUNC_SHIFT) /* Flash */
-#define GPIO_FUNC_SPI (4 << GPIO_FUNC_SHIFT) /* SPI */
-#define GPIO_FUNC_I2C (6 << GPIO_FUNC_SHIFT) /* I2C */
+#define GPIO_FUNC_I2C1 (6 << GPIO_FUNC_SHIFT) /* I2C1 */
#define GPIO_FUNC_UART (7 << GPIO_FUNC_SHIFT) /* UART */
-#define GPIO_FUNC_PWM (8 << GPIO_FUNC_SHIFT) /* PWM */
-#define GPIO_FUNC_EXT_PA (9 << GPIO_FUNC_SHIFT) /* Analog */
+#define GPIO_FUNC_CAM (9 << GPIO_FUNC_SHIFT) /* CSI */
#define GPIO_FUNC_ANA (10 << GPIO_FUNC_SHIFT) /* Analog */
#define GPIO_FUNC_SWGPIO (11 << GPIO_FUNC_SHIFT) /* Software GPIO */
-#define GPIO_FUNC_JTAG (14 << GPIO_FUNC_SHIFT) /* JTAG */
+#define GPIO_FUNC_PWM0 (16 << GPIO_FUNC_SHIFT) /* PWM0 */
+#define GPIO_FUNC_SPI1 (18 << GPIO_FUNC_SHIFT) /* SPI1 */
+#define GPIO_FUNC_JTAG_D0 (27 << GPIO_FUNC_SHIFT) /* JTAG */
/****************************************************************************
* Public Types
diff --git a/arch/risc-v/src/bl808/bl808_spi.c
b/arch/risc-v/src/bl808/bl808_spi.c
new file mode 100644
index 0000000000..2e00f32a6a
--- /dev/null
+++ b/arch/risc-v/src/bl808/bl808_spi.c
@@ -0,0 +1,1337 @@
+/****************************************************************************
+ * arch/risc-v/src/bl808/bl808_spi.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/compiler.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/signal.h>
+#include <nuttx/spi/spi.h>
+
+#include <arch/board/board.h>
+
+#include "bl808_gpio.h"
+#include "bl808_spi.h"
+#include "hardware/bl808_glb.h"
+#include "hardware/bl808_mm_glb.h"
+#include "hardware/bl808_spi.h"
+#include "riscv_internal.h"
+
+/* This file is based on bl602/bl602_spi.c */
+
+#if defined(CONFIG_BL808_SPI0) || defined(CONFIG_BL808_SPI1)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SPI_FREQ_DEFAULT 400000
+#define SPI_CLK_PRE_DIV 160000000
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* SPI frequency cal configuration */
+
+struct prescale_and_count_cal_ctx_s
+{
+ uint64_t desired_ticks;
+ uint64_t count_max;
+ uint64_t error;
+ uint64_t count;
+ uint32_t prescale;
+ uint8_t update;
+};
+
+/* SPI clock configuration */
+
+struct spi_clock_cfg_s
+{
+ uint8_t start_len; /* Length of start condition */
+ uint8_t stop_len; /* Length of stop condition */
+ uint8_t data_phase0_len; /* Length of data phase 0,affecting clock */
+ uint8_t data_phase1_len; /* Length of data phase 1,affecting clock */
+ uint8_t interval_len; /* Length of interval between frame */
+};
+
+/* SPI Device hardware configuration */
+
+struct bl808_spi_config_s
+{
+ uint32_t clk_freq; /* SPI clock frequency */
+ enum spi_mode_e mode; /* SPI default mode */
+
+ bool deglitch_enable; /* Enable or disable de-glitch function */
+ bool continuous_enable; /* Enable or disable master continuous transfer
+ * mode,enable:SS will stay asserted if next data
+ * is valid
+ */
+ bool byte_invert; /* The byte is sent first in SPI transfer ,0 is send
+ * 0byte first; 1 is send 3byte first
+ */
+ bool bit_invert; /* The bit is sent first in SPI transfer ,0 is each
byte
+ * is sent out MSB first; 1 is each byte is sent out
LSB
+ * first
+ */
+};
+
+struct bl808_spi_priv_s
+{
+ /* Externally visible part of the SPI interface */
+
+ struct spi_dev_s spi_dev;
+
+ /* SPI block ID */
+
+ uint8_t idx;
+
+ /* Port configuration */
+
+ const struct bl808_spi_config_s *config;
+
+ int refs; /* Referernce count */
+
+ /* Held while chip is selected for mutual exclusion */
+
+ mutex_t lock;
+
+ uint32_t frequency; /* Requested clock frequency */
+ uint32_t actual; /* Actual clock frequency */
+
+ enum spi_mode_e mode; /* Actual SPI hardware mode */
+
+ /* Actual SPI send/receive bits once transmission */
+
+ uint8_t nbits;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int bl808_spi_lock(struct spi_dev_s *dev, bool lock);
+
+static void bl808_spi_select(struct spi_dev_s *dev, uint32_t devid,
+ bool selected);
+
+static uint32_t bl808_spi_setfrequency(struct spi_dev_s *dev,
+ uint32_t frequency);
+static void bl808_spi_setmode(struct spi_dev_s *dev,
+ enum spi_mode_e mode);
+static void bl808_spi_setbits(struct spi_dev_s *dev, int nbits);
+#ifdef CONFIG_SPI_HWFEATURES
+static int bl808_spi_hwfeatures(struct spi_dev_s *dev,
+ spi_hwfeatures_t features);
+#endif
+static uint8_t bl808_spi_status(struct spi_dev_s *dev,
+ uint32_t devid);
+#ifdef CONFIG_SPI_CMDDATA
+static int bl808_spi_cmddata(struct spi_dev_s *dev,
+ uint32_t devid, bool cmd);
+#endif
+static uint32_t bl808_spi_send(struct spi_dev_s *dev, uint32_t wd);
+static void bl808_spi_exchange(struct spi_dev_s *dev,
+ const void *txbuffer,
+ void *rxbuffer, size_t nwords);
+#ifndef CONFIG_SPI_EXCHANGE
+static void bl808_spi_sndblock(struct spi_dev_s *dev,
+ const void *txbuffer, size_t nwords);
+static void bl808_spi_recvblock(struct spi_dev_s *dev,
+ void *rxbuffer, size_t nwords);
+#endif
+#ifdef CONFIG_SPI_TRIGGER
+static int bl808_spi_trigger(struct spi_dev_s *dev);
+#endif
+static void bl808_spi_init(struct spi_dev_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct spi_ops_s bl808_spi_ops =
+{
+ .lock = bl808_spi_lock,
+ .select = bl808_spi_select,
+ .setfrequency = bl808_spi_setfrequency,
+#ifdef CONFIG_SPI_DELAY_CONTROL
+ .setdelay = bl808_spi_setdelay,
+#endif
+ .setmode = bl808_spi_setmode,
+ .setbits = bl808_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = bl808_spi_hwfeatures,
+#endif
+ .status = bl808_spi_status,
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = bl808_spi_cmddata,
+#endif
+ .send = bl808_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = bl808_spi_exchange,
+#else
+ .sndblock = bl808_spi_sndblock,
+ .recvblock = bl808_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_TRIGGER
+ .trigger = bl808_spi_trigger,
+#endif
+ .registercallback = NULL,
+};
+
+#ifdef CONFIG_BL808_SPI0
+static const struct bl808_spi_config_s bl808_spi0_config =
+{
+ .clk_freq = SPI_FREQ_DEFAULT,
+ .mode = SPIDEV_MODE0,
+
+#ifdef CONFIG_BL808_SPI0_DEG_ENABLE
+ .deglitch_enable = 1,
+#else
+ .deglitch_enable = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI0_CONT_ENABLE
+ .continuous_enable = 1,
+#else
+ .continuous_enable = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI0_BYTE_INV
+ .byte_invert = 1,
+#else
+ .byte_invert = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI0_BIT_INV
+ .bit_invert = 1,
+#else
+ .bit_invert = 0,
+#endif
+};
+
+static struct bl808_spi_priv_s bl808_spi0_priv =
+{
+ .spi_dev =
+ {
+ .ops = &bl808_spi_ops
+ },
+ .idx = 0,
+ .config = &bl808_spi0_config,
+ .lock = NXMUTEX_INITIALIZER,
+};
+
+#endif /* CONFIG_BL808_SPI0 */
+
+#ifdef CONFIG_BL808_SPI1
+static const struct bl808_spi_config_s bl808_spi1_config =
+{
+ .clk_freq = SPI_FREQ_DEFAULT,
+ .mode = SPIDEV_MODE0,
+
+#ifdef CONFIG_BL808_SPI1_DEG_ENABLE
+ .deglitch_enable = 1,
+#else
+ .deglitch_enable = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI1_CONT_ENABLE
+ .continuous_enable = 1,
+#else
+ .continuous_enable = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI1_BYTE_INV
+ .byte_invert = 1,
+#else
+ .byte_invert = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI1_BIT_INV
+ .bit_invert = 1,
+#else
+ .bit_invert = 0,
+#endif
+};
+
+static struct bl808_spi_priv_s bl808_spi1_priv =
+{
+ .spi_dev =
+ {
+ .ops = &bl808_spi_ops
+ },
+ .idx = 1,
+ .config = &bl808_spi1_config,
+ .lock = NXMUTEX_INITIALIZER,
+};
+
+#endif /* CONFIG_BL808_SPI1 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl808_check_with_new_prescale
+ *
+ * Description:
+ * Check if the option prescale
+ *
+ ****************************************************************************/
+
+static void
+bl808_check_with_new_prescale(struct prescale_and_count_cal_ctx_s *p_ctx,
+ uint32_t prescale_new)
+{
+ uint64_t count = p_ctx->desired_ticks / prescale_new;
+ uint64_t error;
+
+ if (count > p_ctx->count_max)
+ {
+ count = p_ctx->count_max;
+ }
+
+ error = p_ctx->desired_ticks - count * prescale_new;
+
+ if (p_ctx->error > error)
+ {
+ p_ctx->error = error;
+ p_ctx->count = count;
+ p_ctx->prescale = prescale_new;
+ p_ctx->update = 1;
+ }
+}
+
+/****************************************************************************
+ * Name: bl808_prescale_and_count_cal
+ *
+ * Description:
+ * prescale and count cal
+ *
+ ****************************************************************************/
+
+static int
+bl808_prescale_and_count_cal(uint32_t counter_width,
+ uint32_t prescale_max, size_t ticks,
+ uint32_t *p_prescale, size_t *p_count)
+{
+ struct prescale_and_count_cal_ctx_s ctx;
+
+ uint32_t prescale_min;
+ uint32_t prescale;
+
+ size_t count_max;
+
+ count_max = ((uint64_t)1ull << counter_width) - 1;
+
+ if (ticks <= count_max)
+ {
+ *p_prescale = 1;
+ *p_count = ticks;
+
+ return 0;
+ }
+
+ prescale_min = ticks / count_max;
+
+ ctx.count_max = count_max;
+ ctx.desired_ticks = ticks;
+ ctx.error = ticks;
+ ctx.count = count_max;
+ ctx.prescale = 1;
+ ctx.update = 0;
+
+ if (prescale_max < prescale_min)
+ {
+ return -1;
+ }
+
+ for (prescale = prescale_min; prescale <= prescale_max; prescale++)
+ {
+ bl808_check_with_new_prescale(&ctx, prescale);
+ if (ctx.error == 0)
+ {
+ break;
+ }
+ }
+
+ if (ctx.update)
+ {
+ *p_prescale = ctx.prescale;
+ *p_count = ctx.count;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/****************************************************************************
+ * Name: bl808_set_spi_clk
+ *
+ * Description:
+ * set SPI clock
+ *
+ ****************************************************************************/
+
+static void bl808_set_spi_clk(uint8_t div, uint8_t idx)
+{
+ if (idx == 0)
+ {
+ modifyreg32(BL808_GLB_SPI_CFG0,
+ SPI_CFG_CLK_DIV_MASK,
+ (div << SPI_CFG_CLK_DIV_SHIFT));
+ }
+ else
+ {
+ modifyreg32(BL808_MM_GLB_CLK_CTRL_PERI,
+ CLK_CTRL_PERI_SPI_DIV_MASK,
+ (div << CLK_CTRL_PERI_SPI_DIV_SHIFT));
+ }
+}
+
+/****************************************************************************
+ * Name: bl808_clockconfig
+ *
+ * Description:
+ * SPI clock config
+ *
+ ****************************************************************************/
+
+static void bl808_clockconfig(struct spi_clock_cfg_s *clockcfg, uint8_t idx)
+{
+ /* Configure length of data phase1/0 and start/stop condition */
+
+ modifyreg32(BL808_SPI_PRD_0(idx), SPI_PRD_0_CR_S_MASK,
+ (clockcfg->start_len - 1));
+ modifyreg32(BL808_SPI_PRD_0(idx), SPI_PRD_0_CR_P_MASK,
+ (clockcfg->stop_len - 1) << SPI_PRD_0_CR_P_SHIFT);
+ modifyreg32(BL808_SPI_PRD_0(idx), SPI_PRD_0_CR_D_PH_0_MASK,
+ (clockcfg->data_phase0_len - 1) << SPI_PRD_0_CR_D_PH_0_SHIFT);
+ modifyreg32(BL808_SPI_PRD_0(idx), SPI_PRD_0_CR_D_PH_1_MASK,
+ (clockcfg->data_phase1_len - 1) << SPI_PRD_0_CR_D_PH_1_SHIFT);
+
+ /* Configure length of interval between frame */
+
+ modifyreg32(BL808_SPI_PRD_1(idx), SPI_PRD_1_CR_I_MASK,
+ clockcfg->interval_len - 1);
+}
+
+/****************************************************************************
+ * Name: bl808_spi_lock
+ *
+ * Description:
+ * Lock or unlock the SPI device
+ *
+ * Input Parameters:
+ * priv - Private SPI device structure
+ * lock - true: Lock spi bus, false: unlock SPI bus
+ *
+ * Returned Value:
+ * The result of lock or unlock the SPI device
+ *
+ ****************************************************************************/
+
+static int bl808_spi_lock(struct spi_dev_s *dev, bool lock)
+{
+ int ret;
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+
+ if (lock)
+ {
+ ret = nxmutex_lock(&priv->lock);
+ }
+ else
+ {
+ ret = nxmutex_unlock(&priv->lock);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: bl808_spi_select
+ *
+ * Description:
+ * Enable/disable the SPI chip select. The implementation of this method
+ * must include handshaking: If a device is selected, it must hold off
+ * all other attempts to select the device until the device is deselected.
+ *
+ * If disable bl808_SPI_SWCS, driver will use hardware CS so that when
+ * once transmission is started, hardware select the device and when this
+ * transmission is done, hardware deselect the device automatically. And
+ * the function will do nothing.
+ *
+ * Input Parameters:
+ * priv - Private SPI device structure
+ * devid - Identifies the device to select
+ * selected - true: slave selected, false: slave de-selected
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void bl808_spi_select(struct spi_dev_s *dev, uint32_t devid,
+ bool selected)
+{
+ /* we used hardware CS */
+
+ spiinfo("devid: %u, CS: %s\n", devid, selected ? "select" : "free");
+
+#ifdef CONFIG_SPI_CMDDATA
+ /* revert MISO from GPIO Pin to SPI Pin */
+
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+ if (!selected)
+ {
+#ifdef CONFIG_BL808_SPI0
+ if (priv->idx == 0)
+ {
+ bl808_configgpio(CONFIG_BL808_SPI0_MISO,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI0);
+ }
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+ if (priv->idx == 1)
+ {
+ bl808_configgpio(CONFIG_BL808_SPI1_MISO,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI0);
+ }
+#endif
+ }
+#endif
+}
+
+/****************************************************************************
+ * Name: bl808_spi_setfrequency
+ *
+ * Description:
+ * Set the SPI frequency.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * frequency - The SPI frequency requested
+ *
+ * Returned Value:
+ * Returns the actual frequency selected
+ *
+ ****************************************************************************/
+
+static uint32_t bl808_spi_setfrequency(struct spi_dev_s *dev,
+ uint32_t frequency)
+{
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+ uint8_t idx = priv->idx;
+ struct spi_clock_cfg_s clockcfg;
+ size_t count;
+ uint32_t ticks;
+ uint32_t clk_div;
+
+ if (priv->frequency == frequency)
+ {
+ /* We are already at this frequency. Return the actual. */
+
+ return priv->actual;
+ }
+
+ ticks = SPI_CLK_PRE_DIV / frequency;
+
+ /* Width of SPI1 clk div is 8, vs 5 for SPI0 */
+
+ uint32_t max_div = (idx == 0) ? 32 : 256;
+
+ if (bl808_prescale_and_count_cal(8, max_div, ticks, &clk_div, &count) != 0)
+ {
+ spierr("SPI div clk error\n");
+ DEBUGPANIC();
+
+ return -1;
+ }
+
+ bl808_set_spi_clk(1, clk_div - 1);
+
+ clockcfg.start_len = count;
+ clockcfg.stop_len = count;
+ clockcfg.data_phase0_len = count;
+ clockcfg.data_phase1_len = count;
+ clockcfg.interval_len = count;
+
+ bl808_clockconfig(&clockcfg, idx);
+
+ priv->frequency = frequency;
+
+ spiinfo("frequency=%u, actual=%u\n", priv->frequency, priv->actual);
+
+ return priv->actual;
+}
+
+/****************************************************************************
+ * Name: bl808_spi_setdelay
+ *
+ * Description:
+ * Set the SPI Delays in nanoseconds. Optional.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * startdelay - The delay between CS active and first CLK
+ * stopdelay - The delay between last CLK and CS inactive
+ * csdelay - The delay between CS inactive and CS active again
+ * ifdelay - The delay between frames
+ *
+ * Returned Value:
+ * Returns zero (OK) on success; a negated errno value is return on any
+ * failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_DELAY_CONTROL
+static int bl808_spi_setdelay(struct spi_dev_s *dev, uint32_t startdelay,
+ uint32_t stopdelay, uint32_t csdelay,
+ uint32_t ifdelay)
+{
+ spierr("SPI CS delay control not supported\n");
+ DEBUGPANIC();
+
+ return -1;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_setmode
+ *
+ * Description:
+ * Set the SPI mode.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * mode - The SPI mode requested
+ *
+ * Returned Value:
+ * none
+ *
+ ****************************************************************************/
+
+static void
+bl808_spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode)
+{
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+ uint8_t idx = priv->idx;
+
+ spiinfo("mode=%d\n", mode);
+
+ /* Has the mode changed? */
+
+ if (mode != priv->mode)
+ {
+ switch (mode)
+ {
+ /* NOTE: CPHA definition in the register is inverted compared
+ * to the standard. See reference manual or bouffalo_sdk.
+ */
+
+ case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_SCLK_POL,
+ SPI_CFG_CR_SCLK_PH);
+ break;
+
+ case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_SCLK_POL
+ | SPI_CFG_CR_SCLK_PH, 0);
+ break;
+
+ case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
+ modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_SCLK_POL
+ | SPI_CFG_CR_SCLK_PH);
+ break;
+
+ case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_SCLK_PH,
+ SPI_CFG_CR_SCLK_POL);
+ break;
+
+ default:
+ return;
+ }
+
+ priv->mode = mode;
+ }
+}
+
+/****************************************************************************
+ * Name: bl808_spi_setbits
+ *
+ * Description:
+ * Set the number if bits per word.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * nbits - The number of bits in an SPI word.
+ *
+ * Returned Value:
+ * none
+ *
+ ****************************************************************************/
+
+static void bl808_spi_setbits(struct spi_dev_s *dev, int nbits)
+{
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+ uint8_t idx = priv->idx;
+
+ spiinfo("nbits=%d\n", nbits);
+
+ /* Has the number of bits changed? */
+
+ if (nbits != priv->nbits)
+ {
+ /* Save the selection so that subsequent re-configurations
+ * will be faster.
+ */
+
+ switch (nbits)
+ {
+ case 8:
+
+ /* set valid width for each fifo entry 8 bit */
+
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_FRAME_SIZE_MASK, 0);
+ break;
+
+ case 16:
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_FRAME_SIZE_MASK,
+ 1 << SPI_CFG_CR_FRAME_SIZE_SHIFT);
+ break;
+
+ case 24:
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_FRAME_SIZE_MASK,
+ 2 << SPI_CFG_CR_FRAME_SIZE_SHIFT);
+ break;
+
+ case 32:
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_FRAME_SIZE_MASK,
+ 3 << SPI_CFG_CR_FRAME_SIZE_SHIFT);
+ break;
+
+ default:
+ return;
+ }
+
+ priv->nbits = nbits;
+ }
+}
+
+/****************************************************************************
+ * Name: bl808_spi_status
+ *
+ * Description:
+ * Get SPI/MMC status. Optional.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * devid - Identifies the device to report status on
+ *
+ * Returned Value:
+ * Returns a bitset of status values (see SPI_STATUS_* defines)
+ *
+ ****************************************************************************/
+
+static uint8_t bl808_spi_status(struct spi_dev_s *dev, uint32_t devid)
+{
+ uint8_t status = 0;
+
+ return status;
+}
+
+/****************************************************************************
+ * Name: bl808_spi_cmddata
+ *
+ * Description:
+ * Some devices require an additional out-of-band bit to specify if the
+ * next word sent to the device is a command or data. This is typical, for
+ * example, in "9-bit" displays where the 9th bit is the CMD/DATA bit.
+ * This function provides selection of command or data.
+ *
+ * This "latches" the CMD/DATA state. It does not have to be called before
+ * every word is transferred; only when the CMD/DATA state changes. This
+ * method is required if CONFIG_SPI_CMDDATA is selected in the NuttX
+ * configuration
+ *
+ * This function reconfigures MISO from SPI Pin to GPIO Pin, and sets
+ * MISO to high (data) or low (command). bl808_spi_select() will revert
+ * MISO back from GPIO Pin to SPI Pin. We must revert because the SPI Bus
+ * may be used by other drivers.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * cmd - TRUE: The following word is a command; FALSE: the following words
+ * are data.
+ *
+ * Returned Value:
+ * OK unless an error occurs. Then a negated errno value is returned
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_CMDDATA
+static int bl808_spi_cmddata(struct spi_dev_s *dev,
+ uint32_t devid, bool cmd)
+{
+ spiinfo("devid: %" PRIu32 " CMD: %s\n", devid, cmd ? "command" :
+ "data");
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+
+ if (devid == SPIDEV_DISPLAY(0))
+ {
+ gpio_pinset_t gpio;
+ int ret;
+
+ /* reconfigure MISO from SPI Pin to GPIO Pin,
+ * then write 0 for command or 1 for data
+ */
+
+#ifdef CONFIG_BL808_SPI0
+ if (priv->idx == 0)
+ {
+ bl808_configgpio(BL808_SPI0_MISO, GPIO_OUTPUT
+ | GPIO_PULLUP
+ | GPIO_FUNC_SWGPIO);
+
+ bl808_gpiowrite(BL808_SPI0_MISO, !cmd);
+ }
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+ if (priv->idx == 1)
+ {
+ bl808_configgpio(BL808_SPI1_MISO, GPIO_OUTPUT
+ | GPIO_PULLUP
+ | GPIO_FUNC_SWGPIO);
+
+ bl808_gpiowrite(BL808_SPI1_MISO, !cmd);
+ }
+#endif
+
+ return OK;
+ }
+
+ spierr("SPI cmddata not supported\n");
+ DEBUGPANIC();
+
+ return -ENODEV;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_hwfeatures
+ *
+ * Description:
+ * Set hardware-specific feature flags.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * features - H/W feature flags
+ *
+ * Returned Value:
+ * Zero (OK) if the selected H/W features are enabled; A negated errno
+ * value if any H/W feature is not supportable.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_HWFEATURES
+static int bl808_spi_hwfeatures(struct spi_dev_s *dev,
+ spi_hwfeatures_t features)
+{
+ /* Other H/W features are not supported */
+
+ spierr("SPI hardware specific feature not supported\n");
+ DEBUGPANIC();
+
+ return -1;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_poll_send
+ *
+ * Description:
+ * Exchange one word on SPI by polling mode.
+ *
+ * Input Parameters:
+ * priv - SPI private state data
+ * wd - The word to send. the size of the data is determined by the
+ * number of bits selected for the SPI interface.
+ *
+ * Returned Value:
+ * Received value
+ *
+ ****************************************************************************/
+
+static uint32_t bl808_spi_poll_send(struct bl808_spi_priv_s *priv,
+ uint32_t wd)
+{
+ uint8_t idx = priv->idx;
+ uint32_t val;
+ uint32_t tmp_val = 0;
+
+ /* spi fifo clear */
+
+ modifyreg32(BL808_SPI_FIFO_CFG_0(idx), 0,
+ SPI_FIFO_CFG_0_RX_CLR
+ | SPI_FIFO_CFG_0_TX_CLR);
+
+ /* write data to tx fifo */
+
+ putreg32(wd, BL808_SPI_FIFO_WDATA(idx));
+
+ /* spi enable master */
+
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_S_EN, SPI_CFG_CR_M_EN);
+
+ while (0 == tmp_val)
+ {
+ /* get data from rx fifo */
+
+ tmp_val = getreg32(BL808_SPI_FIFO_CFG_1(idx));
+ tmp_val = (tmp_val & SPI_FIFO_CFG_1_RX_CNT_MASK)
+ >> SPI_FIFO_CFG_1_RX_CNT_SHIFT;
+ }
+
+ val = getreg32(BL808_SPI_FIFO_RDATA(idx));
+
+ spiinfo("send=%x and recv=%x\n", wd, val);
+
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_M_EN, 0);
+
+ return val;
+}
+
+/****************************************************************************
+ * Name: bl808_spi_send
+ *
+ * Description:
+ * Exchange one word on SPI.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * wd - The word to send. the size of the data is determined by the
+ * number of bits selected for the SPI interface.
+ *
+ * Returned Value:
+ * Received value
+ *
+ ****************************************************************************/
+
+static uint32_t bl808_spi_send(struct spi_dev_s *dev, uint32_t wd)
+{
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+ return bl808_spi_poll_send(priv, wd);
+}
+
+/****************************************************************************
+ * Name: bl808_spi_poll_exchange
+ *
+ * Description:
+ * Exchange a block of data from SPI.
+ *
+ * Input Parameters:
+ * priv - SPI private state data
+ * txbuffer - A pointer to the buffer of data to be sent
+ * rxbuffer - A pointer to the buffer in which to receive data
+ * nwords - the length of data that to be exchanged in units of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface. If nbits <= 8, the data is
+ * packed into uint8_t's; if nbits >8, the data is packed into
+ * uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void bl808_spi_poll_exchange(struct bl808_spi_priv_s *priv,
+ const void *txbuffer,
+ void *rxbuffer, size_t nwords)
+{
+ int i;
+ uint32_t w_wd = 0xffff;
+ uint32_t r_wd;
+
+ for (i = 0; i < nwords; i++)
+ {
+ if (txbuffer)
+ {
+ if (priv->nbits == 8)
+ {
+ w_wd = ((uint8_t *)txbuffer)[i];
+ }
+ else
+ {
+ w_wd = ((uint16_t *)txbuffer)[i];
+ }
+ }
+
+ r_wd = bl808_spi_poll_send(priv, w_wd);
+
+ if (rxbuffer)
+ {
+ if (priv->nbits == 8)
+ {
+ ((uint8_t *)rxbuffer)[i] = r_wd;
+ }
+ else
+ {
+ ((uint16_t *)rxbuffer)[i] = r_wd;
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: bl808_spi_exchange
+ *
+ * Description:
+ * Exchange a block of data from SPI.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * txbuffer - A pointer to the buffer of data to be sent
+ * rxbuffer - A pointer to the buffer in which to receive data
+ * nwords - the length of data that to be exchanged in units of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface. If nbits <= 8, the data is
+ * packed into uint8_t's; if nbits >8, the data is packed into
+ * uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void bl808_spi_exchange(struct spi_dev_s *dev,
+ const void *txbuffer, void *rxbuffer,
+ size_t nwords)
+{
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+ bl808_spi_poll_exchange(priv, txbuffer, rxbuffer, nwords);
+}
+
+#ifndef CONFIG_SPI_EXCHANGE
+
+/****************************************************************************
+ * Name: bl808_spi_sndblock
+ *
+ * Description:
+ * Send a block of data on SPI.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * buffer - A pointer to the buffer of data to be sent
+ * nwords - the length of data to send from the buffer in number of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface. If nbits <= 8, the data is
+ * packed into uint8_t's; if nbits >8, the data is packed into
+ * uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void bl808_spi_sndblock(struct spi_dev_s *dev,
+ const void *txbuffer, size_t nwords)
+{
+ spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords);
+
+ bl808_spi_exchange(dev, txbuffer, NULL, nwords);
+}
+
+/****************************************************************************
+ * Name: bl808_spi_recvblock
+ *
+ * Description:
+ * Receive a block of data from SPI.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * buffer - A pointer to the buffer in which to receive data
+ * nwords - the length of data that can be received in the buffer in number
+ * of words. The wordsize is determined by the number of bits-
+ * per-word selected for the SPI interface. If nbits <= 8, the
+ * data is packed into uint8_t's; if nbits >8, the data is packed
+ * into uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void bl808_spi_recvblock(struct spi_dev_s *dev,
+ void *rxbuffer, size_t nwords)
+{
+ spiinfo("rxbuffer=%p nwords=%d\n", rxbuffer, nwords);
+
+ bl808_spi_exchange(dev, NULL, rxbuffer, nwords);
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_trigger
+ *
+ * Description:
+ * Trigger a previously configured DMA transfer.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ *
+ * Returned Value:
+ * OK - Trigger was fired
+ * -ENOSYS - Trigger not fired due to lack of DMA or low level support
+ * -EIO - Trigger not fired because not previously primed
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_TRIGGER
+static int bl808_spi_trigger(struct spi_dev_s *dev)
+{
+ spierr("SPI trigger not supported\n");
+ DEBUGPANIC();
+
+ return -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_init
+ *
+ * Description:
+ * Initialize bl808 SPI hardware interface
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void bl808_spi_init(struct spi_dev_s *dev)
+{
+ struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+ const struct bl808_spi_config_s *config = priv->config;
+ uint8_t idx = priv->idx;
+
+#ifdef CONFIG_BL808_SPI0
+ if (idx == 0)
+ {
+ bl808_configgpio(CONFIG_BL808_SPI0_MISO,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI0);
+
+ bl808_configgpio(CONFIG_BL808_SPI0_MOSI,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI0);
+
+ bl808_configgpio(CONFIG_BL808_SPI0_SCLK,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI0);
+
+ bl808_configgpio(CONFIG_BL808_SPI0_SS,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI0);
+
+ modifyreg32(BL808_GLB_PARM_CFG0, 0,
+ 1 << PARM_SPI_0_MASTER_MODE_SHIFT);
+ }
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+ if (idx == 1)
+ {
+ bl808_configgpio(CONFIG_BL808_SPI1_MISO,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI1);
+
+ bl808_configgpio(CONFIG_BL808_SPI1_MOSI,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI1);
+
+ bl808_configgpio(CONFIG_BL808_SPI1_SCLK,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI1);
+
+ bl808_configgpio(CONFIG_BL808_SPI1_SS,
+ GPIO_INPUT
+ | GPIO_DRV_1
+ | GPIO_SMT_EN
+ | GPIO_PULLUP
+ | GPIO_FUNC_SPI1);
+
+ modifyreg32(BL808_GLB_PARM_CFG0, 0,
+ 1 << PARM_MM_SPI_MASTER_MODE_SHIFT);
+ }
+#endif
+
+ /* Disable RX ignore */
+
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_RXD_IGNR_EN, 0);
+
+ /* Set deglitch */
+
+ if (config->deglitch_enable)
+ {
+ modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_DEG_EN);
+ }
+ else
+ {
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_DEG_EN, 0);
+ }
+
+ /* Set continuous transfer */
+
+ if (config->continuous_enable)
+ {
+ modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_M_CONT_EN);
+ }
+ else
+ {
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_M_CONT_EN, 0);
+ }
+
+ /* Set byte inversion */
+
+ if (config->byte_invert)
+ {
+ modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_BYTE_INV);
+ }
+ else
+ {
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_BYTE_INV, 0);
+ }
+
+ /* Set bit inversion */
+
+ if (config->bit_invert)
+ {
+ modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_BIT_INV);
+ }
+ else
+ {
+ modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_BIT_INV, 0);
+ }
+
+ bl808_spi_setfrequency(dev, config->clk_freq);
+ bl808_spi_setbits(dev, 8);
+ bl808_spi_setmode(dev, config->mode);
+
+ /* spi fifo clear */
+
+ modifyreg32(BL808_SPI_FIFO_CFG_0(idx), 0, SPI_FIFO_CFG_0_RX_CLR
+ | SPI_FIFO_CFG_0_TX_CLR);
+}
+
+/****************************************************************************
+ * Name: bl808_spibus_initialize
+ *
+ * Description:
+ * Initialize and register the configured SPI busses
+ *
+ ****************************************************************************/
+
+struct spi_dev_s *bl808_spibus_initialize(int bus)
+{
+ struct spi_dev_s *spi_dev;
+ struct bl808_spi_priv_s *priv;
+
+#ifdef CONFIG_BL808_SPI0
+ if (bus == 0)
+ {
+ priv = &bl808_spi0_priv;
+ }
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+ if (bus == 1)
+ {
+ priv = &bl808_spi1_priv;
+ }
+#endif
+
+ spi_dev = (struct spi_dev_s *)priv;
+
+ nxmutex_lock(&priv->lock);
+ if (priv->refs == 0)
+ {
+ bl808_spi_init(spi_dev);
+ }
+
+ priv->refs++;
+
+ nxmutex_unlock(&priv->lock);
+
+ return spi_dev;
+}
+
+#endif /* CONFIG_BL808_SPI0 || CONFIG_BL808_SPI1 */
diff --git a/arch/risc-v/src/bl808/bl808_spi.h
b/arch/risc-v/src/bl808/bl808_spi.h
new file mode 100644
index 0000000000..6bcb3fb043
--- /dev/null
+++ b/arch/risc-v/src/bl808/bl808_spi.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * arch/risc-v/src/bl808/bl808_spi.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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 __ARCH_RISCV_SRC_BL808_BL808_SPI_H
+#define __ARCH_RISCV_SRC_BL808_BL808_SPI_H
+
+/* This file is based on bl602/bl602_spi.h */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/spi_transfer.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl808_spibus_initialize
+ *
+ * Description:
+ * Initialize the selected SPI bus
+ *
+ * Input Parameters:
+ * Port number (for hardware that has multiple SPI interfaces)
+ *
+ * Returned Value:
+ * Valid SPI device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct spi_dev_s *bl808_spibus_initialize(int bus);
+
+#ifdef __cplusplus
+}
+#endif
+#undef EXTERN
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_RISCV_SRC_BL808_BL808_SPI_H */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_glb.h
b/arch/risc-v/src/bl808/hardware/bl808_glb.h
index d5bc359cb1..23f907a065 100644
--- a/arch/risc-v/src/bl808/hardware/bl808_glb.h
+++ b/arch/risc-v/src/bl808/hardware/bl808_glb.h
@@ -36,6 +36,8 @@
#define BL808_GLB_UART_CFG1_OFFSET 0x154
#define BL808_GLB_UART_CFG2_OFFSET 0x158
+#define BL808_GLB_SPI_CFG0_OFFSET 0x1b0
+#define BL808_GLB_PARM_CFG0_OFFSET 0x510
#define BL808_GPIO_CFG_OFFSET 0x0008c4 /* gpio_cfg0 */
@@ -43,15 +45,32 @@
#define BL808_GLB_UART_CFG1 (BL808_GLB_BASE + BL808_GLB_UART_CFG1_OFFSET)
#define BL808_GLB_UART_CFG2 (BL808_GLB_BASE + BL808_GLB_UART_CFG2_OFFSET)
+#define BL808_GLB_SPI_CFG0 (BL808_GLB_BASE + BL808_GLB_SPI_CFG0_OFFSET)
+#define BL808_GLB_PARM_CFG0 (BL808_GLB_BASE + BL808_GLB_PARM_CFG0_OFFSET)
#define BL808_GPIO_CFG(n) (BL808_GLB_BASE + BL808_GPIO_CFG_OFFSET + 4*n)
/* Register bit definitions *************************************************/
/* UART_CFG registers *******************************************************/
+
#define UART_CFG_SIG_SEL_SHIFT(n) ((n % 8) * 4)
#define UART_CFG_SIG_SEL_MASK(n) (0x0f << UART_CFG_SIG_SEL_SHIFT(n))
+/* SPI_CFG0 *****************************************************************/
+
+#define SPI_CFG_CLK_DIV_SHIFT 0
+#define SPI_CFG_CLK_DIV_MASK (0x1f << SPI_CFG_CLK_DIV_SHIFT)
+#define SPI_CFG_CLK_EN_SHIFT 8
+#define SPI_CFG_CLK_SEL_SHIFT 9
+#define SPI_CFG_SWAP_SET_SHIFT 16
+#define SPI_CFG_SWAP_SET_MASK (0x0f << SPI_CFG_SWAP_SET_SHIFT);
+
+/* PARM_CFG0 ****************************************************************/
+
+#define PARM_SPI_0_MASTER_MODE_SHIFT 12
+#define PARM_MM_SPI_MASTER_MODE_SHIFT 27
+
/* GPIO_CFG registers *******************************************************/
/* bit definitions from lupyuen's wip-nuttx, branch gpio2 *******************/
diff --git a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
b/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
index bed2b31756..aaff526633 100644
--- a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
+++ b/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
@@ -33,9 +33,12 @@
#define BL808_GPADC_BASE 0x20002000ul
#define BL808_UART0_BASE 0x2000a000ul
#define BL808_UART1_BASE 0x2000a100ul
+#define BL808_SPI0_BASE 0x2000a200ul
#define BL808_UART2_BASE 0x2000aa00ul
#define BL808_AON_BASE 0x2000f000ul
#define BL808_UART3_BASE 0x30002000ul
+#define BL808_MM_GLB_BASE 0x30007000ul
+#define BL808_SPI1_BASE 0x30008000ul
#define BL808_PLIC_BASE 0xe0000000ul
#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MEMORYMAP_H */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_glb.h
b/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h
similarity index 51%
copy from arch/risc-v/src/bl808/hardware/bl808_glb.h
copy to arch/risc-v/src/bl808/hardware/bl808_mm_glb.h
index d5bc359cb1..a23e0001da 100644
--- a/arch/risc-v/src/bl808/hardware/bl808_glb.h
+++ b/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h
@@ -1,5 +1,5 @@
/****************************************************************************
- * arch/risc-v/src/bl808/hardware/bl808_glb.h
+ * arch/risc-v/src/bl808/hardware/bl808_mm_glb.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -18,8 +18,8 @@
*
****************************************************************************/
-#ifndef __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_GLB_H
-#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_GLB_H
+#ifndef __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H
+#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H
/****************************************************************************
* Included Files
@@ -34,36 +34,25 @@
/* Register offsets *********************************************************/
-#define BL808_GLB_UART_CFG1_OFFSET 0x154
-#define BL808_GLB_UART_CFG2_OFFSET 0x158
-
-#define BL808_GPIO_CFG_OFFSET 0x0008c4 /* gpio_cfg0 */
+#define BL808_MM_GLB_CLK_CTRL_PERI_OFFSET 0x10
/* Register definitions *****************************************************/
-#define BL808_GLB_UART_CFG1 (BL808_GLB_BASE + BL808_GLB_UART_CFG1_OFFSET)
-#define BL808_GLB_UART_CFG2 (BL808_GLB_BASE + BL808_GLB_UART_CFG2_OFFSET)
-
-#define BL808_GPIO_CFG(n) (BL808_GLB_BASE + BL808_GPIO_CFG_OFFSET + 4*n)
+#define BL808_MM_GLB_CLK_CTRL_PERI (BL808_MM_GLB_BASE \
+ + BL808_MM_GLB_CLK_CTRL_PERI_OFFSET)
/* Register bit definitions *************************************************/
-/* UART_CFG registers *******************************************************/
-#define UART_CFG_SIG_SEL_SHIFT(n) ((n % 8) * 4)
-#define UART_CFG_SIG_SEL_MASK(n) (0x0f << UART_CFG_SIG_SEL_SHIFT(n))
-
-/* GPIO_CFG registers *******************************************************/
-
-/* bit definitions from lupyuen's wip-nuttx, branch gpio2 *******************/
+/* CLK_CTRL_PERI ************************************************************/
-#define GPIO_CFGCTL0_GPIO_0_FUNC_SEL_SHIFT (8)
-#define GPIO_CFGCTL0_GPIO_0_FUNC_SEL_MASK (0x0f <<
GPIO_CFGCTL0_GPIO_0_FUNC_SEL_SHIFT)
-#define GPIO_CFGCTL0_GPIO_0_OE (1 << 6)
-#define GPIO_CFGCTL0_GPIO_0_PD (1 << 5)
-#define GPIO_CFGCTL0_GPIO_0_PU (1 << 4)
-#define GPIO_CFGCTL0_GPIO_0_DRV_SHIFT (2)
-#define GPIO_CFGCTL0_GPIO_0_DRV_MASK (0x03 <<
GPIO_CFGCTL0_GPIO_0_DRV_SHIFT)
-#define GPIO_CFGCTL0_GPIO_0_SMT (1 << 1)
-#define GPIO_CFGCTL0_GPIO_0_IE (1 << 0)
+#define CLK_CTRL_PERI_I2C0_DIV_SHIFT 0
+#define CLK_CTRL_PERI_I2C0_DIV_MASK (0xff << CLK_CTRL_PERI_I2C0_DIV_SHIFT)
+#define CLK_CTRL_PERI_I2C0_EN_SHIFT 9
+#define CLK_CTRL_PERI_UART_DIV_EN_SHIFT 16
+#define CLK_CTRL_PERI_UART_DIV_SHIFT 17
+#define CLK_CTRL_PERI_UART_DIV_MASK (0x07 << CLK_CTRL_PERI_UART_DIV_SHIFT)
+#define CLK_CTRL_PERI_SPI_DIV_EN_SHIFT 23
+#define CLK_CTRL_PERI_SPI_DIV_SHIFT 24
+#define CLK_CTRL_PERI_SPI_DIV_MASK (0xff << CLK_CTRL_PERI_SPI_DIV_SHIFT)
-#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_GLB_H */
+#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_spi.h
b/arch/risc-v/src/bl808/hardware/bl808_spi.h
new file mode 100644
index 0000000000..6b7343d946
--- /dev/null
+++ b/arch/risc-v/src/bl808/hardware/bl808_spi.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+ * arch/risc-v/src/bl808/hardware/bl808_spi.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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 __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_SPI_H
+#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_SPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "bl808_memorymap.h"
+
+/* This file is based on bl602/hardware/bl602_spi.h */
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define BL808_SPI_BASE(n) ((n == 0) ? BL808_SPI0_BASE \
+ : BL808_SPI1_BASE)
+
+/* Register offsets *********************************************************/
+
+#define BL808_SPI_CFG_OFFSET 0x000000 /* spi_config */
+#define BL808_SPI_INT_STS_OFFSET 0x000004 /* spi_int_sts */
+#define BL808_SPI_BUS_BUSY_OFFSET 0x000008 /* spi_bus_busy */
+#define BL808_SPI_PRD_0_OFFSET 0x000010 /* spi_prd_0 */
+#define BL808_SPI_PRD_1_OFFSET 0x000014 /* spi_prd_1 */
+#define BL808_SPI_RXD_IGNR_OFFSET 0x000018 /* spi_rxd_ignr */
+#define BL808_SPI_STO_VALUE_OFFSET 0x00001c /* spi_sto_value */
+#define BL808_SPI_FIFO_CFG_0_OFFSET 0x000080 /* spi_fifo_config_0 */
+#define BL808_SPI_FIFO_CFG_1_OFFSET 0x000084 /* spi_fifo_config_1 */
+#define BL808_SPI_FIFO_WDATA_OFFSET 0x000088 /* spi_fifo_wdata */
+#define BL808_SPI_FIFO_RDATA_OFFSET 0x00008c /* spi_fifo_rdata */
+
+/* Register definitions *****************************************************/
+
+#define BL808_SPI_CFG(n) (BL808_SPI_BASE(n) + BL808_SPI_CFG_OFFSET)
+#define BL808_SPI_INT_STS(n) (BL808_SPI_BASE(n) + BL808_SPI_INT_STS_OFFSET)
+#define BL808_SPI_BUS_BUSY(n) (BL808_SPI_BASE(n) +
BL808_SPI_BUS_BUSY_OFFSET)
+#define BL808_SPI_PRD_0(n) (BL808_SPI_BASE(n) + BL808_SPI_PRD_0_OFFSET)
+#define BL808_SPI_PRD_1(n) (BL808_SPI_BASE(n) + BL808_SPI_PRD_1_OFFSET)
+#define BL808_SPI_RXD_IGNR(n) (BL808_SPI_BASE(n) +
BL808_SPI_RXD_IGNR_OFFSET)
+#define BL808_SPI_STO_VALUE(n) (BL808_SPI_BASE(n) +
BL808_SPI_STO_VALUE_OFFSET)
+#define BL808_SPI_FIFO_CFG_0(n) (BL808_SPI_BASE(n) +
BL808_SPI_FIFO_CFG_0_OFFSET)
+#define BL808_SPI_FIFO_CFG_1(n) (BL808_SPI_BASE(n) +
BL808_SPI_FIFO_CFG_1_OFFSET)
+#define BL808_SPI_FIFO_WDATA(n) (BL808_SPI_BASE(n) +
BL808_SPI_FIFO_WDATA_OFFSET)
+#define BL808_SPI_FIFO_RDATA(n) (BL808_SPI_BASE(n) +
BL808_SPI_FIFO_RDATA_OFFSET)
+
+/* Register bit definitions *************************************************/
+
+#define SPI_CFG_CR_DEG_CNT_SHIFT (12)
+#define SPI_CFG_CR_DEG_CNT_MASK (0x0f << SPI_CFG_CR_DEG_CNT_SHIFT)
+#define SPI_CFG_CR_DEG_EN (1 << 11)
+#define SPI_CFG_CR_M_CONT_EN (1 << 9)
+#define SPI_CFG_CR_RXD_IGNR_EN (1 << 8)
+#define SPI_CFG_CR_BYTE_INV (1 << 7)
+#define SPI_CFG_CR_BIT_INV (1 << 6)
+#define SPI_CFG_CR_SCLK_PH (1 << 5)
+#define SPI_CFG_CR_SCLK_POL (1 << 4)
+#define SPI_CFG_CR_FRAME_SIZE_SHIFT (2)
+#define SPI_CFG_CR_FRAME_SIZE_MASK (0x03 << SPI_CFG_CR_FRAME_SIZE_SHIFT)
+#define SPI_CFG_CR_S_EN (1 << 1)
+#define SPI_CFG_CR_M_EN (1 << 0)
+
+#define SPI_INT_STS_CR_FER_EN (1 << 29)
+#define SPI_INT_STS_CR_TXU_EN (1 << 28)
+#define SPI_INT_STS_CR_STO_EN (1 << 27)
+#define SPI_INT_STS_CR_RXF_EN (1 << 26)
+#define SPI_INT_STS_CR_TXF_EN (1 << 25)
+#define SPI_INT_STS_CR_END_EN (1 << 24)
+#define SPI_INT_STS_RSVD_21 (1 << 21)
+#define SPI_INT_STS_CR_TXU_CLR (1 << 20)
+#define SPI_INT_STS_CR_STO_CLR (1 << 19)
+#define SPI_INT_STS_RSVD_18 (1 << 18)
+#define SPI_INT_STS_RSVD_17 (1 << 17)
+#define SPI_INT_STS_CR_END_CLR (1 << 16)
+#define SPI_INT_STS_CR_FER_MASK (1 << 13)
+#define SPI_INT_STS_CR_TXU_MASK (1 << 12)
+#define SPI_INT_STS_CR_STO_MASK (1 << 11)
+#define SPI_INT_STS_CR_RXF_MASK (1 << 10)
+#define SPI_INT_STS_CR_TXF_MASK (1 << 9)
+#define SPI_INT_STS_CR_END_MASK (1 << 8)
+#define SPI_INT_STS_FER_INT (1 << 5)
+#define SPI_INT_STS_TXU_INT (1 << 4)
+#define SPI_INT_STS_STO_INT (1 << 3)
+#define SPI_INT_STS_RXF_INT (1 << 2)
+#define SPI_INT_STS_TXF_INT (1 << 1)
+#define SPI_INT_STS_END_INT (1 << 0)
+
+#define SPI_BUS_BUSY_STS_BUS_BUSY (1 << 0)
+
+#define SPI_PRD_0_CR_D_PH_1_SHIFT (24)
+#define SPI_PRD_0_CR_D_PH_1_MASK (0xff << SPI_PRD_0_CR_D_PH_1_SHIFT)
+#define SPI_PRD_0_CR_D_PH_0_SHIFT (16)
+#define SPI_PRD_0_CR_D_PH_0_MASK (0xff << SPI_PRD_0_CR_D_PH_0_SHIFT)
+#define SPI_PRD_0_CR_P_SHIFT (8)
+#define SPI_PRD_0_CR_P_MASK (0xff << SPI_PRD_0_CR_P_SHIFT)
+#define SPI_PRD_0_CR_S_MASK (0xff)
+
+#define SPI_PRD_1_CR_I_MASK (0xff)
+
+#define SPI_RXD_IGNR_CR_IGNR_S_SHIFT (16)
+#define SPI_RXD_IGNR_CR_IGNR_S_MASK (0x1f <<
SPI_RXD_IGNR_CR_RXD_IGNR_S_SHIFT)
+#define SPI_RXD_IGNR_CR_IGNR_P_MASK (0x1f)
+
+#define SPI_STO_VALUE_CR_VALUE_MASK (0xfff)
+
+#define SPI_FIFO_CFG_0_RX_UNDERFLOW (1 << 7)
+#define SPI_FIFO_CFG_0_RX_OVERFLOW (1 << 6)
+#define SPI_FIFO_CFG_0_TX_UNDERFLOW (1 << 5)
+#define SPI_FIFO_CFG_0_TX_OVERFLOW (1 << 4)
+#define SPI_FIFO_CFG_0_RX_CLR (1 << 3)
+#define SPI_FIFO_CFG_0_TX_CLR (1 << 2)
+#define SPI_FIFO_CFG_0_DMA_RX_EN (1 << 1)
+#define SPI_FIFO_CFG_0_DMA_TX_EN (1 << 0)
+
+#define SPI_FIFO_CFG_1_RX_TH_SHIFT (24)
+#define SPI_FIFO_CFG_1_RX_TH_MASK (0x1f << SPI_FIFO_CFG_1_RX_TH_SHIFT)
+#define SPI_FIFO_CFG_1_TX_TH_SHIFT (16)
+#define SPI_FIFO_CFG_1_TX_TH_MASK (0x1f << SPI_FIFO_CFG_1_TX_TH_SHIFT)
+#define SPI_FIFO_CFG_1_RX_CNT_SHIFT (8)
+#define SPI_FIFO_CFG_1_RX_CNT_MASK (0x3f << SPI_FIFO_CFG_1_RX_CNT_SHIFT)
+#define SPI_FIFO_CFG_1_TX_CNT_MASK (0x3f)
+
+#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_SPI_H */
diff --git a/boards/risc-v/bl808/ox64/configs/spi/defconfig
b/boards/risc-v/bl808/ox64/configs/spi/defconfig
new file mode 100644
index 0000000000..3c6a4a7296
--- /dev/null
+++ b/boards/risc-v/bl808/ox64/configs/spi/defconfig
@@ -0,0 +1,100 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that
includes your
+# modifications.
+#
+# CONFIG_DISABLE_OS_API is not set
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_ADDRENV=y
+CONFIG_ARCH_BOARD="ox64"
+CONFIG_ARCH_BOARD_BL808_OX64=y
+CONFIG_ARCH_CHIP="bl808"
+CONFIG_ARCH_CHIP_BL808=y
+CONFIG_ARCH_DATA_NPAGES=128
+CONFIG_ARCH_DATA_VBASE=0x80100000
+CONFIG_ARCH_HEAP_NPAGES=128
+CONFIG_ARCH_HEAP_VBASE=0x80200000
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_KERNEL_STACKSIZE=3072
+CONFIG_ARCH_PGPOOL_MAPPING=y
+CONFIG_ARCH_PGPOOL_PBASE=0x50600000
+CONFIG_ARCH_PGPOOL_SIZE=4194304
+CONFIG_ARCH_PGPOOL_VBASE=0x50600000
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_TEXT_NPAGES=128
+CONFIG_ARCH_TEXT_VBASE=0x80000000
+CONFIG_ARCH_USE_MMU=y
+CONFIG_ARCH_USE_MPU=y
+CONFIG_ARCH_USE_S_MODE=y
+CONFIG_BL808_SPI0=y
+CONFIG_BL808_UART0=y
+CONFIG_BL808_UART1=y
+CONFIG_BL808_UART2=y
+CONFIG_BL808_UART3=y
+CONFIG_BOARDCTL_ROMDISK=y
+CONFIG_BOARD_LATE_INITIALIZE=y
+CONFIG_BOARD_LOOPSPERMSEC=1120
+CONFIG_BUILD_KERNEL=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_ASSERTIONS_EXPRESSION=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEV_ZERO=y
+CONFIG_ELF=y
+CONFIG_EXAMPLES_HELLO=m
+CONFIG_FS_PROCFS=y
+CONFIG_FS_ROMFS=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INIT_FILEPATH="/system/bin/init"
+CONFIG_INIT_MOUNT=y
+CONFIG_INIT_MOUNT_FLAGS=0x1
+CONFIG_INIT_MOUNT_TARGET="/system/bin"
+CONFIG_INIT_STACKSIZE=3072
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_ENVPATH=y
+CONFIG_LIBC_EXECFUNCS=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_MEMSET_64BIT=y
+CONFIG_MEMSET_OPTSPEED=y
+CONFIG_MM_PGALLOC=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_FILE_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_PATH_INITIAL="/system/bin"
+CONFIG_RAM_SIZE=1048576
+CONFIG_RAM_START=0x50200000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HAVE_PARENT=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2021
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_NSH_PROGNAME="init"
+CONFIG_SYSTEM_SPITOOL=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_BAUD=2000000
+CONFIG_UART0_BITS=7
+CONFIG_UART1_BAUD=2000000
+CONFIG_UART1_BITS=7
+CONFIG_UART2_BAUD=2000000
+CONFIG_UART2_BITS=7
+CONFIG_UART3_BAUD=2000000
+CONFIG_UART3_BITS=7
+CONFIG_UART3_SERIAL_CONSOLE=y
+CONFIG_USEC_PER_TICK=1000
+CONFIG_USERLED=y
+CONFIG_USERLED_LOWER=y
diff --git a/boards/risc-v/bl808/ox64/src/bl808_appinit.c
b/boards/risc-v/bl808/ox64/src/bl808_appinit.c
index 0fe3b21c8a..9f0305bcbd 100644
--- a/boards/risc-v/bl808/ox64/src/bl808_appinit.c
+++ b/boards/risc-v/bl808/ox64/src/bl808_appinit.c
@@ -38,6 +38,9 @@
#ifdef CONFIG_USERLED
#include <nuttx/leds/userled.h>
#endif
+#if defined(CONFIG_BL808_SPI0) || defined(CONFIG_BL808_SPI1)
+#include "bl808_spi.h"
+#endif
#include "bl808_gpadc.h"
/****************************************************************************
@@ -170,6 +173,16 @@ void board_late_initialize(void)
#endif
+#ifdef CONFIG_BL808_SPI0
+ struct spi_dev_s *spi0 = bl808_spibus_initialize(0);
+ spi_register(spi0, 0);
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+ struct spi_dev_s *spi1 = bl808_spibus_initialize(1);
+ spi_register(spi1, 1);
+#endif
+
#ifdef CONFIG_NSH_ARCHINIT
mount(NULL, "/proc", "procfs", 0, NULL);