diff --git a/bsps/aarch64/raspberrypi/include/bsp/irq.h b/bsps/aarch64/raspberrypi/include/bsp/irq.h index d493e83707..f543295c07 100644 --- a/bsps/aarch64/raspberrypi/include/bsp/irq.h +++ b/bsps/aarch64/raspberrypi/include/bsp/irq.h @@ -47,6 +47,9 @@ #define BCM2835_IRQ_ID_GPU_TIMER_M2 (BCM2711_IRQ_VC_PERIPHERAL_BASE + 2) #define BCM2835_IRQ_ID_GPU_TIMER_M3 (BCM2711_IRQ_VC_PERIPHERAL_BASE + 3) +/* Interrupt Vectors: SPI */ +#define BCM2711_IRQ_SPI (BCM2711_IRQ_VC_PERIPHERAL_BASE + 54) + #define BCM2835_IRQ_ID_USB 9 #define BCM2835_IRQ_ID_AUX 29 #define BCM2835_IRQ_ID_SPI_SLAVE 43 diff --git a/bsps/aarch64/raspberrypi/include/bsp/raspberrypi-spi.h b/bsps/aarch64/raspberrypi/include/bsp/raspberrypi-spi.h new file mode 100644 index 0000000000..1ce301f898 --- /dev/null +++ b/bsps/aarch64/raspberrypi/include/bsp/raspberrypi-spi.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup raspberrypi_4_spi + * + * @brief Raspberry Pi specific SPI definitions. + */ + +/* + * Copyright (C) 2024 Ning Yang + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LIBBSP_AARCH64_RASPBERRYPI_4_SPI_H +#define LIBBSP_AARCH64_RASPBERRYPI_4_SPI_H + +#include +#include + +typedef struct +{ + uint32_t spics; +#define RPI_SPICS_LEN_LONG BSP_BIT32(25) +#define RPI_SPICS_DMA_LEN BSP_BIT32(24) +#define RPI_SPICS_CSPOL2 BSP_BIT32(23) +#define RPI_SPICS_CSPOL1 BSP_BIT32(22) +#define RPI_SPICS_CSPOL0 BSP_BIT32(21) +#define RPI_SPICS_RXF BSP_BIT32(20) +#define RPI_SPICS_RXR BSP_BIT32(19) +#define RPI_SPICS_TXD BSP_BIT32(18) +#define RPI_SPICS_RXD BSP_BIT32(17) +#define RPI_SPICS_DONE BSP_BIT32(16) +#define RPI_SPICS_LEN BSP_BIT32(13) +#define RPI_SPICS_REN BSP_BIT32(12) +#define RPI_SPICS_ADCS BSP_BIT32(11) +#define RPI_SPICS_INTR BSP_BIT32(10) +#define RPI_SPICS_INTD BSP_BIT32(9) +#define RPI_SPICS_DMAEN BSP_BIT32(8) +#define RPI_SPICS_TA BSP_BIT32(7) +#define RPI_SPICS_CSPOL BSP_BIT32(6) +#define RPI_SPICS_CLEAR_TX BSP_BIT32(5) +#define RPI_SPICS_CLEAR_RX BSP_BIT32(4) +#define RPI_SPICS_CPOL BSP_BIT32(3) +#define RPI_SPICS_CPHA BSP_BIT32(2) +#define RPI_SPICS_CS(val) BSP_FLD32(val, 0, 1) +#define RPI_SPICS_CS_SET(reg,val) BSP_FLD32SET(reg, val, 0, 1) + uint32_t spififo; +#define RPI_SPIFIFO_DATA(val) BSP_FLD32(val, 0, 31) +#define RPI_SPIFIFO_DATA_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define RPI_SPIFIFO_DATA_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t spiclk; +#define RPI_SPICLK_CDIV(val) BSP_FLD32(val, 0, 15) +#define RPI_SPICLK_CDIV_GET(reg) BSP_FLD32GET(reg, 0, 15) +#define RPI_SPICLK_CDIV_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15) + uint32_t spidlen; +#define RPI_SPIDLEN_LEN(val) BSP_FLD32(val, 0, 15) +#define RPI_SPIDLEN_LEN_GET(reg) BSP_FLD32GET(reg, 0, 15) +#define RPI_SPIDLEN_LEN_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15) + uint32_t spiltoh; +#define RPI_SPILTOH_TOH(val) BSP_FLD32(val, 0, 3) +#define RPI_SPILTOH_TOH_GET(reg) BSP_FLD32GET(reg, 0, 3) +#define RPI_SPILTOH_TOH_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3) + uint32_t spidc; +#define RPI_SPIDC_RPANIC(val) BSP_FLD32(val, 24, 31) +#define RPI_SPIDC_RPANIC_GET(reg) BSP_FLD32GET(reg, 24, 31) +#define RPI_SPIDC_RPANIC_SET(reg, val) BSP_FLD32SET(reg, val, 24, 31) +#define RPI_SPIDC_RDREQ(val) BSP_FLD32(val, 16, 23) +#define RPI_SPIDC_RDREQ_GET(reg) BSP_FLD32GET(reg, 16, 23) +#define RPI_SPIDC_RDREQ_SET(reg, val) BSP_FLD32SET(reg, val, 16, 23) +#define RPI_SPIDC_TPANIC(val) BSP_FLD32(val, 8, 15) +#define RPI_SPIDC_TPANIC_GET(reg) BSP_FLD32GET(reg, 8, 15) +#define RPI_SPIDC_TPANIC_SET(reg, val) BSP_FLD32SET(reg, val, 8, 15) +#define RPI_SPIDC_TDREQ(val) BSP_FLD32(val, 0, 7) +#define RPI_SPIDC_TDREQ_GET(reg) BSP_FLD32GET(reg, 0, 7) +#define RPI_SPIDC_TDREQ_SET(reg, val) BSP_FLD32SET(reg, val, 0, 7) +} raspberrypi_spi; + +typedef enum { + raspberrypi_SPI0, + raspberrypi_SPI3, + raspberrypi_SPI4, + raspberrypi_SPI5, + raspberrypi_SPI6 +} raspberrypi_spi_device; + +/** + * @brief Register a spi device. + * + * @param device The optional devices are raspberrypi_SPI0, raspberrypi_SPI3, + * raspberrypi_SPI4, raspberrypi_SPI5, raspberrypi_SPI6. + * + * @retval RTEMS_SUCCESSFUL Successfully registered SPI device. + * @retval RTEMS_INVALID_NUMBER This status code indicates that a specified + * number was invalid. + * @retval RTEMS_UNSATISFIED This status code indicates that the request was + * not satisfied. + */ +rtems_status_code raspberrypi_spi_init(raspberrypi_spi_device device); + +#endif /* LIBBSP_AARCH64_RASPBERRYPI_4_SPI_H */ \ No newline at end of file diff --git a/bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h b/bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h index 128c9f19df..3592d26126 100644 --- a/bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h +++ b/bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h @@ -237,6 +237,20 @@ /** @} */ +/** +* @name SPI Registers +* +* @{ +*/ + +#define BCM2711_SPI0_BASE (RPI_PERIPHERAL_BASE + 0x204000) +#define BCM2711_SPI3_BASE (RPI_PERIPHERAL_BASE + 0x204600) +#define BCM2711_SPI4_BASE (RPI_PERIPHERAL_BASE + 0x204800) +#define BCM2711_SPI5_BASE (RPI_PERIPHERAL_BASE + 0x204A00) +#define BCM2711_SPI6_BASE (RPI_PERIPHERAL_BASE + 0x204C00) + +/** @} */ + /** * @name Mailbox Registers * diff --git a/bsps/aarch64/raspberrypi/spi/raspberrypi-spi.c b/bsps/aarch64/raspberrypi/spi/raspberrypi-spi.c new file mode 100644 index 0000000000..0d0a44bff1 --- /dev/null +++ b/bsps/aarch64/raspberrypi/spi/raspberrypi-spi.c @@ -0,0 +1,582 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsAArch64Raspberrypi4 + * + * @brief SPI Driver + */ + +/* + * Copyright (C) 2024 Ning Yang + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include + +typedef struct { + spi_bus base; + volatile raspberrypi_spi *regs; + const spi_ioc_transfer *msg; + uint32_t msg_todo; + uint8_t *rx_buf; + const uint8_t *tx_buf; + uint32_t todo; + uint8_t num_cs; + uint32_t in_transfer; + rtems_id task_id; + rtems_vector_number irq; +}raspberrypi_spi_bus; + +static int raspberrypi_spi_check_msg( + raspberrypi_spi_bus *bus, + const spi_ioc_transfer *msg, + uint32_t n +) +{ + while (n > 0) { + if (msg->bits_per_word != 8) { + return -EINVAL; + } + + if ((msg->mode & + ~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) { + return -EINVAL; + } + + if (msg->cs >= bus->num_cs) { + return -EINVAL; + } + + ++msg; + --n; + } + + return 0; +} + +/* Calculates a clock divider to be used with the GPU core clock rate + * to set a SPI clock rate the closest (<=) to a desired frequency. */ +static rtems_status_code rpi_spi_calculate_clock_divider( + uint32_t clock_hz, + uint16_t *clock_divider +) +{ + uint16_t divider; + uint32_t clock_rate; + + /* Calculates an initial clock divider. */ + divider = GPU_CORE_CLOCK_RATE / clock_hz; + + /* Because the divider must be a power of two (as per the BCM2835 datasheet), + * calculate the next greater power of two. */ + --divider; + + divider |= (divider >> 1); + divider |= (divider >> 2); + divider |= (divider >> 4); + divider |= (divider >> 8); + + ++divider; + + clock_rate = GPU_CORE_CLOCK_RATE / divider; + + /* If the resulting clock rate is greater than the desired frequency, + * try the next greater power of two divider. */ + while (clock_rate > clock_hz) { + divider = (divider << 1); + + clock_rate = GPU_CORE_CLOCK_RATE / divider; + } + + *clock_divider = divider; + + return RTEMS_SUCCESSFUL; +} + +static int raspberrypi_spi_config( + raspberrypi_spi_bus *bus, + volatile raspberrypi_spi *regs, + uint32_t speed_hz, + uint32_t mode, + uint8_t cs +) +{ + spi_bus *base = &bus->base; + uint32_t spics = regs->spics; + rtems_status_code sc; + uint16_t clock_divider; + + /* Calculate the most appropriate clock divider. */ + sc = rpi_spi_calculate_clock_divider(speed_hz, &clock_divider); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + /* Set the bus clock divider. */ + regs->spiclk = RPI_SPICLK_CDIV_SET(regs->spiclk, clock_divider); + + if ((mode & SPI_CPHA) != 0) { + spics |= RPI_SPICS_CPHA; + } else { + spics &= ~RPI_SPICS_CPHA; + } + + if ((mode & SPI_CPOL) != 0) { + spics |= RPI_SPICS_CPOL; + } else { + spics &= ~RPI_SPICS_CPOL; + } + + if ((mode & SPI_CS_HIGH) != 0) { + spics |= RPI_SPICS_CSPOL; + } else { + spics &= ~RPI_SPICS_CSPOL; + } + + spics = RPI_SPICS_CS_SET(spics, cs); + + regs->spics = spics; + + base->speed_hz = speed_hz; + base->mode = mode; + base->cs = cs; + return 0; +} + +#ifdef BSP_SPI_USE_INTERRUPTS +static void raspberrypi_spi_done(raspberrypi_spi_bus *bus) +{ + volatile raspberrypi_spi *regs; + regs = bus->regs; + regs->spics = regs->spics & ~RPI_SPICS_TA; + rtems_event_transient_send(bus->task_id); +} + +static bool raspberrpi_spi_TX_FULL(volatile raspberrypi_spi *regs) +{ + return !(regs->spics & RPI_SPICS_TXD); +} + +static void raspberrypi_spi_push( + raspberrypi_spi_bus *bus, + volatile raspberrypi_spi *regs +) +{ + uint8_t val; + while (bus->todo > 0 && !raspberrpi_spi_TX_FULL(regs)) { + val = 0; + if (bus->tx_buf != NULL) { + val = *bus->tx_buf; + ++bus->tx_buf; + } + + --bus->todo; + regs->spififo = val; + ++bus->in_transfer; + } +} + +static void raspberrypi_spi_next_msg(raspberrypi_spi_bus *bus) +{ + const spi_ioc_transfer *msg; + spi_bus *base; + volatile raspberrypi_spi *regs; + regs=bus->regs; + + if (bus->msg_todo > 0) { + base = &bus->base; + msg = bus->msg; + + if ( + msg->speed_hz != base->speed_hz + || msg->mode != base->mode + || msg->cs != base->cs + ) { + raspberrypi_spi_config( + bus, + regs, + msg->speed_hz, + msg->mode, + msg->cs + ); + } + + bus->todo = msg->len; + bus->rx_buf = msg->rx_buf; + bus->tx_buf = msg->tx_buf; + raspberrypi_spi_push(bus, regs); + } else { + raspberrypi_spi_done(bus); + } +} + +static void raspberrypi_spi_start(raspberrypi_spi_bus *bus) +{ + volatile raspberrypi_spi *regs; + regs = bus->regs; + + regs->spics = regs->spics | RPI_SPICS_INTR | RPI_SPICS_INTD; + /* + * Set TA = 1. This will immediately trigger a first interrupt with + * DONE = 1. + */ + regs->spics = regs->spics | RPI_SPICS_TA; +} + +static bool raspberrypi_spi_irq(volatile raspberrypi_spi *regs) +{ + /* Check whether the interrupt is generated by this SPI device */ + if(regs->spics & RPI_SPICS_INTD && regs->spics & RPI_SPICS_DONE) { + return 1; + } + + if(regs->spics & RPI_SPICS_INTR && regs->spics & RPI_SPICS_RXR) { + return 1; + } + + return 0; +} + +static void raspberrypi_spi_interrupt(void *arg) +{ + raspberrypi_spi_bus *bus; + volatile raspberrypi_spi *regs; + uint32_t val; + + bus = arg; + regs = bus->regs; + + if (raspberrypi_spi_irq(regs)) { + + if (bus->todo > 0) { + raspberrypi_spi_push(bus, regs); + } else { + --bus->msg_todo; + ++bus->msg; + raspberrypi_spi_next_msg(bus); + } + + while (regs->spics & RPI_SPICS_RXD && bus->in_transfer > 0) { + /* RX FIFO contains at least 1 byte. */ + val = regs->spififo; + if (bus->rx_buf != NULL) { + *bus->rx_buf = (uint8_t)val; + ++bus->rx_buf; + } + --bus->in_transfer; + } + + } +} +#else +static void raspberrypi_spi_polling_tx_rx(raspberrypi_spi_bus *bus) +{ + volatile raspberrypi_spi *regs = bus->regs; + + const unsigned char *sbuffer = bus->tx_buf; + unsigned char *rbuffer; + unsigned int size; + unsigned int read_count, write_count; + unsigned int data; + + while (bus->msg_todo) { + rbuffer = bus->rx_buf; + size = bus->todo; + + regs->spics = regs->spics | RPI_SPICS_CLEAR_RX | RPI_SPICS_CLEAR_TX + | RPI_SPICS_TA; + + read_count = 0; + write_count = 0; + + while (read_count < size || write_count < size) { + if (write_count < size && regs->spics & RPI_SPICS_TXD) { + if (sbuffer) { + regs->spififo = *sbuffer++; + } else { + regs->spififo = 0; + } + + write_count++; + } + + if (read_count < size && regs->spics & RPI_SPICS_RXD) { + data = regs->spififo; + + if (rbuffer) { + *rbuffer++ = data; + } + + read_count++; + } + } + + while (!(regs->spics & RPI_SPICS_DONE)) { + /*wait*/ + } + regs->spics = (regs->spics & ~RPI_SPICS_TA); + + bus->msg_todo--; + + bus->msg++; + bus->rx_buf = bus->msg->rx_buf; + bus->tx_buf = bus->msg->tx_buf; + bus->todo = bus->msg->len; + } +} + +static void raspberrypi_spi_transfer_msg( + raspberrypi_spi_bus *bus +) +{ + volatile raspberrypi_spi *regs = bus->regs; + uint32_t msg_todo = bus->msg_todo; + const spi_ioc_transfer *msg = bus->msg; + + if (msg_todo > 0) { + if ( + msg->speed_hz != bus->base.speed_hz + || msg->mode != bus->base.mode + || msg->cs != bus->base.cs + ) { + raspberrypi_spi_config( + bus, + regs, + msg->speed_hz, + msg->mode, + msg->cs + ); + } + + bus->todo = msg->len; + bus->rx_buf = msg->rx_buf; + bus->tx_buf = msg->tx_buf; + raspberrypi_spi_polling_tx_rx(bus); + } +} +#endif + +static int raspberrypi_spi_transfer( + spi_bus *base, + const spi_ioc_transfer *msgs, + uint32_t msg_count +) +{ + int rv = 0; + raspberrypi_spi_bus *bus; + bus = (raspberrypi_spi_bus *) base; + + rv = raspberrypi_spi_check_msg(bus, msgs, msg_count); + if (rv == 0) { + bus->msg_todo = msg_count; + bus->msg = msgs; +#ifdef BSP_SPI_USE_INTERRUPTS + bus->task_id = rtems_task_self(); + + raspberrypi_spi_start(bus); + rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); +#else + raspberrypi_spi_transfer_msg(bus); +#endif + } + + return rv; +} + +static void raspberrypi_spi_destroy(spi_bus *base) +{ + raspberrypi_spi_bus *bus; + bus = (raspberrypi_spi_bus *) base; + +#ifdef BSP_SPI_USE_INTERRUPTS + rtems_interrupt_handler_remove( + bus->irq, + raspberrypi_spi_interrupt, + bus + ); +#endif + + spi_bus_destroy_and_free(&bus->base); +} + +static int raspberrypi_spi_setup(spi_bus *base) +{ + raspberrypi_spi_bus *bus; + uint32_t mode = base->mode; + + bus = (raspberrypi_spi_bus *) base; + + if (mode & SPI_LOOP) { + return -EINVAL; + } + + return raspberrypi_spi_config( + bus, + bus->regs, + bus->base.speed_hz, + bus->base.mode, + bus->base.cs + ); +} + +static rtems_status_code raspberrypi_spi_init_gpio( + raspberrypi_spi_device device +) +{ + switch (device) { + case raspberrypi_SPI0: + raspberrypi_gpio_set_function(7, GPIO_AF0); /* CS1 */ + raspberrypi_gpio_set_pull(7, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(8, GPIO_AF0); /* CS0 */ + raspberrypi_gpio_set_pull(8, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(9, GPIO_AF0); /* MISO */ + raspberrypi_gpio_set_function(10, GPIO_AF0); /* MOSI */ + raspberrypi_gpio_set_function(11, GPIO_AF0); /* SCLK */ + break; + case raspberrypi_SPI3: + raspberrypi_gpio_set_function(24, GPIO_AF5); + raspberrypi_gpio_set_pull(24, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(0, GPIO_AF3); + raspberrypi_gpio_set_pull(0, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(1, GPIO_AF3); + raspberrypi_gpio_set_function(2, GPIO_AF3); + raspberrypi_gpio_set_function(3, GPIO_AF3); + break; + case raspberrypi_SPI4: + raspberrypi_gpio_set_function(25, GPIO_AF5); + raspberrypi_gpio_set_pull(25, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(4, GPIO_AF3); + raspberrypi_gpio_set_pull(4, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(5, GPIO_AF3); + raspberrypi_gpio_set_function(6, GPIO_AF3); + raspberrypi_gpio_set_function(7, GPIO_AF3); + break; + case raspberrypi_SPI5: + raspberrypi_gpio_set_function(26, GPIO_AF5); + raspberrypi_gpio_set_pull(26, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(12, GPIO_AF3); + raspberrypi_gpio_set_pull(12, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(13, GPIO_AF3); + raspberrypi_gpio_set_function(14, GPIO_AF3); + raspberrypi_gpio_set_function(15, GPIO_AF3); + break; + case raspberrypi_SPI6: + raspberrypi_gpio_set_function(27, GPIO_AF5); + raspberrypi_gpio_set_pull(27, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(18, GPIO_AF3); + raspberrypi_gpio_set_pull(18, GPIO_PULL_NONE); + raspberrypi_gpio_set_function(19, GPIO_AF3); + raspberrypi_gpio_set_function(20, GPIO_AF3); + raspberrypi_gpio_set_function(21, GPIO_AF3); + break; + default: + return RTEMS_INVALID_NUMBER; + break; + } + return RTEMS_SUCCESSFUL; +} + +rtems_status_code raspberrypi_spi_init(raspberrypi_spi_device device) +{ + raspberrypi_spi_bus *bus; + int eno; + volatile raspberrypi_spi *regs; + const char *bus_path; + + bus = (raspberrypi_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus)); + if (bus == NULL) { + return RTEMS_UNSATISFIED; + } + + switch (device) { + case raspberrypi_SPI0: + regs = (volatile raspberrypi_spi *) BCM2711_SPI0_BASE; + bus_path = "/dev/spidev0"; + break; + case raspberrypi_SPI3: + regs = (volatile raspberrypi_spi *) BCM2711_SPI3_BASE; + bus_path = "/dev/spidev3"; + break; + case raspberrypi_SPI4: + regs = (volatile raspberrypi_spi *) BCM2711_SPI4_BASE; + bus_path = "/dev/spidev4"; + break; + case raspberrypi_SPI5: + regs = (volatile raspberrypi_spi *) BCM2711_SPI5_BASE; + bus_path = "/dev/spidev5"; + break; + case raspberrypi_SPI6: + regs = (volatile raspberrypi_spi *) BCM2711_SPI6_BASE; + bus_path = "/dev/spidev6"; + break; + default: + spi_bus_destroy_and_free(&bus->base); + return RTEMS_INVALID_NUMBER; + break; + } + + bus->regs = regs; + bus->num_cs = 2; + + bus->base.transfer = raspberrypi_spi_transfer; + bus->base.destroy = raspberrypi_spi_destroy; + bus->base.setup = raspberrypi_spi_setup; + bus->base.bits_per_word = 8; + bus->base.max_speed_hz = 250000000; + bus->base.cs = 0; +#ifdef BSP_SPI_USE_INTERRUPTS + bus->irq = BCM2711_IRQ_SPI; + + eno = rtems_interrupt_handler_install( + bus->irq, + "SPI", + RTEMS_INTERRUPT_SHARED, + raspberrypi_spi_interrupt, + bus + ); + if (eno != RTEMS_SUCCESSFUL) { + return EAGAIN; + } +#endif + + eno = spi_bus_register(&bus->base, bus_path); + if (eno != 0) { + spi_bus_destroy_and_free(&bus->base); + return RTEMS_UNSATISFIED; + } + + eno = raspberrypi_spi_init_gpio(device); + if (eno != 0) { + spi_bus_destroy_and_free(&bus->base); + return RTEMS_INVALID_NUMBER; + } + + return RTEMS_SUCCESSFUL; +} \ No newline at end of file diff --git a/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml b/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml index 7be95ec59f..484caa4fef 100644 --- a/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml +++ b/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml @@ -19,6 +19,10 @@ install: - bsps/aarch64/raspberrypi/include/bsp/irq.h - bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h links: +- role: build-dependency + uid: optcorerate +- role: build-dependency + uid: optspiirq - role: build-dependency uid: objclock - role: build-dependency @@ -51,6 +55,8 @@ links: uid: ../../objirq - role: build-dependency uid: objgpio +- role: build-dependency + uid: objspi source: - bsps/aarch64/raspberrypi/console/console.c - bsps/aarch64/raspberrypi/start/bspstart.c diff --git a/spec/build/bsps/aarch64/raspberrypi/objspi.yml b/spec/build/bsps/aarch64/raspberrypi/objspi.yml new file mode 100644 index 0000000000..f4b163578f --- /dev/null +++ b/spec/build/bsps/aarch64/raspberrypi/objspi.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: objects +cflags: [] +copyrights: + - Copyright (C) 2024 Ning Yang +cppflags: [] +cxxflags: [] +enabled-by: true +includes: [] +install: + - destination: ${BSP_INCLUDEDIR}/bsp + source: + - bsps/aarch64/raspberrypi/include/bsp/raspberrypi-spi.h +links: [] +source: + - bsps/aarch64/raspberrypi/spi/raspberrypi-spi.c +type: build diff --git a/spec/build/bsps/aarch64/raspberrypi/optcorerate.yml b/spec/build/bsps/aarch64/raspberrypi/optcorerate.yml new file mode 100644 index 0000000000..7187e2a350 --- /dev/null +++ b/spec/build/bsps/aarch64/raspberrypi/optcorerate.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-integer: null +- define: null +build-type: option +copyrights: +- Copyright (C) 2024 Ning Yang +default: +- enabled-by: true + value: 500000000 +description: | + Frequency of the GPU processor core in MHz. +enabled-by: true +format: '{}' +links: [] +name: GPU_CORE_CLOCK_RATE +type: build diff --git a/spec/build/bsps/aarch64/raspberrypi/optspiirq.yml b/spec/build/bsps/aarch64/raspberrypi/optspiirq.yml new file mode 100644 index 0000000000..9294d9ce7d --- /dev/null +++ b/spec/build/bsps/aarch64/raspberrypi/optspiirq.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-boolean: null +- define-condition: null +build-type: option +copyrights: +- Copyright (C) 2024 Ning Yang +default: +- enabled-by: true + value: true +description: | + Use interrupt mode in the SPI driver. +enabled-by: true +format: '{}' +links: [] +name: BSP_SPI_USE_INTERRUPTS +type: build