diff --git a/plat/arm/board/common/drivers/norflash/norflash.c b/plat/arm/board/common/drivers/norflash/norflash.c index cc63d758ea2f9bb9c7b39f9428afbc45e4281429..053696eedc70fbf2b6373cef00e204de0b5a3ff3 100644 --- a/plat/arm/board/common/drivers/norflash/norflash.c +++ b/plat/arm/board/common/drivers/norflash/norflash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -8,6 +8,14 @@ #include #include +/* + * This file supplies a low level interface to the vexpress NOR flash + * memory of juno and fvp. This memory is organized as an interleaved + * memory of two chips with a 16 bit word. It means that every 32 bit + * access is going to access to two different chips. This is very + * important when we send commands or read status of the chips + */ + /* Helper macros to access two flash banks in parallel */ #define NOR_2X16(d) ((d << 16) | (d & 0xffff)) @@ -18,6 +26,9 @@ */ #define DWS_WORD_PROGRAM_RETRIES 1000 +/* Helper macro to detect end of command */ +#define NOR_CMD_END (NOR_DWS | NOR_DWS << 16l) + /* * Poll Write State Machine. Return values: * 0 = WSM ready @@ -25,24 +36,16 @@ */ static int nor_poll_dws(uintptr_t base_addr, unsigned int retries) { - uint32_t status; - int ret; + unsigned long status; - for (;;) { + do { nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG); status = mmio_read_32(base_addr); - if ((status & NOR_DWS) && - (status & (NOR_DWS << 16))) { - ret = 0; - break; - } - if (retries-- == 0) { - ret = -EBUSY; - break; - } - } + if ((status & NOR_CMD_END) == NOR_CMD_END) + return 0; + } while (retries-- > 0); - return ret; + return -EBUSY; } void nor_send_cmd(uintptr_t base_addr, unsigned long cmd) @@ -51,6 +54,9 @@ void nor_send_cmd(uintptr_t base_addr, unsigned long cmd) } /* + * This function programs a word in the flash. Be aware that it only + * can reset bits that were previously set. It cannot set bits that + * were previously reset. The resulting bits = old_bits & new bits. * Return values: * 0 = success * -EBUSY = WSM not ready @@ -66,24 +72,24 @@ int nor_word_program(uintptr_t base_addr, unsigned long data) mmio_write_32(base_addr, data); ret = nor_poll_dws(base_addr, DWS_WORD_PROGRAM_RETRIES); - if (ret != 0) { - goto word_program_end; - } - - /* Full status check */ - nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG); - status = mmio_read_32(base_addr); + if (ret == 0) { + /* Full status check */ + nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG); + status = mmio_read_32(base_addr); - if (status & (NOR_PS | NOR_BLS)) { - nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG); - ret = -EPERM; + if (status & (NOR_PS | NOR_BLS)) { + nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG); + ret = -EPERM; + } } -word_program_end: nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); return ret; } +/* + * Lock a full 256 block + */ void nor_lock(uintptr_t base_addr) { nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK); @@ -91,10 +97,12 @@ void nor_lock(uintptr_t base_addr) nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); } +/* + * unlock a full 256 block + */ void nor_unlock(uintptr_t base_addr) { nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK); mmio_write_32(base_addr, NOR_2X16(NOR_UNLOCK_BLOCK)); nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); } -