diff options
-rw-r--r-- | chip/npcx/registers.h | 29 | ||||
-rw-r--r-- | chip/npcx/system.c | 138 | ||||
-rw-r--r-- | chip/npcx/system_chip.h | 11 | ||||
-rw-r--r-- | core/cortex-m/ec.lds.S | 7 |
4 files changed, 175 insertions, 10 deletions
diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h index 78acaefbd5..2154f8efa3 100644 --- a/chip/npcx/registers.h +++ b/chip/npcx/registers.h @@ -86,6 +86,7 @@ #define NPCX_PECI_BASE_ADDR 0x400D4000 #define NPCX_TWD_BASE_ADDR 0x400D8000 #define NPCX_ESPI_BASE_ADDR 0x4000A000 +#define NPCX_GDMA_BASE_ADDR 0x40011000 /* Multi-Modules Map */ #define NPCX_PWM_BASE_ADDR(mdl) (0x40080000 + ((mdl) * 0x2000L)) @@ -1443,6 +1444,34 @@ enum { }; /******************************************************************************/ +/* GDMA (General DMA) Registers */ +#define NPCX_GDMA_CTL REG32(NPCX_GDMA_BASE_ADDR + 0x000) +#define NPCX_GDMA_SRCB REG32(NPCX_GDMA_BASE_ADDR + 0x004) +#define NPCX_GDMA_DSTB REG32(NPCX_GDMA_BASE_ADDR + 0x008) +#define NPCX_GDMA_TCNT REG32(NPCX_GDMA_BASE_ADDR + 0x00C) +#define NPCX_GDMA_CSRC REG32(NPCX_GDMA_BASE_ADDR + 0x010) +#define NPCX_GDMA_CDST REG32(NPCX_GDMA_BASE_ADDR + 0x014) +#define NPCX_GDMA_CTCNT REG32(NPCX_GDMA_BASE_ADDR + 0x018) + + +/******************************************************************************/ +/* GDMA register fields */ +#define NPCX_GDMA_CTL_GDMAEN 0 +#define NPCX_GDMA_CTL_GDMAMS FIELD(2, 2) +#define NPCX_GDMA_CTL_DADIR 4 +#define NPCX_GDMA_CTL_SADIR 5 +#define NPCX_GDMA_CTL_SAFIX 7 +#define NPCX_GDMA_CTL_SIEN 8 +#define NPCX_GDMA_CTL_BME 9 +#define NPCX_GDMA_CTL_SBMS 11 +#define NPCX_GDMA_CTL_TWS FIELD(12, 2) +#define NPCX_GDMA_CTL_DM 15 +#define NPCX_GDMA_CTL_SOFTREQ 16 +#define NPCX_GDMA_CTL_TC 18 +#define NPCX_GDMA_CTL_GDMAERR 20 +#define NPCX_GDMA_CTL_BLOCK_BUG_CORRECTION_DISABLE 26 + +/******************************************************************************/ /* Nuvoton internal used only registers */ #define NPCX_INTERNAL_CTRL1 REG8(0x400DB000) #define NPCX_INTERNAL_CTRL2 REG8(0x400DD000) diff --git a/chip/npcx/system.c b/chip/npcx/system.c index babfbe15a3..d8ff38f0f4 100644 --- a/chip/npcx/system.c +++ b/chip/npcx/system.c @@ -39,9 +39,14 @@ #define CPUTS(outstr) cputs(CC_SYSTEM, outstr) #define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) -/* Begin address for the .lpram section; defined in linker script */ +/* Begin address of Suspend RAM for hibernate utility */ uintptr_t __lpram_fw_start = CONFIG_LPRAM_BASE; +/* Offset of little FW in Suspend Ram for GDMA bypass */ +#define LFW_OFFSET 0x160 +/* Begin address of Suspend RAM for little FW (GDMA utilities). */ +uintptr_t __lpram_lfw_start = CONFIG_LPRAM_BASE + LFW_OFFSET; + /*****************************************************************************/ /* Internal functions */ @@ -253,7 +258,7 @@ void system_mpu_config(void) CPU_MPU_RASR = 0x1308001D; } -void __keep __attribute__ ((section(".lowpower_ram"))) +void __keep __attribute__ ((noreturn, section(".lowpower_ram"))) __enter_hibernate_in_lpram(void) { /* @@ -849,19 +854,132 @@ DECLARE_HOST_COMMAND(EC_CMD_RTC_GET_ALARM, #endif /* CONFIG_HOSTCMD_RTC */ #ifdef CONFIG_EXTERNAL_STORAGE +void __keep __attribute__ ((noreturn, section(".lowpower_ram2"))) +__start_gdma(uint32_t exeAddr) +{ + /* Enable GDMA now */ + SET_BIT(NPCX_GDMA_CTL, NPCX_GDMA_CTL_GDMAEN); + + /* Start GDMA */ + SET_BIT(NPCX_GDMA_CTL, NPCX_GDMA_CTL_SOFTREQ); + + /* Wait for transfer to complete/fail */ + while (!IS_BIT_SET(NPCX_GDMA_CTL, NPCX_GDMA_CTL_TC) && + !IS_BIT_SET(NPCX_GDMA_CTL, NPCX_GDMA_CTL_GDMAERR)) + ; + + /* Disable GDMA now */ + CLEAR_BIT(NPCX_GDMA_CTL, NPCX_GDMA_CTL_GDMAEN); + + /* + * Failure occurs during GMDA transaction. Let watchdog issue and + * boot from RO region again. + */ + if (IS_BIT_SET(NPCX_GDMA_CTL, NPCX_GDMA_CTL_GDMAERR)) + while (1) + ; + + /* + * Jump to the exeAddr address if needed. Setting bit 0 of address to + * indicate it's a thumb branch for cortex-m series CPU. + */ + ((void (*)(void))(exeAddr | 0x01))(); + + /* Should never get here */ + while (1) + ; +} + +static void system_download_from_flash(uint32_t srcAddr, uint32_t dstAddr, + uint32_t size, uint32_t exeAddr) +{ + int i; + uint8_t chunkSize = 16; /* 4 data burst mode. ie.16 bytes */ + /* + * GDMA utility in Suspend RAM. Setting bit 0 of address to indicate + * it's a thumb branch for cortex-m series CPU. + */ + void (*__start_gdma_in_lpram)(uint32_t) = + (void(*)(uint32_t))(__lpram_lfw_start | 0x01); + + /* + * Before enabling burst mode for better performance of GDMA, it's + * important to make sure srcAddr, dstAddr and size of transactions + * are 16 bytes aligned in case failure occurs. + */ + ASSERT((size % chunkSize) == 0 && (srcAddr % chunkSize) == 0 && + (dstAddr % chunkSize) == 0); + + /* Check valid address for jumpiing */ + ASSERT(exeAddr != 0x0); + + /* Enable power for the Low Power RAM */ + CLEAR_BIT(NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_6), 6); + + /* Enable Low Power RAM */ + NPCX_LPRAM_CTRL = 1; + + /* + * Initialize GDMA for flash reading. + * [31:21] - Reserved. + * [20] - GDMAERR = 0 (Indicate GMDA transfer error) + * [19] - Reserved. + * [18] - TC = 0 (Terminal Count. Indicate operation is end.) + * [17] - Reserved. + * [16] - SOFTREQ = 0 (Don't trigger here) + * [15] - DM = 0 (Set normal demand mode) + * [14] - Reserved. + * [13:12] - TWS. = 10 (One double-word for every GDMA transaction) + * [11:10] - Reserved. + * [9] - BME = 1 (4-data ie.16 bytes - Burst mode enable) + * [8] - SIEN = 0 (Stop interrupt disable) + * [7] - SAFIX = 0 (Fixed source address) + * [6] - Reserved. + * [5] - SADIR = 0 (Source address incremented) + * [4] - DADIR = 0 (Destination address incremented) + * [3:2] - GDMAMS = 00 (Software mode) + * [1] - Reserved. + * [0] - ENABLE = 0 (Don't enable yet) + */ + NPCX_GDMA_CTL = 0x00002200; + + /* Set source base address */ + NPCX_GDMA_SRCB = CONFIG_MAPPED_STORAGE_BASE + srcAddr; + + /* Set destination base address */ + NPCX_GDMA_DSTB = dstAddr; + + /* Set number of transfers */ + NPCX_GDMA_TCNT = (size / chunkSize); + + /* Clear Transfer Complete event */ + SET_BIT(NPCX_GDMA_CTL, NPCX_GDMA_CTL_TC); + + /* Copy the __start_gdma_in_lpram instructions to LPRAM */ + for (i = 0; i < &__flash_lplfw_end - &__flash_lplfw_start; i++) + *((uint32_t *)__lpram_lfw_start + i) = + *(&__flash_lplfw_start + i); + + /* Start GDMA in Suspend RAM */ + __start_gdma_in_lpram(exeAddr); +} + void system_jump_to_booter(void) { - enum API_RETURN_STATUS_T status; + enum API_RETURN_STATUS_T status __attribute__((unused)); static uint32_t flash_offset; static uint32_t flash_used; static uint32_t addr_entry; - /* RO region FW */ + /* + * Get memory offset and size for RO/RW regions. + * Both of them need 16-bytes alignment since GDMA burst mode. + */ if (IS_BIT_SET(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION)) { flash_offset = CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_RO_STORAGE_OFF; flash_used = CONFIG_RO_SIZE; - } else { /* RW region FW */ + } else { flash_offset = CONFIG_EC_WRITABLE_STORAGE_OFF + CONFIG_RW_STORAGE_OFF; flash_used = CONFIG_RW_SIZE; @@ -877,6 +995,15 @@ void system_jump_to_booter(void) */ clock_turbo(); + /* Bypass for GMDA issue of ROM api utilities */ +#if defined(CHIP_VARIANT_NPCX5M5G) || defined(CHIP_VARIANT_NPCX5M6G) + system_download_from_flash( + flash_offset, /* The offset of the data in spi flash */ + CONFIG_PROGRAM_MEMORY_BASE, /* RAM Addr of downloaded data */ + flash_used, /* Number of bytes to download */ + addr_entry /* jump to this address after download */ + ); +#else download_from_flash( flash_offset, /* The offset of the data in spi flash */ CONFIG_PROGRAM_MEMORY_BASE, /* RAM Addr of downloaded data */ @@ -885,6 +1012,7 @@ void system_jump_to_booter(void) addr_entry, /* jump to this address after download */ &status /* Status fo download */ ); +#endif } uint32_t system_get_lfw_address() diff --git a/chip/npcx/system_chip.h b/chip/npcx/system_chip.h index bc218b5816..b15c030dc4 100644 --- a/chip/npcx/system_chip.h +++ b/chip/npcx/system_chip.h @@ -22,11 +22,14 @@ void system_watchdog_reset(void); /* Check reset cause and return reset flags */ void system_check_reset_cause(void); -/* End address for the .lpram section; defined in linker script */ -extern unsigned int __lpram_fw_end; -/* Begin flash address for the lpram codes; defined in linker script */ +/* Begin flash address for hibernate utility; defined in linker script */ extern unsigned int __flash_lpfw_start; -/* End flash address for the lpram codes; defined in linker script */ +/* End flash address for hibernate utility; defined in linker script */ extern unsigned int __flash_lpfw_end; +/* Begin flash address for little FW; defined in linker script */ +extern unsigned int __flash_lplfw_start; +/* End flash address for little FW; defined in linker script */ +extern unsigned int __flash_lplfw_end; + #endif /* __CROS_EC_SYSTEM_CHIP_H */ diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S index 97458f8a13..2b70535fa6 100644 --- a/core/cortex-m/ec.lds.S +++ b/core/cortex-m/ec.lds.S @@ -93,8 +93,13 @@ SECTIONS __flash_lpfw_start = .; /* Entering deep idle FW for better power consumption */ KEEP(*(.lowpower_ram)) - . = ALIGN(4); + . = ALIGN(4); __flash_lpfw_end = .; + __flash_lplfw_start = .; + /* GDMA utilities for better FW download speed */ + KEEP(*(.lowpower_ram2)) + . = ALIGN(4); + __flash_lplfw_end = .; } > CDRAM AT > FLASH #else } > FLASH |