From 6ac5a6a2bbb3654acc239b2e28850870d3816b60 Mon Sep 17 00:00:00 2001 From: Manuel Aebischer Date: Thu, 31 Oct 2024 13:57:47 +0100 Subject: [PATCH] drivers: flash: rpi_pico: Modifications to support rp2350 The exisiting flash driver had some quite complicated implementations for edge cases where partial pages where written. This commit modifies the driver to always use the flash_range_program function from boot ROM. This is a bit less efficient on partial page writes, but simplifies the code a lot and adds compatibility to the new rp2350. Signed-off-by: Manuel Aebischer --- boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi | 1 + drivers/flash/flash_rpi_pico.c | 212 +++--------------- dts/arm/raspberrypi/rpi_pico/rp2350.dtsi | 4 +- .../flash/common/boards/rpi_pico.overlay | 22 ++ .../flash/common/boards/rpi_pico2_m33.overlay | 22 ++ 5 files changed, 81 insertions(+), 180 deletions(-) create mode 100644 tests/drivers/flash/common/boards/rpi_pico.overlay create mode 100644 tests/drivers/flash/common/boards/rpi_pico2_m33.overlay diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi index 522413c94f1a..85defeb758c8 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi @@ -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; diff --git a/drivers/flash/flash_rpi_pico.c b/drivers/flash/flash_rpi_pico.c index de86ea7cdd70..0c70160690f0 100644 --- a/drivers/flash/flash_rpi_pico.c +++ b/drivers/flash/flash_rpi_pico.c @@ -13,180 +13,26 @@ #include #include #include -#include #include -#include -#include -#include -#include -#include -#include 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) +#define FLASH_BASE CONFIG_FLASH_BASE_ADDRESS 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); @@ -194,6 +40,8 @@ static bool is_valid_range(off_t offset, uint32_t 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; } @@ -210,35 +58,41 @@ static int flash_rpi_read(const struct device *dev, off_t offset, void *data, si static int flash_rpi_write(const struct device *dev, off_t offset, const void *data, size_t size) { - uint32_t key; - size_t bytes_to_write; - uint8_t *data_pointer = (uint8_t *)data; + ARG_UNUSED(dev); + + const uint8_t *data_pointer = (const uint8_t *)data; 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; } - key = irq_lock(); + uint32_t key = irq_lock(); - if ((offset & (PAGE_SIZE - 1)) > 0) { - bytes_to_write = MIN(PAGE_SIZE - (offset & (PAGE_SIZE - 1)), size); - memcpy(flash_ram_buffer, data_pointer, bytes_to_write); - flash_write_partial(offset, flash_ram_buffer, bytes_to_write); + off_t offset_within_page = offset & (PAGE_SIZE - 1); + + if (offset_within_page > 0) { + off_t page_offset = offset & ~(PAGE_SIZE - 1); + size_t bytes_to_write = MIN(PAGE_SIZE - offset_within_page, size); + + memcpy(flash_ram_buffer, (uint8_t *)(CONFIG_FLASH_BASE_ADDRESS + page_offset), + PAGE_SIZE); + memcpy(flash_ram_buffer + offset_within_page, data_pointer, bytes_to_write); + flash_range_program(page_offset, flash_ram_buffer, PAGE_SIZE); data_pointer += bytes_to_write; size -= bytes_to_write; offset += bytes_to_write; } while (size >= PAGE_SIZE) { - bytes_to_write = PAGE_SIZE; + size_t bytes_to_write = PAGE_SIZE; memcpy(flash_ram_buffer, data_pointer, bytes_to_write); - flash_range_program(offset, flash_ram_buffer, bytes_to_write); + flash_range_program(offset, flash_ram_buffer, PAGE_SIZE); data_pointer += bytes_to_write; size -= bytes_to_write; offset += bytes_to_write; @@ -246,7 +100,9 @@ static int flash_rpi_write(const struct device *dev, off_t offset, const void *d if (size > 0) { memcpy(flash_ram_buffer, data_pointer, size); - flash_write_partial(offset, flash_ram_buffer, size); + memcpy(flash_ram_buffer + size, + (uint8_t *)(CONFIG_FLASH_BASE_ADDRESS + offset + size), PAGE_SIZE - size); + flash_range_program(offset, flash_ram_buffer, PAGE_SIZE); } irq_unlock(key); @@ -256,25 +112,25 @@ static int flash_rpi_write(const struct device *dev, off_t offset, const void *d static int flash_rpi_erase(const struct device *dev, off_t offset, size_t size) { - uint32_t key; + ARG_UNUSED(dev); if (size == 0) { return 0; } 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; } - key = irq_lock(); + uint32_t key = irq_lock(); flash_range_erase(offset, size); @@ -298,7 +154,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; @@ -316,5 +172,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); diff --git a/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi b/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi index 62da179b6679..3d1f72d3a326 100644 --- a/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi +++ b/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi @@ -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>; @@ -202,7 +202,7 @@ write-block-size = <1>; erase-block-size = ; }; - status = "disabled"; + status = "okay"; }; reset: reset-controller@40020000 { diff --git a/tests/drivers/flash/common/boards/rpi_pico.overlay b/tests/drivers/flash/common/boards/rpi_pico.overlay new file mode 100644 index 000000000000..1b186732b4e8 --- /dev/null +++ b/tests/drivers/flash/common/boards/rpi_pico.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Manuel Aebischer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &code_partition; + +&flash0 { + partitions { + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (DT_SIZE_M(2) - 0x100)>; + read-only; + }; + + storage_partition: partition@20000 { + label = "storage-partition"; + reg = <0x20000 (DT_SIZE_M(2))>; + }; + }; +}; diff --git a/tests/drivers/flash/common/boards/rpi_pico2_m33.overlay b/tests/drivers/flash/common/boards/rpi_pico2_m33.overlay new file mode 100644 index 000000000000..1b186732b4e8 --- /dev/null +++ b/tests/drivers/flash/common/boards/rpi_pico2_m33.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Manuel Aebischer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &code_partition; + +&flash0 { + partitions { + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (DT_SIZE_M(2) - 0x100)>; + read-only; + }; + + storage_partition: partition@20000 { + label = "storage-partition"; + reg = <0x20000 (DT_SIZE_M(2))>; + }; + }; +};