Skip to content

Add support for Raspberry Pi Pico 2 flash controller. #89182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
chosen {
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,flash-controller = &qmi;
zephyr,console = &uart0;
zephyr,shell-uart = &uart0;
zephyr,code-partition = &code_partition;
Expand Down
179 changes: 14 additions & 165 deletions drivers/flash/flash_rpi_pico.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,187 +13,34 @@
#include <zephyr/drivers/flash.h>
#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
#include <zephyr/toolchain.h>

#include <hardware/flash.h>
#include <hardware/regs/io_qspi.h>
#include <hardware/regs/pads_qspi.h>
#include <hardware/structs/ssi.h>
#include <hardware/structs/xip_ctrl.h>
#include <hardware/resets.h>
#include <pico/bootrom.h>

LOG_MODULE_REGISTER(flash_rpi_pico, CONFIG_FLASH_LOG_LEVEL);

#define DT_DRV_COMPAT raspberrypi_pico_flash_controller

#define PAGE_SIZE 256
#define PAGE_SIZE 256
#define SECTOR_SIZE DT_PROP(DT_CHOSEN(zephyr_flash), erase_block_size)
#define ERASE_VALUE 0xff
#define FLASH_SIZE KB(CONFIG_FLASH_SIZE)
#define FLASH_BASE CONFIG_FLASH_BASE_ADDRESS
#define SSI_BASE_ADDRESS DT_REG_ADDR(DT_CHOSEN(zephyr_flash_controller))
#define FLASH_SIZE KB(CONFIG_FLASH_SIZE)

static const struct flash_parameters flash_rpi_parameters = {
.write_block_size = 1,
.erase_value = ERASE_VALUE,
};

/**
* Low level flash functions are based on:
* github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
* and
* github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_flash/flash.c
*/

#define FLASHCMD_PAGE_PROGRAM 0x02
#define FLASHCMD_READ_STATUS 0x05
#define FLASHCMD_WRITE_ENABLE 0x06
#define BOOT2_SIZE_WORDS 64

enum outover {
OUTOVER_NORMAL = 0,
OUTOVER_INVERT,
OUTOVER_LOW,
OUTOVER_HIGH
};

static ssi_hw_t *const ssi = (ssi_hw_t *)SSI_BASE_ADDRESS;
static uint32_t boot2_copyout[BOOT2_SIZE_WORDS];
static bool boot2_copyout_valid;
static uint8_t flash_ram_buffer[PAGE_SIZE];

static void __no_inline_not_in_flash_func(flash_init_boot2_copyout)(void)
{
if (boot2_copyout_valid) {
return;
}
for (int i = 0; i < BOOT2_SIZE_WORDS; ++i) {
boot2_copyout[i] = ((uint32_t *)FLASH_BASE)[i];
}
__compiler_memory_barrier();
boot2_copyout_valid = true;
}

static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void)
{
((void (*)(void))((uint32_t)boot2_copyout+1))();
}

void __no_inline_not_in_flash_func(flash_cs_force)(enum outover over)
{
io_rw_32 *reg = (io_rw_32 *) (IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SS_CTRL_OFFSET);
*reg = (*reg & ~IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS)
| (over << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB);
(void) *reg;
}

int __no_inline_not_in_flash_func(flash_was_aborted)()
{
return *(io_rw_32 *) (IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SD1_CTRL_OFFSET)
& IO_QSPI_GPIO_QSPI_SD1_CTRL_INOVER_BITS;
}

void __no_inline_not_in_flash_func(flash_put_get)(const uint8_t *tx, uint8_t *rx, size_t count,
size_t rx_skip)
{
const uint max_in_flight = 16 - 2;
size_t tx_count = count;
size_t rx_count = count;
bool did_something;
uint32_t tx_level;
uint32_t rx_level;
uint8_t rxbyte;

while (tx_count || rx_skip || rx_count) {
tx_level = ssi_hw->txflr;
rx_level = ssi_hw->rxflr;
did_something = false;
if (tx_count && tx_level + rx_level < max_in_flight) {
ssi->dr0 = (uint32_t) (tx ? *tx++ : 0);
--tx_count;
did_something = true;
}
if (rx_level) {
rxbyte = ssi->dr0;
did_something = true;
if (rx_skip) {
--rx_skip;
} else {
if (rx) {
*rx++ = rxbyte;
}
--rx_count;
}
}

if (!did_something && __builtin_expect(flash_was_aborted(), 0)) {
break;
}
}
flash_cs_force(OUTOVER_HIGH);
}

void __no_inline_not_in_flash_func(flash_put_get_wrapper)(uint8_t cmd, const uint8_t *tx,
uint8_t *rx, size_t count)
{
flash_cs_force(OUTOVER_LOW);
ssi->dr0 = cmd;
flash_put_get(tx, rx, count, 1);
}

static ALWAYS_INLINE void flash_put_cmd_addr(uint8_t cmd, uint32_t addr)
{
flash_cs_force(OUTOVER_LOW);
addr |= cmd << 24;
for (int i = 0; i < 4; ++i) {
ssi->dr0 = addr >> 24;
addr <<= 8;
}
}

void __no_inline_not_in_flash_func(flash_write_partial_internal)(uint32_t addr, const uint8_t *data,
size_t size)
{
uint8_t status_reg;

flash_put_get_wrapper(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0);
flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, addr);
flash_put_get(data, NULL, size, 4);

do {
flash_put_get_wrapper(FLASHCMD_READ_STATUS, NULL, &status_reg, 1);
} while (status_reg & 0x1 && !flash_was_aborted());
}

void __no_inline_not_in_flash_func(flash_write_partial)(uint32_t flash_offs, const uint8_t *data,
size_t count)
{
rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)
rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH);
rom_flash_exit_xip_fn exit_xip = (rom_flash_exit_xip_fn)
rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
rom_flash_flush_cache_fn flush_cache = (rom_flash_flush_cache_fn)
rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE);

flash_init_boot2_copyout();

__compiler_memory_barrier();

connect_internal_flash();
exit_xip();
flash_write_partial_internal(flash_offs, data, count);
flush_cache();
flash_enable_xip_via_boot2();
}

static bool is_valid_range(off_t offset, uint32_t size)
{
return (offset >= 0) && ((offset + size) <= FLASH_SIZE);
}

static int flash_rpi_read(const struct device *dev, off_t offset, void *data, size_t size)
{
ARG_UNUSED(dev);

if (size == 0) {
return 0;
}
Expand All @@ -214,13 +61,15 @@ static int flash_rpi_write(const struct device *dev, off_t offset, const void *d
size_t bytes_to_write;
uint8_t *data_pointer = (uint8_t *)data;

ARG_UNUSED(dev);

if (size == 0) {
return 0;
}

if (!is_valid_range(offset, size)) {
LOG_ERR("Write range exceeds the flash boundaries. Offset=%#lx, Size=%u",
offset, size);
LOG_ERR("Write range exceeds the flash boundaries. Offset=%#lx, Size=%u", offset,
size);
return -EINVAL;
}

Expand Down Expand Up @@ -263,14 +112,14 @@ static int flash_rpi_erase(const struct device *dev, off_t offset, size_t size)
}

if (!is_valid_range(offset, size)) {
LOG_ERR("Erase range exceeds the flash boundaries. Offset=%#lx, Size=%u",
offset, size);
LOG_ERR("Erase range exceeds the flash boundaries. Offset=%#lx, Size=%u", offset,
size);
return -EINVAL;
}

if ((offset % SECTOR_SIZE) || (size % SECTOR_SIZE)) {
LOG_ERR("Erase range is not a multiple of the sector size. Offset=%#lx, Size=%u",
offset, size);
offset, size);
return -EINVAL;
}

Expand Down Expand Up @@ -298,7 +147,7 @@ static const struct flash_pages_layout flash_rpi_pages_layout = {
};

void flash_rpi_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
size_t *layout_size)
size_t *layout_size)
{
*layout = &flash_rpi_pages_layout;
*layout_size = 1;
Expand All @@ -316,5 +165,5 @@ static DEVICE_API(flash, flash_rpi_driver_api) = {
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
};

DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL,
CONFIG_FLASH_INIT_PRIORITY, &flash_rpi_driver_api);
DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY,
&flash_rpi_driver_api);
3 changes: 1 addition & 2 deletions dts/arm/raspberrypi/rpi_pico/rp2350.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@

qmi: flash-controller@400d0000 {
compatible = "raspberrypi,pico-flash-controller";
reg = <0x400d0000 0xfc>;
reg = <0x400d0000 0x54>;

#address-cells = <1>;
#size-cells = <1>;
Expand All @@ -202,7 +202,6 @@
write-block-size = <1>;
erase-block-size = <DT_SIZE_K(4)>;
};
status = "disabled";
};

reset: reset-controller@40020000 {
Expand Down
2 changes: 1 addition & 1 deletion west.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ manifest:
- hal
- name: hal_rpi_pico
path: modules/hal/rpi_pico
revision: 7b57b24588797e6e7bf18b6bda168e6b96374264
revision: 5a981c7c29e3846646549a1902183684f0147e1d
groups:
- hal
- name: hal_silabs
Expand Down