mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
rp23xx: Add external QSPI PSRAM (APS6404) support for the Pimoroni Pico Plus 2.
Adds a driver for the external QSPI PSRAM hanging off QMI chip select 1, such as the 8 MiB APS6404 fitted on the Pimoroni Pico Plus 2. rp23xx_psramconfig() assigns the CS1 pin, reads the device ID over the QMI direct interface to confirm an APS6404-family part (KGD 0x5D), resets it into quad mode and programs the QMI M1 timing/read/write formats so the region at 0x11000000 becomes directly addressable and writable. Because driving the QMI in direct mode stalls execute-in-place from the flash, the detection and (re)configuration code runs from RAM (.time_critical) with interrupts disabled; the command bytes are selected with immediates rather than a .rodata table for the same reason. The register values follow the Raspberry Pi Pico SDK setup_psram(). The detection routine only keeps the QMI DIRECT_CSR synchronization that is strictly necessary. Each candidate busy-wait was removed one at a time and re-verified on hardware: the post-enable "cooldown" waits, the READ_ID TXEMPTY wait (redundant with the BUSY wait after it), and a fixed nop delay proved unnecessary and are omitted. The three BUSY waits that remain -- after the quad-mode nudge, after each READ_ID byte, and after each reset/quad-enable command -- are required and carry a comment explaining that the frame must finish shifting before the chip select is deasserted, and what breaks otherwise (garbage ID reads, or the shared QMI bus wedging). rp23xx_psram_restore() re-applies the M1 configuration and is meant to be called from the flash write path, which goes through the bootrom and reconfigures the shared QMI for chip select 0. rp23xx_heaps.c is wired into the build and now uses the detected size, so the PSRAM is exposed to the memory manager (added to the main heap, used as a separate heap, or as the user heap) and is skipped cleanly when no PSRAM is present. Enabled by default on the pimoroni-pico-2-plus:nsh configuration, where it adds the 8 MiB to the main heap. A documentation page for the Pimoroni Pico Plus 2 is added alongside the other rp23xx boards, covering its serial console, LED, the external PSRAM and how it is exposed to the heap, the supported capabilities and the available configurations, with a photo of the board. Tested on Pimoroni Pico Plus 2 hardware: detection reports the 8 MiB APS6404, the region is read/write across its whole range (ramtest word, half-word and byte passes, marching/pattern/address-in-address), and the heap reports the extra 8 MiB. Assisted-by: Claude Code:claude-opus-4-8 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
parent
5fd518a27c
commit
8770fbea0f
10 changed files with 691 additions and 8 deletions
|
|
@ -0,0 +1,172 @@
|
|||
===============================
|
||||
Pimoroni Pico Plus 2
|
||||
===============================
|
||||
|
||||
.. tags:: chip:rp2350
|
||||
|
||||
The `Pimoroni Pico Plus 2 <https://shop.pimoroni.com/products/pimoroni-pico-plus-2>`_
|
||||
is an RP2350B based board in the Raspberry Pi Pico form factor, with a
|
||||
USB-C connector, a large 16 MiB of flash and 8 MiB of external QSPI PSRAM.
|
||||
|
||||
.. figure:: pico-plus-2.jpg
|
||||
:align: center
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
* RP2350B microcontroller chip (QFN-80 variant)
|
||||
* Dual-core Arm Cortex-M33 processor running up to 150 MHz
|
||||
* 520 KiB of internal SRAM
|
||||
* 16 MiB of on-board QSPI flash memory
|
||||
* 8 MiB of on-board QSPI PSRAM (APS6404) on chip select 1
|
||||
* USB-C connector, USB 1.1 host and device support
|
||||
* Qwiic / STEMMA QT (I2C) connector
|
||||
* SP/CE debug and expansion connectors
|
||||
* Reset and BOOTSEL buttons
|
||||
* 48 multi-function GPIO pins broken out on castellated and through-hole pads
|
||||
* Drag & drop programming using mass storage over USB
|
||||
* 12 Programmable IO (PIO) state machines for custom peripheral support
|
||||
|
||||
Serial Console
|
||||
==============
|
||||
|
||||
By default a serial console appears on GPIO0 (TX) and GPIO1 (RX). This
|
||||
console runs at 115200-8N1.
|
||||
|
||||
The board can be configured to use the USB connection as the serial console.
|
||||
See the ``usbnsh`` configuration.
|
||||
|
||||
Buttons and LEDs
|
||||
================
|
||||
|
||||
The user LED is controlled by GPIO25 and is configured as autoled by default.
|
||||
|
||||
A BOOTSEL button, which if held down when power is first applied to the board,
|
||||
will cause the RP2350 to boot into programming mode and appear as a storage
|
||||
device to the computer connected via USB. Saving a ``.uf2`` file to this
|
||||
device will replace the flash contents. A separate RESET button is also
|
||||
provided.
|
||||
|
||||
PSRAM
|
||||
=====
|
||||
|
||||
The distinguishing feature of the Pimoroni Pico Plus 2 is the 8 MiB of
|
||||
external QSPI PSRAM (an APS6404 part) hanging off the QMI on chip select 1
|
||||
(GPIO47). NuttX detects the PSRAM at boot, switches it to quad mode and
|
||||
maps it read/write at ``0x11000000``.
|
||||
|
||||
PSRAM support is enabled by default in the ``nsh`` configuration
|
||||
(``CONFIG_RP23XX_PSRAM``), which adds the 8 MiB to the main heap. The
|
||||
chip select pin is configured with ``CONFIG_RP23XX_PSRAM_CS1_GPIO`` (47 on
|
||||
this board) and the way the PSRAM is exposed to the memory manager (single
|
||||
heap, separate heap, or user heap) is selectable. See the
|
||||
:doc:`RP23xx PSRAM section <../../index>` for the details of each mode.
|
||||
|
||||
.. note::
|
||||
|
||||
The PSRAM is considerably slower than the internal SRAM. The QMI is
|
||||
shared with the flash: writing to the flash goes through the bootrom,
|
||||
which reconfigures the QMI for chip select 0 and disturbs the PSRAM
|
||||
configuration on chip select 1. ``rp23xx_psram_restore()`` re-applies it
|
||||
and is intended to be called from the flash write path after each erase or
|
||||
program.
|
||||
|
||||
Supported Capabilities
|
||||
======================
|
||||
|
||||
NuttX supports the following Pico Plus 2 capabilities:
|
||||
|
||||
* UART (console port)
|
||||
|
||||
* GPIO 0 (UART0 TX) and GPIO 1 (UART0 RX) are used for the console.
|
||||
|
||||
* External QSPI PSRAM (8 MiB)
|
||||
* I2C
|
||||
* SPI (master only)
|
||||
* DMAC
|
||||
* PWM
|
||||
* ADC
|
||||
* Watchdog
|
||||
* USB device
|
||||
|
||||
* MSC, CDC/ACM serial and composite devices are supported.
|
||||
* CDC/ACM serial device can be used for the console.
|
||||
|
||||
* PIO (RP2350 Programmable I/O)
|
||||
* Flash ROM Boot
|
||||
* SRAM Boot
|
||||
|
||||
* If the Pico SDK is available, a ``nuttx.uf2`` file which can be used in
|
||||
BOOTSEL mode will be created.
|
||||
|
||||
* Persistent flash filesystem in unused flash ROM
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
1. Download and install the toolchain and, optionally, the Raspberry Pi
|
||||
Pico SDK (needed to generate the ``nuttx.uf2`` image).
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ git clone -b 2.2.0 --recurse-submodules https://github.com/raspberrypi/pico-sdk.git
|
||||
$ export PICO_SDK_PATH=<absolute_path_to_pico-sdk_directory>
|
||||
|
||||
2. Configure and build NuttX
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ git clone https://github.com/apache/nuttx.git nuttx
|
||||
$ git clone https://github.com/apache/nuttx-apps.git apps
|
||||
$ cd nuttx
|
||||
$ make distclean
|
||||
$ ./tools/configure.sh pimoroni-pico-2-plus:nsh
|
||||
$ make V=1
|
||||
|
||||
3. Connect the board to the USB port while pressing BOOTSEL. The board will
|
||||
be detected as a USB Mass Storage Device. Then copy ``nuttx.uf2`` into
|
||||
the device (the same way as standard Pico SDK applications).
|
||||
|
||||
4. To access the console, connect GPIO 0 and 1 to a device such as a
|
||||
USB-serial converter, or use the ``usbnsh`` configuration for a console
|
||||
over USB CDC/ACM.
|
||||
|
||||
Configurations
|
||||
==============
|
||||
|
||||
nsh
|
||||
---
|
||||
|
||||
Basic NuttShell configuration (console enabled on UART0, at 115200 bps) with
|
||||
the external PSRAM added to the main heap.
|
||||
|
||||
usbnsh
|
||||
------
|
||||
|
||||
Basic NuttShell configuration (console enabled via USB CDC/ACM).
|
||||
|
||||
smp
|
||||
---
|
||||
|
||||
Basic NuttShell configuration (console enabled on UART0, at 115200 bps) with
|
||||
both Arm cores enabled.
|
||||
|
||||
audiopack
|
||||
---------
|
||||
|
||||
Configuration for the Pimoroni Pico Audio Pack.
|
||||
|
||||
composite
|
||||
---------
|
||||
|
||||
USB composite device configuration.
|
||||
|
||||
usbmsc
|
||||
------
|
||||
|
||||
USB mass storage device configuration.
|
||||
|
||||
userled
|
||||
-------
|
||||
|
||||
Configuration demonstrating user-controlled LED access.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 320 KiB |
|
|
@ -105,4 +105,8 @@ if(CONFIG_RP23XX_FLASH_MTD)
|
|||
list(APPEND SRCS rp23xx_flash_mtd.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_RP23XX_PSRAM)
|
||||
list(APPEND SRCS rp23xx_psram.c rp23xx_heaps.c)
|
||||
endif()
|
||||
|
||||
target_sources(arch PRIVATE ${SRCS})
|
||||
|
|
|
|||
|
|
@ -9,6 +9,51 @@ config RP23XX_RP2350B
|
|||
bool "Use RP2350B variant (QFN-80)"
|
||||
default n
|
||||
|
||||
config RP23XX_PSRAM
|
||||
bool "External QSPI PSRAM"
|
||||
default n
|
||||
---help---
|
||||
Enable support for external QSPI PSRAM connected to QMI chip
|
||||
select 1, such as the 8 MiB APS6404 fitted on the Pimoroni Pico
|
||||
Plus 2. The chip is detected and switched to quad mode at boot,
|
||||
after which it is directly addressable and writable at
|
||||
0x11000000. Configure the chip-select pin under the Board
|
||||
Selection menu (RP23XX_PSRAM_CS1_GPIO).
|
||||
|
||||
if RP23XX_PSRAM
|
||||
|
||||
choice
|
||||
prompt "PSRAM heap usage"
|
||||
default RP23XX_PSRAM_HEAP_SINGLE
|
||||
---help---
|
||||
How the detected PSRAM is exposed to the memory manager.
|
||||
|
||||
config RP23XX_PSRAM_HEAP_SINGLE
|
||||
bool "Add PSRAM to the main heap"
|
||||
depends on !MM_KERNEL_HEAP
|
||||
---help---
|
||||
Add the PSRAM region to the main heap. Requires
|
||||
CONFIG_MM_REGIONS greater than 1 so the extra region can be
|
||||
registered.
|
||||
|
||||
config RP23XX_PSRAM_HEAP_USER
|
||||
bool "PSRAM as the user heap"
|
||||
depends on MM_KERNEL_HEAP
|
||||
---help---
|
||||
Use the PSRAM as the (user) heap and the internal SRAM as the
|
||||
kernel heap.
|
||||
|
||||
config RP23XX_PSRAM_HEAP_SEPARATE
|
||||
bool "Separate PSRAM heap"
|
||||
select ARCH_HAVE_EXTRA_HEAPS
|
||||
---help---
|
||||
Expose the PSRAM as a separate named heap ("psram") rather than
|
||||
adding it to the main heap.
|
||||
|
||||
endchoice
|
||||
|
||||
endif # RP23XX_PSRAM
|
||||
|
||||
config RP23XX_DMAC
|
||||
bool "DMAC support"
|
||||
default y
|
||||
|
|
|
|||
|
|
@ -108,3 +108,8 @@ endif
|
|||
ifeq ($(CONFIG_RP23XX_FLASH_MTD),y)
|
||||
CHIP_CSRCS += rp23xx_flash_mtd.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RP23XX_PSRAM),y)
|
||||
CHIP_CSRCS += rp23xx_psram.c
|
||||
CHIP_CSRCS += rp23xx_heaps.c
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@
|
|||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The QMI registers share the XIP-QMI peripheral base. */
|
||||
|
||||
#define RP23XX_QMI_BASE RP23XX_XIP_QMI_BASE
|
||||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
#define RP23XX_QMI_DIRECT_CSR_OFFSET 0x00000000
|
||||
|
|
|
|||
|
|
@ -30,15 +30,21 @@
|
|||
#include <nuttx/mm/mm.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "rp23xx_psram.h"
|
||||
|
||||
#if defined(CONFIG_RP23XX_PSRAM)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
static void * const psram_start = (void *)0x11000000ul;
|
||||
static const size_t psram_size = 8 * 1024 * 1024;
|
||||
/* The PSRAM base address is fixed; the size is whatever rp23xx_psramconfig()
|
||||
* detected at boot (0 if no PSRAM is fitted). psramconfig() runs from
|
||||
* rp23xx_boardinitialize(), before any of the heap hooks below, so the
|
||||
* detected size is always available here.
|
||||
*/
|
||||
|
||||
#define PSRAM_START ((void *)RP23XX_PSRAM_BASE)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
|
@ -56,9 +62,14 @@ static struct mm_heap_s *g_psramheap;
|
|||
#if CONFIG_MM_REGIONS > 1
|
||||
void arm_addregion(void)
|
||||
{
|
||||
/* Add the PSRAM region to main heap */
|
||||
size_t psram_size = rp23xx_psram_size();
|
||||
|
||||
kumm_addregion(psram_start, psram_size);
|
||||
/* Add the detected PSRAM region to the main heap */
|
||||
|
||||
if (psram_size > 0)
|
||||
{
|
||||
kumm_addregion(PSRAM_START, psram_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -85,8 +96,8 @@ void up_allocate_kheap(void **heap_start, size_t *heap_size)
|
|||
|
||||
void up_allocate_heap(void **heap_start, size_t *heap_size)
|
||||
{
|
||||
*heap_start = psram_start;
|
||||
*heap_size = psram_size;
|
||||
*heap_start = PSRAM_START;
|
||||
*heap_size = rp23xx_psram_size();
|
||||
}
|
||||
|
||||
#elif defined (CONFIG_RP23XX_PSRAM_HEAP_SEPARATE)
|
||||
|
|
@ -97,7 +108,12 @@ void up_allocate_heap(void **heap_start, size_t *heap_size)
|
|||
|
||||
void up_extraheaps_init(void)
|
||||
{
|
||||
g_psramheap = mm_initialize("psram", psram_start, psram_size);
|
||||
size_t psram_size = rp23xx_psram_size();
|
||||
|
||||
if (psram_size > 0)
|
||||
{
|
||||
g_psramheap = mm_initialize("psram", PSRAM_START, psram_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
346
arch/arm/src/rp23xx/rp23xx_psram.c
Normal file
346
arch/arm/src/rp23xx/rp23xx_psram.c
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rp23xx/rp23xx_psram.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
|
||||
*
|
||||
* Driver for the external QSPI PSRAM (an APS6404-family part) fitted on
|
||||
* boards such as the Pimoroni Pico Plus 2. It hangs off QMI chip select 1
|
||||
* and, once configured, is directly addressable and writable at
|
||||
* RP23XX_PSRAM_BASE (0x11000000).
|
||||
*
|
||||
* The QMI is the same serial interface that serves execute-in-place from the
|
||||
* flash on chip select 0. Reprogramming it uses direct (non-XIP) mode,
|
||||
* which stalls all XIP fetches, so the detection and configuration code must
|
||||
* run from RAM with interrupts disabled -- hence the .time_critical section,
|
||||
* which the board linker scripts copy to RAM. The sequence follows the
|
||||
* Raspberry Pi Pico SDK's setup_psram().
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "rp23xx_gpio.h"
|
||||
#include "rp23xx_psram.h"
|
||||
#include "hardware/rp23xx_qmi.h"
|
||||
#include "hardware/rp23xx_xip.h"
|
||||
#include "hardware/rp23xx_memorymap.h"
|
||||
|
||||
#ifdef CONFIG_RP23XX_PSRAM
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Detection and (re)configuration touch the QMI in direct mode, which stalls
|
||||
* execute-in-place from the flash. The code that does so must therefore run
|
||||
* from RAM: the board linker scripts copy the .time_critical section there.
|
||||
*/
|
||||
|
||||
#define RP23XX_PSRAM_RAMFUNC \
|
||||
__attribute__((section(".time_critical.rp23xx_psram"), noinline))
|
||||
|
||||
/* GPIO function select for the XIP chip-select-1 line (PSRAM). */
|
||||
|
||||
#define RP23XX_GPIO_FUNC_XIP_CS1 9
|
||||
|
||||
/* PSRAM interface width for direct-mode transfers (quad). */
|
||||
|
||||
#define QMI_DIRECT_TX_IWIDTH_Q (2 << RP23XX_QMI_DIRECT_TX_IWIDTH_SHIFT)
|
||||
|
||||
/* Final QMI M1 register values for the APS6404 in quad mode. Computed from
|
||||
* the field layout in the RP2350 datasheet to match the Pico SDK:
|
||||
*
|
||||
* TIMING: COOLDOWN=1, PAGEBREAK=1024, SELECT_HOLD=3, MAX_SELECT=16,
|
||||
* MIN_DESELECT=7, RXDELAY=1, CLKDIV=2.
|
||||
* RFMT: quad prefix/addr/suffix/dummy/data, 8-bit prefix, 24 dummy bits.
|
||||
* RCMD: read prefix 0xeb.
|
||||
* WFMT: quad prefix/addr/suffix/dummy/data, 8-bit prefix, no dummy.
|
||||
* WCMD: write prefix 0x38.
|
||||
*/
|
||||
|
||||
#define RP23XX_PSRAM_M1_TIMING 0x61a07102
|
||||
#define RP23XX_PSRAM_M1_RFMT 0x000612aa
|
||||
#define RP23XX_PSRAM_M1_RCMD 0x000000eb
|
||||
#define RP23XX_PSRAM_M1_WFMT 0x000012aa
|
||||
#define RP23XX_PSRAM_M1_WCMD 0x00000038
|
||||
|
||||
/* APS6404 SPI opcodes used during detection and mode switching. */
|
||||
|
||||
#define PSRAM_CMD_READ_ID 0x9f
|
||||
#define PSRAM_CMD_RSTEN 0x66
|
||||
#define PSRAM_CMD_RST 0x99
|
||||
#define PSRAM_CMD_QUAD_ENABLE 0x35
|
||||
|
||||
#define PSRAM_KGD_PASS 0x5d
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static size_t g_psram_size;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_psram_apply_format
|
||||
*
|
||||
* Description:
|
||||
* Program the QMI M1 timing/format/command registers and mark the region
|
||||
* writable. Shared by the initial configuration and the post-flash
|
||||
* restore. Runs from RAM.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void RP23XX_PSRAM_RAMFUNC
|
||||
rp23xx_psram_apply_format(void)
|
||||
{
|
||||
putreg32(RP23XX_PSRAM_M1_TIMING, RP23XX_QMI_M1_TIMING);
|
||||
putreg32(RP23XX_PSRAM_M1_RFMT, RP23XX_QMI_M1_RFMT);
|
||||
putreg32(RP23XX_PSRAM_M1_RCMD, RP23XX_QMI_M1_RCMD);
|
||||
putreg32(RP23XX_PSRAM_M1_WFMT, RP23XX_QMI_M1_WFMT);
|
||||
putreg32(RP23XX_PSRAM_M1_WCMD, RP23XX_QMI_M1_WCMD);
|
||||
|
||||
/* Allow the memory-mapped window to accept writes. */
|
||||
|
||||
putreg32(getreg32(RP23XX_XIP_CTRL_BASE) | RP23XX_XIP_CTRL_WRITABLE_M1,
|
||||
RP23XX_XIP_CTRL_BASE);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_psram_detect
|
||||
*
|
||||
* Description:
|
||||
* Read the PSRAM device ID over the QMI direct interface and return the
|
||||
* detected size in bytes, or 0 if the part does not respond correctly.
|
||||
* Runs from RAM with the caller holding interrupts disabled.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static size_t RP23XX_PSRAM_RAMFUNC
|
||||
rp23xx_psram_detect(void)
|
||||
{
|
||||
uint8_t kgd = 0;
|
||||
uint8_t eid = 0;
|
||||
size_t size;
|
||||
size_t i;
|
||||
|
||||
/* Enable direct mode at a conservative clock divisor. No BUSY wait is
|
||||
* needed for the previous XIP transfer's cooldown: it drains before the
|
||||
* first chip-select assertion below (verified on hardware).
|
||||
*/
|
||||
|
||||
putreg32((30 << RP23XX_QMI_DIRECT_CSR_CLKDIV_SHIFT) |
|
||||
RP23XX_QMI_DIRECT_CSR_EN, RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
/* Nudge the part out of any quad-continuation mode left by a prior init by
|
||||
* clocking one quad byte with CS asserted.
|
||||
*/
|
||||
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) |
|
||||
RP23XX_QMI_DIRECT_CSR_ASSERT_CS1N, RP23XX_QMI_DIRECT_CSR);
|
||||
putreg32(RP23XX_QMI_DIRECT_TX_OE | QMI_DIRECT_TX_IWIDTH_Q | 0xf5,
|
||||
RP23XX_QMI_DIRECT_TX);
|
||||
|
||||
/* This BUSY wait is required: the frame must finish shifting before the
|
||||
* chip select is deasserted, else the nudge is truncated, the part stays
|
||||
* in quad-continuation mode, and the ID read below returns garbage so
|
||||
* detection fails (verified on hardware).
|
||||
*/
|
||||
|
||||
while ((getreg32(RP23XX_QMI_DIRECT_CSR) & RP23XX_QMI_DIRECT_CSR_BUSY) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
(void)getreg32(RP23XX_QMI_DIRECT_RX);
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) &
|
||||
~RP23XX_QMI_DIRECT_CSR_ASSERT_CS1N, RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
/* Read the identification: command 0x9f followed by six bytes. The
|
||||
* Known-Good-Die marker is byte 5 and the size code is byte 6.
|
||||
*/
|
||||
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) |
|
||||
RP23XX_QMI_DIRECT_CSR_ASSERT_CS1N, RP23XX_QMI_DIRECT_CSR);
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
putreg32(i == 0 ? PSRAM_CMD_READ_ID : 0xff, RP23XX_QMI_DIRECT_TX);
|
||||
|
||||
/* This BUSY wait is required: the byte must finish shifting in before
|
||||
* DIRECT_RX is read, else the KGD/EID bytes are sampled early as
|
||||
* garbage and detection fails (verified on hardware). A TXEMPTY wait
|
||||
* ahead of it is redundant -- BUSY already covers the whole transfer.
|
||||
*/
|
||||
|
||||
while ((getreg32(RP23XX_QMI_DIRECT_CSR) &
|
||||
RP23XX_QMI_DIRECT_CSR_BUSY) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
if (i == 5)
|
||||
{
|
||||
kgd = (uint8_t)getreg32(RP23XX_QMI_DIRECT_RX);
|
||||
}
|
||||
else if (i == 6)
|
||||
{
|
||||
eid = (uint8_t)getreg32(RP23XX_QMI_DIRECT_RX);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)getreg32(RP23XX_QMI_DIRECT_RX);
|
||||
}
|
||||
}
|
||||
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) &
|
||||
~(RP23XX_QMI_DIRECT_CSR_ASSERT_CS1N | RP23XX_QMI_DIRECT_CSR_EN),
|
||||
RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
if (kgd != PSRAM_KGD_PASS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset the device and place it in quad mode: RSTEN, RST, quad-enable. */
|
||||
|
||||
putreg32((30 << RP23XX_QMI_DIRECT_CSR_CLKDIV_SHIFT) |
|
||||
RP23XX_QMI_DIRECT_CSR_EN, RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
/* The command byte is selected with a ternary rather than a lookup
|
||||
* table on purpose: a "static const" array is emitted to .rodata in
|
||||
* flash, and reading it here -- while the QMI is in direct mode and
|
||||
* flash is inaccessible -- would fault. An immediate keeps it in RAM.
|
||||
*/
|
||||
|
||||
uint8_t cmd = (i == 0) ? PSRAM_CMD_RSTEN :
|
||||
(i == 1) ? PSRAM_CMD_RST :
|
||||
PSRAM_CMD_QUAD_ENABLE;
|
||||
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) |
|
||||
RP23XX_QMI_DIRECT_CSR_ASSERT_CS1N, RP23XX_QMI_DIRECT_CSR);
|
||||
putreg32(cmd, RP23XX_QMI_DIRECT_TX);
|
||||
|
||||
/* This BUSY wait is required: the command must finish shifting before
|
||||
* the chip select is deasserted. Cutting it short truncates the
|
||||
* RSTEN/RST/quad-enable commands, so the part is not reset into quad
|
||||
* mode and later accesses fail or wedge the shared QMI bus (verified
|
||||
* on hardware). No extra settling delay is needed after CS deassert:
|
||||
* the QMI's own minimum-deselect timing covers it.
|
||||
*/
|
||||
|
||||
while ((getreg32(RP23XX_QMI_DIRECT_CSR) &
|
||||
RP23XX_QMI_DIRECT_CSR_BUSY) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) &
|
||||
~RP23XX_QMI_DIRECT_CSR_ASSERT_CS1N, RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
(void)getreg32(RP23XX_QMI_DIRECT_RX);
|
||||
}
|
||||
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) &
|
||||
~(RP23XX_QMI_DIRECT_CSR_ASSERT_CS1N | RP23XX_QMI_DIRECT_CSR_EN),
|
||||
RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
/* Decode the size from the EID byte (APS6404 family). */
|
||||
|
||||
size = 1024 * 1024;
|
||||
if (eid == 0x26 || (eid >> 5) == 2)
|
||||
{
|
||||
size *= 8;
|
||||
}
|
||||
else if ((eid >> 5) == 0)
|
||||
{
|
||||
size *= 2;
|
||||
}
|
||||
else if ((eid >> 5) == 1)
|
||||
{
|
||||
size *= 4;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_psramconfig
|
||||
****************************************************************************/
|
||||
|
||||
size_t RP23XX_PSRAM_RAMFUNC
|
||||
rp23xx_psramconfig(void)
|
||||
{
|
||||
irqstate_t flags;
|
||||
size_t size;
|
||||
|
||||
rp23xx_gpio_set_function(CONFIG_RP23XX_PSRAM_CS1_GPIO,
|
||||
RP23XX_GPIO_FUNC_XIP_CS1);
|
||||
|
||||
flags = up_irq_save();
|
||||
|
||||
size = rp23xx_psram_detect();
|
||||
if (size != 0)
|
||||
{
|
||||
rp23xx_psram_apply_format();
|
||||
}
|
||||
|
||||
up_irq_restore(flags);
|
||||
|
||||
g_psram_size = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_psram_size
|
||||
****************************************************************************/
|
||||
|
||||
size_t rp23xx_psram_size(void)
|
||||
{
|
||||
return g_psram_size;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_psram_restore
|
||||
****************************************************************************/
|
||||
|
||||
void RP23XX_PSRAM_RAMFUNC
|
||||
rp23xx_psram_restore(void)
|
||||
{
|
||||
if (g_psram_size != 0)
|
||||
{
|
||||
rp23xx_psram_apply_format();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RP23XX_PSRAM */
|
||||
89
arch/arm/src/rp23xx/rp23xx_psram.h
Normal file
89
arch/arm/src/rp23xx/rp23xx_psram.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rp23xx/rp23xx_psram.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_PSRAM_H
|
||||
#define __ARCH_ARM_SRC_RP23XX_RP23XX_PSRAM_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The QSPI PSRAM is mapped through QMI chip select 1 at this address */
|
||||
|
||||
#define RP23XX_PSRAM_BASE 0x11000000
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_psramconfig
|
||||
*
|
||||
* Description:
|
||||
* Detect and initialise the external QSPI PSRAM on QMI chip select 1.
|
||||
* Assigns the CS1 function to CONFIG_RP23XX_PSRAM_CS1_GPIO, reads the
|
||||
* device ID to confirm an APS6404-family part is present, switches it to
|
||||
* quad mode and programs the QMI M1 read/write formats so the region at
|
||||
* RP23XX_PSRAM_BASE becomes directly addressable (and writable).
|
||||
*
|
||||
* Returned Value:
|
||||
* The size of the detected PSRAM in bytes, or 0 if no PSRAM was found.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
size_t rp23xx_psramconfig(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_psram_size
|
||||
*
|
||||
* Description:
|
||||
* Return the size in bytes detected by the last rp23xx_psramconfig(), or 0
|
||||
* if PSRAM is absent or has not been configured.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
size_t rp23xx_psram_size(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_psram_restore
|
||||
*
|
||||
* Description:
|
||||
* Re-apply the QMI M1 (PSRAM) format and timing registers. Programming
|
||||
* the flash goes through the bootrom, which reconfigures the shared QMI
|
||||
* interface for chip select 0; this restores the CS1 configuration
|
||||
* afterwards so the memory-mapped PSRAM keeps working across a flash
|
||||
* erase or program. Runs from RAM and does nothing when no PSRAM was
|
||||
* detected.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp23xx_psram_restore(void);
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_RP23XX_RP23XX_PSRAM_H */
|
||||
|
|
@ -28,12 +28,14 @@ CONFIG_EXAMPLES_HELLO=y
|
|||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_FS_PROCFS_REGISTER=y
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_MM_REGIONS=2
|
||||
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_RP23XX_PSRAM=y
|
||||
CONFIG_RR_INTERVAL=200
|
||||
CONFIG_SCHED_WAITPID=y
|
||||
CONFIG_START_DAY=9
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue