/*
- * 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
*/
#include <mmio.h>
#include <norflash.h>
+/*
+ * 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))
*/
#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
*/
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)
}
/*
+ * 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
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);
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);
}
-