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))>; + }; + }; +};