diff --git a/Documentation/platforms/arm64/bcm2711/boards/raspberrypi-4b/index.rst b/Documentation/platforms/arm64/bcm2711/boards/raspberrypi-4b/index.rst index 4337e067a60..3db438e527d 100644 --- a/Documentation/platforms/arm64/bcm2711/boards/raspberrypi-4b/index.rst +++ b/Documentation/platforms/arm64/bcm2711/boards/raspberrypi-4b/index.rst @@ -4,6 +4,26 @@ Raspberry Pi 4B .. tags:: chip:bcm2711, experimental +.. warning:: + + The board support for this device is experimental. Not all features are + implemented and they have not been extensively tested by many users. + + Help is wanted if you are interested in supporting a feature or if you've + found an issue with any of the implementation! See :doc:`the contributing + guidelines `. + +.. warning:: + + The SPI driver implemented for the :doc:`BCM2711 <../../index>` has only been + tested on SPI0. It appears that even using the special `overlays + `_ + for the device tree passed to the proprietary firmware does not properly + initialize the remaining SPI interfaces, and thus they have not been working + properly. More effort is required to reverse engineer the magic incantations + required to initialize these interfaces, at which point it is assumed that + the driver implementation should extend to SPI3-6. + The `Raspberry Pi 4B `_ is an ARM64 hobbyist board created by Raspberry Pi. @@ -139,17 +159,14 @@ Board Peripheral Support SMP is currently unsupported. +To see support for general chip peripherals (I2C, SPI, UART, etc), see the +:doc:`BCM2711 page <../../index>` + NuttX for the Raspberry Pi 4 supports these on-board peripherals: ======================== ======= Peripheral Support ======================== ======= -I2C Partial (able to read, that's it) -UART Mini UART yes, PL011 no -GPIO Partial -PWM No -SPI No -PCM No AV port No HDMI No WiFi No diff --git a/Documentation/platforms/arm64/bcm2711/index.rst b/Documentation/platforms/arm64/bcm2711/index.rst index fd8f44a93db..35791210e46 100644 --- a/Documentation/platforms/arm64/bcm2711/index.rst +++ b/Documentation/platforms/arm64/bcm2711/index.rst @@ -2,12 +2,38 @@ BCM2711 ======= -The `BCM2711 `_ is a Broadcom SoC used for -the Raspberry Pi 4B board. +.. tags:: chip:bcm2711, experimental + +.. warning:: + + The support for this chip is experimental. Not all features are + implemented and they have not been extensively tested by many users. + + Help is wanted if you are interested in supporting a feature or if you've + found an issue with any of the implementation! See :doc:`the contributing + guidelines `. + +The `BCM2711 +`_ +is a Broadcom SoC used for the Raspberry Pi 4B board. - **CPU:** Quad-core ARM Cortex-A72 - **Interrupt Controller:** GIC400 +Supported Peripherals +===================== + +======================== ======= +Peripheral Support +======================== ======= +I2C Partial (able to read, that's it) +UART Mini UART yes, PL011 no +GPIO Partial +PWM No +SPI Interrupt-based driver (no DMA) for all SPI except 1 & 2 (auxiliary) +PCM No +======================== ======= + Supported Boards ================ diff --git a/arch/arm64/include/bcm2711/irq.h b/arch/arm64/include/bcm2711/irq.h index 1275fda79e6..287022d4a6d 100644 --- a/arch/arm64/include/bcm2711/irq.h +++ b/arch/arm64/include/bcm2711/irq.h @@ -20,8 +20,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM64_SRC_BCM2711_IRQ_H -#define __ARCH_ARM64_SRC_BCM2711_IRQ_H +#ifndef __ARCH_ARM64_INCLUDE_BCM2711_IRQ_H +#define __ARCH_ARM64_INCLUDE_BCM2711_IRQ_H /**************************************************************************** * Pre-processor Definitions @@ -122,8 +122,6 @@ #define BCM_IRQ_VC_EMMC BCM_IRQ_VC(62) #define BCM_IRQ_VC_ETHPCIESEC BCM_IRQ_VC(63) -/* TODO: what about PACTL_CS address section 6.2.4? */ - /* ETH_PCIe interrupts */ #define BCM_IRQ_ETH_BASE 160 @@ -143,4 +141,4 @@ #define BCM_IRQ_ARMLOCAL_IRQ_SOURCEN_MAILBOX_CORE3_IRQ (1 << 4) #define BCM_IRQ_ARMLOCAL_IRQ_SOURCEN_CNT_V_IRQ (1 << 3) -#endif // __ARCH_ARM64_SRC_BCM2711_IRQ_H +#endif // __ARCH_ARM64_INCLUDE_BCM2711_IRQ_H diff --git a/arch/arm64/src/bcm2711/Kconfig b/arch/arm64/src/bcm2711/Kconfig index 70fbfeed9dd..31236464e83 100644 --- a/arch/arm64/src/bcm2711/Kconfig +++ b/arch/arm64/src/bcm2711/Kconfig @@ -103,17 +103,92 @@ config BCM2711_SPI if BCM2711_SPI -config BCM2711_SPI1 - bool "SPI1" +config BCM2711_SPI0 + bool "SPI0" + depends on BCM2711_SPI default n ---help--- - Enable the SPI1 interface. + Enable the SPI0 interface. + +if BCM2711_SPI0 + +config BCM2711_SPI0_CE0 + int "CE0 GPIO" + depends on BCM2711_SPI0 + default 8 + ---help--- + The GPIO pin for the chip enable 0 signal (8, 36, 43) + +config BCM2711_SPI0_CE1 + int "CE1 GPIO" + depends on BCM2711_SPI0 + default 7 + ---help--- + The GPIO pin for the chip enable 1 signal (7, 35, 44) + +config BCM2711_SPI0_MISO + int "MISO GPIO" + depends on BCM2711_SPI0 + default 9 + ---help--- + The GPIO pin for the MISO signal (9, 37, 40) + +config BCM2711_SPI0_MOSI + int "MOSI GPIO" + depends on BCM2711_SPI0 + default 10 + ---help--- + The GPIO pin for the MOSI signal (10, 38, 41) + +config BCM2711_SPI0_SCLK + int "SCLK GPIO" + depends on BCM2711_SPI0 + default 11 + ---help--- + The GPIO pin for the SCLK signal (11, 39, 42) + +endif + +config BCM2711_SPI1 + bool "SPI1" + depends on BCM2711_SPI + default n + ---help--- + Enable the SPI1 interface (auxiliary). config BCM2711_SPI2 bool "SPI2" default n ---help--- - Enable the SPI2 interface. + Enable the SPI2 interface (auxiliary). + +config BCM2711_SPI3 + bool "SPI3" + depends on BCM2711_SPI + default n + ---help--- + Enable the SPI3 interface. + +config BCM2711_SPI4 + bool "SPI4" + depends on BCM2711_SPI + default n + ---help--- + Enable the SPI4 interface. + +config BCM2711_SPI5 + bool "SPI5" + depends on BCM2711_SPI + default n + ---help--- + Enable the SPI5 interface. + +config BCM2711_SPI6 + bool "SPI6" + depends on BCM2711_SPI + default n + ---help--- + Enable the SPI6 interface. endif # BCM2711_SPI diff --git a/arch/arm64/src/bcm2711/bcm2711_gpio.c b/arch/arm64/src/bcm2711/bcm2711_gpio.c index f3c2e4d5e92..f155e58a66a 100644 --- a/arch/arm64/src/bcm2711/bcm2711_gpio.c +++ b/arch/arm64/src/bcm2711/bcm2711_gpio.c @@ -327,22 +327,25 @@ void bcm2711_gpio_set_pulls(uint32_t gpio, bool up, bool down) if (gpio <= 15) { value = (direction << (gpio * 2)); - modreg32(value, value, BCM_GPIO_PUP_PDN_CNTRL_REG0); + modreg32(value, (0x3 << (gpio * 2)), BCM_GPIO_PUP_PDN_CNTRL_REG0); } else if (gpio <= 31 && gpio > 15) { value = (direction << ((gpio - 16) * 2)); - modreg32(value, value, BCM_GPIO_PUP_PDN_CNTRL_REG1); + modreg32(value, (0x3 << ((gpio - 16) * 2)), + BCM_GPIO_PUP_PDN_CNTRL_REG1); } else if (gpio <= 47 && gpio > 31) { value = (direction << ((gpio - 32) * 2)); - modreg32(value, value, BCM_GPIO_PUP_PDN_CNTRL_REG2); + modreg32(value, (0x3 << ((gpio - 32) * 2)), + BCM_GPIO_PUP_PDN_CNTRL_REG2); } else if (gpio <= 57 && gpio > 47) { value = (direction << ((gpio - 48) * 2)); - modreg32(value, value, BCM_GPIO_PUP_PDN_CNTRL_REG3); + modreg32(value, (0x3 << ((gpio - 48) * 2)), + BCM_GPIO_PUP_PDN_CNTRL_REG3); } } diff --git a/arch/arm64/src/bcm2711/bcm2711_spi.c b/arch/arm64/src/bcm2711/bcm2711_spi.c index c09067739ef..585c63215b6 100644 --- a/arch/arm64/src/bcm2711/bcm2711_spi.c +++ b/arch/arm64/src/bcm2711/bcm2711_spi.c @@ -27,19 +27,25 @@ #include #include +#include #include +#include #include #include #include #include #include +#include #include #include "arm64_arch.h" #include "arm64_gic.h" +#include "bcm2711_gpio.h" #include "chip.h" #include "hardware/bcm2711_aux.h" +#include "hardware/bcm2711_irq.h" +#include "hardware/bcm2711_spi.h" /**************************************************************************** * Pre-processor Definitions @@ -49,16 +55,116 @@ #define CORE_CLOCK_FREQUENCY 150000000 -/* Calculate the value required in the speed register for the correct +/* Calculate the value required in the CDIV register for the correct * frequency. */ -#define SPI_SPEED_FIELD(spiclk) ((CORE_CLOCK_FREQUENCY / (2 * (spiclk))) - 1) +#define SPI_CDIV(freq) (CORE_CLOCK_FREQUENCY / (freq)) /* Calculate the actual frequency based on the speed field. */ -#define SPI_ACTUAL_FREQ(speedfield) \ - (CORE_CLOCK_FREQUENCY / (2 * ((speedfield) + 1))) +#define SPI_ACTUAL_FREQ(cdiv) (CORE_CLOCK_FREQUENCY / (cdiv)) + +/* SPI interface pins (GPIO pins) */ + +/* SPI0 (has alternate pin options, except CE2) */ + +#ifdef CONFIG_BCM2711_SPI0 +#if CONFIG_BCM2711_SPI0_CE0 == 8 +#define SPI0_CE0_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_CE0 == 36 +#define SPI0_CE0_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_CE0 == 43 +#define SPI0_CE0_ALT BCM_GPIO_FUNC4 +#else +#error "Invalid GPIO number for SPI0 CE0" +#endif + +#if CONFIG_BCM2711_SPI0_CE1 == 7 +#define SPI0_CE1_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_CE1 == 35 +#define SPI0_CE1_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_CE1 == 44 +#define SPI0_CE1_ALT BCM_GPIO_FUNC4 +#else +#error "Invalid GPIO number for SPI0 CE1" +#endif + +#if CONFIG_BCM2711_SPI0_MISO == 9 +#define SPI0_MISO_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_MISO == 37 +#define SPI0_MISO_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_MISO == 40 +#define SPI0_MISO_ALT BCM_GPIO_FUNC4 +#else +#error "Invalid GPIO number for SPI0 MISO" +#endif + +#if CONFIG_BCM2711_SPI0_MOSI == 10 +#define SPI0_MOSI_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_MOSI == 38 +#define SPI0_MOSI_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_MOSI == 41 +#define SPI0_MOSI_ALT BCM_GPIO_FUNC4 +#else +#error "Invalid GPIO number for SPI0 MOSI" +#endif + +#if CONFIG_BCM2711_SPI0_SCLK == 11 +#define SPI0_SCLK_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_SCLK == 39 +#define SPI0_SCLK_ALT BCM_GPIO_FUNC0 +#elif CONFIG_BCM2711_SPI0_SCLK == 42 +#define SPI0_SCLK_ALT BCM_GPIO_FUNC4 +#else +#error "Invalid GPIO number for SPI0 SCLK" +#endif + +#define SPI0_CE2 45 +#endif + +/* SPI1 */ + +#define SPI1_MISO 19 +#define SPI1_MOSI 20 +#define SPI1_SCLK 21 +#define SPI1_CE0 18 +#define SPI1_CE1 17 +#define SPI1_CE2 16 + +/* SPI2 (datasheet does not mention this interface's available pins) */ + +/* SPI3 (no CE2) */ + +#define SPI3_MISO 1 +#define SPI3_MOSI 2 +#define SPI3_SCLK 3 +#define SPI3_CE0 0 +#define SPI3_CE1 24 + +/* SPI4 (no CE2) */ + +#define SPI4_MISO 5 +#define SPI4_MOSI 6 +#define SPI4_SCLK 7 +#define SPI4_CE0 4 +#define SPI4_CE1 25 + +/* SPI5 (no CE2) */ + +#define SPI5_MISO 13 +#define SPI5_MOSI 14 +#define SPI5_SCLK 15 +#define SPI5_CE0 12 +#define SPI5_CE1 26 + +/* SPI6 (no CE2) */ + +#define SPI6_MISO 19 +#define SPI6_MOSI 20 +#define SPI6_SCLK 21 +#define SPI6_CE0 18 +#define SPI6_CE1 27 /**************************************************************************** * Private Types @@ -71,11 +177,16 @@ struct bcm2711_spidev_s struct spi_dev_s spidev; /* Externally visible */ uint32_t base; /* Base address of SPI interface register */ mutex_t lock; /* Mutual exclusion during chip select */ + sem_t wait; /* Where to wait for transfer completion */ uint32_t freq; /* Request clock frequency */ uint32_t actualfreq; /* Actual clock frequency */ uint8_t nbits; /* Word bit-width */ uint8_t mode; /* 0, 1, 2 or 3 */ - uint8_t port; /* 1 or 2 */ + uint8_t port; /* SPI 0-6 */ + bool initialized; /* Already initialized */ + uint8_t *txbuffer; /* Transmit buffer for current transfer */ + uint8_t *rxbuffer; /* Receive buffer for current transfer */ + size_t nwords; /* Number of words in exchange */ }; /**************************************************************************** @@ -84,19 +195,20 @@ struct bcm2711_spidev_s /* SPI methods */ -static int spi_lock(struct spi_dev_s *dev, bool lock); -static uint32_t spi_setfrequency(struct spi_dev_s *dev, uint32_t frequency); -static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode); -static void spi_setbits(struct spi_dev_s *dev, int nbits); -static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd); -static void unused_code spi_exchange(struct spi_dev_s *dev, - const void *txbuffer, void *rxbuffer, - size_t nwords); - +static int spi_lock(FAR struct spi_dev_s *dev, bool lock); +static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, + uint32_t frequency); +static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); +static void spi_setbits(FAR struct spi_dev_s *dev, int nbits); +static uint32_t spi_send(FAR struct spi_dev_s *dev, uint32_t wd); +static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, + void *rxbuffer, size_t nwords); +static void spi_select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected); #ifndef CONFIG_SPI_EXCHANGE -static void spi_sndblock(struct spi_dev_s *dev, const void *buffer, +static void spi_sndblock(FAR struct spi_dev_s *dev, const void *buffer, size_t nwords); -static void spi_recvblock(struct spi_dev_s *dev, void *buffer, +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords); #endif /* CONFIG_SPI_EXCHANGE */ @@ -104,69 +216,375 @@ static void spi_recvblock(struct spi_dev_s *dev, void *buffer, * Private Data ****************************************************************************/ -/* Operations for SPI interfaces */ +/* Operations for non-auxiliary SPI interfaces */ static const struct spi_ops_s g_spiops = { - .lock = spi_lock, - .setfrequency = spi_setfrequency, - .setmode = spi_setmode, - .setbits = spi_setbits, - .send = spi_send, + .lock = spi_lock, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, + .send = spi_send, + .select = spi_select, #ifdef CONFIG_SPI_EXCHANGE - .exchange = spi_exchange, + .exchange = spi_exchange, #else - .sndblock = spi_sndblock, - .recvblock = spi_recvblock, + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, #endif /* CONFIG_SPI_EXCHANGE */ #ifdef CONFIG_SPI_HWFEATURES - .hwfeatures = NULL, + .hwfeatures = NULL, #endif /* CONFIG_SPI_HWFEATURES */ #ifdef CONFIG_SPI_CALLBACK - .registercallback = /* TODO */, /* Provided externally */ + .registercallback = NULL, + /* TODO when needed */, /* Provided externally */ #else - .registercallback = 0, /* Not implemented */ + .registercallback = NULL, /* Not implemented */ #endif }; -#define CONFIG_BCM2711_SPI1 // TODO remove -#if defined(CONFIG_BCM2711_SPI1) +/* True if the interrupt handler for SPI is attached, false otherwise */ -static struct bcm2711_spidev_s g_spi1dev = +static bool g_interrupts = false; + +#if defined(CONFIG_BCM2711_SPI0) +static struct bcm2711_spidev_s g_spi0dev = { - .spidev = - { - .ops = &g_spiops, - }, - .base = BCM_AUX_SPI1_BASEADDR, - .frequency = 0, - .port = 1, - .lock = NXMUTEX_INITIALIZER, + .spidev = + { + .ops = &g_spiops, + }, + .base = BCM_SPI0_BASEADDR, + .freq = 0, + .port = 0, + .lock = NXMUTEX_INITIALIZER, + .wait = NXSEM_INITIALIZER(0, 0), + .txbuffer = NULL, + .rxbuffer = NULL, + .nwords = 0, }; +#endif -#endif /* defined(CONFIG_BCM2711_SPI1) */ - -#define CONFIG_BCM2711_SPI2 // TODO remove -#if defined(CONFIG_BCM2711_SPI2) - -static struct bcm2711_spidev_s g_spi2dev = +#if defined(CONFIG_BCM2711_SPI3) +static struct bcm2711_spidev_s g_spi3dev = { - .spidev = - { - .ops = &g_spiops, - }, - .base = BCM_AUX_SPI2_BASEADDR, - .frequency = 0, - .port = 2, - .lock = NXMUTEX_INITIALIZER, + .spidev = + { + .ops = &g_spiops, + }, + .base = BCM_SPI3_BASEADDR, + .freq = 0, + .port = 3, + .lock = NXMUTEX_INITIALIZER, + .wait = NXSEM_INITIALIZER(0, 0), + .txbuffer = NULL, + .rxbuffer = NULL, + .nwords = 0, }; +#endif -#endif /* defined(CONFIG_BCM2711_SPI2) */ +#if defined(CONFIG_BCM2711_SPI4) +static struct bcm2711_spidev_s g_spi4dev = +{ + .spidev = + { + .ops = &g_spiops, + }, + .base = BCM_SPI4_BASEADDR, + .freq = 0, + .port = 4, + .lock = NXMUTEX_INITIALIZER, + .wait = NXSEM_INITIALIZER(0, 0), + .txbuffer = NULL, + .rxbuffer = NULL, + .nwords = 0, +}; +#endif + +#if defined(CONFIG_BCM2711_SPI5) +static struct bcm2711_spidev_s g_spi5dev = +{ + .spidev = + { + .ops = &g_spiops, + }, + .base = BCM_SPI5_BASEADDR, + .freq = 0, + .port = 5, + .lock = NXMUTEX_INITIALIZER, + .wait = NXSEM_INITIALIZER(0, 0), + .txbuffer = NULL, + .rxbuffer = NULL, + .nwords = 0, +}; +#endif + +#if defined(CONFIG_BCM2711_SPI6) +static struct bcm2711_spidev_s g_spi6dev = +{ + .spidev = + { + .ops = &g_spiops, + }, + .base = BCM_SPI6_BASEADDR, + .freq = 0, + .port = 6, + .lock = NXMUTEX_INITIALIZER, + .wait = NXSEM_INITIALIZER(0, 0), + .txbuffer = NULL, + .rxbuffer = NULL, + .nwords = 0, +}; +#endif /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: spi_interrupt_en + * + * Description: + * Enable/disable interrupts for the SPI interfaces. + * + * Input Parameters: + * priv - Device-specific state data + * en - true: enable interrupts, false: disable interrupts + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_interrupt_en(struct bcm2711_spidev_s *priv, bool en) +{ + uint32_t regval; + + DEBUGASSERT(priv); + + if (en) + { + regval = (BCM_SPI_CS_INTR | BCM_SPI_CS_INTD); + } + else + { + regval = 0; + } + + modreg32(regval, (BCM_SPI_CS_INTR | BCM_SPI_CS_INTD), + BCM_SPI_CS(priv->base)); +} + +/**************************************************************************** + * Name: spi_fill_txfifo + * + * Description: + * Write as much data to the TX FIFO as possible without overflowing it. TX + * will also stop if RX is 3/4 full. This function will not do anything if + * the SPI device has no data waiting to be written. + * + * Input Parameters: + * dev - The SPI device to write to. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_fill_txfifo(struct bcm2711_spidev_s *dev) +{ + uint32_t data; + while ((getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_TXD) && + !(getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_RXR) && + dev->nwords) + { + if (dev->txbuffer) + { + data = (uint32_t)*dev->txbuffer++; + } + + putreg32(dev->txbuffer ? data : 0xff, BCM_SPI_FIFO(dev->base)); + + dev->nwords--; + } +} + +/**************************************************************************** + * Name: spi_drain_rxfifo + * + * Description: + * Read as much data from the RX FIFO as possible. Will not do anything if + * there is no data to be read. + * + * Input Parameters: + * dev - The SPI device to write to. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_drain_rxfifo(struct bcm2711_spidev_s *dev) +{ + uint32_t data; + + while (getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_RXD) + { + data = getreg32(BCM_SPI_FIFO(dev->base)); + if (dev->rxbuffer) + { + *dev->rxbuffer++ = (uint8_t)data; + } + } +} + +/**************************************************************************** + * Name: spi_interrupt_handler + * + * Description: + * The interrupt service routine for a given SPI interface. + * + * Input Parameters: + * dev - The SPI device to be serviced. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int spi_service_interrupt(struct bcm2711_spidev_s *dev) +{ + int err = 0; + + /* From peripheral data sheet: + * + * If DONE is set and data to write (this means it is the first interrupt), + * write up to 64 bytes to SPI_FIFO. If DONE is set and no more data, set + * TA = 0. Read trailing data from SPI_FIFO until RXD is 0. + * + * If RXR is set read 48 bytes data from SPI_FIFO and if more data to + * write, write up to 48 bytes to SPI_FIFO + */ + + if (getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_DONE) + { + if (dev->nwords > 0) + { + /* While there is space to write and stuff to write, write it to + * the FIFO. Check here if the RX FIFO needs reading so we don't + * overflow it either. + */ + + spi_fill_txfifo(dev); + } + else + { + /* Mark transfer as over, there is nothing left to write */ + + modreg32(0, BCM_SPI_CS_TA, BCM_SPI_CS(dev->base)); + + /* Drain the remaining data to be read */ + + spi_drain_rxfifo(dev); + + /* Clean buffers. */ + + dev->txbuffer = NULL; + dev->rxbuffer = NULL; + + /* Post the semaphore to let the caller know the transfer is over */ + + nxsem_post(&dev->wait); + } + } + + /* If the RX FIFO needs to be read */ + + if (getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_RXR) + { + /* Read RX FIFO into buffer (if provided) until empty */ + + spi_drain_rxfifo(dev); + + /* If more information can be written now, then write it */ + + spi_fill_txfifo(dev); + } + + return err; +} + +/**************************************************************************** + * Name: spi_interrupt_handler + * + * Description: + * The interrupt handler for SPI interrupts. + * + * Input Parameters: + * irq - The IRQ number + * context - The interrupt context + * arg - NULL in this case, all data is grabbed from the SPI device global + * definitions + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int spi_interrupt_handler(int irq, FAR void *context, FAR void *arg) +{ + uint32_t pactl; + + /* Check which SPI interfaces need to be serviced and service them */ + + pactl = getreg32(BCM_PACTL_CS); + + if (pactl & BCM_PACTL_CS_SPI0) + { +#if defined(CONFIG_BCM2711_SPI0) + spi_service_interrupt(&g_spi0dev); +#endif + } + else if (pactl & BCM_PACTL_CS_SPI1) + { +#if defined(CONFIG_BCM2711_SPI1) +#error "SPI1 interrupt not implemented" +#endif + } + else if (pactl & BCM_PACTL_CS_SPI2) + { +#if defined(CONFIG_BCM2711_SPI2) +#error "SPI1 interrupt not implemented" +#endif + } + else if (pactl & BCM_PACTL_CS_SPI3) + { +#if defined(CONFIG_BCM2711_SPI3) + spi_service_interrupt(&g_spi3dev); +#endif + } + else if (pactl & BCM_PACTL_CS_SPI4) + { +#if defined(CONFIG_BCM2711_SPI4) + spi_service_interrupt(&g_spi4dev); +#endif + } + else if (pactl & BCM_PACTL_CS_SPI5) + { +#if defined(CONFIG_BCM2711_SPI5) + spi_service_interrupt(&g_spi5dev); +#endif + } + else if (pactl & BCM_PACTL_CS_SPI6) + { +#if defined(CONFIG_BCM2711_SPI6) + spi_service_interrupt(&g_spi6dev); +#endif + } + + return 0; +} + /**************************************************************************** * Name: spi_lock * @@ -184,7 +602,7 @@ static struct bcm2711_spidev_s g_spi2dev = * lock - true: Lock spi bus, false: unlock SPI bus * * Returned Value: - * None + * Result of locking the mutex, 0 on success. * ****************************************************************************/ @@ -221,24 +639,296 @@ static uint32_t spi_setfrequency(struct spi_dev_s *dev, uint32_t frequency) { struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev; - /* Calculate the speed field value needed */ + DEBUGASSERT(priv); - uint32_t speed = SPI_SPEED_FIELD(frequency); + /* Calculate the clock divisor needed (must be a multiple of 2) */ - /* Save the speed field to take effect */ + uint32_t cdiv = SPI_CDIV(frequency); + cdiv &= ~0x1; /* Clear last bit to guarantee multiple of 2 rounded down */ + DEBUGASSERT(cdiv < 0xffff); - modreg32(BCM_SPI_CNTL0_SPEED, speed << 20, BCM_SPI_CNTL0_REG(priv->base)); + /* Save the clock divisor to take effect */ + + putreg32(cdiv, BCM_SPI_CLK(priv->base)); /* Calculate the new actual and save settings */ priv->freq = frequency; - priv->actualfreq = SPI_ACTUAL_FREQ(speed); + priv->actualfreq = SPI_ACTUAL_FREQ(cdiv); - spiinfo("Frequency %" PRId32 "->%" PRId32 "\n", - frequency, priv->actualfreq); + spiinfo("Frequency %" PRId32 "->%" PRId32 "\n", frequency, + priv->actualfreq); return priv->actualfreq; } +/**************************************************************************** + * Name: spi_setmode + * + * Description: + * Set the SPI mode. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The SPI mode requested + * + * Returned Value: None + * + ****************************************************************************/ + +static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode) +{ + struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev; + uint32_t regval; + + DEBUGASSERT(priv); + + /* No change to SPI mode */ + + if (mode == priv->mode) + { + return; + } + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0, CPHA=0 */ + regval = 0; + break; + case SPIDEV_MODE1: /* CPOL=0, CPHA=1 */ + regval = BCM_SPI_CS_CPHA; + break; + case SPIDEV_MODE2: /* CPOL=1, CPHA=0 */ + regval = BCM_SPI_CS_CPOL; + break; + case SPIDEV_MODE3: /* CPOL=1, CPHA=1 */ + regval = BCM_SPI_CS_CPOL | BCM_SPI_CS_CPHA; + break; + default: + spierr("Bad SPI mode: %d\n", mode); + DEBUGASSERT(false); + return; + } + + spiinfo("SPI set mode: %d", mode); + modreg32(regval, (BCM_SPI_CS_CPOL | BCM_SPI_CS_CPHA), + BCM_SPI_CS(priv->base)); + priv->mode = mode; +} + +/**************************************************************************** + * Name: spi_setbits + * + * Description: + * Set the number of bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_setbits(struct spi_dev_s *dev, int nbits) +{ + struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev; + + DEBUGASSERT(priv); + + /* As far as I'm aware, the BCM2711 only supports 8 bits per word? */ + + DEBUGASSERT(nbits == 8); +} + +/**************************************************************************** + * Name: 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: + * response + * + ****************************************************************************/ + +static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd) +{ + struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev; + uint32_t regval; + + /* Wait until the TX FIFO can accept data */ + + while (!(getreg32(BCM_SPI_CS(priv->base)) & BCM_SPI_CS_TXD)) + ; + + /* Make sure TA (transfer active) bit is set */ + + modreg32(BCM_SPI_CS_TA, BCM_SPI_CS_TA, BCM_SPI_CS(priv->base)); + + /* Write the byte to the TX FIFO */ + + putreg32(wd, BCM_SPI_FIFO(priv->base)); + + /* Wait for the RX FIFO not empty */ + + while (!(getreg32(BCM_SPI_CS(priv->base)) & BCM_SPI_CS_RXD)) + ; + + /* Get the value from the RX FIFO */ + + regval = getreg32(BCM_SPI_FIFO(priv->base)); + spiinfo("%04" PRIx32 "->%04" PRIx32 "\n", wd, regval); + + /* Wait for done signal */ + + while (!(getreg32(BCM_SPI_CS(priv->base)) & BCM_SPI_CS_DONE)) + ; + + /* End the transfer */ + + modreg32(0, BCM_SPI_CS_TA, BCM_SPI_CS(priv->base)); + + return regval; +} + +/**************************************************************************** + * Name: spi_exchange + * + * Description: + * Wrapper function to 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 spi_exchange(struct spi_dev_s *dev, const void *txbuffer, + void *rxbuffer, size_t nwords) +{ + struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev; + + /* Set the buffers up */ + + priv->txbuffer = (void *)txbuffer; + priv->rxbuffer = rxbuffer; + priv->nwords = nwords; + + /* Start the transfer */ + + modreg32(BCM_SPI_CS_TA, BCM_SPI_CS_TA, BCM_SPI_CS(priv->base)); + + /* Block on semaphore until transfers are all done */ + + nxsem_wait_uninterruptible(&priv->wait); +} + +/**************************************************************************** + * Name: 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 + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void spi_sndblock(struct spi_dev_s *dev, const void *buffer, + size_t nwords) +{ + return spi_exchange(dev, buffer, NULL, nwords); +} + +/**************************************************************************** + * Name: spi_recvblock + * + * Description: + * Revice 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 spi_recvblock(struct spi_dev_s *dev, void *buffer, size_t nwords) +{ + return spi_exchange(dev, NULL, buffer, nwords); +} +#endif /* !CONFIG_SPI_EXCHANGE */ + +/**************************************************************************** + * Name: spi_select + * + * Description: + * Enables/disables the chosen chip select ping for the BCM2711 SPI + * interface. Some SPI interfaces have up to 3 chip select options. The CS + * pin is automatically asserted and de-asserted during transfers, so this + * function will only choose which CS interface is active at any time. + * + ****************************************************************************/ + +static void spi_select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev; + spiinfo("Select devid %u", devid); + + /* Get the last bits of the device ID, indicating index (TODO: is this + * appropriate?) + */ + + devid = devid & 0xffff; + DEBUGASSERT(priv); + DEBUGASSERT(devid < 2); + spiinfo("Using chip enable %u", devid); + + /* Do nothing if not actively selecting a peripheral device */ + + if (!selected) + { + return; + } + + /* Set chip select pin to be the active pin */ + + modreg32(devid & 0x3, BCM_SPI_CS_CS, BCM_SPI_CS(priv->base)); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -259,5 +949,196 @@ static uint32_t spi_setfrequency(struct spi_dev_s *dev, uint32_t frequency) struct spi_dev_s *bcm2711_spibus_initialize(int port) { - return NULL; + int err; + struct bcm2711_spidev_s *priv = NULL; + + switch (port) + { +#if defined(CONFIG_BCM2711_SPI0) + case 0: + priv = &g_spi0dev; + break; +#endif +#if defined(CONFIG_BCM2711_SPI1) + case 1: +#error "SPI1 is not implemented" + break; +#endif +#if defined(CONFIG_BCM2711_SPI2) + case 2: +#error "SPI2 is not implemented" + break; +#endif +#if defined(CONFIG_BCM2711_SPI3) + case 3: + priv = &g_spi3dev; + break; +#endif +#if defined(CONFIG_BCM2711_SPI4) + case 4: + priv = &g_spi4dev; + break; +#endif +#if defined(CONFIG_BCM2711_SPI5) + case 5: + priv = &g_spi5dev; + break; +#endif +#if defined(CONFIG_BCM2711_SPI6) + case 6: + priv = &g_spi6dev; + break; +#endif + default: + return NULL; + } + + if (priv->initialized) + { + return &priv->spidev; + } + + /* Perform initialization */ + + priv->nbits = 8; + priv->freq = 0; + priv->mode = SPIDEV_MODE0; + priv->txbuffer = NULL; + priv->rxbuffer = NULL; + priv->nwords = 0; + + /* If the main SPI interrupt handler is not attached yet, attach it */ + + if (!g_interrupts) + { + err = irq_attach(BCM_IRQ_VC_SPI, spi_interrupt_handler, NULL); + + if (err) + { + spierr("Could not attach SPI interrupt handler: %d\n", err); + irqerr("Could not attach SPI interrupt handler: %d\n", err); + return NULL; + } + + arm64_gic_irq_set_priority(BCM_IRQ_VC_SPI, 0, IRQ_TYPE_LEVEL); + up_enable_irq(BCM_IRQ_VC_SPI); + g_interrupts = true; + + irqinfo("SPI interrupt handler attached."); + spiinfo("SPI interrupt handler attached."); + } + + /* Enable SPI interface interrupts for non-auxiliary SPI devices */ + + if (port != 1 && port != 2) + { + spiinfo("Enabled interrupts for SPI%d\n", port); + spi_interrupt_en(priv, true); + } + + /* Set up GPIO pins for the interface */ + + switch (port) + { +#if defined(CONFIG_BCM2711_SPI0) + case 0: + bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_CE0, true, false); + bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_CE1, true, false); + bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_MOSI, false, true); + bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_MISO, false, true); + bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_SCLK, false, true); + + bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_CE0, SPI0_CE0_ALT); + bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_CE1, SPI0_CE1_ALT); + bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_MOSI, SPI0_MOSI_ALT); + bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_MISO, SPI0_MISO_ALT); + bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_SCLK, SPI0_SCLK_ALT); + break; +#endif +#if defined(CONFIG_BCM2711_SPI1) + case 1: + bcm2711_gpio_set_pulls(SPI1_CE0, true, false); + bcm2711_gpio_set_pulls(SPI1_CE1, true, false); + bcm2711_gpio_set_pulls(SPI2_CE1, true, false); + bcm2711_gpio_set_pulls(SPI1_MOSI, false, true); + bcm2711_gpio_set_pulls(SPI1_MISO, false, true); + bcm2711_gpio_set_pulls(SPI1_SCLK, false, true); + + bcm2711_gpio_set_func(SPI1_CE0, BCM_GPIO_FUNC4); + bcm2711_gpio_set_func(SPI1_CE1, BCM_GPIO_FUNC4); + bcm2711_gpio_set_func(SPI1_CE2, BCM_GPIO_FUNC4); + bcm2711_gpio_set_func(SPI1_MOSI, BCM_GPIO_FUNC4); + bcm2711_gpio_set_func(SPI1_MISO, BCM_GPIO_FUNC4); + bcm2711_gpio_set_func(SPI1_SCLK, BCM_GPIO_FUNC4); + break; +#endif +#if defined(CONFIG_BCM2711_SPI2) + case 2: +#error "SPI2 is not implemented" + break; +#endif +#if defined(CONFIG_BCM2711_SPI3) + case 3: + bcm2711_gpio_set_pulls(SPI3_CE0, true, false); + bcm2711_gpio_set_pulls(SPI3_CE1, true, false); + bcm2711_gpio_set_pulls(SPI3_MOSI, false, true); + bcm2711_gpio_set_pulls(SPI3_MISO, false, true); + bcm2711_gpio_set_pulls(SPI3_SCLK, false, true); + + bcm2711_gpio_set_func(SPI3_CE0, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI3_CE1, BCM_GPIO_FUNC5); + bcm2711_gpio_set_func(SPI3_MOSI, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI3_MISO, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI3_SCLK, BCM_GPIO_FUNC3); + break; +#endif +#if defined(CONFIG_BCM2711_SPI4) + case 4: + bcm2711_gpio_set_pulls(SPI4_CE0, true, false); + bcm2711_gpio_set_pulls(SPI4_CE1, true, false); + bcm2711_gpio_set_pulls(SPI4_MOSI, false, true); + bcm2711_gpio_set_pulls(SPI4_MISO, false, true); + bcm2711_gpio_set_pulls(SPI4_SCLK, false, true); + + bcm2711_gpio_set_func(SPI4_CE0, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI4_CE1, BCM_GPIO_FUNC5); + bcm2711_gpio_set_func(SPI4_MOSI, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI4_MISO, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI4_SCLK, BCM_GPIO_FUNC3); + break; +#endif +#if defined(CONFIG_BCM2711_SPI5) + case 5: + bcm2711_gpio_set_pulls(SPI5_CE0, true, false); + bcm2711_gpio_set_pulls(SPI5_CE1, true, false); + bcm2711_gpio_set_pulls(SPI5_MOSI, false, true); + bcm2711_gpio_set_pulls(SPI5_MISO, false, true); + bcm2711_gpio_set_pulls(SPI5_SCLK, false, true); + + bcm2711_gpio_set_func(SPI5_CE0, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI5_CE1, BCM_GPIO_FUNC5); + bcm2711_gpio_set_func(SPI5_MOSI, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI5_MISO, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI5_SCLK, BCM_GPIO_FUNC3); + break; +#endif +#if defined(CONFIG_BCM2711_SPI6) + case 6: + bcm2711_gpio_set_pulls(SPI6_CE0, true, false); + bcm2711_gpio_set_pulls(SPI6_CE1, true, false); + bcm2711_gpio_set_pulls(SPI6_MOSI, false, true); + bcm2711_gpio_set_pulls(SPI6_MISO, false, true); + bcm2711_gpio_set_pulls(SPI6_SCLK, false, true); + + bcm2711_gpio_set_func(SPI6_CE0, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI6_CE1, BCM_GPIO_FUNC5); + bcm2711_gpio_set_func(SPI6_MOSI, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI6_MISO, BCM_GPIO_FUNC3); + bcm2711_gpio_set_func(SPI6_SCLK, BCM_GPIO_FUNC3); + break; +#endif + } + + priv->initialized = true; + return &priv->spidev; } diff --git a/arch/arm64/src/bcm2711/hardware/bcm2711_irq.h b/arch/arm64/src/bcm2711/hardware/bcm2711_irq.h index 70315a498a1..e57df74f434 100644 --- a/arch/arm64/src/bcm2711/hardware/bcm2711_irq.h +++ b/arch/arm64/src/bcm2711/hardware/bcm2711_irq.h @@ -33,108 +33,6 @@ * Pre-processor Definitions ****************************************************************************/ -/* ARM_LOCAL interrupts */ - -/* ARMC interrupts */ - -#define BCM_IRQ_ARMC_TIMER 0 /* Timer */ -#define BCM_IRQ_ARMC_MAILBOX 1 /* Mailbox */ -#define BCM_IRQ_ARMC_DOORBELL0 2 /* Doorbell 0 */ -#define BCM_IRQ_ARMC_DOORBELL1 3 /* Doorbell 1 */ -#define BCM_IRQ_ARMC_VPU0HALT 4 /* VPU 0 halted */ -#define BCM_IRQ_ARMC_VPU1HALT 5 /* VPU 1 halted */ -#define BCM_IRQ_ARMC_ARMADDRERR 6 /* ARM address error */ -#define BCM_IRQ_ARMC_ARMAXIERR 7 /* ARM AXI error */ -#define BCM_IRQ_ARMC_SWI0 8 /* Software interrupt 0 */ -#define BCM_IRQ_ARMC_SWI1 9 /* Software interrupt 1 */ -#define BCM_IRQ_ARMC_SWI2 10 /* Software interrupt 2 */ -#define BCM_IRQ_ARMC_SWI3 11 /* Software interrupt 3 */ -#define BCM_IRQ_ARMC_SWI4 12 /* Software interrupt 4 */ -#define BCM_IRQ_ARMC_SWI5 13 /* Software interrupt 5 */ -#define BCM_IRQ_ARMC_SWI6 14 /* Software interrupt 6 */ -#define BCM_IRQ_ARMC_SWI7 15 /* Software interrupt 7 */ - -/* VideoCore interrupts */ - -#define BCM_IRQ_VC_TIMER0 0 -#define BCM_IRQ_VC_TIMER1 1 -#define BCM_IRQ_VC_TIMER2 2 -#define BCM_IRQ_VC_TIMER3 3 -#define BCM_IRQ_VC_H2640 4 -#define BCM_IRQ_VC_H2641 5 -#define BCM_IRQ_VC_H2642 6 -#define BCM_IRQ_VC_JPEG 7 -#define BCM_IRQ_VC_ISP 8 -#define BCM_IRQ_VC_USB 9 -#define BCM_IRQ_VC_V3D 10 -#define BCM_IRQ_VC_TRANSPOSE 11 -#define BCM_IRQ_VC_MCSYNC0 12 -#define BCM_IRQ_VC_MCSYNC1 13 -#define BCM_IRQ_VC_MCSYNC2 14 -#define BCM_IRQ_VC_MCSYNC3 15 -#define BCM_IRQ_VC_DMA0 16 -#define BCM_IRQ_VC_DMA1 17 -#define BCM_IRQ_VC_DMA2 18 -#define BCM_IRQ_VC_DMA3 19 -#define BCM_IRQ_VC_DMA4 20 -#define BCM_IRQ_VC_DMA5 21 -#define BCM_IRQ_VC_DMA6 22 -#define BCM_IRQ_VC_DMA7N8 23 -#define BCM_IRQ_VC_DMA9N10 24 -#define BCM_IRQ_VC_DMA11 25 -#define BCM_IRQ_VC_DMA12 26 -#define BCM_IRQ_VC_DMA13 27 -#define BCM_IRQ_VC_DMA14 28 -#define BCM_IRQ_VC_AUX 29 -#define BCM_IRQ_VC_ARM 30 -#define BCM_IRQ_VC_DMA15 31 -#define BCM_IRQ_VC_HDMICEC 32 -#define BCM_IRQ_VC_HVS 33 -#define BCM_IRQ_VC_RPIVID 34 -#define BCM_IRQ_VC_SDC 35 -#define BCM_IRQ_VC_DSI0 36 -#define BCM_IRQ_VC_PIXVLV2 37 -#define BCM_IRQ_VC_CAM0 38 -#define BCM_IRQ_VC_CAM1 39 -#define BCM_IRQ_VC_HDMI0 40 -#define BCM_IRQ_VC_HDMI1 41 -#define BCM_IRQ_VC_PIXVLV3 42 -#define BCM_IRQ_VC_SPIBSCSLV 43 -#define BCM_IRQ_VC_DSI1 44 -#define BCM_IRQ_VC_PXLVLV0 45 -#define BCM_IRQ_VC_PXLVLV1N4 46 -#define BCM_IRQ_VC_CPR 47 -#define BCM_IRQ_VC_SMI 48 -#define BCM_IRQ_VC_GPIO0 49 -#define BCM_IRQ_VC_GPIO1 50 -#define BCM_IRQ_VC_GPIO2 51 -#define BCM_IRQ_VC_GPIO3 52 -#define BCM_IRQ_VC_I2C 53 -#define BCM_IRQ_VC_SPI 54 -#define BCM_IRQ_VC_PCMI2S 55 -#define BCM_IRQ_VC_SDHOST 56 -#define BCM_IRQ_VC_PL011UART 57 -#define BCM_IRQ_VC_ETHPCIE 58 -#define BCM_IRQ_VC_VEC 59 -#define BCM_IRQ_VC_CPG 60 -#define BCM_IRQ_VC_RNG 61 -#define BCM_IRQ_VC_EMMC 62 -#define BCM_IRQ_VC_ETHPCIESEC 63 - -/* TODO: what about PACTL_CS address section 6.2.4? */ - -/* ETH_PCIe interrupts */ - -#define BCM_IRQ_ETH_AVS 9 -#define BCM_IRQ_ETH_PCIE0_INTA 15 -#define BCM_IRQ_ETH_PCIE0_INTB 16 -#define BCM_IRQ_ETH_PCIE0_INTC 17 -#define BCM_IRQ_ETH_PCIE0_INTD 18 -#define BCM_IRQ_ETH_PCIE0_MSI 20 -#define BCM_IRQ_ETH_GENET0_A 29 -#define BCM_IRQ_ETH_GENET0_B 30 -#define BCM_IRQ_ETH_USB0_XHCI0 48 - /* ARM_LOCAL interrupt register offsets */ #define BCM_IRQ_ARMLOCAL_ARM_CONTROL_OFFSET 0x00 @@ -605,4 +503,29 @@ #define BCM_IRQ_ARMC_SWIRQ_SET_SW_INT (0xff) #define BCM_IRQ_ARMC_SWIRQ_CLEAR_SW_INT (0xff) +/* PACTL_CS register bit definitions */ + +#define BCM_PACTL_CS_SPI0 (1 << 0) +#define BCM_PACTL_CS_SPI1 (1 << 1) +#define BCM_PACTL_CS_SPI2 (1 << 2) +#define BCM_PACTL_CS_SPI3 (1 << 3) +#define BCM_PACTL_CS_SPI4 (1 << 4) +#define BCM_PACTL_CS_SPI5 (1 << 5) +#define BCM_PACTL_CS_SPI6 (1 << 6) + +#define BCM_PACTL_CS_I2C0 (1 << 8) +#define BCM_PACTL_CS_I2C1 (1 << 9) +#define BCM_PACTL_CS_I2C2 (1 << 10) +#define BCM_PACTL_CS_I2C3 (1 << 11) +#define BCM_PACTL_CS_I2C4 (1 << 12) +#define BCM_PACTL_CS_I2C5 (1 << 13) +#define BCM_PACTL_CS_I2C6 (1 << 14) +#define BCM_PACTL_CS_I2C7 (1 << 15) + +#define BCM_PACTL_CS_UART5 (1 << 16) +#define BCM_PACTL_CS_UART4 (1 << 17) +#define BCM_PACTL_CS_UART3 (1 << 18) +#define BCM_PACTL_CS_UART2 (1 << 19) +#define BCM_PACTL_CS_UART0 (1 << 20) + #endif /* __ARCH_ARM64_SRC_BCM2711_IRQ_H */ diff --git a/arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h b/arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h index 0ee903a6092..d1b48e26650 100644 --- a/arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h +++ b/arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h @@ -103,6 +103,10 @@ #define BCM_DMA15_BASE \ (BCM_PERIPHERAL_BASEADDR + 0x000e05000) /* DMA Channel 15 */ +/* PACTL register address */ + +#define BCM_PACTL_CS (BCM_PERIPHERAL_BASEADDR + 0x204e00) + /* ARM_LOCAL base address */ #if defined(CONFIG_BCM2711_LOW_PERIPHERAL) diff --git a/arch/arm64/src/bcm2711/hardware/bcm2711_spi.h b/arch/arm64/src/bcm2711/hardware/bcm2711_spi.h index 6131d1653b4..58ac2341cce 100644 --- a/arch/arm64/src/bcm2711/hardware/bcm2711_spi.h +++ b/arch/arm64/src/bcm2711/hardware/bcm2711_spi.h @@ -44,40 +44,12 @@ /* SPI register addresses */ -#define BCM_SPI0_CS (BCM_SPI0_BASEADDR + BCM_SPI_CS_OFFSET) -#define BCM_SPI0_FIFO (BCM_SPI0_BASEADDR + BCM_SPI_FIFO_OFFSET) -#define BCM_SPI0_CLK (BCM_SPI0_BASEADDR + BCM_SPI_CLK_OFFSET) -#define BCM_SPI0_DLEN (BCM_SPI0_BASEADDR + BCM_SPI_DLEN_OFFSET) -#define BCM_SPI0_LTOH (BCM_SPI0_BASEADDR + BCM_SPI_LTOH_OFFSET) -#define BCM_SPI0_DC (BCM_SPI0_BASEADDR + BCM_SPI_DC_OFFSET) - -#define BCM_SPI3_CS (BCM_SPI3_BASEADDR + BCM_SPI_CS_OFFSET) -#define BCM_SPI3_FIFO (BCM_SPI3_BASEADDR + BCM_SPI_FIFO_OFFSET) -#define BCM_SPI3_CLK (BCM_SPI3_BASEADDR + BCM_SPI_CLK_OFFSET) -#define BCM_SPI3_DLEN (BCM_SPI3_BASEADDR + BCM_SPI_DLEN_OFFSET) -#define BCM_SPI3_LTOH (BCM_SPI3_BASEADDR + BCM_SPI_LTOH_OFFSET) -#define BCM_SPI3_DC (BCM_SPI3_BASEADDR + BCM_SPI_DC_OFFSET) - -#define BCM_SPI4_CS (BCM_SPI4_BASEADDR + BCM_SPI_CS_OFFSET) -#define BCM_SPI4_FIFO (BCM_SPI4_BASEADDR + BCM_SPI_FIFO_OFFSET) -#define BCM_SPI4_CLK (BCM_SPI4_BASEADDR + BCM_SPI_CLK_OFFSET) -#define BCM_SPI4_DLEN (BCM_SPI4_BASEADDR + BCM_SPI_DLEN_OFFSET) -#define BCM_SPI4_LTOH (BCM_SPI4_BASEADDR + BCM_SPI_LTOH_OFFSET) -#define BCM_SPI4_DC (BCM_SPI4_BASEADDR + BCM_SPI_DC_OFFSET) - -#define BCM_SPI5_CS (BCM_SPI5_BASEADDR + BCM_SPI_CS_OFFSET) -#define BCM_SPI5_FIFO (BCM_SPI5_BASEADDR + BCM_SPI_FIFO_OFFSET) -#define BCM_SPI5_CLK (BCM_SPI5_BASEADDR + BCM_SPI_CLK_OFFSET) -#define BCM_SPI5_DLEN (BCM_SPI5_BASEADDR + BCM_SPI_DLEN_OFFSET) -#define BCM_SPI5_LTOH (BCM_SPI5_BASEADDR + BCM_SPI_LTOH_OFFSET) -#define BCM_SPI5_DC (BCM_SPI5_BASEADDR + BCM_SPI_DC_OFFSET) - -#define BCM_SPI6_CS (BCM_SPI6_BASEADDR + BCM_SPI_CS_OFFSET) -#define BCM_SPI6_FIFO (BCM_SPI6_BASEADDR + BCM_SPI_FIFO_OFFSET) -#define BCM_SPI6_CLK (BCM_SPI6_BASEADDR + BCM_SPI_CLK_OFFSET) -#define BCM_SPI6_DLEN (BCM_SPI6_BASEADDR + BCM_SPI_DLEN_OFFSET) -#define BCM_SPI6_LTOH (BCM_SPI6_BASEADDR + BCM_SPI_LTOH_OFFSET) -#define BCM_SPI6_DC (BCM_SPI6_BASEADDR + BCM_SPI_DC_OFFSET) +#define BCM_SPI_CS(base) ((base) + BCM_SPI_CS_OFFSET) +#define BCM_SPI_FIFO(base) ((base) + BCM_SPI_FIFO_OFFSET) +#define BCM_SPI_CLK(base) ((base) + BCM_SPI_CLK_OFFSET) +#define BCM_SPI_DLEN(base) ((base) + BCM_SPI_DLEN_OFFSET) +#define BCM_SPI_LTOH(base) ((base) + BCM_SPI_LTOH_OFFSET) +#define BCM_SPI_DC(base) ((base) + BCM_SPI_DC_OFFSET) /* SPI register bit definitions */ @@ -123,4 +95,8 @@ #define BCM_SPI_DC_TPANIC (0xff << 8) #define BCM_SPI_DC_TDREQ (0xff << 0) +/* Informational constants */ + +#define BCM_SPI_FIFO_DEPTH 16 + #endif /* __ARCH_ARM64_SRC_BCM2711_SPI_H */