diff --git a/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst b/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst index 9313dd2cbff..85d245ce7df 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 a91742fe229..f8f9d95d44e 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 4de1636b059..0b743f1063a 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 0766d0dd5b6..0156783813c 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 89e9abe62c6..ffb276ace9a 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 f9b25c88bdc..d51bdea6999 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 00000000000..2e00f32a6ae --- /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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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 00000000000..6bcb3fb0439 --- /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 + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#include +#include + +/**************************************************************************** + * 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 d5bc359cb17..23f907a0653 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 bed2b317566..aaff526633e 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_mm_glb.h b/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h new file mode 100644 index 00000000000..a23e0001da1 --- /dev/null +++ b/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * 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 + * 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_MM_GLB_H +#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "bl808_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define BL808_MM_GLB_CLK_CTRL_PERI_OFFSET 0x10 + +/* Register definitions *****************************************************/ + +#define BL808_MM_GLB_CLK_CTRL_PERI (BL808_MM_GLB_BASE \ + + BL808_MM_GLB_CLK_CTRL_PERI_OFFSET) + +/* Register bit definitions *************************************************/ + +/* CLK_CTRL_PERI ************************************************************/ + +#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_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 00000000000..6b7343d9467 --- /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 +#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 00000000000..3c6a4a72960 --- /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 0fe3b21c8ae..9f0305bcbd0 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 #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);