Skip to content

Commit

Permalink
Bulk operation optimisation.
Browse files Browse the repository at this point in the history
  • Loading branch information
tzarc committed Jul 1, 2022
1 parent ba3d230 commit 8fe4781
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 63 deletions.
22 changes: 11 additions & 11 deletions docs/platformdev_rp2040.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

The following table shows the current driver status for peripherals on RP2040 MCUs:

| System | Support |
| ------------------------------------ | ---------------------------------------------- |
| [ADC driver](adc_driver.md) | Support planned (no ETA) |
| [Audio](audio_driver.md) | Support planned (no ETA) |
| [I2C driver](i2c_driver.md) | :heavy_check_mark: |
| [SPI driver](spi_driver.md) | :heavy_check_mark: |
| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver |
| [External EEPROMs](eeprom_driver.md) | :heavy_check_mark: using `I2C` or `SPI` driver |
| [EEPROM emulation](eeprom_driver.md) | Support planned (no ETA) |
| [serial driver](serial_driver.md) | :heavy_check_mark: using `SIO` or `PIO` driver |
| [UART driver](uart_driver.md) | Support planned (no ETA) |
| System | Support |
| ---------------------------------------------------------------- | ---------------------------------------------- |
| [ADC driver](adc_driver.md) | Support planned (no ETA) |
| [Audio](audio_driver.md) | Support planned (no ETA) |
| [I2C driver](i2c_driver.md) | :heavy_check_mark: |
| [SPI driver](spi_driver.md) | :heavy_check_mark: |
| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver |
| [External EEPROMs](eeprom_driver.md) | :heavy_check_mark: using `I2C` or `SPI` driver |
| [EEPROM emulation](eeprom_driver.md#wear_leveling-configuration) | :heavy_check_mark: |
| [serial driver](serial_driver.md) | :heavy_check_mark: using `SIO` or `PIO` driver |
| [UART driver](uart_driver.md) | Support planned (no ETA) |

## GPIO

Expand Down
104 changes: 58 additions & 46 deletions platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
* Copyright (c) 2022 Nick Brassel (@tzarc)
* Copyright (c) 2022 Stefan Kerkmann (@KarlK90)
*
* SPDX-License-Identifier: BSD-3-Clause
*/
Expand All @@ -11,32 +12,30 @@
#include "hardware/structs/ssi.h"
#include "hardware/structs/ioqspi.h"

#define BOOT2_SIZE_WORDS 64
#include <stdbool.h>
#include "timer.h"
#include "wear_leveling.h"
#include "wear_leveling_internal.h"

#ifndef WEAR_LEVELING_RP2040_FLASH_BULK_COUNT
# define WEAR_LEVELING_RP2040_FLASH_BULK_COUNT 64
#endif // WEAR_LEVELING_RP2040_FLASH_BULK_COUNT

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

extern uint8_t BOOT2_ROM[256];
static uint32_t BOOT2_ROM_RAM[64];

static ssi_hw_t *const ssi = (ssi_hw_t *)XIP_SSI_BASE;

// Sanity check
#undef static_assert
#define static_assert _Static_assert
check_hw_layout(ssi_hw_t, ssienr, SSI_SSIENR_OFFSET);
check_hw_layout(ssi_hw_t, spi_ctrlr0, SSI_SPI_CTRLR0_OFFSET);

static uint32_t boot2_copyout[BOOT2_SIZE_WORDS];
static bool boot2_copyout_valid = false;

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 *)XIP_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))boot2_copyout + 1)();
((void (*)(void))BOOT2_ROM_RAM + 1)();
}

// Bitbanging the chip select using IO overrides, in case RAM-resident IRQs
Expand Down Expand Up @@ -126,41 +125,44 @@ static void __no_inline_not_in_flash_func(flash_enable_write)(void) {
_flash_do_cmd(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0);
}

static void __no_inline_not_in_flash_func(pico_program_u16)(uint32_t flash_offs, uint16_t data) {
static void __no_inline_not_in_flash_func(pico_program_bulk)(uint32_t flash_address, uint16_t *values, size_t item_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 flash_exit_xip = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
rom_flash_range_program_fn flash_range_program = (rom_flash_range_program_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_RANGE_PROGRAM);
rom_flash_flush_cache_fn flash_flush_cache = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE);
assert(connect_internal_flash && flash_exit_xip && flash_range_program && flash_flush_cache);
flash_init_boot2_copyout();
assert(connect_internal_flash && flash_exit_xip && flash_flush_cache);

__compiler_memory_barrier();
static uint16_t bulk_write_buffer[WEAR_LEVELING_RP2040_FLASH_BULK_COUNT];

while (item_count) {
size_t batch_size = MIN(item_count, WEAR_LEVELING_RP2040_FLASH_BULK_COUNT);
for (int i = 0; i < batch_size; i++, values++, item_count--) {
bulk_write_buffer[i] = ~(*values);
}
__compiler_memory_barrier();

connect_internal_flash();
flash_exit_xip();
connect_internal_flash();
flash_exit_xip();
flash_enable_write();

flash_enable_write();
flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, flash_offs);
flash_put_get((uint8_t *)&data, NULL, 2, 4);
flash_wait_ready();
flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, flash_address);
flash_put_get((uint8_t *)bulk_write_buffer, NULL, batch_size * sizeof(backing_store_int_t), 4);
flash_wait_ready();
flash_address += batch_size * sizeof(backing_store_int_t);

flash_flush_cache(); // Note this is needed to remove CSn IO force as well
// as cache flushing
flash_enable_xip_via_boot2();
flash_flush_cache();
flash_enable_xip_via_boot2();
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// QMK Wear-Leveling Backing Store implementation

#include <stdbool.h>
#include "timer.h"
#include "wear_leveling.h"
#include "wear_leveling_internal.h"

static int intr_stat;
static int interrupts;

bool backing_store_init(void) {
bs_dprintf("Init\n");
memcpy(BOOT2_ROM_RAM, BOOT2_ROM, sizeof(BOOT2_ROM));
__compiler_memory_barrier();
return true;
}

Expand All @@ -174,23 +176,27 @@ bool backing_store_erase(void) {
uint32_t start = timer_read32();
#endif

static_assert(WEAR_LEVELING_BACKING_SIZE % 4096 == 0, "Backing size must be a multiple of 4096");
_Static_assert(WEAR_LEVELING_BACKING_SIZE % 4096 == 0, "Backing size must be a multiple of 4096");

intr_stat = save_and_disable_interrupts();
interrupts = save_and_disable_interrupts();
flash_range_erase((WEAR_LEVELING_RP2040_FLASH_BASE), (WEAR_LEVELING_BACKING_SIZE));
restore_interrupts(intr_stat);
restore_interrupts(interrupts);

bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start)));
return true;
}

bool backing_store_write(uint32_t address, backing_store_int_t value) {
return backing_store_write_bulk(address, &value, 1);
}

bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) {
uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address;
bs_dprintf("Write ");
wl_dump(offset, &value, sizeof(backing_store_int_t));
intr_stat = save_and_disable_interrupts();
pico_program_u16(offset, ~value);
restore_interrupts(intr_stat);
wl_dump(offset, values, sizeof(backing_store_int_t) * item_count);
interrupts = save_and_disable_interrupts();
pico_program_bulk(offset, values, item_count);
restore_interrupts(interrupts);
return true;
}

Expand All @@ -199,10 +205,16 @@ bool backing_store_lock(void) {
}

bool backing_store_read(uint32_t address, backing_store_int_t *value) {
uint32_t offset = (XIP_BASE) + (WEAR_LEVELING_RP2040_FLASH_BASE) + address;
backing_store_int_t *loc = (backing_store_int_t *)offset;
*value = ~(*loc);
return backing_store_read_bulk(address, value, 1);
}

bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) {
uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address;
backing_store_int_t *loc = (backing_store_int_t *)((XIP_BASE) + offset);
for (size_t i = 0; i < item_count; ++i) {
values[i] = ~loc[i];
}
bs_dprintf("Read ");
wl_dump(offset, loc, sizeof(backing_store_int_t));
wl_dump(offset, values, item_count * sizeof(backing_store_int_t));
return true;
}
12 changes: 6 additions & 6 deletions platforms/chibios/vendors/RP/stage2_bootloaders.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

#if defined(RP2040_FLASH_AT25SF128A)

uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = {
uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = {
0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b,
0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
Expand All @@ -40,7 +40,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = {

#elif defined(RP2040_FLASH_GD25Q64CS)

uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = {
uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = {
0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b,
0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
Expand All @@ -67,7 +67,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = {

#elif defined(RP2040_FLASH_W25X10CL)

uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = {
uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = {
0x00, 0xb5, 0x14, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
0x12, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x11, 0x49, 0x12, 0x48,
0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xbb, 0x21, 0x19, 0x66, 0x02, 0x21,
Expand All @@ -94,7 +94,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = {

#elif defined(RP2040_FLASH_IS25LP080)

uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = {
uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = {
0x00, 0xb5, 0x2b, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
0x29, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x28, 0x48, 0x00, 0xf0,
0x42, 0xf8, 0x28, 0x4a, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, 0x19, 0x66,
Expand All @@ -121,7 +121,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = {

#elif defined(RP2040_FLASH_GENERIC_03H)

uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = {
uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = {
0x00, 0xb5, 0x0c, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
0x0a, 0x49, 0x19, 0x60, 0x0a, 0x49, 0x0b, 0x48, 0x01, 0x60, 0x00, 0x21,
0x59, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0,
Expand All @@ -148,7 +148,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = {

#else

uint8_t BOOTLOADER_SECTION BOOT2_W25Q080[256] = {
uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = {
0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b,
0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
Expand Down

0 comments on commit 8fe4781

Please sign in to comment.