diff --git a/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/index.rst b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/index.rst new file mode 100644 index 0000000000000..28eb3e74a9922 --- /dev/null +++ b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/index.rst @@ -0,0 +1,276 @@ +====================== +Pimoroni Pico Plus 2 W +====================== + +.. tags:: chip:rp2350, chip:rp2350b, wifi + +The `Pimoroni Pico Plus 2 W `_ +is a Raspberry Pi Pico form-factor board built around the RP2350B -- the 80-pin +variant of the RP2350 with 48 GPIOs. It adds 16MB of flash, 8MB of PSRAM, a +USB-C connector, a Qw/ST (Qwiic/STEMMA QT) connector, and an Infineon CYW43439 +for 2.4GHz WiFi and Bluetooth. The radio is carried on a Raspberry Pi RM2 +module, which is where the CYW43439 lives. + +.. figure:: pimoroni-pico-plus-2-w.jpg + :align: center + + Pimoroni Pico Plus 2 W, front and back (photo: Pimoroni) + +Features +======== + +* RP2350B microcontroller chip (QFN-80 package) +* Dual-core ARM Cortex-M33 processor at up to 150MHz, with FPU and DSP +* Also contains two Hazard3 RISC-V cores, selectable instead of the M33 pair +* 520kB of on-chip SRAM +* 16MB of on-board QSPI flash +* 8MB of on-board QSPI PSRAM (chip select on GPIO 47) +* 48 multi-function GPIO pins, 30 of them on the castellated headers +* 4x UART, 2x SPI, 2x I2C, 8x 12-bit ADC, 24x PWM channels +* 12x Programmable IO (PIO) state machines across 3 PIO blocks +* USB-C, supporting device and host +* Infineon CYW43439 for 2.4GHz WiFi 4 (802.11n) and Bluetooth 5.2 +* Qw/ST connector on I2C0 +* BOOT and RESET buttons; BOOT is also readable at runtime on GPIO 45 +* Battery connector with charging, and VSYS monitoring on GPIO 43 + +Serial Console +============== + +By default the serial console is UART0 on GPIO 0 (TX, pin 1) and GPIO 1 +(RX, pin 2), at 115200-8N1. + +The board can instead be configured to put the console on the USB-C connector +(the ``usbnsh`` configuration). Note that the RP2350 USB device support is +still marked experimental in NuttX and the CDC/ACM console is known to corrupt +data and stop responding after a handful of commands. Prefer the UART console +for anything that matters. + +Wireless Communication +====================== + +The on-board Infineon CYW43439 is reached over a half-duplex gSPI bus driven by +a PIO state machine, implemented in ``arch/arm/src/rp23xx/rp23xx_cyw43439.c``. +It presents itself as the ``wlan0`` network device and supports 2.4GHz WiFi 4 +(802.11n) in station mode. Bluetooth is not supported. + +The chip's firmware is not downloaded until ``wlan0`` is brought up, so nothing +on the wireless chip -- including the LED, see below -- responds before that. + +CYW43439 firmware +----------------- + +The driver links the wireless chip's firmware and CLM blob into the NuttX +binary, so a copy has to be available at build time. ``CONFIG_CYW43439_FIRMWARE_BIN_PATH`` +points at it and defaults to:: + + ${PICO_SDK_PATH}/lib/cyw43-driver/firmware/43439A0-7.95.49.00.combined + +This is the WiFi firmware padded up to a 256-byte boundary with the CLM blob +appended, and ``CONFIG_CYW43439_FIRMWARE_LEN`` is the *unpadded* length of just +the firmware part (224190 bytes for this release). + +pico-sdk 2.x no longer ships that file as a binary -- it only carries the same +bytes as a C array in ``lib/cyw43-driver/firmware/w43439A0_7_95_49_00_combined.h``. +If that is all you have, convert the array back to a binary, for example:: + + $ python3 -c ' + import re, sys + text = open(sys.argv[1]).read() + body = text.split("{", 1)[1].split("};", 1)[0] + data = bytes(int(b, 16) for b in re.findall(r"0x([0-9a-fA-F]{2})", body)) + open(sys.argv[2], "wb").write(data) + ' ${PICO_SDK_PATH}/lib/cyw43-driver/firmware/w43439A0_7_95_49_00_combined.h \ + ${PICO_SDK_PATH}/lib/cyw43-driver/firmware/43439A0-7.95.49.00.combined + +The header's own ``CYW43_WIFI_FW_LEN`` and ``CYW43_CLM_LEN`` macros tell you the +lengths to expect: 224190 + 984, in a 225240-byte file. + +If the file is missing the build still succeeds, but a placeholder is linked in +and the wireless chip will not come up. + +User LED +======== + +**The board's only LED is wired to GPIO 0 of the CYW43439, not to a pin of the +RP2350.** Setting it therefore means an iovar request over the gSPI bus, which +has two consequences: + +* The LED does not respond until ``wlan0`` has been brought up, because that is + when the wireless chip's firmware is downloaded. Before that, every write + fails with ``-EIO``. +* Driving the LED blocks, so it cannot be done from interrupt context. That + rules out ``CONFIG_ARCH_LEDS``, whose ``board_autoled_on()`` is called from + interrupt handlers and from assertion handling. This board therefore + supports ``CONFIG_USERLED`` only, and a build with ``CONFIG_ARCH_LEDS`` + enabled is rejected with an explicit error. + +With ``CONFIG_USERLED`` the LED appears as ``/dev/userleds`` and can be driven +with the ``leds`` example. Board code can also reach it, and the CYW43439's +other two GPIOs, through ``include/rp23xx_extra_gpio.h``: + +===== ========= ============================================================== +GPIO Direction Function +===== ========= ============================================================== +0 output On-board LED +1 output Voltage regulator mode: 1 selects PWM (less ripple) over PFM +2 input Non-zero if power is coming from USB or the VBUS pin +===== ========= ============================================================== + +Buttons +------- + +The board has two physical buttons, BOOT and RESET. + +BOOT is also wired to GPIO 45, active low, so once NuttX is running it can be +read as an ordinary user button -- this is the pin pico-sdk calls +``PIMORONI_PICO_PLUS2_W_USER_SW_PIN``. It appears as ``/dev/buttons`` with +``CONFIG_INPUT_BUTTONS``, and is the single button reported by +``board_buttons()``. RESET is not readable as a GPIO. + +The internal pull-up is enabled on GPIO 45, and must be: erratum RP2350-E9 +means a floating Bank 0 input on RP2350 A2 leaks around 120uA and settles at +roughly 2.2V, which the internal pull-down is far too weak to overcome. The +pull-up is unaffected by the erratum. + +Held down while power is applied or while RESET is released, BOOT instead makes +the RP2350 come up in bootloader mode, where it appears as a storage device over +USB; copying a .UF2 file to it replaces the flash contents. + +Pin Mapping +=========== + +The castellated headers follow the Raspberry Pi Pico pinout, with the RP2350B's +extra GPIOs brought out on the two rows of pads inside the headers. + +===== ========== ============================================================= +Pin Signal Notes +===== ========== ============================================================= +1 GPIO0 Default TX for UART0 serial console +2 GPIO1 Default RX for UART0 serial console +3 Ground +4 GPIO2 +5 GPIO3 +6 GPIO4 Default SDA for I2C0, also on the Qw/ST connector +7 GPIO5 Default SCL for I2C0, also on the Qw/ST connector +8 Ground +9 GPIO6 +10 GPIO7 +11 GPIO8 +12 GPIO9 +13 Ground +14 GPIO10 +15 GPIO11 +16 GPIO12 +17 GPIO13 +18 Ground +19 GPIO14 +20 GPIO15 +21 GPIO16 Default RX for SPI0 +22 GPIO17 Default CSn for SPI0 +23 Ground +24 GPIO18 Default SCK for SPI0 +25 GPIO19 Default TX for SPI0 +26 GPIO20 +27 GPIO21 +28 Ground +29 GPIO22 +30 Run +31 GPIO26 ADC0 +32 GPIO27 ADC1 +33 AGND Analog ground +34 GPIO28 ADC2 +35 ADC_VREF Analog reference voltage +36 3V3 Power output to peripherals +37 3V3_EN Pull to ground to turn off +38 Ground +39 VSYS +5V supply to the board +40 VBUS Connected to USB +5V +===== ========== ============================================================= + +Other RP2350B Pins +================== + +===== ================================================================ +GPIO Function +===== ================================================================ +23 Output - CYW43439 power enable (WL_REG_ON) +24 I/O - CYW43439 gSPI data line, doubles as its interrupt request +25 Output - CYW43439 chip select +29 Output - CYW43439 gSPI clock +43 Input - VSYS monitoring, via ADC +45 Input - BOOT button, active low, readable as a user button +47 Output - PSRAM chip select +===== ================================================================ + +Note that GPIO 23, 24, 25 and 29 are the same pins the Raspberry Pi Pico W uses +for its CYW43439, so the wireless wiring is identical despite the larger +package. Do not use them for anything else. + +Installation & Build +==================== + +For instructions on how to install the build dependencies and create a NuttX +image for this board, consult the main :doc:`RP23XX documentation <../../index>`. + +Configurations +============== + +All configurations listed below can be configured using the following command +in the ``nuttx`` directory (again, consult the main +:doc:`RP23XX documentation <../../index>`): + +.. code:: console + + $ ./tools/configure.sh pimoroni-pico-plus-2-w: + +nsh +--- + +Basic NuttShell configuration, console on UART0 at 115200 bps. The wireless +chip is not enabled, so this configuration has no network and no LED. + +usbnsh +------ + +Basic NuttShell configuration with the console on USB CDC/ACM at 115200 bps. +See the caveat under `Serial Console`_. + +wifi +---- + +NuttShell configuration with the console on UART0 at 115200 bps and the +CYW43439 enabled: ``wlan0`` in station mode, WAPI, DHCP client, DNS client and +``ping``. ``/dev/userleds`` and ``/dev/buttons`` are registered too. + +After loading this configuration, set the country code to match your region in +:menuselection:`Device Drivers --> Wireless Device Support --> IEEE 802.11 Device Support`, +and set your network's credentials in +:menuselection:`Application Configuration --> Network Utilities --> Network initialization --> WAPI Configuration`. + +Alternatively, leave the built-in credentials alone and associate at runtime: + +.. code:: console + + nsh> wapi mode wlan0 2 + nsh> wapi psk wlan0 "my-passphrase" 3 2 + nsh> wapi essid wlan0 my-ssid 1 + nsh> renew wlan0 + nsh> ifconfig + lo Link encap:Local Loopback at RUNNING mtu 1518 + inet addr:127.0.0.1 DRaddr:127.0.0.1 Mask:255.0.0.0 + + wlan0 Link encap:Ethernet HWaddr 28:cd:c1:ff:d3:be at RUNNING mtu 576 + inet addr:192.168.0.118 DRaddr:192.168.0.1 Mask:255.255.255.0 + + nsh> ping -c 3 8.8.8.8 + PING 8.8.8.8 56 bytes of data + 56 bytes from 8.8.8.8: icmp_seq=0 time=20.0 ms + 56 bytes from 8.8.8.8: icmp_seq=1 time=10.0 ms + 56 bytes from 8.8.8.8: icmp_seq=2 time=10.0 ms + 3 packets transmitted, 3 received, 0% packet loss, time 3030 ms + rtt min/avg/max/mdev = 10.000/13.333/20.000/4.714 ms + +The ``3`` and ``2`` arguments to ``wapi psk`` select WPA_ALG_CCMP and WPA_VER_2; +run ``wapi help`` for the other values. ``wapi scan wlan0`` lists the visible +access points. diff --git a/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/pimoroni-pico-plus-2-w.jpg b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/pimoroni-pico-plus-2-w.jpg new file mode 100644 index 0000000000000..8ed9964f5a7ea Binary files /dev/null and b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/pimoroni-pico-plus-2-w.jpg differ diff --git a/arch/arm/src/rp23xx/CMakeLists.txt b/arch/arm/src/rp23xx/CMakeLists.txt index 90387a8bb8b62..0fb295a496671 100644 --- a/arch/arm/src/rp23xx/CMakeLists.txt +++ b/arch/arm/src/rp23xx/CMakeLists.txt @@ -117,4 +117,8 @@ if(CONFIG_RP23XX_OTP) list(APPEND SRCS rp23xx_otp.c) endif() +if(CONFIG_IEEE80211_INFINEON_CYW43439) + list(APPEND SRCS rp23xx_cyw43439.c) +endif() + target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/arm/src/rp23xx/Make.defs b/arch/arm/src/rp23xx/Make.defs index 47e790bd17b73..3fbd4b32e46a8 100644 --- a/arch/arm/src/rp23xx/Make.defs +++ b/arch/arm/src/rp23xx/Make.defs @@ -121,3 +121,7 @@ endif ifeq ($(CONFIG_RP23XX_OTP),y) CHIP_CSRCS += rp23xx_otp.c endif + +ifeq ($(CONFIG_IEEE80211_INFINEON_CYW43439),y) +CHIP_CSRCS += rp23xx_cyw43439.c +endif diff --git a/arch/arm/src/rp23xx/rp23xx_cyw43439.c b/arch/arm/src/rp23xx/rp23xx_cyw43439.c new file mode 100644 index 0000000000000..0f74fb2617e55 --- /dev/null +++ b/arch/arm/src/rp23xx/rp23xx_cyw43439.c @@ -0,0 +1,890 @@ +/**************************************************************************** + * arch/arm/src/rp23xx/rp23xx_cyw43439.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "rp23xx_cyw43439.h" +#include "rp23xx_pio.h" +#include "rp23xx_pio_instructions.h" + +#ifdef CONFIG_NDEBUG +# define PRINT_GSPI(block) +#else +void bcmf_hexdump(uint8_t *data, unsigned int len, unsigned long offset); +bool g_print_gspi = false; +# define PRINT_GSPI(block) if (g_print_gspi) { block } +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define GSPI_CLOCK_FREQ 31250000 /* Hz (Max: 50MHz) */ + +#define PIO_WRAP_TARGET 0 +#define PIO_WRAP 5 + +#define TX_FIFO_SIZE 4 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef struct dma_info_s +{ + sem_t sem; + uint8_t status; +} dma_info_t; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the PIO program to write and then read from the data pin. + * + * The X register is the output bit count register. It should be set + * to one less than the total number of BITS to be transmitted. + * + * The Y register is the input bit count register. It too must be set + * to one less than the total number of bits to be read. + * + * The PIO's state machine is set up to auto-pull data from the input + * fifo whenever the output shift register is empty. This happens at + * the start and every 32 bits thereafter. + * + * The state machine also auto-pushes whenever we have a full 32 bits + * in the input shift register. To make sure we receive all the data, + * we need to make sure that the read bit count is a multiple of 32. + * (Y = 32*N - 1 for some integer N) + */ + +static const uint16_t cyw_program_instructions[] = +{ + 0x6001, /* 0: out pins, 1 side 0 # Write one bit */ + 0x1040, /* 1: jmp x--, 0 side 1 # Loop until write count is zero */ + 0xe080, /* 2: set pindirs, 0 side 0 # Make data pin an input */ + 0xb042, /* 3: nop side 1 # Keep clock in sync */ + 0x4001, /* 4: in pins, 1 side 0 # Read 1 bit */ + 0x1084, /* 5: jmp y--, 4 side 1 # Loop until read count is zero */ +}; + +static const rp23xx_pio_program_t pio_program = +{ + .instructions = cyw_program_instructions, + .length = 6, /* Six, count 'em, six. */ + .origin = -1, /* Put it wherever it fits */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dma_complete + * + * Description: + * Called on completion of the DMA transfer. + * + * Input Parameters: + * handle - handle to our DMA channel + * status - status of the transfer + * arg - Pointer to dma info structure. + * + ****************************************************************************/ + +static void dma_complete(DMA_HANDLE handle, uint8_t status, void *arg) +{ + dma_info_t *dma_info = arg; + + /* Remember the status and post the dma complete event. */ + + dma_info->status = status; + nxsem_post(&(dma_info->sem)); +} + +/**************************************************************************** + * Name: my_init + * + * Description: + * Connect to and initialize the cyw43439. + * + ****************************************************************************/ + +static int my_init(gspi_dev_t *gspi) +{ + rp23xx_gspi_t *rp_io = (rp23xx_gspi_t *)(gspi->io_dev); + + uint32_t divisor; + irqstate_t flags; + int pio_sm; + rp23xx_pio_sm_config config = + { + 0 + }; + + /* Make sure the cyw43439 chip is deselected, and off. + * so we know it is reset + */ + + rp23xx_gpio_put(rp_io->gpio_select, true); /* deselect */ + rp23xx_gpio_put(rp_io->gpio_on, false); /* power off */ + + /* Pull the data line low so that we initialise to gSPI mode */ + + rp23xx_gpio_init(rp_io->gpio_data); + rp23xx_gpio_setdir(rp_io->gpio_data, true); + rp23xx_gpio_put(rp_io->gpio_data, false); + + nxsched_usleep(50000); /* Leave off for at least 50ms. */ + + rp23xx_gpio_put(rp_io->gpio_on, true); /* power on */ + + nxsched_usleep(50000); /* Wait a bit to let the power come up. */ + + /* Don't let anyone else grab a PIO while we are doing so. */ + + flags = enter_critical_section(); + + /* Find a PIO instance and load program. */ + + for (rp_io->pio = 0; rp_io->pio < RP23XX_PIO_NUM; ++rp_io->pio) + { + /* Try to claim a state machine. */ + + pio_sm = rp23xx_pio_claim_unused_sm(rp_io->pio, false); + + /* If we did not get one try the next pio block, if any. */ + + if (pio_sm < 0) continue; + + rp_io->pio_sm = pio_sm; + + /* See if we have space in this block to load our program. */ + + if (rp23xx_pio_can_add_program(rp_io->pio, &pio_program)) + { + /* Great! load the program and exit the pio choice loop. */ + + rp_io->pio_location = rp23xx_pio_add_program(rp_io->pio, + &pio_program); + + break; + } + + /* Oops -- no room at the inn! Release sm and try next pio. */ + + rp23xx_pio_sm_unclaim(rp_io->pio, rp_io->pio_sm); + } + + if (rp_io->pio >= RP23XX_PIO_NUM) + { + leave_critical_section(flags); + return -ENOMEM; + } + + leave_critical_section(flags); + + /* ==== Configure the PIO State Machine ==== */ + + /* Configure pins that are used by PIO. */ + + rp23xx_pio_gpio_init(rp_io->pio, rp_io->gpio_data); + rp23xx_pio_gpio_init(rp_io->pio, rp_io->gpio_clock); + + rp23xx_gpio_set_input_hysteresis_enabled(rp_io->gpio_data, true); + + /* Hold the data and clock lines low while nothing is driving them. + * + * The data line doubles as the chip's active-high interrupt request, and + * we service it with a level-high interrupt, so it must read low whenever + * the cyw43439 has released it. The RP2350 pads come out of reset with + * the pull-down enabled, but say so explicitly rather than rely on that. + */ + + rp23xx_gpio_set_pulls(rp_io->gpio_data, false, true); + rp23xx_gpio_set_pulls(rp_io->gpio_clock, false, true); + + rp23xx_gpio_set_slew_fast(rp_io->gpio_clock, true); + rp23xx_gpio_set_drive_strength(rp_io->gpio_clock, + RP23XX_PADS_BANK0_GPIO_DRIVE_12MA); + + /* Set the clock divisor as appropriate for our system clock + * speed, so the pio clock runs the requested bit clock rate. + */ + + divisor = ((uint64_t)BOARD_SYS_FREQ << 8) / (2 * GSPI_CLOCK_FREQ); + + rp23xx_sm_config_set_clkdiv_int_frac(&config, + divisor >> 8, + divisor & 0xff); + + /* Set the wrap points as required by the program. */ + + rp23xx_sm_config_set_wrap(&config, + rp_io->pio_location + PIO_WRAP_TARGET, + rp_io->pio_location + PIO_WRAP); + + /* set to shift left, 32 bits, with autopull/push */ + + rp23xx_sm_config_set_in_shift(&config, false, true, 32); + rp23xx_sm_config_set_out_shift(&config, false, true, 32); + + /* Configure a single mandatory side-set pin. */ + + rp23xx_sm_config_set_sideset(&config, 1, false, false); + + /* Configure our GPIO clock pin as side-set output. */ + + rp23xx_sm_config_set_sideset_pins(&config, rp_io->gpio_clock); + + /* Configure out GPIO data pin as an OUT pin, SET pin, and IN pin */ + + rp23xx_sm_config_set_out_pins(&config, rp_io->gpio_data, 1); + rp23xx_sm_config_set_set_pins(&config, rp_io->gpio_data, 1); + rp23xx_sm_config_set_in_pins (&config, rp_io->gpio_data); + + /* Load the configuration into the state machine. */ + + rp23xx_pio_sm_init(rp_io->pio, + rp_io->pio_sm, + rp_io->pio_location, + &config); + + /* Disable the input synchronizers on the data pin */ + + rp23xx_pio_set_input_sync_bypass(rp_io->pio, rp_io->gpio_data, true); + + wlinfo("finished\n"); + + return OK; +} + +/**************************************************************************** + * Name: my_set_isr + * + * Description: + * Setup the data line interrupt service routine. + * + ****************************************************************************/ + +static int my_set_isr(gspi_dev_t *gspi, + xcpt_t thread_isr, + void *thread_isr_arg) +{ + rp23xx_gspi_t *rp_io = (rp23xx_gspi_t *)(gspi->io_dev); + + /* Set up, but do not enable, interrupt service for the data pin */ + + rp23xx_gpio_irq_attach(rp_io->gpio_intr, + RP23XX_GPIO_INTR_LEVEL_HIGH, + thread_isr, + thread_isr_arg); + + wlinfo("attached\n"); + + return OK; +} + +/**************************************************************************** + * Name: my_interrupt_enable + * + * Description: + * Setup the data line isr. + * + ****************************************************************************/ + +static int my_interrupt_enable(gspi_dev_t *gspi, + bool enable) +{ + rp23xx_gspi_t *rp_io = (rp23xx_gspi_t *)(gspi->io_dev); + static int disable_count = 0; + + if (enable) + { + if (--disable_count <= 0) rp23xx_gpio_enable_irq(rp_io->gpio_intr); + } + else + { + rp23xx_gpio_disable_irq(rp_io->gpio_intr); + ++disable_count; + } + + return OK; +} + +/**************************************************************************** + * Name: my_deinit + * + * Description: + * Disconnect from cyw43439 and cleanup. + * + ****************************************************************************/ + +static int my_deinit(gspi_dev_t *gspi) +{ + rp23xx_gspi_t *rp_io = (rp23xx_gspi_t *)(gspi->io_dev); + + rp23xx_gpio_irq_attach(rp_io->gpio_data, + RP23XX_GPIO_INTR_EDGE_LOW, + NULL, + NULL); + + rp23xx_pio_sm_set_enabled(rp_io->pio, rp_io->pio_sm, false); + rp23xx_pio_remove_program(rp_io->pio, &pio_program, rp_io->pio_location); + rp23xx_pio_sm_unclaim(rp_io->pio, rp_io->pio_sm); + + /* Turn the power off to the cyw43439. */ + + rp23xx_gpio_put(rp_io->gpio_on, false); + + return OK; +} + +/**************************************************************************** + * Name: my_write + * + * Description: + * write data to the cyw43439 + * + ****************************************************************************/ + +static int my_write(struct gspi_dev_s *gspi, + bool increment, + enum gspi_cmd_func_e function, + uint32_t address, + uint16_t length, + const uint32_t *data) +{ + rp23xx_gspi_t *rp_io = (rp23xx_gspi_t *)(gspi->io_dev); + dma_info_t dma_info; + DMA_HANDLE xfer_dma = rp23xx_dmachannel(); + uint32_t command = (0x1 << 31) + | ((increment ? 1 : 0) << 30) + | ((function & 0x3) << 28) + | ((address & 0x1ffff) << 11) + | (length & 0x7ff); + + dma_config_t dma_config = + { + .size = RP23XX_DMA_SIZE_WORD, + .noincr = false, + .dreq = rp23xx_pio_get_dreq(rp_io->pio, + rp_io->pio_sm, + true), + }; + + PRINT_GSPI( + printf("------ cmd: 0x%08lx [W %d %d 0x%05lX %d]\n", command, + increment, + function, + address, + length); + bcmf_hexdump((void *)data, length, (uint32_t)data); + ) + + /* Claim the exclusive lock */ + + nxmutex_lock(&gspi->lock); + + /* Reset the PIO state machine just to be sure. */ + + rp23xx_pio_sm_set_enabled(rp_io->pio, rp_io->pio_sm, false); + + rp23xx_pio_sm_clear_fifos(rp_io->pio, rp_io->pio_sm); + + rp23xx_pio_sm_restart(rp_io->pio, rp_io->pio_sm); + + rp23xx_pio_sm_clkdiv_restart(rp_io->pio, rp_io->pio_sm); + + rp23xx_pio_sm_exec(rp_io->pio, + rp_io->pio_sm, + pio_encode_jmp(rp_io->pio_location)); + + /* Set the PIO X and Y registers. + * + * We load X (the TX bit length) with one less than the number of + * bits to transmit to the chip. This length includes the 32-bit + * command word and all the 32-bit data words. Since the length + * parameter is a byte count we round up just to be sure. + * + * We load Y (the RX bit length) with zero as we're not reading + * any data. + * + * This is slightly magical. The way we load the X is to first + * push the number of bits to transmit onto the transmit fifo. + * Then we force the PIO state machine to execute the instruction + * "out x, 32" which transfers the word from the output shift + * register (OSR) to the X register. When this instruction executes + * the PIO will notice that the OSR is empty, so will automatically + * pull a value (the one we just added) from the input fifo. + * + * Loading the Y works the same way. + */ + + rp23xx_pio_sm_put(rp_io->pio, rp_io->pio_sm, 32 * ((length + 3) / 4) + 31); + rp23xx_pio_sm_exec(rp_io->pio, rp_io->pio_sm, pio_encode_out(pio_x, 32)); + + rp23xx_pio_sm_put(rp_io->pio, rp_io->pio_sm, 0); + rp23xx_pio_sm_exec(rp_io->pio, rp_io->pio_sm, pio_encode_out(pio_y, 32)); + + /* Disable interrupts so data won't trigger interrupt. */ + + my_interrupt_enable(gspi, false); + + /* Make sure the clock and data pins direction set to output. */ + + rp23xx_pio_sm_set_pindirs_with_mask(rp_io->pio, + rp_io->pio_sm, + (1 << rp_io->gpio_data) + | (1 << rp_io->gpio_clock), + (1 << rp_io->gpio_data) + | (1 << rp_io->gpio_clock)); + + /* Make sure there is nothing in the fifos before starting DMA. */ + + rp23xx_pio_sm_clear_fifos(rp_io->pio, rp_io->pio_sm); + + /* Load the command into the transmit fifo. */ + + if (function == gspi_f0_bus_rev16) + { + __asm ("rev16 %0, %0" : "+l" (command) : :); + } + + __asm ("rev %0, %0" : "+l" (command) : :); + + putreg32(command, RP23XX_PIO_TXF(rp_io->pio, rp_io->pio_sm)); + + /* Initialize and start the transmit DMA. It will + * keep adding data to the TX_FIFO until all data is sent. + */ + + nxsem_init(&dma_info.sem, 0, 0); + + rp23xx_dmastop(xfer_dma); + + rp23xx_txdmasetup(xfer_dma, + (uintptr_t) RP23XX_PIO_TXF(rp_io->pio, + rp_io->pio_sm), + (uintptr_t) data, + (length + 3) & 0xfffffffc, + dma_config); + + modifyreg32(rp23xx_dma_register(xfer_dma, + RP23XX_DMA_CTRL_TRIG_OFFSET), + RP23XX_DMA_CTRL_TRIG_BSWAP, + RP23XX_DMA_CTRL_TRIG_BSWAP); + + rp23xx_dmastart(xfer_dma, dma_complete, &dma_info); + + /* Assert gpio_select by pulling line low */ + + rp23xx_gpio_put(rp_io->gpio_select, false); + UP_DMB(); + + /* Enable the state machine. This starts the pio program running */ + + rp23xx_pio_sm_set_enabled(rp_io->pio, rp_io->pio_sm, true); + + /* Wait for transfer to complete */ + + nxsem_wait(&dma_info.sem); + + /* At this point all the data has been queued but my not have all been + * sent. We know that the PIO program will make the data line an input + * once all the data is sent so we'll check for this. + * + * The RP2350 GPIO_STATUS register dropped the RP2040's OEFROMPERI field, + * so watch OETOPAD instead. No override is configured on this pad, so + * the two carry the same value. + */ + + while (getreg32(RP23XX_IO_BANK0_GPIO_STATUS(rp_io->gpio_data)) + & RP23XX_IO_BANK0_GPIO_STATUS_OETOPAD) + { + /* Just busy wait -- testing indicates a worst case of + * 20 loops (100 instructions). + */ + } + + /* Un-assert select by pulling line high. */ + + UP_DMB(); + rp23xx_gpio_put(rp_io->gpio_select, true); + + /* Free the DMA controller */ + + rp23xx_dmafree(xfer_dma); + nxsem_destroy(&dma_info.sem); + + /* Disable the PIO */ + + rp23xx_pio_sm_set_enabled(rp_io->pio, rp_io->pio_sm, false); + + /* At this point the data pin is input so it should have been + * pulled high by rp23xx's gpio pullup. + */ + + my_interrupt_enable(gspi, true); + + /* Release the exclusive lock */ + + nxmutex_unlock(&gspi->lock); + return dma_info.status; +} + +/**************************************************************************** + * Name: my_read + * + * Description: + * read data to the cyw43439 + * + ****************************************************************************/ + +static int my_read(struct gspi_dev_s *gspi, + bool increment, + enum gspi_cmd_func_e function, + uint32_t address, + uint16_t length, + uint32_t *buffer) +{ + rp23xx_gspi_t *rp_io = (rp23xx_gspi_t *)(gspi->io_dev); + dma_info_t dma_info; + DMA_HANDLE xfer_dma = rp23xx_dmachannel(); + DMA_HANDLE ctrl_dma = rp23xx_dmachannel(); + uint32_t temp_word; + uint32_t bit_length; + uint32_t command = ((increment ? 1 : 0) << 30) + | ((function & 0x3) << 28) + | ((address & 0x1ffff) << 11) + | (length & 0x7ff); + + uint32_t pacing = rp23xx_pio_get_dreq(rp_io->pio, + rp_io->pio_sm, + false); + + dma_control_block_t ctrl_blks[] = + { + /* For F1 transfers we read 1 word that we throw away */ + + { + rp23xx_dma_ctrl_blk_ctrl(ctrl_dma, + RP23XX_DMA_SIZE_WORD, + pacing, + 0), + (uintptr_t) RP23XX_PIO_RXF(rp_io->pio, rp_io->pio_sm), + (uintptr_t) &temp_word, + 1, + }, + + /* Read requested data into output buffer */ + + { + rp23xx_dma_ctrl_blk_ctrl(ctrl_dma, + RP23XX_DMA_SIZE_WORD, + pacing, + RP23XX_DMA_CTRL_TRIG_INCR_WRITE + | RP23XX_DMA_CTRL_TRIG_BSWAP), + (uintptr_t) RP23XX_PIO_RXF(rp_io->pio, rp_io->pio_sm), + (uintptr_t) buffer, + (length + 3) / 4, + }, + + RP23XX_DMA_CTRL_BLOCK_END + }; + + PRINT_GSPI( + printf("------ cmd: 0x%08lx [R %d %d 0x%05lX %d]\n", command, + increment, + function, + address, + length); + ) + + /* Claim the exclusive lock */ + + nxmutex_lock(&gspi->lock); + + /* Reset the PIO state machine just to be sure. */ + + rp23xx_pio_sm_set_enabled(rp_io->pio, rp_io->pio_sm, false); + + rp23xx_pio_sm_clear_fifos(rp_io->pio, rp_io->pio_sm); + + rp23xx_pio_sm_restart(rp_io->pio, rp_io->pio_sm); + + rp23xx_pio_sm_clkdiv_restart(rp_io->pio, rp_io->pio_sm); + + rp23xx_pio_sm_exec(rp_io->pio, + rp_io->pio_sm, + pio_encode_jmp(rp_io->pio_location)); + + /* Set the PIO X and Y registers. + * + * We load X (the TX bit length) with one less than the number of + * bits to transmit to the chip. Since we only send the 32-bit command + * word we set X to 31. + * + * We load Y with the number of bits to read. This is based on the + * byte count in "length" which we round up to a 32-bit boundary so the + * pio program will be sure to autopush the final data to the output fifo. + * + * This is slightly magical. The way we load the X is to first + * push the number of bits to transmit onto the transmit fifo. + * Then we force the PIO state machine to execute the instruction + * "out x, 32" which transfers the word from the output shift + * register (OSR) to the X register. When this instruction executes + * the PIO will notice that the OSR is empty, so will automatically + * pull a value (the one we just added) from the input fifo. + * + * Loading the Y works the same way. + */ + + rp23xx_pio_sm_put(rp_io->pio, rp_io->pio_sm, 31); + rp23xx_pio_sm_exec(rp_io->pio, rp_io->pio_sm, pio_encode_out(pio_x, 32)); + + /* RX bit length is 32 bits for each 4 bytes requested. */ + + bit_length = 32 * ((length + 3) / 4); + + /* For F1 reads add 32 bits for delay */ + + if (function == gspi_f1_backplane) + { + bit_length += 32; + } + + rp23xx_pio_sm_put(rp_io->pio, rp_io->pio_sm, bit_length); + rp23xx_pio_sm_exec(rp_io->pio, rp_io->pio_sm, pio_encode_out(pio_y, 32)); + + /* Disable interrupts so data won't trigger interrupt. */ + + my_interrupt_enable(gspi, false); + + /* Make sure the clock and data pins direction set to output. */ + + rp23xx_pio_sm_set_pindirs_with_mask(rp_io->pio, + rp_io->pio_sm, + (1 << rp_io->gpio_data) + | (1 << rp_io->gpio_clock), + (1 << rp_io->gpio_data) + | (1 << rp_io->gpio_clock)); + + /* Make sure there is nothing in the fifos before starting DMA. */ + + rp23xx_pio_sm_clear_fifos(rp_io->pio, rp_io->pio_sm); + + /* Load the command into the transmit fifo. */ + + if (function == gspi_f0_bus_rev16) + { + __asm ("rev16 %0, %0" : "+l" (command) : :); + } + + __asm ("rev %0, %0" : "+l" (command) : :); + + putreg32(command, RP23XX_PIO_TXF(rp_io->pio, rp_io->pio_sm)); + + /* Initialize and start the control DMA. It will + * use the xfer_dma to transfer data from the chip. + */ + + nxsem_init(&dma_info.sem, 0, 0); + + rp23xx_dmastop(ctrl_dma); + rp23xx_dmastop(xfer_dma); + + /* Check the function bits if the command word to see if + * this is an F1 read. If it is we throw away the first + * four bytes read as this is a delay word. + */ + + rp23xx_ctrl_dmasetup(ctrl_dma, + xfer_dma, + &ctrl_blks[function == 1 ? 0 : 1], + dma_complete, + &dma_info); + + rp23xx_dmastart(ctrl_dma, NULL, NULL); + + /* Assert gpio_select by pulling line low */ + + rp23xx_gpio_put(rp_io->gpio_select, false); + UP_DMB(); + + /* Enable the state machine. This starts the pio program running */ + + rp23xx_pio_sm_set_enabled(rp_io->pio, rp_io->pio_sm, true); + + /* Wait for transfer to complete */ + + nxsem_wait(&dma_info.sem); + + PRINT_GSPI( + bcmf_hexdump((void *)buffer, length, (uint32_t)buffer); + ) + + /* Un-assert select by pulling line high. */ + + UP_DMB(); + rp23xx_gpio_put(rp_io->gpio_select, true); + + /* Free the DMA controllers */ + + rp23xx_dmafree(ctrl_dma); + rp23xx_dmafree(xfer_dma); + + nxsem_destroy(&dma_info.sem); + + /* Disable the PIO */ + + rp23xx_pio_sm_set_enabled(rp_io->pio, rp_io->pio_sm, false); + + /* At this point the data pin is input so it should have been + * pulled high by rp23xx's gpio pullup. + */ + + my_interrupt_enable(gspi, true); + + /* Release the exclusive lock */ + + nxmutex_unlock(&gspi->lock); + return dma_info.status; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rp23xx_cyw_setup + * + * Description: + * Initialize the cyw43439 private data and PIO communication. + * + ****************************************************************************/ + +gspi_dev_t *rp23xx_cyw_setup(uint8_t gpio_on, + uint8_t gpio_select, + uint8_t gpio_data, + uint8_t gpio_clock, + uint8_t gpio_intr) +{ + gspi_dev_t *gspi; + rp23xx_gspi_t *rp_io; + int err; + + wlinfo("entered.\n"); + + gspi = kmm_zalloc(sizeof(gspi_dev_t)); + + if (gspi == NULL) + { + set_errno(ENOMEM); + return NULL; + } + + rp_io = kmm_zalloc(sizeof(rp23xx_gspi_t)); + + if (rp_io == NULL) + { + kmm_free(gspi); + set_errno(ENOMEM); + return NULL; + } + + gspi->init = my_init; + gspi->deinit = my_deinit; + gspi->set_isr = my_set_isr; + gspi->interrupt_enable = my_interrupt_enable; + gspi->write = my_write; + gspi->read = my_read; + gspi->io_dev = rp_io; + + rp_io->gpio_on = gpio_on; + rp_io->gpio_select = gpio_select; + rp_io->gpio_data = gpio_data; + rp_io->gpio_clock = gpio_clock; + rp_io->gpio_intr = gpio_intr; + + nxmutex_init(&gspi->lock); + + /* Initialize the cyw43439 power-on and chip select lines. */ + + rp23xx_gpio_init(gpio_on); + rp23xx_gpio_setdir(gpio_on, true); + rp23xx_gpio_put(gpio_on, false); /* set low to turn wifi chip off */ + + rp23xx_gpio_init(gpio_select); + rp23xx_gpio_setdir(gpio_select, true); + rp23xx_gpio_put(gpio_select, true); /* set high to deselect chip */ + + err = bcmf_gspi_initialize(gspi); + + if (err != OK) + { + kmm_free(gspi); + kmm_free(rp_io); + + set_errno(err); + return NULL; + } + + wlinfo("setup complete. gspi = 0x%p\n", gspi); + + return gspi; +} + +/**************************************************************************** + * Name: rp23xx_cyw_remove + * + * Description: + * Deinitialize the cyw43439 PIO communication. + * + ****************************************************************************/ + +void rp23xx_cyw_remove(gspi_dev_t *gspi) +{ + /* gspi_deregister((gspi_dev_t *)gspi); */ +} + +/**************************************************************************** + * Name: bcmf_board_etheraddr + ****************************************************************************/ + +bool bcmf_board_etheraddr(struct ether_addr *ethaddr) +{ + return false; +} diff --git a/arch/arm/src/rp23xx/rp23xx_cyw43439.h b/arch/arm/src/rp23xx/rp23xx_cyw43439.h new file mode 100644 index 0000000000000..66157ad71ef9c --- /dev/null +++ b/arch/arm/src/rp23xx/rp23xx_cyw43439.h @@ -0,0 +1,110 @@ +/**************************************************************************** + * arch/arm/src/rp23xx/rp23xx_cyw43439.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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_ARM_SRC_RP23XX_RP23XX_CYW43439_H +#define __ARCH_ARM_SRC_RP23XX_RP23XX_CYW43439_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef struct rp23xx_gspi_s +{ + uint32_t pio; /* The pio instance we are using. */ + uint32_t pio_sm; /* The state machine we are using. */ + uint32_t pio_location; /* the program location in the pio. */ + uint8_t gpio_on; /* Set high to power chip on */ + uint8_t gpio_select; /* Pull low to select chip */ + uint8_t gpio_data; /* Data line -- idle low */ + uint8_t gpio_clock; /* Clock line -- idle low */ + uint8_t gpio_intr; /* May be shared with data */ +} rp23xx_gspi_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: rp23xx_cyw_setup + * + * Description: + * Initialize the cyw43439 device. + * + * Returns: + * A pointer to the cyw43439 device + * + ****************************************************************************/ + +gspi_dev_t *rp23xx_cyw_setup(uint8_t gpio_on, + uint8_t gpio_select, + uint8_t gpio_data, + uint8_t gpio_clock, + uint8_t gpio_intr); + +/**************************************************************************** + * Name: rp23xx_cyw_remove + * + * Description: + * Deinitialize the cyw43439 device. + * + * Parameters: + * A pointer (as returned by rp23xx_cyw_setup) to the device to remove. + * + ****************************************************************************/ + +void rp23xx_cyw_remove(gspi_dev_t *dev); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_RP23XX_RP23XX_CYW43439_H */ diff --git a/boards/Kconfig b/boards/Kconfig index 44e9a245bd3e0..5e58d7b6097df 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -2266,6 +2266,23 @@ config ARCH_BOARD_PIMORONI_PICO_2_PLUS ---help--- This is a port to the Pimoroni Pico 2 Plus board. +config ARCH_BOARD_PIMORONI_PICO_PLUS_2_W + bool "Pimoroni Pico Plus 2 W" + depends on ARCH_CHIP_RP23XX + select ARCH_HAVE_LEDS + select ARCH_HAVE_BUTTONS + select ARCH_HAVE_IRQBUTTONS + select RP23XX_RP2350B + ---help--- + This is a port to the Pimoroni Pico Plus 2 W board, which adds an + Infineon CYW43439 WiFi/Bluetooth chip to the Pico Plus 2. + + The board's only LED is wired to a GPIO of the CYW43439 rather than + to a pin of the RP2350, so driving it means a transaction on the gSPI + bus. That works for the CONFIG_USERLED interface but not for + CONFIG_ARCH_LEDS, which is called from interrupt context, so + CONFIG_ARCH_LEDS is rejected at build time on this board. + config ARCH_BOARD_WAVESHARE_RP2040_LCD_1_28 bool "Waveshare RP2040 LCD 1.28 board" depends on ARCH_CHIP_RP2040 @@ -3936,6 +3953,7 @@ config ARCH_BOARD default "raspberrypi-pico-2-rv" if ARCH_BOARD_RASPBERRYPI_PICO_2_RV default "xiao-rp2350" if ARCH_BOARD_XIAO_RP2350 default "pimoroni-pico-2-plus" if ARCH_BOARD_PIMORONI_PICO_2_PLUS + default "pimoroni-pico-plus-2-w" if ARCH_BOARD_PIMORONI_PICO_PLUS_2_W default "w5500-evb-pico" if ARCH_BOARD_W5500_EVB_PICO default "waveshare-rp2040-zero" if ARCH_BOARD_WAVESHARE_RP2040_ZERO default "rx65n" if ARCH_BOARD_RX65N @@ -4473,6 +4491,9 @@ endif if ARCH_BOARD_PIMORONI_PICO_2_PLUS source "boards/arm/rp23xx/pimoroni-pico-2-plus/Kconfig" endif +if ARCH_BOARD_PIMORONI_PICO_PLUS_2_W +source "boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig" +endif if ARCH_BOARD_ARDUINO_DUE source "boards/arm/sam34/arduino-due/Kconfig" endif diff --git a/boards/arm/rp23xx/common/src/CMakeLists.txt b/boards/arm/rp23xx/common/src/CMakeLists.txt index b56fd15859201..02fc89626e419 100644 --- a/boards/arm/rp23xx/common/src/CMakeLists.txt +++ b/boards/arm/rp23xx/common/src/CMakeLists.txt @@ -110,6 +110,38 @@ if(CONFIG_ARCH_BOARD_COMMON) list(APPEND SRCS rp23xx_max6675.c) endif() + # Firmware blob for the Infineon CYW43439 WiFi chip. rp23xx_firmware.c + # .incbin's it, so it has to be staged somewhere on the include path. + if(CONFIG_IEEE80211_INFINEON_CYW43439) + list(APPEND SRCS rp23xx_firmware.c) + + string(REPLACE "\"" "" CYW43439_FIRMWARE_SRC + "${CONFIG_CYW43439_FIRMWARE_BIN_PATH}") + string(CONFIGURE "${CYW43439_FIRMWARE_SRC}" CYW43439_FIRMWARE_SRC) + + set(CYW43439_FIRMWARE "${CMAKE_CURRENT_BINARY_DIR}/cyw43439.firmware.image") + + if(EXISTS "${CYW43439_FIRMWARE_SRC}") + configure_file("${CYW43439_FIRMWARE_SRC}" "${CYW43439_FIRMWARE}" COPYONLY) + else() + # NuttX built with this dummy will not talk to the wireless chip. It only + # exists so that a tree without a pico-sdk checkout still compiles. + message( + WARNING "cyw43439 firmware not found at ${CYW43439_FIRMWARE_SRC}; " + "the wireless chip will not work. See the board Kconfig help.") + file(WRITE "${CYW43439_FIRMWARE}" "dummy\n") + endif() + + set_property( + SOURCE rp23xx_firmware.c + APPEND + PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}") + set_property( + SOURCE rp23xx_firmware.c + APPEND + PROPERTY OBJECT_DEPENDS "${CYW43439_FIRMWARE}") + endif() + endif() target_sources(board PRIVATE ${SRCS}) target_compile_options(board PRIVATE ${RP23XXFLAGS}) diff --git a/boards/arm/rp23xx/common/src/Make.defs b/boards/arm/rp23xx/common/src/Make.defs index 52b1244b533de..d400a49268cd4 100644 --- a/boards/arm/rp23xx/common/src/Make.defs +++ b/boards/arm/rp23xx/common/src/Make.defs @@ -110,6 +110,13 @@ ifeq ($(CONFIG_SENSORS_MAX6675),y) CSRCS += rp23xx_max6675.c endif +# Firmware blob for the Infineon CYW43439 WiFi chip. The board that carries +# the chip stages the blob itself, see its src/Make.defs. + +ifeq ($(CONFIG_IEEE80211_INFINEON_CYW43439),y) + CSRCS += rp23xx_firmware.c +endif + DEPPATH += --dep-path src VPATH += :src CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src diff --git a/boards/arm/rp23xx/common/src/rp23xx_firmware.c b/boards/arm/rp23xx/common/src/rp23xx_firmware.c new file mode 100644 index 0000000000000..5a8b242d0a012 --- /dev/null +++ b/boards/arm/rp23xx/common/src/rp23xx_firmware.c @@ -0,0 +1,164 @@ +/**************************************************************************** + * boards/arm/rp23xx/common/src/rp23xx_firmware.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define _STR(x) #x +#define STR(x) _STR(x) + +#define ROUNDED_FIRMWARE_LEN ((CONFIG_CYW43439_FIRMWARE_LEN + 0xff) & ~0xff) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_IEEE80211_INFINEON_CYW43439 + +/**************************************************************************** + * Character array of NVRAM image + * Generated from cyw943439wlpth_rev1_0.txt + * $ Copyright Broadcom Corporation $ + ****************************************************************************/ + +const uint8_t g_cyw43439_nvram_image[] __attribute__((aligned(4))) = + "NVRAMRev=$Rev$" "\x00" + "manfid=0x2d0" "\x00" + "prodid=0x0727" "\x00" + "vendid=0x14e4" "\x00" + "devid=0x43e2" "\x00" + "boardtype=0x0887" "\x00" + "boardrev=0x1100" "\x00" + "boardnum=22" "\x00" + "macaddr=00:A0:50:b5:59:5e" "\x00" + "sromrev=11" "\x00" + "boardflags=0x00404001" "\x00" + "boardflags3=0x04000000" "\x00" + "xtalfreq=37400" "\x00" + "nocrc=1" "\x00" + "ag0=255" "\x00" + "aa2g=1" "\x00" + "ccode=ALL" "\x00" + "pa0itssit=0x20" "\x00" + "extpagain2g=0" "\x00" + "pa2ga0=-168,6649,-778" "\x00" + "AvVmid_c0=0x0,0xc8" "\x00" + "cckpwroffset0=5" "\x00" + "maxp2ga0=84" "\x00" + "txpwrbckof=6" "\x00" + "cckbw202gpo=0" "\x00" + "legofdmbw202gpo=0x66111111" "\x00" + "mcsbw202gpo=0x77711111" "\x00" + "propbw202gpo=0xdd" "\x00" + "ofdmdigfilttype=18" "\x00" + "ofdmdigfilttypebe=18" "\x00" + "papdmode=1" "\x00" + "papdvalidtest=1" "\x00" + "pacalidx2g=45" "\x00" + "papdepsoffset=-30" "\x00" + "papdendidx=58" "\x00" + "ltecxmux=0" "\x00" + "ltecxpadnum=0x0102" "\x00" + "ltecxfnsel=0x44" "\x00" + "ltecxgcigpio=0x01" "\x00" + "il0macaddr=00:90:4c:c5:12:38" "\x00" + "wl0id=0x431b" "\x00" + "deadman_to=0xffffffff" "\x00" + "muxenab=0x100" "\x00" + "spurconfig=0x3" "\x00" + "glitch_based_crsmin=1" "\x00" + "btc_mode=1" "\x00" + "\x00\x00"; + +const unsigned int g_cyw43439_nvram_len = sizeof(g_cyw43439_nvram_image); + +/**************************************************************************** + * Include the firmware blob. This assembly code defines the global + * symbol g_cyw43439_firmware_image as the address of this included + * blob. This is similar in effect to the C statement: + * const uint8_t g_cyw43439_firmware_image[] = {...}; + * const uint8_t ng_cyw43439_clm_blob_image[] = {...}; + ****************************************************************************/ + +/* These are defined as array because the symbols name an actual address + * not a pointer to an address. This is not one of the many cases where + * pointers and arrays are interchangeable in C. + */ + +extern const uint8_t g_cyw43439_firmware_image[]; +extern const uint8_t g_cyw43439_clm_blob_image[]; +extern const unsigned int g_cyw43439_clm_blob_len; + +/* This assembly code does the following: + * - Force 16-byte alignment + * - Defines g_cyw43439_firmware_image as a location in memory + * - Copies the firmware image file data to that location. + * - Defines g_cyw43439_firmware_end as the location directly beyond + * that data. + * - Defines g_cyw43439_clm_blob_image as a location within that + * data where the clm_blob begins. + * - Force 4-byte alignment + * - Allocates an integer named g_cyw43439_clm_blob_len that + * contains the length of the clm_blob. + */ + +__asm__("\n .balign 16" + "\n .globl g_cyw43439_firmware_image" + "\n .globl g_cyw43439_clm_blob_image" + "\n .globl g_cyw43439_clm_blob_len" + "\n g_cyw43439_firmware_image:" + "\n .incbin \"cyw43439.firmware.image\"" + "\n firmware_end:" + "\n g_cyw43439_clm_blob_image=g_cyw43439_firmware_image+" + STR(ROUNDED_FIRMWARE_LEN) + "\n .balign 4" + "\n g_cyw43439_clm_blob_len:" + "\n .word firmware_end-g_cyw43439_clm_blob_image" + "\n"); + +/**************************************************************************** + * Other CYW43439 Firmware global definitions + ****************************************************************************/ + +#ifndef CONFIG_IEEE80211_BROADCOM_FWFILES + +const unsigned int g_cyw43439_firmware_len = CONFIG_CYW43439_FIRMWARE_LEN; + +#endif /* CONFIG_IEEE80211_BROADCOM_FWFILES */ + +#endif /* CONFIG_IEEE80211_INFINEON_CYW43439 */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* This file contributes data only. The section banner is here because + * tools/checkpatch.sh refuses to check a C file without one. + */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt new file mode 100644 index 0000000000000..d9f79aced510e --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt @@ -0,0 +1,40 @@ +# ############################################################################## +# boards/arm/rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +# +# ############################################################################## + +add_subdirectory(src) + +add_custom_target( + nuttx_post_build + DEPENDS nuttx + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Regenerate nuttx.uf2") + +# The uf2 command to convert ELF/BIN to UF2 +add_custom_command( + TARGET nuttx_post_build + POST_BUILD + COMMAND picotool ARGS uf2 convert --quiet -t elf nuttx nuttx.uf2 + COMMAND_EXPAND_LISTS + COMMAND ${CMAKE_COMMAND} -E echo "nuttx.uf2" >> + ${CMAKE_BINARY_DIR}/nuttx.manifest + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Regenerate nuttx.uf2") diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig new file mode 100644 index 0000000000000..eab5f150fd0a6 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig @@ -0,0 +1,54 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_BOARD_PIMORONI_PICO_PLUS_2_W + +# The board's only LED hangs off a GPIO of the CYW43439, so setting it means a +# transaction on the gSPI bus. board_autoled_on() is called from interrupt +# handlers and from assertion handling, where that is not permissible, so this +# board supports the CONFIG_USERLED interface only. Override the generic +# "default y" so that a fresh configuration does not select something this +# board cannot implement. + +config ARCH_LEDS + default n + +menuconfig RP23XX_INFINEON_CYW43439 + bool "Has Infineon cyw43439 WiFi chip" + depends on IEEE80211_INFINEON_CYW43439 + default y + +endif + +if RP23XX_INFINEON_CYW43439 + +config CYW43439_FIRMWARE_BIN_PATH + string "Path to Infineon 43439 firmware file" + default "${PICO_SDK_PATH}/lib/cyw43-driver/firmware/43439A0-7.95.49.00.combined" + ---help--- + This should be a path to a file containing both the cyw43439 firmware and + the CLM blob. The firmware should be padded to a 256 byte boundary and + then the CLM blob should be appended. + + If this file is updated, check the CYW43439_FIRMWARE_LEN below to make sure + it reflects the un-padded length of the firmware part. + + pico-sdk 2.x no longer ships this blob as a binary, only as the C header + lib/cyw43-driver/firmware/w43439A0_7_95_49_00_combined.h. If that is all + you have, convert the byte array in that header back to a binary and point + this option at the result. + +config CYW43439_FIRMWARE_LEN + int "Infineon 43439 firmware length (bytes)" + default 224190 + ---help--- + This is the length of just the base firmware in the firmware file specified + by the "Path to Infineon 43439 firmware file" configuration option. + + This length does not include the length of any padding nor the length of + the appended clm_blob. If a clm_blob is present in the firmware file, this + length will be less than the length of the whole file. + +endif diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/nsh/defconfig b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/nsh/defconfig new file mode 100644 index 0000000000000..78496bffa9d2f --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/nsh/defconfig @@ -0,0 +1,48 @@ +# +# 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_ARCH_LEDS is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_DISABLE_DATE is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="pimoroni-pico-plus-2-w" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_PIMORONI_PICO_PLUS_2_W=y +CONFIG_ARCH_CHIP="rp23xx" +CONFIG_ARCH_CHIP_RP23XX=y +CONFIG_ARCH_RAMVECTORS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=10450 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_HOST_MACOS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=532480 +CONFIG_RAM_START=0x20000000 +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=9 +CONFIG_START_MONTH=2 +CONFIG_START_YEAR=2021 +CONFIG_SYSLOG_CONSOLE=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART0_SERIAL_CONSOLE=y diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/usbnsh/defconfig b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/usbnsh/defconfig new file mode 100644 index 0000000000000..eb4346b23077d --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/usbnsh/defconfig @@ -0,0 +1,52 @@ +# +# 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_ARCH_LEDS is not set +# CONFIG_DEV_CONSOLE is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_DISABLE_DATE is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +# CONFIG_RP23XX_UART0 is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="pimoroni-pico-plus-2-w" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_PIMORONI_PICO_PLUS_2_W=y +CONFIG_ARCH_CHIP="rp23xx" +CONFIG_ARCH_CHIP_RP23XX=y +CONFIG_ARCH_RAMVECTORS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=10450 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_CONSOLE=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_HOST_MACOS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_NSH_USBCONSOLE=y +CONFIG_RAM_SIZE=532480 +CONFIG_RAM_START=0x20000000 +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=9 +CONFIG_START_MONTH=2 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_USBDEV=y +CONFIG_USBDEV_BUSPOWERED=y diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/wifi/defconfig b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/wifi/defconfig new file mode 100644 index 0000000000000..aea2230382f80 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/wifi/defconfig @@ -0,0 +1,89 @@ +# +# 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_ARCH_LEDS is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_DISABLE_DATE is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="pimoroni-pico-plus-2-w" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_PIMORONI_PICO_PLUS_2_W=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="rp23xx" +CONFIG_ARCH_CHIP_RP23XX=y +CONFIG_ARCH_IRQBUTTONS=y +CONFIG_ARCH_RAMVECTORS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=10450 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DRIVERS_IEEE80211=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXAMPLES_BUTTONS=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_LEDS=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_HOST_MACOS=y +CONFIG_IEEE80211_BROADCOM_DEFAULT_COUNTRY="XX" +CONFIG_IEEE80211_BROADCOM_DMABUF_ALIGNMENT=16 +CONFIG_IEEE80211_BROADCOM_FRAME_POOL_SIZE=32 +CONFIG_IEEE80211_BROADCOM_FULLMAC_GSPI=y +CONFIG_IEEE80211_INFINEON_CYW43439=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INPUT=y +CONFIG_INPUT_BUTTONS=y +CONFIG_INPUT_BUTTONS_LOWER=y +CONFIG_IOB_NBUFFERS=196 +CONFIG_IOB_NCHAINS=24 +CONFIG_NET=y +CONFIG_NETDB_DNSCLIENT=y +CONFIG_NETDB_DNSCLIENT_RECV_TIMEOUT=3 +CONFIG_NETDEV_LATEINIT=y +CONFIG_NETDEV_WIRELESS_IOCTL=y +CONFIG_NETINIT_DHCPC=y +CONFIG_NETINIT_DNS=y +CONFIG_NETINIT_DNSIPADDR=0x08080808 +CONFIG_NETINIT_WAPI_PASSPHRASE="-ssid-passphrase-" +CONFIG_NETINIT_WAPI_SSID="-my-ssid-" +CONFIG_NET_BROADCAST=y +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_LOOPBACK=y +CONFIG_NET_TCP=y +CONFIG_NET_TCP_DELAYED_ACK=y +CONFIG_NET_UDP=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=532480 +CONFIG_RAM_START=0x20000000 +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=9 +CONFIG_START_MONTH=2 +CONFIG_START_YEAR=2021 +CONFIG_SYSLOG_CONSOLE=y +CONFIG_SYSTEM_DHCPC_RENEW=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_PING=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_USERLED=y +CONFIG_USERLED_LOWER=y +CONFIG_WIRELESS_WAPI=y +CONFIG_WIRELESS_WAPI_CMDTOOL=y +CONFIG_WQUEUE_NOTIFIER=y diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/board.h b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/board.h new file mode 100644 index 0000000000000..b1ca2264d3f41 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/board.h @@ -0,0 +1,154 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/board.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_BOARD_H +#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_BOARD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "rp23xx_i2cdev.h" +#include "rp23xx_spidev.h" +#include "rp23xx_i2sdev.h" +#include "rp23xx_spisd.h" + +#ifndef __ASSEMBLY__ +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Clocking *****************************************************************/ + +#define MHZ 1000000 + +#define BOARD_XOSC_FREQ (12 * MHZ) +#define BOARD_XOSC_STARTUPDELAY 1 +#define BOARD_PLL_SYS_FREQ (150 * MHZ) +#define BOARD_PLL_USB_FREQ (48 * MHZ) + +#define BOARD_REF_FREQ (12 * MHZ) +#define BOARD_SYS_FREQ (150 * MHZ) +#define BOARD_PERI_FREQ (150 * MHZ) +#define BOARD_USB_FREQ (48 * MHZ) +#define BOARD_ADC_FREQ (48 * MHZ) +#define BOARD_HSTX_FREQ (150 * MHZ) + +#define BOARD_UART_BASEFREQ BOARD_PERI_FREQ + +#define BOARD_TICK_CLOCK (1 * MHZ) + +/* definitions for pico-sdk */ + +/* GPIO definitions *********************************************************/ + +#define BOARD_NGPIOOUT 1 +#define BOARD_NGPIOIN 1 +#define BOARD_NGPIOINT 1 + +/* LED definitions **********************************************************/ + +/* The only LED on this board is wired to GPIO 0 of the CYW43439 wireless + * chip, not to a GPIO of the RP2350. Driving it means sending an iovar + * request over the gSPI bus, which can only be done from task context and + * only once the wireless chip has been activated by bringing wlan0 up. + * + * That rules out CONFIG_ARCH_LEDS -- board_autoled_on() is called from + * interrupt handlers and from assertion handling, where a bus transaction + * is not permissible. So this board provides the user LED interface only + * (CONFIG_USERLED) and does not select ARCH_HAVE_LEDS. + */ + +/* LED index values for use with board_userled() */ + +#define BOARD_LED1 0 +#define BOARD_NLEDS 1 + +#define BOARD_LED_GREEN BOARD_LED1 + +/* LED bits for use with board_userled_all() */ + +#define BOARD_LED1_BIT (1 << BOARD_LED1) + +/* BUTTON definitions *******************************************************/ + +/* The board has two physical buttons, BOOT and RESET. BOOT is also wired + * to GPIO 45, active low, so once NuttX is running it can be read as an + * ordinary user button. pico-sdk calls that pin the board's USER_SW_PIN. + * RESET is not visible as a GPIO. + */ + +#define NUM_BUTTONS 1 + +#define BUTTON_USER1 0 +#define BUTTON_USER1_BIT (1 << BUTTON_USER1) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: rp23xx_boardearlyinitialize + * + * Description: + * + ****************************************************************************/ + +void rp23xx_boardearlyinitialize(void); + +/**************************************************************************** + * Name: rp23xx_boardinitialize + * + * Description: + * + ****************************************************************************/ + +void rp23xx_boardinitialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_BOARD_H */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_extra_gpio.h b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_extra_gpio.h new file mode 100644 index 0000000000000..a188c3c8a7d71 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_extra_gpio.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_extra_gpio.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_EXTRA_GPIO_H +#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_EXTRA_GPIO_H + +/**************************************************************************** + * These functions control the GPIO pins on the CYW43439 wireless chip, not + * the GPIO pins of the RP2350. The pin assignments for the Pimoroni Pico + * Plus 2 W are: + * + * GPIO 0 - output - controls the onboard LED + * GPIO 1 - output - controls the onboard voltage regulator mode. + * GPIO 2 - input - Reads as non-zero if power supplied by USB or VBUS pin. + * + * These only work once the wireless chip has been activated, which happens + * when the wlan0 network interface is brought up. Until then every access + * fails with -EIO. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define RP23XX_EXTRA_GPIO_NUM 3 /* Number of extra GPIO pins */ + +#define RP23XX_EXTRA_GPIO_LED 0 /* Onboard LED */ +#define RP23XX_EXTRA_GPIO_VREG 1 /* Voltage regulator mode */ +#define RP23XX_EXTRA_GPIO_VBUS 2 /* VBUS present */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +EXTERN gspi_dev_t *g_cyw43439; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: rp23xx_extra_gpio_put + * + * Description: + * Change the state of a GPIO pin on the CYW43439. + * + * Returned Value: + * OK on success, or a negated errno. -EIO means the wireless chip is not + * running yet, which is the case until wlan0 has been brought up. + * + ****************************************************************************/ + +static inline int rp23xx_extra_gpio_put(uint32_t gpio, bool value) +{ + DEBUGASSERT(gpio < RP23XX_EXTRA_GPIO_NUM); + + if (g_cyw43439 == NULL) + { + return -EIO; + } + + return bcmf_set_gpio(g_cyw43439->priv, gpio, value); +} + +/**************************************************************************** + * Name: rp23xx_extra_gpio_get + * + * Description: + * Read the state of a GPIO pin on the CYW43439. + * + * Returned Value: + * OK on success, or a negated errno. -EIO means the wireless chip is not + * running yet, which is the case until wlan0 has been brought up. + * + ****************************************************************************/ + +static inline int rp23xx_extra_gpio_get(uint32_t gpio, bool *value) +{ + DEBUGASSERT(gpio < RP23XX_EXTRA_GPIO_NUM); + + if (g_cyw43439 == NULL) + { + return -EIO; + } + + return bcmf_get_gpio(g_cyw43439->priv, gpio, value); +} + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_EXTRA_GPIO_H */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.h b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.h new file mode 100644 index 0000000000000..408bc491ffd9f --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2CDEV_H +#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2CDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2cdev_initialize + * + * Description: + * Initialize i2c driver and register the /dev/i2c device. + * + ****************************************************************************/ + +#ifdef CONFIG_RP23XX_I2C_DRIVER +int board_i2cdev_initialize(int bus); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2CDEV_H */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.h b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.h new file mode 100644 index 0000000000000..185d08d0ddee0 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2SDEV_H +#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2SDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2sdev_initialize + * + * Description: + * Initialize i2s driver and register the /dev/audio/pcm0 device. + * + ****************************************************************************/ + +#ifdef CONFIG_RP23XX_I2S +int board_i2sdev_initialize(int bus); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2SDEV_H */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spidev.h b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spidev.h new file mode 100644 index 0000000000000..70444529a36c0 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spidev.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spidev.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPIDEV_H +#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPIDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_spidev_initialize + * + * Description: + * Initialize spi driver and register the /dev/spi device. + * + ****************************************************************************/ + +int board_spidev_initialize(int bus); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPIDEV_H */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spisd.h b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spisd.h new file mode 100644 index 0000000000000..3c21497a667a7 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spisd.h @@ -0,0 +1,85 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spisd.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPISD_H +#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPISD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_spisd_initialize + * + * Description: + * Initialize the SPI-based SD card. + * + ****************************************************************************/ + +#ifdef CONFIG_RP23XX_SPISD +int board_spisd_initialize(int minor, int bus); +#endif + +/**************************************************************************** + * Name: board_spisd_status + * + * Description: + * Get the status whether SD Card is present or not. + * + ****************************************************************************/ + +#ifdef CONFIG_RP23XX_SPISD +uint8_t board_spisd_status(struct spi_dev_s *dev, uint32_t devid); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPISD_H */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/Make.defs b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/Make.defs new file mode 100644 index 0000000000000..b3f9d906ec7ca --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/Make.defs @@ -0,0 +1,43 @@ +############################################################################ +# boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/Make.defs +# +# 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. +# +############################################################################ + +include $(TOPDIR)/.config +include $(TOPDIR)/tools/Config.mk +include $(TOPDIR)/tools/rp23xx/Config.mk +include $(TOPDIR)/arch/arm/src/armv8-m/Toolchain.defs + +ifeq ($(CONFIG_BOOT_RUNFROMFLASH),y) + LDSCRIPT = memmap_default.ld +else ifeq ($(CONFIG_BOOT_COPYTORAM),y) + LDSCRIPT = memmap_copy_to_ram.ld +else + LDSCRIPT = memmap_no_flash.ld +endif + +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) + +CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe +CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe +CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ + +NXFLATLDFLAGS1 = -r -d -warn-common +NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-pcrel.ld -no-check-sections +LDNXFLATFLAGS = -e main -s 2048 diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_copy_to_ram.ld b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_copy_to_ram.ld new file mode 100644 index 0000000000000..3e75acbd25d2a --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_copy_to_ram.ld @@ -0,0 +1,340 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_copy_to_ram.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +MEMORY +{ + FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 16384k + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k + SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + /* Second stage bootloader is prepended to the image. It must be 256 bytes big + and checksummed. It is usually built by the boot_stage2 target + in the Raspberry Pi Pico SDK + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .flashtext : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + . = ALIGN(4); + } > FLASH + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + /* Vector table goes first in RAM, to avoid large alignment hole */ + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .text : { + __ram_text_start__ = .; + *(.init) + *(.text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + . = ALIGN(4); + __ram_text_end__ = .; + } > RAM AT> FLASH + __ram_text_source__ = LOADADDR(.text); + . = ALIGN(4); + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + . = ALIGN(4); + *(.rodata*) + *(.srodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + /* GOT/PLT must live INSIDE the copied .data range so a flat + * -fPIC object (e.g. a PIC static library linked into an app) + * gets an initialised GOT in RAM at boot; otherwise an orphan + * .got lands after _edata, is never copied, and every GOT- + * indirected access reads a NULL pointer (hardfault). */ + . = ALIGN(4); + *(.got) + *(.got.plt) + *(.got*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + } > RAM + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT > FLASH + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > FLASH + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y + + .flash_end : { + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); + } > FLASH =0xaa + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_default.ld b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_default.ld new file mode 100644 index 0000000000000..ea93cf337b6e9 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_default.ld @@ -0,0 +1,353 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_default.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +MEMORY +{ + FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 16384k + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k + SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .text : { + __logical_binary_start = .; + _stext = ABSOLUTE(.); + + KEEP (*(.vectors)) + + LONG(0xffffded3) + LONG(0x10210142) + LONG(0x000001ff) + LONG(0x00000000) + LONG(0xab123579) + + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *libgcc.a:cmse_nonsecure_call.o + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.eh_frame*) + . = ALIGN(4); + _etext = ABSOLUTE(.); + } > FLASH + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + _eronly = ABSOLUTE(.); + __binary_info_end = .; + . = ALIGN(4); + + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .data : { + __data_start__ = .; + _sdata = ABSOLUTE(.); + + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + /* GOT/PLT must live INSIDE the copied .data range so a flat + * -fPIC object (e.g. a PIC static library linked into an app) + * gets an initialised GOT in RAM at boot; otherwise an orphan + * .got lands after _edata, is never copied, and every GOT- + * indirected access reads a NULL pointer (hardfault). */ + . = ALIGN(4); + *(.got) + *(.got.plt) + *(.got*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + *(.jcr) + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > RAM AT> FLASH + + .tdata : { + _stdata = ABSOLUTE(.); + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + _etdata = ABSOLUTE(.); + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + _stbss = ABSOLUTE(.); + . = ALIGN(4); + __bss_start__ = .; + _sbss = ABSOLUTE(.); + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + _etbss = ABSOLUTE(.); + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + _ebss = ABSOLUTE(.); + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + } > RAM + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT > FLASH + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > FLASH + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y + + .flash_end : { + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); + } > FLASH =0xaa + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_no_flash.ld b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_no_flash.ld new file mode 100644 index 0000000000000..56db21d115623 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_no_flash.ld @@ -0,0 +1,294 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_no_flash.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +MEMORY +{ + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k + SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + /* Note unlike RP2040, we start the image with a vector table even for + NO_FLASH builds. On Arm, the bootrom expects a VT at the start of the + image by default; on RISC-V, the default is to enter the image at its + lowest address, so an IMAGEDEF item is required to specify the + nondefault entry point. */ + + .text : { + __logical_binary_start = .; + _stext = ABSOLUTE(.); + /* Vectors require 512-byte alignment on v8-M when >48 IRQs are used, + so we would waste RAM if the vector table were not at the + start. */ + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + __reset_start = .; + KEEP (*(.reset)) + __reset_end = .; + *(.time_critical*) + *(.text*) + . = ALIGN(4); + *(.init) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + } > RAM + + .rodata : { + . = ALIGN(4); + *(.rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > RAM + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > RAM + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > RAM + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > RAM + __binary_info_end = .; + . = ALIGN(4); + + .data : { + __data_start__ = .; + *(vtable) + *(.data*) + *(.sdata*) + + /* GOT/PLT must live INSIDE the copied .data range so a flat + * -fPIC object (e.g. a PIC static library linked into an app) + * gets an initialised GOT in RAM at boot; otherwise an orphan + * .got lands after _edata, is never copied, and every GOT- + * indirected access reads a NULL pointer (hardfault). */ + . = ALIGN(4); + *(.got) + *(.got.plt) + *(.got*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM + PROVIDE(__data_end__ = .); + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + _etext = LOADADDR(.data); + + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + _stbss = ABSOLUTE(.); + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + _etbss = ABSOLUTE(.); + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + _sbss = ABSOLUTE(.); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + _ebss = ABSOLUTE(.); + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + } > RAM + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/CMakeLists.txt b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/CMakeLists.txt new file mode 100644 index 0000000000000..9c6be9b70533c --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/CMakeLists.txt @@ -0,0 +1,66 @@ +# ############################################################################## +# boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +# +# ############################################################################## + +set(SRCS rp23xx_boardinitialize.c rp23xx_bringup.c) + +if(CONFIG_DEV_GPIO) + list(APPEND SRCS rp23xx_gpio.c) +endif() + +# This board has no LED on an RP2350 pin -- its only LED hangs off the CYW43439, +# and reaching it means a gSPI bus transaction. That rules out +# CONFIG_ARCH_LEDS, whose board_autoled_on() is called from interrupt handlers +# and from assertion handling, so there is no rp23xx_autoleds.c. It also means +# there is no LED at all without the wireless chip. See rp23xx_userleds.c. + +if(CONFIG_ARCH_LEDS) + message( + FATAL_ERROR + "CONFIG_ARCH_LEDS is not supported on this board: the LED hangs off the " + "CYW43439 and cannot be driven from interrupt context. " + "Use CONFIG_USERLED instead.") +endif() + +if(CONFIG_RP23XX_INFINEON_CYW43439) + list(APPEND SRCS rp23xx_userleds.c) +endif() + +if(CONFIG_ARCH_BUTTONS) + list(APPEND SRCS rp23xx_buttons.c) +endif() + +# rp23xx_firmware.c, which carries the CYW43439 firmware blob, is built from +# boards/arm/rp23xx/common/src. + +target_sources(board PRIVATE ${SRCS}) + +if(CONFIG_BOOT_RUNFROMFLASH) + set_property(GLOBAL PROPERTY LD_SCRIPT + "${NUTTX_BOARD_DIR}/scripts/memmap_default.ld") +elseif(CONFIG_BOOT_COPYTORAM) + set_property( + GLOBAL PROPERTY LD_SCRIPT + "${NUTTX_BOARD_DIR}/scripts/memmap_copy_to_ram.ld") +else() + set_property(GLOBAL PROPERTY LD_SCRIPT + "${NUTTX_BOARD_DIR}/scripts/memmap_no_flash.ld") +endif() diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/Make.defs b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/Make.defs new file mode 100644 index 0000000000000..276b544dcc468 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/Make.defs @@ -0,0 +1,95 @@ +############################################################################ +# boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/Make.defs +# +# 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. +# +############################################################################ + +include $(TOPDIR)/Make.defs + +CSRCS = rp23xx_boardinitialize.c +CSRCS += rp23xx_bringup.c + +ifeq ($(CONFIG_DEV_GPIO),y) +CSRCS += rp23xx_gpio.c +endif + +# This board has no LED on an RP2350 pin -- its only LED hangs off the +# CYW43439, and reaching it means a gSPI bus transaction. That rules out +# CONFIG_ARCH_LEDS, whose board_autoled_on() is called from interrupt handlers +# and from assertion handling, so there is no rp23xx_autoleds.c. It also +# means there is no LED at all without the wireless chip. +# See src/rp23xx_userleds.c. + +ifeq ($(CONFIG_ARCH_LEDS),y) +$(error CONFIG_ARCH_LEDS is not supported on this board: the LED hangs off \ + the CYW43439 and cannot be driven from interrupt context. \ + Use CONFIG_USERLED instead) +endif + +ifeq ($(CONFIG_RP23XX_INFINEON_CYW43439),y) +CSRCS += rp23xx_userleds.c +endif + +ifeq ($(CONFIG_ARCH_BUTTONS),y) + CSRCS += rp23xx_buttons.c +endif + +DEPPATH += --dep-path board +VPATH += :board +CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board + +############################################################################ +# The rules below stage the cyw43439 blob out of pico_sdk so that the +# .incbin in rp23xx_firmware.c can pick it up. +# +# rp23xx_firmware.c lives in the *common* src directory, which is both on the +# include path (added by common/src/Make.defs) and reachable via VPATH, so the +# blob is staged next to it there. This mirrors what rp2040 does for the +# Raspberry Pi Pico W. +############################################################################ + +ifeq ($(CONFIG_IEEE80211_INFINEON_CYW43439),y) + +FIRMWARE = src$(DELIM)cyw43439.firmware.image + +# --- If PICO_SDK_PATH is not defined set a dummy path. -------------------- +# See comment below. + +ifeq ($(PICO_SDK_PATH),) + PICO_SDK_PATH = /tmp +endif + +FIRMWARE_SRC := $(patsubst "%",%,$(CONFIG_CYW43439_FIRMWARE_BIN_PATH)) + +# --- If the firmware source does not exist create a dummy file. ----------- +# NuttX built with the cyw43439 driver will not talk to the wireless +# chip when built with this dummy file. The sole purpose of adding +# this dummy is so the CI build tests will not fail. + +$(FIRMWARE_SRC): + $(Q) mkdir -p `dirname $(FIRMWARE_SRC)` + $(Q) echo "dummy" >$(FIRMWARE_SRC) + +$(FIRMWARE): $(FIRMWARE_SRC) + $(call CATFILE, $(FIRMWARE), $(FIRMWARE_SRC)) + +src$(DELIM)rp23xx_firmware.c: $(FIRMWARE) + +distclean:: + $(call DELFILE, $(FIRMWARE)) + +endif diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_boardinitialize.c b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_boardinitialize.c new file mode 100644 index 0000000000000..dfba32a568df2 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_boardinitialize.c @@ -0,0 +1,115 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_boardinitialize.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 "rp23xx_gpio.h" + +#ifdef CONFIG_RP23XX_PSRAM +#include "rp23xx_psram.h" +#endif + +#ifdef CONFIG_ARCH_BOARD_COMMON +#include "rp23xx_common_initialize.h" +#endif /* CONFIG_ARCH_BOARD_COMMON */ + +#include "rp23xx_pico.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rp23xx_boardearlyinitialize + * + * Description: + * + ****************************************************************************/ + +void rp23xx_boardearlyinitialize(void) +{ + #ifdef CONFIG_ARCH_BOARD_COMMON + rp23xx_common_earlyinitialize(); + #endif + + /* --- Place any board specific early initialization here --- */ + + /* Nothing to do for the LED: it hangs off the CYW43439 wireless chip + * rather than an RP2350 pin, and cannot be touched this early. See + * src/rp23xx_userleds.c. + */ +} + +/**************************************************************************** + * Name: rp23xx_boardinitialize + * + * Description: + * + ****************************************************************************/ + +void rp23xx_boardinitialize(void) +{ + #ifdef CONFIG_ARCH_BOARD_COMMON + rp23xx_common_initialize(); + #endif + + #ifdef CONFIG_RP23XX_PSRAM + rp23xx_psramconfig(); + #endif + + /* --- Place any board specific initialization here --- */ +} + +/**************************************************************************** + * Name: board_late_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_late_initialize(). board_late_initialize() will be + * called immediately after up_initialize() is called and just before the + * initial application is started. This additional initialization phase + * may be used, for example, to initialize board-specific device drivers. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARD_LATE_INITIALIZE +void board_late_initialize(void) +{ + rp23xx_bringup(); +} +#endif diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_bringup.c b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_bringup.c new file mode 100644 index 0000000000000..086a98a87321b --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_bringup.c @@ -0,0 +1,132 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_bringup.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 "rp23xx_pico.h" + +#ifdef CONFIG_ARCH_BOARD_COMMON +#include "rp23xx_common_bringup.h" +#endif /* CONFIG_ARCH_BOARD_COMMON */ + +#ifdef CONFIG_USERLED +# include +#endif + +#ifdef CONFIG_INPUT_BUTTONS +# include +#endif + +#ifdef CONFIG_RP23XX_INFINEON_CYW43439 +# include "rp23xx_cyw43439.h" +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_RP23XX_INFINEON_CYW43439 +gspi_dev_t *g_cyw43439 = NULL; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rp23xx_bringup + ****************************************************************************/ + +int rp23xx_bringup(void) +{ + int ret; + + UNUSED(ret); + +#ifdef CONFIG_ARCH_BOARD_COMMON + + ret = rp23xx_common_bringup(); + if (ret < 0) + { + return ret; + } + +#endif /* CONFIG_ARCH_BOARD_COMMON */ + + /* --- Place any board specific bringup code here --- */ + +#ifdef CONFIG_RP23XX_INFINEON_CYW43439 + /* Bring up the CYW43439 wireless chip. This registers the wlan0 network + * device; the chip's firmware is not downloaded until wlan0 is brought up. + * + * Do this before the LED driver, which drives a GPIO on this chip. + */ + + g_cyw43439 = rp23xx_cyw_setup(GPIO_CYW43439_ON, + GPIO_CYW43439_CS, + GPIO_CYW43439_DATA, + GPIO_CYW43439_CLOCK, + GPIO_CYW43439_DATA); + + if (g_cyw43439 == NULL) + { + syslog(LOG_ERR, + "ERROR: failed to initialize the cyw43439 (WiFi chip): %d\n", + errno); + } +#endif + +#if defined(CONFIG_USERLED_LOWER) && defined(CONFIG_RP23XX_INFINEON_CYW43439) + /* Register the LED driver. The LED sits on the wireless chip, so there is + * nothing to register without it. + */ + + ret = userled_lower_initialize("/dev/userleds"); + if (ret < 0) + { + syslog(LOG_ERR, \ + "ERROR: userled_lower_initialize() failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_INPUT_BUTTONS + /* Register the BUTTON driver */ + + ret = btn_lower_initialize("/dev/buttons"); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: btn_lower_initialize() failed: %d\n", ret); + } +#endif + + return OK; +} diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_buttons.c b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_buttons.c new file mode 100644 index 0000000000000..4ef40e210a65b --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_buttons.c @@ -0,0 +1,187 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_buttons.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 "rp23xx_gpio.h" +#include "rp23xx_pico.h" + +#if defined(CONFIG_ARCH_BUTTONS) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_INPUT_BUTTONS) && !defined(CONFIG_ARCH_IRQBUTTONS) +# error "The NuttX Buttons Driver depends on IRQ support to work!\n" +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Pin configuration for the board's BOOT button, which doubles as a user + * button once NuttX is running. + */ + +static const uint32_t g_buttons[NUM_BUTTONS] = +{ + GPIO_BTN_USER1 +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_button_initialize + * + * Description: + * board_button_initialize() must be called to initialize button resources. + * After that, board_buttons() may be called to collect the current state + * of all buttons or board_button_irq() may be called to register button + * interrupt handlers. + * + ****************************************************************************/ + +uint32_t board_button_initialize(void) +{ + int i; + + /* Configure the GPIO pins as inputs. And we will use interrupts */ + + for (i = 0; i < NUM_BUTTONS; i++) + { + /* Initialize input pin */ + + rp23xx_gpio_init(g_buttons[i]); + + /* The button shorts the pin to ground, so pull it up. + * + * Do not be tempted to leave the pin floating or pulled down here: + * erratum RP2350-E9 means a floating Bank 0 input leaks enough current + * to sit at about 2.2 V, and the internal pull-down is far too weak to + * overcome it. The pull-up is unaffected by the erratum. + * + * pull-up = true : pull-down = false + */ + + rp23xx_gpio_set_pulls(g_buttons[i], true, false); + } + + return NUM_BUTTONS; +} + +/**************************************************************************** + * Name: board_buttons + ****************************************************************************/ + +uint32_t board_buttons(void) +{ + uint32_t ret = 0; + int i; + + /* Check that state of each key */ + + for (i = 0; i < NUM_BUTTONS; i++) + { + /* A LOW value means that the key is pressed. */ + + bool released = rp23xx_gpio_get(g_buttons[i]); + + /* Accumulate the set of depressed (not released) keys */ + + if (!released) + { + ret |= (1 << i); + } + } + + return ret; +} + +/**************************************************************************** + * Button support. + * + * Description: + * board_button_initialize() must be called to initialize button resources. + * After that, board_buttons() may be called to collect the current state + * of all buttons or board_button_irq() may be called to register button + * interrupt handlers. + * + * After board_button_initialize() has been called, board_buttons() may be + * called to collect the state of all buttons. board_buttons() returns + * an 32-bit bit set with each bit associated with a button. See the + * BUTTON_*_BIT definitions in board.h for the meaning of each bit. + * + * board_button_irq() may be called to register an interrupt handler that + * will be called when a button is depressed or released. The ID value is + * a button enumeration value that uniquely identifies a button resource. + * See the BUTTON_* definitions in board.h for the meaning of enumeration + * value. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_IRQBUTTONS +int board_button_irq(int id, xcpt_t irqhandler, void *arg) +{ + int ret = -EINVAL; + + /* The following should be atomic */ + + if (id >= MIN_IRQBUTTON && id <= MAX_IRQBUTTON) + { + /* Make sure the interrupt is disabled */ + + rp23xx_gpio_disable_irq(g_buttons[id]); + + /* Attach the interrupt handler */ + + ret = rp23xx_gpio_irq_attach(g_buttons[id], + RP23XX_GPIO_INTR_EDGE_LOW, + irqhandler, + arg); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: irq_attach() failed: %d\n", ret); + return ret; + } + + /* Enable interruption for this pin */ + + rp23xx_gpio_enable_irq(g_buttons[id]); + } + + return ret; +} +#endif + +#endif /* CONFIG_ARCH_BUTTONS */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_gpio.c b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_gpio.c new file mode 100644 index 0000000000000..57c5e8629ac6f --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_gpio.c @@ -0,0 +1,396 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_gpio.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 "arm_internal.h" +#include "chip.h" +#include "rp23xx_gpio.h" + +#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF) + +/* Output pins. + * + * There is no onboard LED on an RP2350 pin on this board -- it hangs off the + * CYW43439 -- so this is just a free header pin. Note that GPIO 23, 24, 25 + * and 29 are wired to the wireless chip and must not be used here. + */ + +#define GPIO_OUT1 2 + +/* Input pins. + */ + +#define GPIO_IN1 6 + +/* Interrupt pins. + */ + +#define GPIO_IRQPIN1 14 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rp23xxgpio_dev_s +{ + struct gpio_dev_s gpio; + uint8_t id; +}; + +struct rp23xxgpint_dev_s +{ + struct rp23xxgpio_dev_s rp23xxgpio; + pin_interrupt_t callback; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#if BOARD_NGPIOOUT > 0 +static int gpout_read(struct gpio_dev_s *dev, bool *value); +static int gpout_write(struct gpio_dev_s *dev, bool value); +#endif + +#if BOARD_NGPIOIN > 0 +static int gpin_read(struct gpio_dev_s *dev, bool *value); +#endif + +#if BOARD_NGPIOINT > 0 +static int gpint_read(struct gpio_dev_s *dev, bool *value); +static int gpint_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback); +static int gpint_enable(struct gpio_dev_s *dev, bool enable); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if BOARD_NGPIOOUT > 0 +static const struct gpio_operations_s gpout_ops = +{ + .go_read = gpout_read, + .go_write = gpout_write, + .go_attach = NULL, + .go_enable = NULL, +}; + +/* This array maps the GPIO pins used as OUTPUT */ + +static const uint32_t g_gpiooutputs[BOARD_NGPIOOUT] = +{ + GPIO_OUT1 +}; + +static struct rp23xxgpio_dev_s g_gpout[BOARD_NGPIOOUT]; +#endif + +#if BOARD_NGPIOIN > 0 +static const struct gpio_operations_s gpin_ops = +{ + .go_read = gpin_read, + .go_write = NULL, + .go_attach = NULL, + .go_enable = NULL, +}; + +/* This array maps the GPIO pins used as INTERRUPT INPUTS */ + +static const uint32_t g_gpioinputs[BOARD_NGPIOIN] = +{ + GPIO_IN1 +}; + +static struct rp23xxgpio_dev_s g_gpin[BOARD_NGPIOIN]; +#endif + +#if BOARD_NGPIOINT > 0 +static const struct gpio_operations_s gpint_ops = +{ + .go_read = gpint_read, + .go_write = NULL, + .go_attach = gpint_attach, + .go_enable = gpint_enable, +}; + +/* This array maps the GPIO pins used as INTERRUPT INPUTS */ + +static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] = +{ + GPIO_IRQPIN1, +}; + +static struct rp23xxgpint_dev_s g_gpint[BOARD_NGPIOINT]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: gpout_read + ****************************************************************************/ + +#if BOARD_NGPIOOUT > 0 +static int gpout_read(struct gpio_dev_s *dev, bool *value) +{ + struct rp23xxgpio_dev_s *rp23xxgpio = + (struct rp23xxgpio_dev_s *)dev; + + DEBUGASSERT(rp23xxgpio != NULL && value != NULL); + DEBUGASSERT(rp23xxgpio->id < BOARD_NGPIOOUT); + gpioinfo("Reading...\n"); + + *value = rp23xx_gpio_get(g_gpiooutputs[rp23xxgpio->id]); + return OK; +} + +/**************************************************************************** + * Name: gpout_write + ****************************************************************************/ + +static int gpout_write(struct gpio_dev_s *dev, bool value) +{ + struct rp23xxgpio_dev_s *rp23xxgpio = + (struct rp23xxgpio_dev_s *)dev; + + DEBUGASSERT(rp23xxgpio != NULL); + DEBUGASSERT(rp23xxgpio->id < BOARD_NGPIOOUT); + gpioinfo("Writing %d\n", (int)value); + + rp23xx_gpio_put(g_gpiooutputs[rp23xxgpio->id], value); + return OK; +} +#endif + +/**************************************************************************** + * Name: gpin_read + ****************************************************************************/ + +#if BOARD_NGPIOIN > 0 +static int gpin_read(struct gpio_dev_s *dev, bool *value) +{ + struct rp23xxgpio_dev_s *rp23xxgpio = + (struct rp23xxgpio_dev_s *)dev; + + DEBUGASSERT(rp23xxgpio != NULL && value != NULL); + DEBUGASSERT(rp23xxgpio->id < BOARD_NGPIOIN); + gpioinfo("Reading... pin %d\n", (int)g_gpioinputs[rp23xxgpio->id]); + + *value = rp23xx_gpio_get(g_gpioinputs[rp23xxgpio->id]); + return OK; +} +#endif + +/**************************************************************************** + * Name: rp23xxgpio_interrupt + ****************************************************************************/ + +#if BOARD_NGPIOINT > 0 +static int rp23xxgpio_interrupt(int irq, void *context, void *arg) +{ + struct rp23xxgpint_dev_s *rp23xxgpint = + (struct rp23xxgpint_dev_s *)arg; + + DEBUGASSERT(rp23xxgpint != NULL && rp23xxgpint->callback != NULL); + gpioinfo("Interrupt! callback=%p\n", rp23xxgpint->callback); + + rp23xxgpint->callback(&rp23xxgpint->rp23xxgpio.gpio, + rp23xxgpint->rp23xxgpio.id); + return OK; +} + +/**************************************************************************** + * Name: gpint_read + ****************************************************************************/ + +static int gpint_read(struct gpio_dev_s *dev, bool *value) +{ + struct rp23xxgpint_dev_s *rp23xxgpint = + (struct rp23xxgpint_dev_s *)dev; + + DEBUGASSERT(rp23xxgpint != NULL && value != NULL); + DEBUGASSERT(rp23xxgpint->rp23xxgpio.id < BOARD_NGPIOINT); + gpioinfo("Reading int pin...\n"); + + *value = rp23xx_gpio_get(g_gpiointinputs[rp23xxgpint->rp23xxgpio.id]); + return OK; +} + +/**************************************************************************** + * Name: gpint_attach + ****************************************************************************/ + +static int gpint_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback) +{ + struct rp23xxgpint_dev_s *rp23xxgpint = + (struct rp23xxgpint_dev_s *)dev; + int irq = g_gpiointinputs[rp23xxgpint->rp23xxgpio.id]; + int ret; + + gpioinfo("Attaching the callback\n"); + + /* Make sure the interrupt is disabled */ + + rp23xx_gpio_disable_irq(irq); + ret = rp23xx_gpio_irq_attach(irq, + RP23XX_GPIO_INTR_EDGE_LOW, + rp23xxgpio_interrupt, + &g_gpint[rp23xxgpint->rp23xxgpio.id]); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: gpint_attach() failed: %d\n", ret); + return ret; + } + + gpioinfo("Attach %p\n", callback); + rp23xxgpint->callback = callback; + return OK; +} + +/**************************************************************************** + * Name: gpint_enable + ****************************************************************************/ + +static int gpint_enable(struct gpio_dev_s *dev, bool enable) +{ + struct rp23xxgpint_dev_s *rp23xxgpint = + (struct rp23xxgpint_dev_s *)dev; + int irq = g_gpiointinputs[rp23xxgpint->rp23xxgpio.id]; + + if (enable) + { + if (rp23xxgpint->callback != NULL) + { + gpioinfo("Enabling the interrupt\n"); + + /* Configure the interrupt for rising edge */ + + rp23xx_gpio_enable_irq(irq); + } + } + else + { + gpioinfo("Disable the interrupt\n"); + rp23xx_gpio_disable_irq(irq); + } + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rp23xx_dev_gpio_init + ****************************************************************************/ + +int rp23xx_dev_gpio_init(void) +{ + int i; + int pincount = 0; + +#if BOARD_NGPIOOUT > 0 + for (i = 0; i < BOARD_NGPIOOUT; i++) + { + /* Setup and register the GPIO pin */ + + g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN; + g_gpout[i].gpio.gp_ops = &gpout_ops; + g_gpout[i].id = i; + gpio_pin_register(&g_gpout[i].gpio, g_gpiooutputs[i]); + + /* Configure the pins that will be used as output */ + + rp23xx_gpio_init(g_gpiooutputs[i]); + rp23xx_gpio_setdir(g_gpiooutputs[i], true); + rp23xx_gpio_put(g_gpiooutputs[i], false); + + pincount++; + } +#endif + + pincount = 0; + +#if BOARD_NGPIOIN > 0 + for (i = 0; i < BOARD_NGPIOIN; i++) + { + /* Setup and register the GPIO pin */ + + g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN; + g_gpin[i].gpio.gp_ops = &gpin_ops; + g_gpin[i].id = i; + gpio_pin_register(&g_gpin[i].gpio, g_gpioinputs[i]); + + /* Configure the pins that will be used as INPUT */ + + rp23xx_gpio_init(g_gpioinputs[i]); + + pincount++; + } +#endif + + pincount = 0; + +#if BOARD_NGPIOINT > 0 + for (i = 0; i < BOARD_NGPIOINT; i++) + { + /* Setup and register the GPIO pin */ + + g_gpint[i].rp23xxgpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN; + g_gpint[i].rp23xxgpio.gpio.gp_ops = &gpint_ops; + g_gpint[i].rp23xxgpio.id = i; + gpio_pin_register(&g_gpint[i].rp23xxgpio.gpio, g_gpiointinputs[i]); + + /* Configure the pins that will be used as interrupt input */ + + rp23xx_gpio_init(g_gpiointinputs[i]); + + /* pull-up = false : pull-down = true */ + + rp23xx_gpio_set_pulls(g_gpiointinputs[i], false, true); + + pincount++; + } +#endif + + return OK; +} +#endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_pico.h b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_pico.h new file mode 100644 index 0000000000000..d3c656896d470 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_pico.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_pico.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_SRC_RP23XX_PICO_H +#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_SRC_RP23XX_PICO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/* CYW43439 wireless chip + * + * The gSPI bus is half duplex -- a single data line carries both directions + * and doubles as the chip's interrupt request line. + */ + +#define GPIO_CYW43439_ON 23 /* Drive high to power the chip up */ +#define GPIO_CYW43439_DATA 24 /* Bidirectional data, also the IRQ */ +#define GPIO_CYW43439_CS 25 /* Drive low to select the chip */ +#define GPIO_CYW43439_CLOCK 29 /* gSPI clock */ + +/* LEDs + * + * The board's only LED hangs off GPIO 0 of the CYW43439, see + * include/rp23xx_extra_gpio.h. There is no LED on an RP2350 pin. + */ + +/* Buttons */ + +/* Buttons GPIO pins definition */ + +/* The board's BOOT button doubles as a user button once NuttX is running. + * It is active low. RESET is not readable as a GPIO. + */ + +#define GPIO_BTN_USER1 45 + +/* Buttons IRQ definitions */ + +#define MIN_IRQBUTTON BUTTON_USER1 +#define MAX_IRQBUTTON BUTTON_USER1 +#define NUM_IRQBUTTONS (MAX_IRQBUTTON - MIN_IRQBUTTON + 1) + +int rp23xx_bringup(void); + +#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_ARCH_BOARD_COMMON) +int rp23xx_dev_gpio_init(void); +#endif + +#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_SRC_RP23XX_PICO_H */ diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_userleds.c b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_userleds.c new file mode 100644 index 0000000000000..78981bb2cb369 --- /dev/null +++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_userleds.c @@ -0,0 +1,94 @@ +/**************************************************************************** + * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_userleds.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * The single LED on this board is wired to GPIO 0 of the CYW43439 wireless + * chip rather than to a pin of the RP2350, so setting it means sending an + * iovar request over the gSPI bus. Two consequences: + * + * - The LED only responds once the wireless chip is running, which happens + * when wlan0 is brought up. Before that every write fails with -EIO. + * - Writing the LED blocks, so it must not be done from interrupt context. + * That is why this board implements the user LED interface only and not + * the CONFIG_ARCH_LEDS auto-LED interface. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#if defined(CONFIG_RP23XX_INFINEON_CYW43439) && !defined(CONFIG_ARCH_LEDS) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_userled_initialize + ****************************************************************************/ + +uint32_t board_userled_initialize(void) +{ + /* Nothing to configure -- the LED lives on the wireless chip, which the + * board bringup has already set up. + */ + + return BOARD_NLEDS; +} + +/**************************************************************************** + * Name: board_userled + ****************************************************************************/ + +void board_userled(int led, bool ledon) +{ + if (led == BOARD_LED1) + { + int ret = rp23xx_extra_gpio_put(RP23XX_EXTRA_GPIO_LED, ledon); + + if (ret < 0) + { + lederr("ERROR: cannot reach the LED on the CYW43439: %d\n", ret); + } + } +} + +/**************************************************************************** + * Name: board_userled_all + ****************************************************************************/ + +void board_userled_all(uint32_t ledset) +{ + board_userled(BOARD_LED1, (ledset & BOARD_LED1_BIT) != 0); +} + +#endif /* CONFIG_RP23XX_INFINEON_CYW43439 && !CONFIG_ARCH_LEDS */