From 2bcddba5ca13f3839f058d4cd290cb3e7e871570 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Tue, 10 Nov 2020 15:06:57 +0100 Subject: [PATCH 1/3] tests/periph_flashpage: Make FLASHPAGE_SIZE optional --- tests/periph_flashpage/main.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/periph_flashpage/main.c b/tests/periph_flashpage/main.c index 1a42f60d7e..27eb769483 100644 --- a/tests/periph_flashpage/main.c +++ b/tests/periph_flashpage/main.c @@ -45,6 +45,7 @@ */ static char raw_buf[64] ALIGNMENT_ATTR; +#ifdef MODULE_PERIPH_FLASHPAGE_PAGEWISE /** * @brief Allocate space for 1 flash page in RAM * @@ -54,6 +55,7 @@ static char raw_buf[64] ALIGNMENT_ATTR; * requires 64 bit alignment. */ static uint8_t page_mem[FLASHPAGE_SIZE] ALIGNMENT_ATTR; +#endif static int getpage(const char *str) { @@ -65,6 +67,7 @@ static int getpage(const char *str) return page; } +#ifdef FLASHPAGE_SIZE static void dumpchar(uint8_t mem) { if (mem >= ' ' && mem <= '~') { @@ -97,6 +100,7 @@ static void dump_local(void) puts("Local page buffer:"); memdump(page_mem, FLASHPAGE_SIZE); } +#endif static int cmd_info(int argc, char **argv) { @@ -104,7 +108,11 @@ static int cmd_info(int argc, char **argv) (void)argv; printf("Flash start addr:\t0x%08x\n", (int)CPU_FLASH_BASE); +#ifdef FLASHPAGE_SIZE printf("Page size:\t\t%i\n", (int)FLASHPAGE_SIZE); +#else + puts("Page size:\t\tvariable"); +#endif printf("Number of pages:\t%i\n", (int)FLASHPAGE_NUMOF); #ifdef FLASHPAGE_RWWEE_NUMOF @@ -120,6 +128,7 @@ static int cmd_info(int argc, char **argv) return 0; } +#ifdef FLASHPAGE_SIZE static int cmd_dump(int argc, char **argv) { int page; @@ -137,7 +146,7 @@ static int cmd_dump(int argc, char **argv) addr = flashpage_addr(page); printf("Flash page %i at address %p\n", page, addr); - memdump(addr, FLASHPAGE_SIZE); + memdump(addr, flashpage_size(page)); return 0; } @@ -172,6 +181,7 @@ static int cmd_read(int argc, char **argv) return 0; } +#endif #ifdef MODULE_PERIPH_FLASHPAGE_PAGEWISE static int cmd_write(int argc, char **argv) @@ -258,6 +268,7 @@ static int cmd_erase(int argc, char **argv) return 0; } +#ifdef FLASHPAGE_SIZE static int cmd_edit(int argc, char **argv) { int offset; @@ -283,6 +294,7 @@ static int cmd_edit(int argc, char **argv) return 0; } +#endif #ifdef MODULE_PERIPH_FLASHPAGE_PAGEWISE static int cmd_test(int argc, char **argv) @@ -614,16 +626,16 @@ static int cmd_test_config(int argc, char **argv) static const shell_command_t shell_commands[] = { { "info", "Show information about pages", cmd_info }, +#ifdef MODULE_PERIPH_FLASHPAGE_PAGEWISE { "dump", "Dump the selected page to STDOUT", cmd_dump }, { "dump_local", "Dump the local page buffer to STDOUT", cmd_dump_local }, { "read", "Copy the given page to the local page buffer and dump to STDOUT", cmd_read }, -#ifdef MODULE_PERIPH_FLASHPAGE_PAGEWISE { "write", "Write the local page buffer to the given page", cmd_write }, #endif { "write_raw", "Write (ASCII, max 64B) data to the given address", cmd_write_raw }, { "erase", "Erase the given page buffer", cmd_erase }, - { "edit", "Write bytes to the local page buffer", cmd_edit }, #ifdef MODULE_PERIPH_FLASHPAGE_PAGEWISE + { "edit", "Write bytes to the local page buffer", cmd_edit }, { "test", "Write and verify test pattern", cmd_test }, { "test_last_pagewise", "Write and verify test pattern on last page available", cmd_test_last }, #endif From f5b6ebf1cb23b74f3574a9c93df2de6bf77aa88f Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Mon, 1 Feb 2021 18:20:06 +0100 Subject: [PATCH 2/3] unittests/flashpage: force uniform flashpage layout The unittest for flashpage only checks the inline flashpage_ functions with the assumption that the flashpage layout is uniform. This commit undefines the macro guarding those functions to force them to be included even when the flashpage peripheral defines own implementations. --- tests/unittests/tests-flashpage/tests-flashpage.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unittests/tests-flashpage/tests-flashpage.c b/tests/unittests/tests-flashpage/tests-flashpage.c index 4a37ac386b..00ddd6c7cc 100644 --- a/tests/unittests/tests-flashpage/tests-flashpage.c +++ b/tests/unittests/tests-flashpage/tests-flashpage.c @@ -27,6 +27,9 @@ #define FLASHPAGE_NUMOF 128 #endif +/* fake uniform flashpage sizes for devices that don't have it */ +#undef PERIPH_FLASHPAGE_CUSTOM_PAGESIZES + #include "periph/flashpage.h" static void test_flashbase_addr(void) From b6e80bf487b62a38481078824488559b121e077d Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Tue, 10 Nov 2020 15:07:35 +0100 Subject: [PATCH 3/3] stm32f4: Initial flashpage support --- cpu/stm32/Makefile.features | 5 ++ cpu/stm32/include/cpu_conf.h | 76 ++++++++++++++++- cpu/stm32/kconfigs/f2/Kconfig | 1 + cpu/stm32/kconfigs/f4/Kconfig | 1 + cpu/stm32/kconfigs/f7/Kconfig | 1 + cpu/stm32/periph/flash_common.c | 4 +- cpu/stm32/periph/flashpage.c | 142 ++++++++++++++++++++++++++++++-- 7 files changed, 218 insertions(+), 12 deletions(-) diff --git a/cpu/stm32/Makefile.features b/cpu/stm32/Makefile.features index 6e3c46ad99..b294249711 100644 --- a/cpu/stm32/Makefile.features +++ b/cpu/stm32/Makefile.features @@ -16,6 +16,11 @@ ifneq (,$(filter $(CPU_FAM),f0 f1 f3 g0 g4 l0 l1 l4 l5 wb)) FEATURES_PROVIDED += periph_flashpage_pagewise endif +# The f2, f4 and f7 do not support the pagewise api +ifneq (,$(filter $(CPU_FAM),f2 f4 f7)) + FEATURES_PROVIDED += periph_flashpage +endif + ifneq (,$(filter $(CPU_FAM),l0 l1)) FEATURES_PROVIDED += periph_eeprom endif diff --git a/cpu/stm32/include/cpu_conf.h b/cpu/stm32/include/cpu_conf.h index d087e4c65f..fdc37fbb7f 100644 --- a/cpu/stm32/include/cpu_conf.h +++ b/cpu/stm32/include/cpu_conf.h @@ -116,7 +116,73 @@ extern "C" { #define FLASHPAGE_SIZE (128U) #endif +#ifdef FLASHPAGE_SIZE #define FLASHPAGE_NUMOF (STM32_FLASHSIZE / FLASHPAGE_SIZE) +#endif + +#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) +#define PERIPH_FLASHPAGE_CUSTOM_PAGESIZES + +/** + * @brief stm32 dual bank configuration + * + * By default, the stm32f4 series with 1MB flash enable the DB1M flag to split + * the 1MB flash into two banks, 2MB devices are always split in two banks. + * On both the stm32f4 and the stm32f7 this can be modified with user + * programmable flags. Detecting the settings at runtime is not supported + * + * @note This must match the setting on the MCU. by default it is assumed that + * the user has not changed this setting manually. + */ +#if (defined(FLASH_OPTCR_DB1M) && (STM32_FLASHSIZE >= (1024 * 1024))) +#define FLASHPAGE_DUAL_BANK 1 +#else +#define FLASHPAGE_DUAL_BANK 0 +#endif + +/* stm32f7 uses single bank with 32KB to 256KB sectors on a number of devices */ +#if defined(CPU_FAM_STM32F7) +#if defined(CPU_LINE_STM32F745xx) || \ + defined(CPU_LINE_STM32F746xx) || \ + defined(CPU_LINE_STM32F750xx) || \ + defined(CPU_LINE_STM32F756xx) || \ + defined(CPU_LINE_STM32F765xx) || \ + defined(CPU_LINE_STM32F767xx) || \ + defined(CPU_LINE_STM32F769xx) || \ + defined(CPU_LINE_STM32F777xx) || \ + defined(CPU_LINE_STM32F779xx) +#define FLASHPAGE_MIN_SECTOR_SIZE (32 * 1024) +#elif defined(CPU_LINE_STM32F722xx) || \ + defined(CPU_LINE_STM32F723xx) || \ + defined(CPU_LINE_STM32F730xx) || \ + defined(CPU_LINE_STM32F732xx) || \ + defined(CPU_LINE_STM32F733xx) +#define FLASHPAGE_MIN_SECTOR_SIZE (16 * 1024) +#else +/* Intentionally error on an unknown line to prevent flashpage errors */ +#error Unknown STM32F7 Line, unable to determine FLASHPAGE_MIN_SECTOR_SIZE +#endif + +#else /* CPU_FAM_STM32F7 */ +#define FLASHPAGE_MIN_SECTOR_SIZE (16 * 1024) +#endif + +#if FLASHPAGE_DUAL_BANK +/* Number of "large" sectors + 4 for the small sectors that together equal a + * single large sector. Times two to account for the two banks */ +#define FLASHPAGE_NUMOF ((STM32_FLASHSIZE / \ + (8 * FLASHPAGE_MIN_SECTOR_SIZE)) + 8) +#else +/* Number of "large" sectors + 4 for the small sectors that together equal a + * single large sector, eg: 1 MB = 7 * 128 KB sectors + 1 64 KB and 4 16 KB + * sectors */ +#define FLASHPAGE_NUMOF ((STM32_FLASHSIZE / \ + (8 * FLASHPAGE_MIN_SECTOR_SIZE)) + 4) +#endif + +#endif + /* The minimum block size which can be written depends on the family. * However, the erase block is always FLASHPAGE_SIZE. @@ -124,13 +190,15 @@ extern "C" { #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ defined(CPU_FAM_STM32L5) -#define FLASHPAGE_WRITE_BLOCK_SIZE (8U) +#define FLASHPAGE_WRITE_BLOCK_SIZE (8U) typedef uint64_t stm32_flashpage_block_t; -#elif defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) -#define FLASHPAGE_WRITE_BLOCK_SIZE (4U) +#elif defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \ + defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) +#define FLASHPAGE_WRITE_BLOCK_SIZE (4U) typedef uint32_t stm32_flashpage_block_t; #else -#define FLASHPAGE_WRITE_BLOCK_SIZE (2U) +#define FLASHPAGE_WRITE_BLOCK_SIZE (2U) typedef uint16_t stm32_flashpage_block_t; #endif diff --git a/cpu/stm32/kconfigs/f2/Kconfig b/cpu/stm32/kconfigs/f2/Kconfig index f99960816f..8956fbfa18 100644 --- a/cpu/stm32/kconfigs/f2/Kconfig +++ b/cpu/stm32/kconfigs/f2/Kconfig @@ -11,6 +11,7 @@ config CPU_FAM_F2 select CPU_CORE_CORTEX_M3 select HAS_CPU_STM32F2 select HAS_CORTEXM_MPU + select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_HWRNG select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/f4/Kconfig b/cpu/stm32/kconfigs/f4/Kconfig index e17e866365..05eddcd7d9 100644 --- a/cpu/stm32/kconfigs/f4/Kconfig +++ b/cpu/stm32/kconfigs/f4/Kconfig @@ -11,6 +11,7 @@ config CPU_FAM_F4 select CPU_CORE_CORTEX_M4F select HAS_CPU_STM32F4 select HAS_CORTEXM_MPU + select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/f7/Kconfig b/cpu/stm32/kconfigs/f7/Kconfig index 9a1d4c8094..0a8303d843 100644 --- a/cpu/stm32/kconfigs/f7/Kconfig +++ b/cpu/stm32/kconfigs/f7/Kconfig @@ -11,6 +11,7 @@ config CPU_FAM_F7 select CPU_CORE_CORTEX_M7 select HAS_CPU_STM32F7 select HAS_CORTEXM_MPU + select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_HWRNG select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/periph/flash_common.c b/cpu/stm32/periph/flash_common.c index 6c8b517bea..ca6faf5748 100644 --- a/cpu/stm32/periph/flash_common.c +++ b/cpu/stm32/periph/flash_common.c @@ -40,7 +40,9 @@ #define FLASH_SR_EOP (FLASH_NSSR_NSEOP) #else #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) + defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ + defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) #define FLASH_KEY1 ((uint32_t)0x45670123) #define FLASH_KEY2 ((uint32_t)0xCDEF89AB) #endif diff --git a/cpu/stm32/periph/flashpage.c b/cpu/stm32/periph/flashpage.c index 1adbea3810..49dcd4b7b0 100644 --- a/cpu/stm32/periph/flashpage.c +++ b/cpu/stm32/periph/flashpage.c @@ -47,6 +47,13 @@ #define FLASH_CR_PER (FLASH_NSCR_NSPER) #define FLASH_CR_BKER (FLASH_NSCR_NSBKER) #define FLASH_CR_PG (FLASH_NSCR_NSPG) +#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) +#define FLASHPAGE_DIV (4U) +#define FLASH_CR_PER (FLASH_CR_SER) +#define FLASH_CR_PNB (FLASH_CR_SNB) +#define FLASH_CR_PNB_Pos (FLASH_CR_SNB_Pos) +#define CNTRL_REG (FLASH->CR) #else #define CNTRL_REG (FLASH->CR) #define CNTRL_REG_LOCK (FLASH_CR_LOCK) @@ -102,7 +109,8 @@ static void _erase_page(void *page_addr) *(uint32_t *)page_addr = 0; #elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ - defined(CPU_FAM_STM32L5) + defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32F2) || \ + defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) DEBUG("[flashpage] erase: setting the page address\n"); uint8_t pn; #if (FLASHPAGE_NUMOF <= MAX_PAGES_PER_BANK) || defined(CPU_FAM_STM32WB) @@ -118,8 +126,19 @@ static void _erase_page(void *page_addr) pn = (uint8_t)page; #endif CNTRL_REG &= ~FLASH_CR_PNB; +#if FLASHPAGE_DUAL_BANK + if (pn > (FLASHPAGE_NUMOF / 2 - 1)) { + pn = pn - (FLASHPAGE_NUMOF / 2); + CNTRL_REG |= FLASH_CR_SNB_4 | (uint32_t)(pn << FLASH_CR_PNB_Pos); + } + else { + CNTRL_REG |= (uint32_t)(pn << FLASH_CR_PNB_Pos); + } +#else CNTRL_REG |= (uint32_t)(pn << FLASH_CR_PNB_Pos); +#endif CNTRL_REG |= FLASH_CR_STRT; + DEBUG("[flashpage] erase: the page address is set and started\n"); #else /* CPU_FAM_STM32F0 || CPU_FAM_STM32F1 || CPU_FAM_STM32F3 */ DEBUG("[flashpage] erase: setting the page address\n"); FLASH->AR = (uint32_t)page_addr; @@ -130,9 +149,26 @@ static void _erase_page(void *page_addr) /* wait as long as device is busy */ _wait_for_pending_operations(); - /* reset PER bit */ +#ifdef FLASH_ACR_DCEN /* Flush the data cache after page erase */ + if (FLASH->ACR & FLASH_ACR_DCEN) { + FLASH->ACR &= ~FLASH_ACR_DCEN; + FLASH->ACR |= FLASH_ACR_DCRST; + FLASH->ACR |= FLASH_ACR_DCEN; + } +#endif +#ifdef FLASH_ACR_ICEN /* Flush the instruction cache after page erase */ + if (FLASH->ACR & FLASH_ACR_ICEN) { + FLASH->ACR &= ~FLASH_ACR_ICEN; + FLASH->ACR |= FLASH_ACR_ICRST; + FLASH->ACR |= FLASH_ACR_ICEN; + } +#endif + +#ifdef FLASH_CR_PNB + /* reset PER bit (if the register settings exist) */ DEBUG("[flashpage] erase: resetting the page erase bit\n"); - CNTRL_REG &= ~(FLASH_CR_PER); + CNTRL_REG &= ~(FLASH_CR_PER | FLASH_CR_PNB); +#endif /* lock the flash module again */ _lock(); @@ -172,8 +208,8 @@ void flashpage_write(void *target_addr, const void *data, size_t len) ((unsigned)data % FLASHPAGE_WRITE_BLOCK_ALIGNMENT))); /* ensure the length doesn't exceed the actual flash size */ - assert(((unsigned)target_addr + len) < - (CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF)) + 1); + assert(((uintptr_t)(target_addr) + len) < + (uintptr_t)flashpage_addr(FLASHPAGE_NUMOF + 1)); stm32_flashpage_block_t *dst = target_addr; const stm32_flashpage_block_t *data_addr = data; @@ -185,9 +221,28 @@ void flashpage_write(void *target_addr, const void *data, size_t len) stmclk_enable_hsi(); #endif +#ifdef FLASH_ACR_DCEN + /* Disable the data cache during page writes */ + bool data_cache = FLASH->ACR & FLASH_ACR_DCEN; + if (data_cache) { + FLASH->ACR &= ~FLASH_ACR_DCEN; + } +#endif +#ifdef FLASH_ACR_ICEN + /* Disable the instruction cache during page writes */ + bool instruction_cache = FLASH->ACR & FLASH_ACR_ICEN; + if (instruction_cache) { + FLASH->ACR &= ~FLASH_ACR_ICEN; + } +#endif + /* unlock the flash module */ _unlock_flash(); +#ifdef FLASH_CR_PSIZE_1 + CNTRL_REG |= FLASH_CR_PSIZE_1; /* Word size parallelism */ +#endif + /* make sure no flash operation is ongoing */ _wait_for_pending_operations(); @@ -195,13 +250,18 @@ void flashpage_write(void *target_addr, const void *data, size_t len) #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \ defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \ defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ - defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) + defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) || \ + defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) /* set PG bit and program page to flash */ CNTRL_REG |= FLASH_CR_PG; #endif for (size_t i = 0; i < (len / sizeof(stm32_flashpage_block_t)); i++) { DEBUG("[flashpage_raw] writing %c to %p\n", (char)data_addr[i], dst); *dst++ = data_addr[i]; +#if defined(CPU_FAM_STM32F7) + __DMB(); +#endif /* wait as long as device is busy */ _wait_for_pending_operations(); } @@ -210,7 +270,9 @@ void flashpage_write(void *target_addr, const void *data, size_t len) #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \ defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \ defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) || \ - defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) + defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) || \ + defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) CNTRL_REG &= ~(FLASH_CR_PG); #endif DEBUG("[flashpage_raw] write: done writing data\n"); @@ -218,6 +280,21 @@ void flashpage_write(void *target_addr, const void *data, size_t len) /* lock the flash module again */ _lock(); +#ifdef FLASH_ACR_DCEN + /* Enable the data cache if it was enabled before. Always reset it */ + FLASH->ACR |= FLASH_ACR_DCRST; + if (data_cache) { + FLASH->ACR |= FLASH_ACR_DCEN; + } +#endif +#ifdef FLASH_ACR_ICEN + /* Enable the instruction cache if it was enabled before. Always reset it */ + FLASH->ACR |= FLASH_ACR_ICRST; + if (instruction_cache) { + FLASH->ACR |= FLASH_ACR_ICEN; + } +#endif + #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \ defined(CPU_FAM_STM32F3) /* restore the HSI state */ @@ -226,3 +303,54 @@ void flashpage_write(void *target_addr, const void *data, size_t len) } #endif } + +#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \ + defined(CPU_FAM_STM32F7) +size_t flashpage_size(unsigned page) +{ + if (page < 4) { + return FLASHPAGE_MIN_SECTOR_SIZE; + } + else if (page == 4) { + return 4 * FLASHPAGE_MIN_SECTOR_SIZE; + } + else { + return 8 * FLASHPAGE_MIN_SECTOR_SIZE; + } +} + +void *flashpage_addr(unsigned page) +{ + uintptr_t addr = CPU_FLASH_BASE; + while (page) { + addr += flashpage_size(--page); + } + + return (void*)addr; +} + +unsigned flashpage_page(void *addr) +{ + /* Calculates the flashpage number based on the address for the + * non-homogeneous flashpage stm32 series. + * These all follow the same pattern of 4 sectors of base size, 1 sector of + * 4 times the base size and the rest of the pages are 8 times the base + * size. Here we calculate the page number as if all pages are of base size + * and then compensate for the larger sectors */ + unsigned page = (((intptr_t)addr - CPU_FLASH_BASE) / + FLASHPAGE_MIN_SECTOR_SIZE); + + /* check if beyond the 4 base sectors + the 4 * base size sector */ + if (page > 7) { + /* Divide by 8 and compensate for the initial 5 sectors */ + page = (page / 8) + 4; + } + /* If the page number is between 4 and 7 (inclusive), the address is in the + * single 4 * base size sector */ + else if (page > 3) { + page = 4; + } + + return page; +} +#endif