/*
 * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <errno.h>

#include <drivers/cfi/v2m_flash.h>
#include <lib/mmio.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.
 */

/*
 * DWS ready poll retries. The number of retries in this driver have been
 * obtained empirically from Juno. FVP implements a zero wait state NOR flash
 * model
 */
#define DWS_WORD_PROGRAM_RETRIES	1000
#define DWS_WORD_ERASE_RETRIES		3000000
#define DWS_WORD_LOCK_RETRIES		1000

/* Helper macro to detect end of command */
#define NOR_CMD_END (NOR_DWS | (NOR_DWS << 16l))

/* Helper macros to access two flash banks in parallel */
#define NOR_2X16(d)			((d << 16) | (d & 0xffff))

static unsigned int nor_status(uintptr_t base_addr)
{
	unsigned long status;

	nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG);
	status = mmio_read_32(base_addr);
	status |= status >> 16; /* merge status from both flash banks */

	return status & 0xFFFF;
}

/*
 * Poll Write State Machine.
 * Return values:
 *    0      = WSM ready
 *    -EBUSY = WSM busy after the number of retries
 */
static int nor_poll_dws(uintptr_t base_addr, unsigned long int retries)
{
	unsigned long status;

	do {
		nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG);
		status = mmio_read_32(base_addr);
		if ((status & NOR_CMD_END) == NOR_CMD_END)
			return 0;
	} while (retries-- > 0);

	return -EBUSY;
}

/*
 * Return values:
 *    0      = success
 *    -EPERM = Device protected or Block locked
 *    -EIO   = General I/O error
 */
static int nor_full_status_check(uintptr_t base_addr)
{
	unsigned long status;

	/* Full status check */
	status = nor_status(base_addr);

	if (status & (NOR_PS | NOR_BLS | NOR_ESS | NOR_PSS))
		return -EPERM;
	if (status & (NOR_VPPS | NOR_ES))
		return -EIO;
	return 0;
}

void nor_send_cmd(uintptr_t base_addr, unsigned long cmd)
{
	mmio_write_32(base_addr, NOR_2X16(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
 *  otherwise it returns a negative value
 */
int nor_word_program(uintptr_t base_addr, unsigned long data)
{
	uint32_t status;
	int ret;

	nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);

	/* Set the device in write word mode */
	nor_send_cmd(base_addr, NOR_CMD_WORD_PROGRAM);
	mmio_write_32(base_addr, data);

	ret = nor_poll_dws(base_addr, DWS_WORD_PROGRAM_RETRIES);
	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 (ret == 0)
		ret = nor_full_status_check(base_addr);
	nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);

	return ret;
}

/*
 * Erase a full 256K block
 * Return values:
 *  0 = success
 *  otherwise it returns a negative value
 */
int nor_erase(uintptr_t base_addr)
{
	int ret;

	nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);

	nor_send_cmd(base_addr, NOR_CMD_BLOCK_ERASE);
	nor_send_cmd(base_addr, NOR_CMD_BLOCK_ERASE_ACK);

	ret = nor_poll_dws(base_addr, DWS_WORD_ERASE_RETRIES);
	if (ret == 0)
		ret = nor_full_status_check(base_addr);
	nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);

	return ret;
}

/*
 * Lock a full 256 block
 * Return values:
 *  0 = success
 *  otherwise it returns a negative value
 */
int nor_lock(uintptr_t base_addr)
{
	int ret;

	nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);

	nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK);
	nor_send_cmd(base_addr, NOR_LOCK_BLOCK);

	ret = nor_poll_dws(base_addr, DWS_WORD_LOCK_RETRIES);
	if (ret == 0)
		ret = nor_full_status_check(base_addr);
	nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);

	return ret;
}

/*
 * unlock a full 256 block
 * Return values:
 *  0 = success
 *  otherwise it returns a negative value
 */
int nor_unlock(uintptr_t base_addr)
{
	int ret;

	nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);

	nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK);
	nor_send_cmd(base_addr, NOR_UNLOCK_BLOCK);

	ret = nor_poll_dws(base_addr, DWS_WORD_LOCK_RETRIES);
	if (ret == 0)
		ret = nor_full_status_check(base_addr);
	nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);

	return ret;
}
