diff mbox series

[U-Boot,v1,08/16] arm: socfpga: stratix10: Add mailbox support for Stratix10 SoC

Message ID 1524131457-19234-9-git-send-email-ley.foon.tan@intel.com
State Superseded
Delegated to: Marek Vasut
Headers show
Series Add Intel Stratix 10 SoC support | expand

Commit Message

Ley Foon Tan April 19, 2018, 9:50 a.m. UTC
Add mailbox support for Stratix SoC

Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
---
 arch/arm/mach-socfpga/Makefile                   |    1 +
 arch/arm/mach-socfpga/include/mach/mailbox_s10.h |  155 +++++++++
 arch/arm/mach-socfpga/mailbox_s10.c              |  378 ++++++++++++++++++++++
 3 files changed, 534 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-socfpga/include/mach/mailbox_s10.h
 create mode 100644 arch/arm/mach-socfpga/mailbox_s10.c

Comments

Marek Vasut April 19, 2018, 2:53 a.m. UTC | #1
On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
> Add mailbox support for Stratix SoC
> 
> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
> ---
>  arch/arm/mach-socfpga/Makefile                   |    1 +
>  arch/arm/mach-socfpga/include/mach/mailbox_s10.h |  155 +++++++++
>  arch/arm/mach-socfpga/mailbox_s10.c              |  378 ++++++++++++++++++++++
>  3 files changed, 534 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-socfpga/include/mach/mailbox_s10.h
>  create mode 100644 arch/arm/mach-socfpga/mailbox_s10.c
> 
> diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
> index b253914..43e18d2 100644
> --- a/arch/arm/mach-socfpga/Makefile
> +++ b/arch/arm/mach-socfpga/Makefile
> @@ -32,6 +32,7 @@ endif
>  
>  ifdef CONFIG_TARGET_SOCFPGA_STRATIX10
>  obj-y	+= clock_manager_s10.o
> +obj-y	+= mailbox_s10.o
>  obj-y	+= misc_s10.o
>  obj-y	+= reset_manager_s10.o
>  obj-y	+= system_manager_s10.o
> diff --git a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
> new file mode 100644
> index 0000000..85e7f84
> --- /dev/null
> +++ b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
> @@ -0,0 +1,155 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
> + *
> + */
> +
> +#ifndef _MAILBOX_S10_H_
> +#define _MAILBOX_S10_H_
> +
> +/* user define Uboot ID */
> +#define MBOX_CLIENT_ID_UBOOT	0xB
> +#define MBOX_ID_UBOOT		0x1
> +
> +#define MBOX_CMD_DIRECT	0
> +#define MBOX_CMD_INDIRECT	1
> +
> +#define MBOX_MAX_CMD_INDEX	2047
> +#define MBOX_CMD_BUFFER_SIZE	32
> +#define MBOX_RESP_BUFFER_SIZE	16
> +
> +#define MBOX_HDR_CMD_LSB	0
> +#define MBOX_HDR_CMD_MSK	(BIT(11) - 1)
> +#define MBOX_HDR_I_LSB		11
> +#define MBOX_HDR_I_MSK		BIT(11)
> +#define MBOX_HDR_LEN_LSB	12
> +#define MBOX_HDR_LEN_MSK	0x007FF000
> +#define MBOX_HDR_ID_LSB		24
> +#define MBOX_HDR_ID_MSK		0x0F000000
> +#define MBOX_HDR_CLIENT_LSB	28
> +#define MBOX_HDR_CLIENT_MSK	0xF0000000
> +
> +/* Interrupt flags */
> +#define MBOX_FLAGS_INT_COE	BIT(0)	/* COUT update interrupt enable */
> +#define MBOX_FLAGS_INT_RIE	BIT(1)	/* RIN update interrupt enable */
> +#define MBOX_FLAGS_INT_UAE	BIT(8)	/* Urgent ACK interrupt enable */
> +#define MBOX_ALL_INTRS		(MBOX_FLAGS_INT_COE | \
> +				 MBOX_FLAGS_INT_RIE | \
> +				 MBOX_FLAGS_INT_UAE)
> +
> +/* Status */
> +#define MBOX_STATUS_UA_MSK	BIT(8)
> +
> +#define MBOX_CMD_HEADER(client, id, len, indirect, cmd)     \
> +	((((cmd) << MBOX_HDR_CMD_LSB) & MBOX_HDR_CMD_MSK) | \
> +	(((indirect) << MBOX_HDR_I_LSB) & MBOX_HDR_I_MSK) | \
> +	(((len) << MBOX_HDR_LEN_LSB) & MBOX_HDR_LEN_MSK)  | \
> +	(((id) << MBOX_HDR_ID_LSB) & MBOX_HDR_ID_MSK)     | \
> +	(((client) << MBOX_HDR_CLIENT_LSB) & MBOX_HDR_CLIENT_MSK))
> +
> +#define MBOX_RESP_ERR_GET(resp)				\
> +	(((resp) & MBOX_HDR_CMD_MSK) >> MBOX_HDR_CMD_LSB)
> +#define MBOX_RESP_LEN_GET(resp)			\
> +	(((resp) & MBOX_HDR_LEN_MSK) >> MBOX_HDR_LEN_LSB)
> +#define MBOX_RESP_ID_GET(resp)				\
> +	(((resp) & MBOX_HDR_ID_MSK) >> MBOX_HDR_ID_LSB)
> +#define MBOX_RESP_CLIENT_GET(resp)			\
> +	(((resp) & MBOX_HDR_CLIENT_MSK) >> MBOX_HDR_CLIENT_LSB)
> +
> +/* Response error list */
> +enum ALT_SDM_MBOX_RESP_CODE {
> +	/* CMD completed successfully, but check resp ARGS for any errors */
> +	MBOX_RESP_STATOK = 0,
> +	/* CMD is incorrectly formatted in some way */
> +	MBOX_RESP_INVALID_COMMAND = 1,
> +	/* BootROM Command code not undesrtood */
> +	MBOX_RESP_UNKNOWN_BR = 2,
> +	/* CMD code not recognized by firmware */
> +	MBOX_RESP_UNKNOWN = 3,
> +	/* Indicates that the device is not configured */
> +	MBOX_RESP_NOT_CONFIGURED = 256,
> +	/* Indicates that the device is busy */
> +	MBOX_RESP_DEVICE_BUSY = 0x1FF,
> +	/* Indicates that there is no valid response available */
> +	MBOX_RESP_NO_VALID_RESP_AVAILABLE = 0x2FF,
> +	/* General Error */
> +	MBOX_RESP_ERROR = 0x3FF,
> +};
> +
> +/* Mailbox command list */
> +#define MBOX_RESTART		2
> +#define MBOX_CONFIG_STATUS	4
> +#define MBOX_RECONFIG		6
> +#define MBOX_RECONFIG_MSEL	7
> +#define MBOX_RECONFIG_DATA	8
> +#define MBOX_RECONFIG_STATUS	9
> +#define MBOX_QSPI_OPEN		50
> +#define MBOX_QSPI_CLOSE		51
> +#define MBOX_QSPI_DIRECT	59
> +#define MBOX_REBOOT_HPS		71
> +
> +struct socfpga_mailbox {

We should probably just use register offset macros in new code, this
struct {} stuff often doesn't work too well and the limitations are showing.

> +	u32 cin;		/* command valid offset */
> +	u32 rout;		/* response output offset */
> +	u32 urg;		/* urgent command */
> +	u32 flags;		/* interrupt enables */
> +	u32 pad_0x10_0x1f[4];	/* 0x10 - 0x1F reserved */
> +	u32 cout;		/* command free offset */
> +	u32 rin;		/* respond valid offset */
> +	u32 pad_0x28;		/* 0x28 reserved */
> +	u32 status;		/* mailbox status */
> +	u32 pad_0x30_0x3f[4];	/* 0x30 - 0x3F reserved */
> +	u32 cmd_buf[MBOX_CMD_BUFFER_SIZE];	/* 0x40 - 0xBC circular command
> +						 * buffer to SDM
> +						 */
> +	u32 resp_buf[MBOX_RESP_BUFFER_SIZE];	/* 0xC0 - 0xFF circular
> +						 * response buffer
> +						 */
> +};
> +
> +/* Use define other than put into struct socfpga_mailbox to save spaces */
> +#define MBOX_DOORBELL_TO_SDM_REG	(SOCFPGA_MAILBOX_ADDRESS + 0x400)
> +#define MBOX_DOORBELL_FROM_SDM_REG	(SOCFPGA_MAILBOX_ADDRESS + 0x480)
> +
> +/******** Status and bit information returned by RECONFIG_STATUS ********/
> +#define RECONFIG_STATUS_RESPONSE_LEN			6
> +#define RECONFIG_STATUS_STATE				0
> +#define RECONFIG_STATUS_PIN_STATUS			2
> +#define RECONFIG_STATUS_SOFTFUNC_STATUS			3
> +
> +#define MBOX_CFGSTAT_STATE_IDLE				0x00000000
> +#define MBOX_CFGSTAT_STATE_CONFIG			0x10000000
> +#define MBOX_CFGSTAT_STATE_FAILACK			0x08000000
> +#define MBOX_CFGSTAT_STATE_ERROR_INVALID		0xf0000001
> +#define MBOX_CFGSTAT_STATE_ERROR_CORRUPT		0xf0000002
> +#define MBOX_CFGSTAT_STATE_ERROR_AUTH			0xf0000003
> +#define MBOX_CFGSTAT_STATE_ERROR_CORE_IO		0xf0000004
> +#define MBOX_CFGSTAT_STATE_ERROR_HARDWARE		0xf0000005
> +#define MBOX_CFGSTAT_STATE_ERROR_FAKE			0xf0000006
> +#define MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO		0xf0000007
> +#define MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR		0xf0000008
> +
> +#define RCF_SOFTFUNC_STATUS_CONF_DONE			BIT(0)
> +#define RCF_SOFTFUNC_STATUS_INIT_DONE			BIT(1)
> +#define RCF_SOFTFUNC_STATUS_SEU_ERROR			BIT(3)
> +#define RCF_PIN_STATUS_NSTATUS				BIT(31)
> +/************************************************************************/
> +
> +int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg, u8 urgent,
> +		  u32 *resp_buf_len, u32 *resp_buf);
> +int mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
> +		       u8 urgent, u32 *resp_buf_len, u32 *resp_buf);
> +int mbox_send_cmd_only(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg);
> +int mbox_send_cmd_only_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg);
> +int mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len);
> +int mbox_rcv_resp_psci(u32 *resp_buf, u32 resp_buf_max_len);
> +int mbox_init(void);
> +
> +#ifdef CONFIG_CADENCE_QSPI
> +int mbox_qspi_close(void);
> +int mbox_qspi_open(void);
> +#endif
> +
> +int mbox_reset_cold(void);
> +
> +#endif /* _MAILBOX_S10_H_ */
> diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c
> new file mode 100644
> index 0000000..ed713a9
> --- /dev/null
> +++ b/arch/arm/mach-socfpga/mailbox_s10.c
> @@ -0,0 +1,378 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
> + *
> + */
> +
> +#include <common.h>
> +#include <wait_bit.h>
> +#include <asm/io.h>
> +#include <asm/arch/mailbox_s10.h>
> +#include <asm/arch/system_manager.h>
> +#include <asm/secure.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +static __always_inline int mbox_polling_resp(u32 rout)
> +{
> +	static const struct socfpga_mailbox *mbox_base =
> +					(void *)SOCFPGA_MAILBOX_ADDRESS;
> +	u32 rin;
> +	unsigned long i = ~0;
> +
> +	while (i) {
> +		rin = readl(&mbox_base->rin);
> +		if (rout != rin)
> +			return 0;

This looks like include/wait_bit.h reimplementation

> +		i--;
> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +/* Check for available slot and write to circular buffer.
> + * It also update command valid offset (cin) register.
> + */
> +static __always_inline int mbox_fill_cmd_circular_buff(u32 header, u32 len,
> +						       u32 *arg)
> +{
> +	static const struct socfpga_mailbox *mbox_base =
> +					(void *)SOCFPGA_MAILBOX_ADDRESS;
> +	u32 cin;
> +	u32 cout;
> +	u32 i;
> +
> +	cin = readl(&mbox_base->cin) % MBOX_CMD_BUFFER_SIZE;
> +	cout = readl(&mbox_base->cout) % MBOX_CMD_BUFFER_SIZE;
> +
> +	/* if command buffer is full or not enough free space
> +	 * to fit the data
> +	 */
> +	if (((cin + 1) % MBOX_CMD_BUFFER_SIZE) == cout ||
> +	    ((MBOX_CMD_BUFFER_SIZE - cin + cout - 1) %
> +	     MBOX_CMD_BUFFER_SIZE) < len)
> +		return -ENOMEM;
> +
> +	/* write header to circular buffer */
> +	writel(header, &mbox_base->cmd_buf[cin++]);
> +	/* wrapping around when it reach the buffer size */
> +	cin %= MBOX_CMD_BUFFER_SIZE;
> +
> +	/* write arguments */
> +	for (i = 0; i < len; i++) {
> +		writel(arg[i], &mbox_base->cmd_buf[cin++]);
> +		/* wrapping around when it reach the buffer size */
> +		cin %= MBOX_CMD_BUFFER_SIZE;
> +	}
> +
> +	/* write command valid offset */
> +	writel(cin, &mbox_base->cin);
> +
> +	return 0;
> +}
> +
> +/* Check the command and fill it into circular buffer */
> +static __always_inline int mbox_prepare_cmd_only(u8 id, u32 cmd,
> +						 u8 is_indirect, u32 len,
> +						 u32 *arg)
> +{
> +	u32 header;
> +	int ret;
> +
> +	/* Total length is command + argument length */
> +	if ((len + 1) > MBOX_CMD_BUFFER_SIZE)
> +		return -EINVAL;
> +
> +	if (cmd > MBOX_MAX_CMD_INDEX)
> +		return -EINVAL;
> +
> +	header = MBOX_CMD_HEADER(MBOX_CLIENT_ID_UBOOT, id, len,
> +				 (is_indirect) ? 1 : 0, cmd);
> +
> +	ret = mbox_fill_cmd_circular_buff(header, len, arg);
> +
> +	return ret;
> +}
> +
> +/* Send command only without waiting for responses from SDM */
> +static __always_inline int __mbox_send_cmd_only(u8 id, u32 cmd,
> +						u8 is_indirect, u32 len,
> +						u32 *arg)
> +{
> +	int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
> +	/* write doorbell */
> +	writel(1, MBOX_DOORBELL_TO_SDM_REG);
> +
> +	return ret;
> +}
> +
> +/* Return number of responses received in buffer */
> +static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)

__always_inline is nonsense, drop it. Let the compiler do it's thing.

> +{
> +	static const struct socfpga_mailbox *mbox_base =
> +					(void *)SOCFPGA_MAILBOX_ADDRESS;
> +	u32 rin;
> +	u32 rout;
> +	u32 resp_len = 0;
> +
> +	/* clear doorbell from SDM if it was SET */
> +	if (readl((const u32 *)MBOX_DOORBELL_FROM_SDM_REG) & 1)
> +		writel(0, MBOX_DOORBELL_FROM_SDM_REG);
> +
> +	/* read current response offset */
> +	rout = readl(&mbox_base->rout);
> +	/* read response valid offset */
> +	rin = readl(&mbox_base->rin);
> +
> +	while (rin != rout && (resp_len < resp_buf_max_len)) {
> +		/* Response received */
> +		if (resp_buf)
> +			resp_buf[resp_len++] =
> +				readl(&mbox_base->resp_buf[rout]);
> +		rout++;
> +		/* wrapping around when it reach the buffer size */
> +		rout %= MBOX_RESP_BUFFER_SIZE;
> +		/* update next ROUT */
> +		writel(rout, &mbox_base->rout);
> +	}
> +
> +	return resp_len;
> +}
> +
> +/* Support one command and up to 31 words argument length only */
> +static __always_inline int __mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect,
> +					   u32 len, u32 *arg, u8 urgent,
> +					   u32 *resp_buf_len, u32 *resp_buf)
> +{
> +	static const struct socfpga_mailbox *mbox_base =
> +					(void *)SOCFPGA_MAILBOX_ADDRESS;
> +
> +	u32 rin;
> +	u32 resp;
> +	u32 rout;
> +	u32 status;
> +	u32 resp_len;
> +	u32 buf_len;
> +	int ret;
> +
> +	ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
> +	if (ret)
> +		return ret;
> +
> +	if (urgent) {
> +		/* Read status because it is toggled */
> +		status = readl(&mbox_base->status) & MBOX_STATUS_UA_MSK;
> +		/* Send command as urgent command */
> +		writel(1, &mbox_base->urg);
> +	}
> +
> +	/* write doorbell */
> +	writel(1, MBOX_DOORBELL_TO_SDM_REG);
> +
> +	while (1) {
> +		ret = ~0;
> +
> +		/* Wait for doorbell from SDM */
> +		while (!readl(MBOX_DOORBELL_FROM_SDM_REG) && ret--)
> +			;
> +		if (!ret)
> +			return -ETIMEDOUT;

wait_for_bit...

> +		/* clear interrupt */
> +		writel(0, MBOX_DOORBELL_FROM_SDM_REG);
> +
> +		if (urgent) {
> +			u32 new_status = readl(&mbox_base->status);
> +			/* urgent command doesn't have response */
> +			writel(0, &mbox_base->urg);
> +			/* Urgent ACK is toggled */
> +			if ((new_status & MBOX_STATUS_UA_MSK) ^ status)
> +				return 0;
> +
> +			return -ECOMM;
> +		}
> +
> +		/* read current response offset */
> +		rout = readl(&mbox_base->rout);
> +
> +		/* read response valid offset */
> +		rin = readl(&mbox_base->rin);
> +
> +		if (rout != rin) {
> +			/* Response received */
> +			resp = readl(&mbox_base->resp_buf[rout]);
> +			rout++;
> +			/* wrapping around when it reach the buffer size */
> +			rout %= MBOX_RESP_BUFFER_SIZE;
> +			/* update next ROUT */
> +			writel(rout, &mbox_base->rout);
> +
> +			/* check client ID and ID */
> +			if ((MBOX_RESP_CLIENT_GET(resp) == MBOX_CLIENT_ID_UBOOT) &&
> +			    (MBOX_RESP_ID_GET(resp) == id)) {
> +				ret = MBOX_RESP_ERR_GET(resp);
> +				if (ret)
> +					return ret;
> +
> +				if (resp_buf_len) {
> +					buf_len = *resp_buf_len;
> +					*resp_buf_len = 0;
> +				} else {
> +					buf_len = 0;
> +				}
> +
> +				resp_len = MBOX_RESP_LEN_GET(resp);
> +				while (resp_len) {
> +					ret = mbox_polling_resp(rout);
> +					if (ret)
> +						return ret;
> +					/* we need to process response buffer
> +					 * even caller doesn't need it
> +					 */
> +					resp = readl(&mbox_base->resp_buf[rout]);
> +					rout++;
> +					resp_len--;
> +					rout %= MBOX_RESP_BUFFER_SIZE;
> +					writel(rout, &mbox_base->rout);
> +					if (buf_len) {
> +						/* copy response to buffer */
> +						resp_buf[*resp_buf_len] = resp;
> +						(*resp_buf_len)++;
> +						buf_len--;
> +					}
> +				}
> +				return ret;
> +			}
> +		}
> +	};
> +
> +	return -EIO;
> +}
> +
> +int mbox_init(void)
> +{
> +	static const struct socfpga_mailbox *mbox_base =
> +					(void *)SOCFPGA_MAILBOX_ADDRESS;
> +	int ret;
> +
> +	/* enable mailbox interrupts */
> +	writel(MBOX_ALL_INTRS, &mbox_base->flags);
> +
> +	/* Ensure urgent request is cleared */
> +	writel(0, &mbox_base->urg);
> +
> +	/* Ensure the Doorbell Interrupt is cleared */
> +	writel(0, MBOX_DOORBELL_FROM_SDM_REG);
> +
> +	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RESTART, MBOX_CMD_DIRECT, 0,
> +			    NULL, 1, 0, NULL);
> +	if (ret)
> +		return ret;
> +
> +	/* Renable mailbox interrupts after MBOX_RESTART */
> +	writel(MBOX_ALL_INTRS, &mbox_base->flags);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_CADENCE_QSPI
> +int mbox_qspi_close(void)
> +{
> +	return mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_CLOSE, MBOX_CMD_DIRECT,
> +			     0, NULL, 0, 0, NULL);
> +}
> +
> +int mbox_qspi_open(void)
> +{
> +	static const struct socfpga_system_manager *sysmgr_regs =
> +		(struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
> +
> +	int ret;
> +	u32 resp_buf[1];
> +	u32 resp_buf_len;
> +
> +	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN, MBOX_CMD_DIRECT,
> +			    0, NULL, 0, 0, NULL);
> +	if (ret) {
> +		/* retry again by closing and reopen the QSPI again */
> +		ret = mbox_qspi_close();
> +		if (ret)
> +			return ret;
> +
> +		ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN,
> +				    MBOX_CMD_DIRECT, 0, NULL, 0, 0, NULL);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	/* HPS will directly control the QSPI controller, no longer mailbox */
> +	resp_buf_len = 1;
> +	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_DIRECT, MBOX_CMD_DIRECT,
> +			    0, NULL, 0, (u32 *)&resp_buf_len,
> +			    (u32 *)&resp_buf);
> +	if (ret)
> +		goto error;
> +
> +	/* We are getting QSPI ref clock and set into sysmgr boot register */
> +	printf("QSPI: Reference clock at %d Hz\n", resp_buf[0]);

Certainly something I can get out of clock or clk command, drop the print.

> +	writel(resp_buf[0], &sysmgr_regs->boot_scratch_cold0);
> +
> +	return 0;
> +
> +error:
> +	mbox_qspi_close();
> +
> +	return ret;
> +}
> +#endif /* CONFIG_CADENCE_QSPI */
> +
> +int mbox_reset_cold(void)
> +{
> +	int ret;
> +
> +	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_REBOOT_HPS, MBOX_CMD_DIRECT,
> +			    0, NULL, 0, 0, NULL);
> +	if (ret) {
> +		/* mailbox sent failure, wait for watchdog to kick in */
> +		while (1)
> +			;

Is this supposed to be hang() ?

> +	}
> +	return 0;
> +}
> +
> +int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
> +		  u8 urgent, u32 *resp_buf_len, u32 *resp_buf)
> +{
> +	return __mbox_send_cmd(id, cmd, is_indirect, len, arg, urgent,
> +			       resp_buf_len, resp_buf);
> +}

__anything is reserved for compiler, drop the leading underscores
>
Ley Foon Tan May 8, 2018, 6:49 a.m. UTC | #2
On Thu, Apr 19, 2018 at 10:53 AM, Marek Vasut <marex@denx.de> wrote:
> On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
>> Add mailbox support for Stratix SoC
>>
>> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
>> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
>> ---
>>  arch/arm/mach-socfpga/Makefile                   |    1 +
>>  arch/arm/mach-socfpga/include/mach/mailbox_s10.h |  155 +++++++++
>>  arch/arm/mach-socfpga/mailbox_s10.c              |  378 ++++++++++++++++++++++
>>  3 files changed, 534 insertions(+), 0 deletions(-)
>>  create mode 100644 arch/arm/mach-socfpga/include/mach/mailbox_s10.h
>>  create mode 100644 arch/arm/mach-socfpga/mailbox_s10.c
>>
>> diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
>> index b253914..43e18d2 100644
>> --- a/arch/arm/mach-socfpga/Makefile
>> +++ b/arch/arm/mach-socfpga/Makefile
>> @@ -32,6 +32,7 @@ endif
>>
>>  ifdef CONFIG_TARGET_SOCFPGA_STRATIX10
>>  obj-y        += clock_manager_s10.o
>> +obj-y        += mailbox_s10.o
>>  obj-y        += misc_s10.o
>>  obj-y        += reset_manager_s10.o
>>  obj-y        += system_manager_s10.o
>> diff --git a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
>> new file mode 100644
>> index 0000000..85e7f84
>> --- /dev/null
>> +++ b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
>> @@ -0,0 +1,155 @@
>> +/* SPDX-License-Identifier: GPL-2.0
>> + *
>> + * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
>> + *
>> + */
>> +
>> +#ifndef _MAILBOX_S10_H_
>> +#define _MAILBOX_S10_H_
>> +
>> +/* user define Uboot ID */
>> +#define MBOX_CLIENT_ID_UBOOT 0xB
>> +#define MBOX_ID_UBOOT                0x1
>> +
>> +#define MBOX_CMD_DIRECT      0
>> +#define MBOX_CMD_INDIRECT    1
>> +
>> +#define MBOX_MAX_CMD_INDEX   2047
>> +#define MBOX_CMD_BUFFER_SIZE 32
>> +#define MBOX_RESP_BUFFER_SIZE        16
>> +
>> +#define MBOX_HDR_CMD_LSB     0
>> +#define MBOX_HDR_CMD_MSK     (BIT(11) - 1)
>> +#define MBOX_HDR_I_LSB               11
>> +#define MBOX_HDR_I_MSK               BIT(11)
>> +#define MBOX_HDR_LEN_LSB     12
>> +#define MBOX_HDR_LEN_MSK     0x007FF000
>> +#define MBOX_HDR_ID_LSB              24
>> +#define MBOX_HDR_ID_MSK              0x0F000000
>> +#define MBOX_HDR_CLIENT_LSB  28
>> +#define MBOX_HDR_CLIENT_MSK  0xF0000000
>> +
>> +/* Interrupt flags */
>> +#define MBOX_FLAGS_INT_COE   BIT(0)  /* COUT update interrupt enable */
>> +#define MBOX_FLAGS_INT_RIE   BIT(1)  /* RIN update interrupt enable */
>> +#define MBOX_FLAGS_INT_UAE   BIT(8)  /* Urgent ACK interrupt enable */
>> +#define MBOX_ALL_INTRS               (MBOX_FLAGS_INT_COE | \
>> +                              MBOX_FLAGS_INT_RIE | \
>> +                              MBOX_FLAGS_INT_UAE)
>> +
>> +/* Status */
>> +#define MBOX_STATUS_UA_MSK   BIT(8)
>> +
>> +#define MBOX_CMD_HEADER(client, id, len, indirect, cmd)     \
>> +     ((((cmd) << MBOX_HDR_CMD_LSB) & MBOX_HDR_CMD_MSK) | \
>> +     (((indirect) << MBOX_HDR_I_LSB) & MBOX_HDR_I_MSK) | \
>> +     (((len) << MBOX_HDR_LEN_LSB) & MBOX_HDR_LEN_MSK)  | \
>> +     (((id) << MBOX_HDR_ID_LSB) & MBOX_HDR_ID_MSK)     | \
>> +     (((client) << MBOX_HDR_CLIENT_LSB) & MBOX_HDR_CLIENT_MSK))
>> +
>> +#define MBOX_RESP_ERR_GET(resp)                              \
>> +     (((resp) & MBOX_HDR_CMD_MSK) >> MBOX_HDR_CMD_LSB)
>> +#define MBOX_RESP_LEN_GET(resp)                      \
>> +     (((resp) & MBOX_HDR_LEN_MSK) >> MBOX_HDR_LEN_LSB)
>> +#define MBOX_RESP_ID_GET(resp)                               \
>> +     (((resp) & MBOX_HDR_ID_MSK) >> MBOX_HDR_ID_LSB)
>> +#define MBOX_RESP_CLIENT_GET(resp)                   \
>> +     (((resp) & MBOX_HDR_CLIENT_MSK) >> MBOX_HDR_CLIENT_LSB)
>> +
>> +/* Response error list */
>> +enum ALT_SDM_MBOX_RESP_CODE {
>> +     /* CMD completed successfully, but check resp ARGS for any errors */
>> +     MBOX_RESP_STATOK = 0,
>> +     /* CMD is incorrectly formatted in some way */
>> +     MBOX_RESP_INVALID_COMMAND = 1,
>> +     /* BootROM Command code not undesrtood */
>> +     MBOX_RESP_UNKNOWN_BR = 2,
>> +     /* CMD code not recognized by firmware */
>> +     MBOX_RESP_UNKNOWN = 3,
>> +     /* Indicates that the device is not configured */
>> +     MBOX_RESP_NOT_CONFIGURED = 256,
>> +     /* Indicates that the device is busy */
>> +     MBOX_RESP_DEVICE_BUSY = 0x1FF,
>> +     /* Indicates that there is no valid response available */
>> +     MBOX_RESP_NO_VALID_RESP_AVAILABLE = 0x2FF,
>> +     /* General Error */
>> +     MBOX_RESP_ERROR = 0x3FF,
>> +};
>> +
>> +/* Mailbox command list */
>> +#define MBOX_RESTART         2
>> +#define MBOX_CONFIG_STATUS   4
>> +#define MBOX_RECONFIG                6
>> +#define MBOX_RECONFIG_MSEL   7
>> +#define MBOX_RECONFIG_DATA   8
>> +#define MBOX_RECONFIG_STATUS 9
>> +#define MBOX_QSPI_OPEN               50
>> +#define MBOX_QSPI_CLOSE              51
>> +#define MBOX_QSPI_DIRECT     59
>> +#define MBOX_REBOOT_HPS              71
>> +
>> +struct socfpga_mailbox {
>
> We should probably just use register offset macros in new code, this
> struct {} stuff often doesn't work too well and the limitations are showing.
Okay, will change this.
>
>> +     u32 cin;                /* command valid offset */
>> +     u32 rout;               /* response output offset */
>> +     u32 urg;                /* urgent command */
>> +     u32 flags;              /* interrupt enables */
>> +     u32 pad_0x10_0x1f[4];   /* 0x10 - 0x1F reserved */
>> +     u32 cout;               /* command free offset */
>> +     u32 rin;                /* respond valid offset */
>> +     u32 pad_0x28;           /* 0x28 reserved */
>> +     u32 status;             /* mailbox status */
>> +     u32 pad_0x30_0x3f[4];   /* 0x30 - 0x3F reserved */
>> +     u32 cmd_buf[MBOX_CMD_BUFFER_SIZE];      /* 0x40 - 0xBC circular command
>> +                                              * buffer to SDM
>> +                                              */
>> +     u32 resp_buf[MBOX_RESP_BUFFER_SIZE];    /* 0xC0 - 0xFF circular
>> +                                              * response buffer
>> +                                              */
>> +};
>> +
>> +/* Use define other than put into struct socfpga_mailbox to save spaces */
>> +#define MBOX_DOORBELL_TO_SDM_REG     (SOCFPGA_MAILBOX_ADDRESS + 0x400)
>> +#define MBOX_DOORBELL_FROM_SDM_REG   (SOCFPGA_MAILBOX_ADDRESS + 0x480)
>> +
>> +/******** Status and bit information returned by RECONFIG_STATUS ********/
>> +#define RECONFIG_STATUS_RESPONSE_LEN                 6
>> +#define RECONFIG_STATUS_STATE                                0
>> +#define RECONFIG_STATUS_PIN_STATUS                   2
>> +#define RECONFIG_STATUS_SOFTFUNC_STATUS                      3
>> +
>> +#define MBOX_CFGSTAT_STATE_IDLE                              0x00000000
>> +#define MBOX_CFGSTAT_STATE_CONFIG                    0x10000000
>> +#define MBOX_CFGSTAT_STATE_FAILACK                   0x08000000
>> +#define MBOX_CFGSTAT_STATE_ERROR_INVALID             0xf0000001
>> +#define MBOX_CFGSTAT_STATE_ERROR_CORRUPT             0xf0000002
>> +#define MBOX_CFGSTAT_STATE_ERROR_AUTH                        0xf0000003
>> +#define MBOX_CFGSTAT_STATE_ERROR_CORE_IO             0xf0000004
>> +#define MBOX_CFGSTAT_STATE_ERROR_HARDWARE            0xf0000005
>> +#define MBOX_CFGSTAT_STATE_ERROR_FAKE                        0xf0000006
>> +#define MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO           0xf0000007
>> +#define MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR          0xf0000008
>> +
>> +#define RCF_SOFTFUNC_STATUS_CONF_DONE                        BIT(0)
>> +#define RCF_SOFTFUNC_STATUS_INIT_DONE                        BIT(1)
>> +#define RCF_SOFTFUNC_STATUS_SEU_ERROR                        BIT(3)
>> +#define RCF_PIN_STATUS_NSTATUS                               BIT(31)
>> +/************************************************************************/
>> +
>> +int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg, u8 urgent,
>> +               u32 *resp_buf_len, u32 *resp_buf);
>> +int mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
>> +                    u8 urgent, u32 *resp_buf_len, u32 *resp_buf);
>> +int mbox_send_cmd_only(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg);
>> +int mbox_send_cmd_only_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg);
>> +int mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len);
>> +int mbox_rcv_resp_psci(u32 *resp_buf, u32 resp_buf_max_len);
>> +int mbox_init(void);
>> +
>> +#ifdef CONFIG_CADENCE_QSPI
>> +int mbox_qspi_close(void);
>> +int mbox_qspi_open(void);
>> +#endif
>> +
>> +int mbox_reset_cold(void);
>> +
>> +#endif /* _MAILBOX_S10_H_ */
>> diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c
>> new file mode 100644
>> index 0000000..ed713a9
>> --- /dev/null
>> +++ b/arch/arm/mach-socfpga/mailbox_s10.c
>> @@ -0,0 +1,378 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
>> + *
>> + */
>> +
>> +#include <common.h>
>> +#include <wait_bit.h>
>> +#include <asm/io.h>
>> +#include <asm/arch/mailbox_s10.h>
>> +#include <asm/arch/system_manager.h>
>> +#include <asm/secure.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +static __always_inline int mbox_polling_resp(u32 rout)
>> +{
>> +     static const struct socfpga_mailbox *mbox_base =
>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>> +     u32 rin;
>> +     unsigned long i = ~0;
>> +
>> +     while (i) {
>> +             rin = readl(&mbox_base->rin);
>> +             if (rout != rin)
>> +                     return 0;
>
> This looks like include/wait_bit.h reimplementation
The reason we use this method instead of using wait_bit because this
function will use in Secure Monitor Call (SMC) call as well.
When run in secure section, timer is not available.  So, we can't use
wait_for_bit.

>
>> +             i--;
>> +     }
>> +
>> +     return -ETIMEDOUT;
>> +}
>> +
>> +/* Check for available slot and write to circular buffer.
>> + * It also update command valid offset (cin) register.
>> + */
>> +static __always_inline int mbox_fill_cmd_circular_buff(u32 header, u32 len,
>> +                                                    u32 *arg)
>> +{
>> +     static const struct socfpga_mailbox *mbox_base =
>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>> +     u32 cin;
>> +     u32 cout;
>> +     u32 i;
>> +
>> +     cin = readl(&mbox_base->cin) % MBOX_CMD_BUFFER_SIZE;
>> +     cout = readl(&mbox_base->cout) % MBOX_CMD_BUFFER_SIZE;
>> +
>> +     /* if command buffer is full or not enough free space
>> +      * to fit the data
>> +      */
>> +     if (((cin + 1) % MBOX_CMD_BUFFER_SIZE) == cout ||
>> +         ((MBOX_CMD_BUFFER_SIZE - cin + cout - 1) %
>> +          MBOX_CMD_BUFFER_SIZE) < len)
>> +             return -ENOMEM;
>> +
>> +     /* write header to circular buffer */
>> +     writel(header, &mbox_base->cmd_buf[cin++]);
>> +     /* wrapping around when it reach the buffer size */
>> +     cin %= MBOX_CMD_BUFFER_SIZE;
>> +
>> +     /* write arguments */
>> +     for (i = 0; i < len; i++) {
>> +             writel(arg[i], &mbox_base->cmd_buf[cin++]);
>> +             /* wrapping around when it reach the buffer size */
>> +             cin %= MBOX_CMD_BUFFER_SIZE;
>> +     }
>> +
>> +     /* write command valid offset */
>> +     writel(cin, &mbox_base->cin);
>> +
>> +     return 0;
>> +}
>> +
>> +/* Check the command and fill it into circular buffer */
>> +static __always_inline int mbox_prepare_cmd_only(u8 id, u32 cmd,
>> +                                              u8 is_indirect, u32 len,
>> +                                              u32 *arg)
>> +{
>> +     u32 header;
>> +     int ret;
>> +
>> +     /* Total length is command + argument length */
>> +     if ((len + 1) > MBOX_CMD_BUFFER_SIZE)
>> +             return -EINVAL;
>> +
>> +     if (cmd > MBOX_MAX_CMD_INDEX)
>> +             return -EINVAL;
>> +
>> +     header = MBOX_CMD_HEADER(MBOX_CLIENT_ID_UBOOT, id, len,
>> +                              (is_indirect) ? 1 : 0, cmd);
>> +
>> +     ret = mbox_fill_cmd_circular_buff(header, len, arg);
>> +
>> +     return ret;
>> +}
>> +
>> +/* Send command only without waiting for responses from SDM */
>> +static __always_inline int __mbox_send_cmd_only(u8 id, u32 cmd,
>> +                                             u8 is_indirect, u32 len,
>> +                                             u32 *arg)
>> +{
>> +     int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
>> +     /* write doorbell */
>> +     writel(1, MBOX_DOORBELL_TO_SDM_REG);
>> +
>> +     return ret;
>> +}
>> +
>> +/* Return number of responses received in buffer */
>> +static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
>
> __always_inline is nonsense, drop it. Let the compiler do it's thing.
This function used in SMC call as well, so it needs to be inline when
in secure section.

>
>> +{
>> +     static const struct socfpga_mailbox *mbox_base =
>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>> +     u32 rin;
>> +     u32 rout;
>> +     u32 resp_len = 0;
>> +
>> +     /* clear doorbell from SDM if it was SET */
>> +     if (readl((const u32 *)MBOX_DOORBELL_FROM_SDM_REG) & 1)
>> +             writel(0, MBOX_DOORBELL_FROM_SDM_REG);
>> +
>> +     /* read current response offset */
>> +     rout = readl(&mbox_base->rout);
>> +     /* read response valid offset */
>> +     rin = readl(&mbox_base->rin);
>> +
>> +     while (rin != rout && (resp_len < resp_buf_max_len)) {
>> +             /* Response received */
>> +             if (resp_buf)
>> +                     resp_buf[resp_len++] =
>> +                             readl(&mbox_base->resp_buf[rout]);
>> +             rout++;
>> +             /* wrapping around when it reach the buffer size */
>> +             rout %= MBOX_RESP_BUFFER_SIZE;
>> +             /* update next ROUT */
>> +             writel(rout, &mbox_base->rout);
>> +     }
>> +
>> +     return resp_len;
>> +}
>> +
>> +/* Support one command and up to 31 words argument length only */
>> +static __always_inline int __mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect,
>> +                                        u32 len, u32 *arg, u8 urgent,
>> +                                        u32 *resp_buf_len, u32 *resp_buf)
>> +{
>> +     static const struct socfpga_mailbox *mbox_base =
>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>> +
>> +     u32 rin;
>> +     u32 resp;
>> +     u32 rout;
>> +     u32 status;
>> +     u32 resp_len;
>> +     u32 buf_len;
>> +     int ret;
>> +
>> +     ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (urgent) {
>> +             /* Read status because it is toggled */
>> +             status = readl(&mbox_base->status) & MBOX_STATUS_UA_MSK;
>> +             /* Send command as urgent command */
>> +             writel(1, &mbox_base->urg);
>> +     }
>> +
>> +     /* write doorbell */
>> +     writel(1, MBOX_DOORBELL_TO_SDM_REG);
>> +
>> +     while (1) {
>> +             ret = ~0;
>> +
>> +             /* Wait for doorbell from SDM */
>> +             while (!readl(MBOX_DOORBELL_FROM_SDM_REG) && ret--)
>> +                     ;
>> +             if (!ret)
>> +                     return -ETIMEDOUT;
>
> wait_for_bit...
Same reason as above.
>
>> +             /* clear interrupt */
>> +             writel(0, MBOX_DOORBELL_FROM_SDM_REG);
>> +
>> +             if (urgent) {
>> +                     u32 new_status = readl(&mbox_base->status);
>> +                     /* urgent command doesn't have response */
>> +                     writel(0, &mbox_base->urg);
>> +                     /* Urgent ACK is toggled */
>> +                     if ((new_status & MBOX_STATUS_UA_MSK) ^ status)
>> +                             return 0;
>> +
>> +                     return -ECOMM;
>> +             }
>> +
>> +             /* read current response offset */
>> +             rout = readl(&mbox_base->rout);
>> +
>> +             /* read response valid offset */
>> +             rin = readl(&mbox_base->rin);
>> +
>> +             if (rout != rin) {
>> +                     /* Response received */
>> +                     resp = readl(&mbox_base->resp_buf[rout]);
>> +                     rout++;
>> +                     /* wrapping around when it reach the buffer size */
>> +                     rout %= MBOX_RESP_BUFFER_SIZE;
>> +                     /* update next ROUT */
>> +                     writel(rout, &mbox_base->rout);
>> +
>> +                     /* check client ID and ID */
>> +                     if ((MBOX_RESP_CLIENT_GET(resp) == MBOX_CLIENT_ID_UBOOT) &&
>> +                         (MBOX_RESP_ID_GET(resp) == id)) {
>> +                             ret = MBOX_RESP_ERR_GET(resp);
>> +                             if (ret)
>> +                                     return ret;
>> +
>> +                             if (resp_buf_len) {
>> +                                     buf_len = *resp_buf_len;
>> +                                     *resp_buf_len = 0;
>> +                             } else {
>> +                                     buf_len = 0;
>> +                             }
>> +
>> +                             resp_len = MBOX_RESP_LEN_GET(resp);
>> +                             while (resp_len) {
>> +                                     ret = mbox_polling_resp(rout);
>> +                                     if (ret)
>> +                                             return ret;
>> +                                     /* we need to process response buffer
>> +                                      * even caller doesn't need it
>> +                                      */
>> +                                     resp = readl(&mbox_base->resp_buf[rout]);
>> +                                     rout++;
>> +                                     resp_len--;
>> +                                     rout %= MBOX_RESP_BUFFER_SIZE;
>> +                                     writel(rout, &mbox_base->rout);
>> +                                     if (buf_len) {
>> +                                             /* copy response to buffer */
>> +                                             resp_buf[*resp_buf_len] = resp;
>> +                                             (*resp_buf_len)++;
>> +                                             buf_len--;
>> +                                     }
>> +                             }
>> +                             return ret;
>> +                     }
>> +             }
>> +     };
>> +
>> +     return -EIO;
>> +}
>> +
>> +int mbox_init(void)
>> +{
>> +     static const struct socfpga_mailbox *mbox_base =
>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>> +     int ret;
>> +
>> +     /* enable mailbox interrupts */
>> +     writel(MBOX_ALL_INTRS, &mbox_base->flags);
>> +
>> +     /* Ensure urgent request is cleared */
>> +     writel(0, &mbox_base->urg);
>> +
>> +     /* Ensure the Doorbell Interrupt is cleared */
>> +     writel(0, MBOX_DOORBELL_FROM_SDM_REG);
>> +
>> +     ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RESTART, MBOX_CMD_DIRECT, 0,
>> +                         NULL, 1, 0, NULL);
>> +     if (ret)
>> +             return ret;
>> +
>> +     /* Renable mailbox interrupts after MBOX_RESTART */
>> +     writel(MBOX_ALL_INTRS, &mbox_base->flags);
>> +
>> +     return 0;
>> +}
>> +
>> +#ifdef CONFIG_CADENCE_QSPI
>> +int mbox_qspi_close(void)
>> +{
>> +     return mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_CLOSE, MBOX_CMD_DIRECT,
>> +                          0, NULL, 0, 0, NULL);
>> +}
>> +
>> +int mbox_qspi_open(void)
>> +{
>> +     static const struct socfpga_system_manager *sysmgr_regs =
>> +             (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
>> +
>> +     int ret;
>> +     u32 resp_buf[1];
>> +     u32 resp_buf_len;
>> +
>> +     ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN, MBOX_CMD_DIRECT,
>> +                         0, NULL, 0, 0, NULL);
>> +     if (ret) {
>> +             /* retry again by closing and reopen the QSPI again */
>> +             ret = mbox_qspi_close();
>> +             if (ret)
>> +                     return ret;
>> +
>> +             ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN,
>> +                                 MBOX_CMD_DIRECT, 0, NULL, 0, 0, NULL);
>> +             if (ret)
>> +                     return ret;
>> +     }
>> +
>> +     /* HPS will directly control the QSPI controller, no longer mailbox */
>> +     resp_buf_len = 1;
>> +     ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_DIRECT, MBOX_CMD_DIRECT,
>> +                         0, NULL, 0, (u32 *)&resp_buf_len,
>> +                         (u32 *)&resp_buf);
>> +     if (ret)
>> +             goto error;
>> +
>> +     /* We are getting QSPI ref clock and set into sysmgr boot register */
>> +     printf("QSPI: Reference clock at %d Hz\n", resp_buf[0]);
>
> Certainly something I can get out of clock or clk command, drop the print.
In Stratix 10, QSPI IP is not in HPS, but in the SDM side. So, SW
needs send mailbox command to get QSPI clock.
Will change printf to debug().

>
>> +     writel(resp_buf[0], &sysmgr_regs->boot_scratch_cold0);
>> +
>> +     return 0;
>> +
>> +error:
>> +     mbox_qspi_close();
>> +
>> +     return ret;
>> +}
>> +#endif /* CONFIG_CADENCE_QSPI */
>> +
>> +int mbox_reset_cold(void)
>> +{
>> +     int ret;
>> +
>> +     ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_REBOOT_HPS, MBOX_CMD_DIRECT,
>> +                         0, NULL, 0, 0, NULL);
>> +     if (ret) {
>> +             /* mailbox sent failure, wait for watchdog to kick in */
>> +             while (1)
>> +                     ;
>
> Is this supposed to be hang() ?
Okay, will change this.

>
>> +     }
>> +     return 0;
>> +}
>> +
>> +int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
>> +               u8 urgent, u32 *resp_buf_len, u32 *resp_buf)
>> +{
>> +     return __mbox_send_cmd(id, cmd, is_indirect, len, arg, urgent,
>> +                            resp_buf_len, resp_buf);
>> +}
>
> __anything is reserved for compiler, drop the leading underscores
Okay, will change to other name.

>>
>
>
> --
> Best regards,
> Marek Vasut
Marek Vasut May 8, 2018, 9:21 a.m. UTC | #3
On 05/08/2018 08:49 AM, Ley Foon Tan wrote:
> On Thu, Apr 19, 2018 at 10:53 AM, Marek Vasut <marex@denx.de> wrote:
>> On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
>>> Add mailbox support for Stratix SoC
>>>
>>> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
>>> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
>>> ---

[...]

>>> +static __always_inline int mbox_polling_resp(u32 rout)
>>> +{
>>> +     static const struct socfpga_mailbox *mbox_base =
>>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>>> +     u32 rin;
>>> +     unsigned long i = ~0;
>>> +
>>> +     while (i) {
>>> +             rin = readl(&mbox_base->rin);
>>> +             if (rout != rin)
>>> +                     return 0;
>>
>> This looks like include/wait_bit.h reimplementation
> The reason we use this method instead of using wait_bit because this
> function will use in Secure Monitor Call (SMC) call as well.
> When run in secure section, timer is not available.  So, we can't use
> wait_for_bit.

Can't you just do timer_init() then ?

>>> +/* Send command only without waiting for responses from SDM */
>>> +static __always_inline int __mbox_send_cmd_only(u8 id, u32 cmd,
>>> +                                             u8 is_indirect, u32 len,
>>> +                                             u32 *arg)
>>> +{
>>> +     int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
>>> +     /* write doorbell */
>>> +     writel(1, MBOX_DOORBELL_TO_SDM_REG);
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +/* Return number of responses received in buffer */
>>> +static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
>>
>> __always_inline is nonsense, drop it. Let the compiler do it's thing.
> This function used in SMC call as well, so it needs to be inline when
> in secure section.

Why ?
Ley Foon Tan May 10, 2018, 8:45 a.m. UTC | #4
On Tue, May 8, 2018 at 5:21 PM, Marek Vasut <marex@denx.de> wrote:
> On 05/08/2018 08:49 AM, Ley Foon Tan wrote:
>> On Thu, Apr 19, 2018 at 10:53 AM, Marek Vasut <marex@denx.de> wrote:
>>> On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
>>>> Add mailbox support for Stratix SoC
>>>>
>>>> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
>>>> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
>>>> ---
>
> [...]
>
>>>> +static __always_inline int mbox_polling_resp(u32 rout)
>>>> +{
>>>> +     static const struct socfpga_mailbox *mbox_base =
>>>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>>>> +     u32 rin;
>>>> +     unsigned long i = ~0;
>>>> +
>>>> +     while (i) {
>>>> +             rin = readl(&mbox_base->rin);
>>>> +             if (rout != rin)
>>>> +                     return 0;
>>>
>>> This looks like include/wait_bit.h reimplementation
>> The reason we use this method instead of using wait_bit because this
>> function will use in Secure Monitor Call (SMC) call as well.
>> When run in secure section, timer is not available.  So, we can't use
>> wait_for_bit.
>
> Can't you just do timer_init() then ?
We can't use timer in secure region. This SMC code is resident in
onchip memory (secure region) while Linux is running.
So, timer might be used by Linux.

>
>>>> +/* Send command only without waiting for responses from SDM */
>>>> +static __always_inline int __mbox_send_cmd_only(u8 id, u32 cmd,
>>>> +                                             u8 is_indirect, u32 len,
>>>> +                                             u32 *arg)
>>>> +{
>>>> +     int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
>>>> +     /* write doorbell */
>>>> +     writel(1, MBOX_DOORBELL_TO_SDM_REG);
>>>> +
>>>> +     return ret;
>>>> +}
>>>> +
>>>> +/* Return number of responses received in buffer */
>>>> +static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
>>>
>>> __always_inline is nonsense, drop it. Let the compiler do it's thing.
>> This function used in SMC call as well, so it needs to be inline when
>> in secure section.
>
> Why ?
These functions needed for normal U-boot and SMC (secure section in
OCM) and we need to copy the whole function to secure section, not
just the API call.
This also avoid code duplication for U-boot and SMC.

Regards
Ley Foon
Marek Vasut May 10, 2018, 10:09 a.m. UTC | #5
On 05/10/2018 10:45 AM, Ley Foon Tan wrote:
> On Tue, May 8, 2018 at 5:21 PM, Marek Vasut <marex@denx.de> wrote:
>> On 05/08/2018 08:49 AM, Ley Foon Tan wrote:
>>> On Thu, Apr 19, 2018 at 10:53 AM, Marek Vasut <marex@denx.de> wrote:
>>>> On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
>>>>> Add mailbox support for Stratix SoC
>>>>>
>>>>> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
>>>>> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
>>>>> ---
>>
>> [...]
>>
>>>>> +static __always_inline int mbox_polling_resp(u32 rout)
>>>>> +{
>>>>> +     static const struct socfpga_mailbox *mbox_base =
>>>>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>>>>> +     u32 rin;
>>>>> +     unsigned long i = ~0;
>>>>> +
>>>>> +     while (i) {
>>>>> +             rin = readl(&mbox_base->rin);
>>>>> +             if (rout != rin)
>>>>> +                     return 0;
>>>>
>>>> This looks like include/wait_bit.h reimplementation
>>> The reason we use this method instead of using wait_bit because this
>>> function will use in Secure Monitor Call (SMC) call as well.
>>> When run in secure section, timer is not available.  So, we can't use
>>> wait_for_bit.
>>
>> Can't you just do timer_init() then ?
> We can't use timer in secure region. This SMC code is resident in
> onchip memory (secure region) while Linux is running.
> So, timer might be used by Linux.

So pieces of U-Boot remain in memory and get called by Linux, right ?

I am CCing a few more people , since this might need further discussion.

btw does this work when Linux is compiled in AArch32 mode while U-Boot
is AArch64 ? I think it might not.

>>>>> +/* Send command only without waiting for responses from SDM */
>>>>> +static __always_inline int __mbox_send_cmd_only(u8 id, u32 cmd,
>>>>> +                                             u8 is_indirect, u32 len,
>>>>> +                                             u32 *arg)
>>>>> +{
>>>>> +     int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
>>>>> +     /* write doorbell */
>>>>> +     writel(1, MBOX_DOORBELL_TO_SDM_REG);
>>>>> +
>>>>> +     return ret;
>>>>> +}
>>>>> +
>>>>> +/* Return number of responses received in buffer */
>>>>> +static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
>>>>
>>>> __always_inline is nonsense, drop it. Let the compiler do it's thing.
>>> This function used in SMC call as well, so it needs to be inline when
>>> in secure section.
>>
>> Why ?
> These functions needed for normal U-boot and SMC (secure section in
> OCM) and we need to copy the whole function to secure section, not
> just the API call.
> This also avoid code duplication for U-boot and SMC.

Thanks for the explanation!
Ley Foon Tan May 11, 2018, 5:45 a.m. UTC | #6
On Thu, May 10, 2018 at 6:09 PM, Marek Vasut <marex@denx.de> wrote:
> On 05/10/2018 10:45 AM, Ley Foon Tan wrote:
>> On Tue, May 8, 2018 at 5:21 PM, Marek Vasut <marex@denx.de> wrote:
>>> On 05/08/2018 08:49 AM, Ley Foon Tan wrote:
>>>> On Thu, Apr 19, 2018 at 10:53 AM, Marek Vasut <marex@denx.de> wrote:
>>>>> On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
>>>>>> Add mailbox support for Stratix SoC
>>>>>>
>>>>>> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
>>>>>> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
>>>>>> ---
>>>
>>> [...]
>>>
>>>>>> +static __always_inline int mbox_polling_resp(u32 rout)
>>>>>> +{
>>>>>> +     static const struct socfpga_mailbox *mbox_base =
>>>>>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>>>>>> +     u32 rin;
>>>>>> +     unsigned long i = ~0;
>>>>>> +
>>>>>> +     while (i) {
>>>>>> +             rin = readl(&mbox_base->rin);
>>>>>> +             if (rout != rin)
>>>>>> +                     return 0;
>>>>>
>>>>> This looks like include/wait_bit.h reimplementation
>>>> The reason we use this method instead of using wait_bit because this
>>>> function will use in Secure Monitor Call (SMC) call as well.
>>>> When run in secure section, timer is not available.  So, we can't use
>>>> wait_for_bit.
>>>
>>> Can't you just do timer_init() then ?
>> We can't use timer in secure region. This SMC code is resident in
>> onchip memory (secure region) while Linux is running.
>> So, timer might be used by Linux.
>
> So pieces of U-Boot remain in memory and get called by Linux, right ?
Normal U-boot (in DDR) is destroyed after Linux is running, only SMC
code Onchip memory will remain.
The existing U-boot have support this SMC feature, platform just need
to configure the CONFIG_ARMV8_SECURE_BASE for the secure section.
Of course, we need to enable CONFIG_ARMV8_PSCI too.

>
> I am CCing a few more people , since this might need further discussion.
>
> btw does this work when Linux is compiled in AArch32 mode while U-Boot
> is AArch64 ? I think it might not.
It should work. PSCI handle checks ESR_EL3.EC field to know whether it
is SMC32 or SMC64.
See code in handle_sync near line 230 in
http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/cpu/armv8/psci.S

>
>>>>>> +/* Send command only without waiting for responses from SDM */
>>>>>> +static __always_inline int __mbox_send_cmd_only(u8 id, u32 cmd,
>>>>>> +                                             u8 is_indirect, u32 len,
>>>>>> +                                             u32 *arg)
>>>>>> +{
>>>>>> +     int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
>>>>>> +     /* write doorbell */
>>>>>> +     writel(1, MBOX_DOORBELL_TO_SDM_REG);
>>>>>> +
>>>>>> +     return ret;
>>>>>> +}
>>>>>> +
>>>>>> +/* Return number of responses received in buffer */
>>>>>> +static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
>>>>>
>>>>> __always_inline is nonsense, drop it. Let the compiler do it's thing.
>>>> This function used in SMC call as well, so it needs to be inline when
>>>> in secure section.
>>>
>>> Why ?
>> These functions needed for normal U-boot and SMC (secure section in
>> OCM) and we need to copy the whole function to secure section, not
>> just the API call.
>> This also avoid code duplication for U-boot and SMC.
>
> Thanks for the explanation!
>
> --

Regards
Ley Foon
Marek Vasut May 11, 2018, 8:44 a.m. UTC | #7
On 05/11/2018 07:45 AM, Ley Foon Tan wrote:
> On Thu, May 10, 2018 at 6:09 PM, Marek Vasut <marex@denx.de> wrote:
>> On 05/10/2018 10:45 AM, Ley Foon Tan wrote:
>>> On Tue, May 8, 2018 at 5:21 PM, Marek Vasut <marex@denx.de> wrote:
>>>> On 05/08/2018 08:49 AM, Ley Foon Tan wrote:
>>>>> On Thu, Apr 19, 2018 at 10:53 AM, Marek Vasut <marex@denx.de> wrote:
>>>>>> On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
>>>>>>> Add mailbox support for Stratix SoC
>>>>>>>
>>>>>>> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
>>>>>>> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
>>>>>>> ---
>>>>
>>>> [...]
>>>>
>>>>>>> +static __always_inline int mbox_polling_resp(u32 rout)
>>>>>>> +{
>>>>>>> +     static const struct socfpga_mailbox *mbox_base =
>>>>>>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>>>>>>> +     u32 rin;
>>>>>>> +     unsigned long i = ~0;
>>>>>>> +
>>>>>>> +     while (i) {
>>>>>>> +             rin = readl(&mbox_base->rin);
>>>>>>> +             if (rout != rin)
>>>>>>> +                     return 0;
>>>>>>
>>>>>> This looks like include/wait_bit.h reimplementation
>>>>> The reason we use this method instead of using wait_bit because this
>>>>> function will use in Secure Monitor Call (SMC) call as well.
>>>>> When run in secure section, timer is not available.  So, we can't use
>>>>> wait_for_bit.
>>>>
>>>> Can't you just do timer_init() then ?
>>> We can't use timer in secure region. This SMC code is resident in
>>> onchip memory (secure region) while Linux is running.
>>> So, timer might be used by Linux.
>>
>> So pieces of U-Boot remain in memory and get called by Linux, right ?
> Normal U-boot (in DDR) is destroyed after Linux is running, only SMC
> code Onchip memory will remain.
> The existing U-boot have support this SMC feature, platform just need
> to configure the CONFIG_ARMV8_SECURE_BASE for the secure section.
> Of course, we need to enable CONFIG_ARMV8_PSCI too.

So piece of U-Boot then becomes the part which handles PSCI calls from
Linux, do I understand it correctly ?

>> I am CCing a few more people , since this might need further discussion.
>>
>> btw does this work when Linux is compiled in AArch32 mode while U-Boot
>> is AArch64 ? I think it might not.
> It should work. PSCI handle checks ESR_EL3.EC field to know whether it
> is SMC32 or SMC64.
> See code in handle_sync near line 230 in
> http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/cpu/armv8/psci.S
Will do, thanks!
Ley Foon Tan May 11, 2018, 9:25 a.m. UTC | #8
On Fri, May 11, 2018 at 4:44 PM, Marek Vasut <marex@denx.de> wrote:
> On 05/11/2018 07:45 AM, Ley Foon Tan wrote:
>> On Thu, May 10, 2018 at 6:09 PM, Marek Vasut <marex@denx.de> wrote:
>>> On 05/10/2018 10:45 AM, Ley Foon Tan wrote:
>>>> On Tue, May 8, 2018 at 5:21 PM, Marek Vasut <marex@denx.de> wrote:
>>>>> On 05/08/2018 08:49 AM, Ley Foon Tan wrote:
>>>>>> On Thu, Apr 19, 2018 at 10:53 AM, Marek Vasut <marex@denx.de> wrote:
>>>>>>> On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
>>>>>>>> Add mailbox support for Stratix SoC
>>>>>>>>
>>>>>>>> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
>>>>>>>> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
>>>>>>>> ---
>>>>>
>>>>> [...]
>>>>>
>>>>>>>> +static __always_inline int mbox_polling_resp(u32 rout)
>>>>>>>> +{
>>>>>>>> +     static const struct socfpga_mailbox *mbox_base =
>>>>>>>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>>>>>>>> +     u32 rin;
>>>>>>>> +     unsigned long i = ~0;
>>>>>>>> +
>>>>>>>> +     while (i) {
>>>>>>>> +             rin = readl(&mbox_base->rin);
>>>>>>>> +             if (rout != rin)
>>>>>>>> +                     return 0;
>>>>>>>
>>>>>>> This looks like include/wait_bit.h reimplementation
>>>>>> The reason we use this method instead of using wait_bit because this
>>>>>> function will use in Secure Monitor Call (SMC) call as well.
>>>>>> When run in secure section, timer is not available.  So, we can't use
>>>>>> wait_for_bit.
>>>>>
>>>>> Can't you just do timer_init() then ?
>>>> We can't use timer in secure region. This SMC code is resident in
>>>> onchip memory (secure region) while Linux is running.
>>>> So, timer might be used by Linux.
>>>
>>> So pieces of U-Boot remain in memory and get called by Linux, right ?
>> Normal U-boot (in DDR) is destroyed after Linux is running, only SMC
>> code Onchip memory will remain.
>> The existing U-boot have support this SMC feature, platform just need
>> to configure the CONFIG_ARMV8_SECURE_BASE for the secure section.
>> Of course, we need to enable CONFIG_ARMV8_PSCI too.
>
> So piece of U-Boot then becomes the part which handles PSCI calls from
> Linux, do I understand it correctly ?
Yes, and we put this piece of code in onchip memory in our platform so
it doesn't corrupted by Linux.

You can see detail in
http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/cpu/armv8/u-boot.lds
All code related to PSCI/SMC will put in secure section.

>
>>> I am CCing a few more people , since this might need further discussion.
>>>
>>> btw does this work when Linux is compiled in AArch32 mode while U-Boot
>>> is AArch64 ? I think it might not.
>> It should work. PSCI handle checks ESR_EL3.EC field to know whether it
>> is SMC32 or SMC64.
>> See code in handle_sync near line 230 in
>> http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/cpu/armv8/psci.S
> Will do, thanks!
>
> --

Regards
Ley Foon
Marek Vasut May 11, 2018, 9:56 a.m. UTC | #9
On 05/11/2018 11:25 AM, Ley Foon Tan wrote:
> On Fri, May 11, 2018 at 4:44 PM, Marek Vasut <marex@denx.de> wrote:
>> On 05/11/2018 07:45 AM, Ley Foon Tan wrote:
>>> On Thu, May 10, 2018 at 6:09 PM, Marek Vasut <marex@denx.de> wrote:
>>>> On 05/10/2018 10:45 AM, Ley Foon Tan wrote:
>>>>> On Tue, May 8, 2018 at 5:21 PM, Marek Vasut <marex@denx.de> wrote:
>>>>>> On 05/08/2018 08:49 AM, Ley Foon Tan wrote:
>>>>>>> On Thu, Apr 19, 2018 at 10:53 AM, Marek Vasut <marex@denx.de> wrote:
>>>>>>>> On 04/19/2018 11:50 AM, Ley Foon Tan wrote:
>>>>>>>>> Add mailbox support for Stratix SoC
>>>>>>>>>
>>>>>>>>> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
>>>>>>>>> Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
>>>>>>>>> ---
>>>>>>
>>>>>> [...]
>>>>>>
>>>>>>>>> +static __always_inline int mbox_polling_resp(u32 rout)
>>>>>>>>> +{
>>>>>>>>> +     static const struct socfpga_mailbox *mbox_base =
>>>>>>>>> +                                     (void *)SOCFPGA_MAILBOX_ADDRESS;
>>>>>>>>> +     u32 rin;
>>>>>>>>> +     unsigned long i = ~0;
>>>>>>>>> +
>>>>>>>>> +     while (i) {
>>>>>>>>> +             rin = readl(&mbox_base->rin);
>>>>>>>>> +             if (rout != rin)
>>>>>>>>> +                     return 0;
>>>>>>>>
>>>>>>>> This looks like include/wait_bit.h reimplementation
>>>>>>> The reason we use this method instead of using wait_bit because this
>>>>>>> function will use in Secure Monitor Call (SMC) call as well.
>>>>>>> When run in secure section, timer is not available.  So, we can't use
>>>>>>> wait_for_bit.
>>>>>>
>>>>>> Can't you just do timer_init() then ?
>>>>> We can't use timer in secure region. This SMC code is resident in
>>>>> onchip memory (secure region) while Linux is running.
>>>>> So, timer might be used by Linux.
>>>>
>>>> So pieces of U-Boot remain in memory and get called by Linux, right ?
>>> Normal U-boot (in DDR) is destroyed after Linux is running, only SMC
>>> code Onchip memory will remain.
>>> The existing U-boot have support this SMC feature, platform just need
>>> to configure the CONFIG_ARMV8_SECURE_BASE for the secure section.
>>> Of course, we need to enable CONFIG_ARMV8_PSCI too.
>>
>> So piece of U-Boot then becomes the part which handles PSCI calls from
>> Linux, do I understand it correctly ?
> Yes, and we put this piece of code in onchip memory in our platform so
> it doesn't corrupted by Linux.
> 
> You can see detail in
> http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/cpu/armv8/u-boot.lds
> All code related to PSCI/SMC will put in secure section.

I see, nice, I didnt know about that. Thanks
diff mbox series

Patch

diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index b253914..43e18d2 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -32,6 +32,7 @@  endif
 
 ifdef CONFIG_TARGET_SOCFPGA_STRATIX10
 obj-y	+= clock_manager_s10.o
+obj-y	+= mailbox_s10.o
 obj-y	+= misc_s10.o
 obj-y	+= reset_manager_s10.o
 obj-y	+= system_manager_s10.o
diff --git a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
new file mode 100644
index 0000000..85e7f84
--- /dev/null
+++ b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
@@ -0,0 +1,155 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#ifndef _MAILBOX_S10_H_
+#define _MAILBOX_S10_H_
+
+/* user define Uboot ID */
+#define MBOX_CLIENT_ID_UBOOT	0xB
+#define MBOX_ID_UBOOT		0x1
+
+#define MBOX_CMD_DIRECT	0
+#define MBOX_CMD_INDIRECT	1
+
+#define MBOX_MAX_CMD_INDEX	2047
+#define MBOX_CMD_BUFFER_SIZE	32
+#define MBOX_RESP_BUFFER_SIZE	16
+
+#define MBOX_HDR_CMD_LSB	0
+#define MBOX_HDR_CMD_MSK	(BIT(11) - 1)
+#define MBOX_HDR_I_LSB		11
+#define MBOX_HDR_I_MSK		BIT(11)
+#define MBOX_HDR_LEN_LSB	12
+#define MBOX_HDR_LEN_MSK	0x007FF000
+#define MBOX_HDR_ID_LSB		24
+#define MBOX_HDR_ID_MSK		0x0F000000
+#define MBOX_HDR_CLIENT_LSB	28
+#define MBOX_HDR_CLIENT_MSK	0xF0000000
+
+/* Interrupt flags */
+#define MBOX_FLAGS_INT_COE	BIT(0)	/* COUT update interrupt enable */
+#define MBOX_FLAGS_INT_RIE	BIT(1)	/* RIN update interrupt enable */
+#define MBOX_FLAGS_INT_UAE	BIT(8)	/* Urgent ACK interrupt enable */
+#define MBOX_ALL_INTRS		(MBOX_FLAGS_INT_COE | \
+				 MBOX_FLAGS_INT_RIE | \
+				 MBOX_FLAGS_INT_UAE)
+
+/* Status */
+#define MBOX_STATUS_UA_MSK	BIT(8)
+
+#define MBOX_CMD_HEADER(client, id, len, indirect, cmd)     \
+	((((cmd) << MBOX_HDR_CMD_LSB) & MBOX_HDR_CMD_MSK) | \
+	(((indirect) << MBOX_HDR_I_LSB) & MBOX_HDR_I_MSK) | \
+	(((len) << MBOX_HDR_LEN_LSB) & MBOX_HDR_LEN_MSK)  | \
+	(((id) << MBOX_HDR_ID_LSB) & MBOX_HDR_ID_MSK)     | \
+	(((client) << MBOX_HDR_CLIENT_LSB) & MBOX_HDR_CLIENT_MSK))
+
+#define MBOX_RESP_ERR_GET(resp)				\
+	(((resp) & MBOX_HDR_CMD_MSK) >> MBOX_HDR_CMD_LSB)
+#define MBOX_RESP_LEN_GET(resp)			\
+	(((resp) & MBOX_HDR_LEN_MSK) >> MBOX_HDR_LEN_LSB)
+#define MBOX_RESP_ID_GET(resp)				\
+	(((resp) & MBOX_HDR_ID_MSK) >> MBOX_HDR_ID_LSB)
+#define MBOX_RESP_CLIENT_GET(resp)			\
+	(((resp) & MBOX_HDR_CLIENT_MSK) >> MBOX_HDR_CLIENT_LSB)
+
+/* Response error list */
+enum ALT_SDM_MBOX_RESP_CODE {
+	/* CMD completed successfully, but check resp ARGS for any errors */
+	MBOX_RESP_STATOK = 0,
+	/* CMD is incorrectly formatted in some way */
+	MBOX_RESP_INVALID_COMMAND = 1,
+	/* BootROM Command code not undesrtood */
+	MBOX_RESP_UNKNOWN_BR = 2,
+	/* CMD code not recognized by firmware */
+	MBOX_RESP_UNKNOWN = 3,
+	/* Indicates that the device is not configured */
+	MBOX_RESP_NOT_CONFIGURED = 256,
+	/* Indicates that the device is busy */
+	MBOX_RESP_DEVICE_BUSY = 0x1FF,
+	/* Indicates that there is no valid response available */
+	MBOX_RESP_NO_VALID_RESP_AVAILABLE = 0x2FF,
+	/* General Error */
+	MBOX_RESP_ERROR = 0x3FF,
+};
+
+/* Mailbox command list */
+#define MBOX_RESTART		2
+#define MBOX_CONFIG_STATUS	4
+#define MBOX_RECONFIG		6
+#define MBOX_RECONFIG_MSEL	7
+#define MBOX_RECONFIG_DATA	8
+#define MBOX_RECONFIG_STATUS	9
+#define MBOX_QSPI_OPEN		50
+#define MBOX_QSPI_CLOSE		51
+#define MBOX_QSPI_DIRECT	59
+#define MBOX_REBOOT_HPS		71
+
+struct socfpga_mailbox {
+	u32 cin;		/* command valid offset */
+	u32 rout;		/* response output offset */
+	u32 urg;		/* urgent command */
+	u32 flags;		/* interrupt enables */
+	u32 pad_0x10_0x1f[4];	/* 0x10 - 0x1F reserved */
+	u32 cout;		/* command free offset */
+	u32 rin;		/* respond valid offset */
+	u32 pad_0x28;		/* 0x28 reserved */
+	u32 status;		/* mailbox status */
+	u32 pad_0x30_0x3f[4];	/* 0x30 - 0x3F reserved */
+	u32 cmd_buf[MBOX_CMD_BUFFER_SIZE];	/* 0x40 - 0xBC circular command
+						 * buffer to SDM
+						 */
+	u32 resp_buf[MBOX_RESP_BUFFER_SIZE];	/* 0xC0 - 0xFF circular
+						 * response buffer
+						 */
+};
+
+/* Use define other than put into struct socfpga_mailbox to save spaces */
+#define MBOX_DOORBELL_TO_SDM_REG	(SOCFPGA_MAILBOX_ADDRESS + 0x400)
+#define MBOX_DOORBELL_FROM_SDM_REG	(SOCFPGA_MAILBOX_ADDRESS + 0x480)
+
+/******** Status and bit information returned by RECONFIG_STATUS ********/
+#define RECONFIG_STATUS_RESPONSE_LEN			6
+#define RECONFIG_STATUS_STATE				0
+#define RECONFIG_STATUS_PIN_STATUS			2
+#define RECONFIG_STATUS_SOFTFUNC_STATUS			3
+
+#define MBOX_CFGSTAT_STATE_IDLE				0x00000000
+#define MBOX_CFGSTAT_STATE_CONFIG			0x10000000
+#define MBOX_CFGSTAT_STATE_FAILACK			0x08000000
+#define MBOX_CFGSTAT_STATE_ERROR_INVALID		0xf0000001
+#define MBOX_CFGSTAT_STATE_ERROR_CORRUPT		0xf0000002
+#define MBOX_CFGSTAT_STATE_ERROR_AUTH			0xf0000003
+#define MBOX_CFGSTAT_STATE_ERROR_CORE_IO		0xf0000004
+#define MBOX_CFGSTAT_STATE_ERROR_HARDWARE		0xf0000005
+#define MBOX_CFGSTAT_STATE_ERROR_FAKE			0xf0000006
+#define MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO		0xf0000007
+#define MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR		0xf0000008
+
+#define RCF_SOFTFUNC_STATUS_CONF_DONE			BIT(0)
+#define RCF_SOFTFUNC_STATUS_INIT_DONE			BIT(1)
+#define RCF_SOFTFUNC_STATUS_SEU_ERROR			BIT(3)
+#define RCF_PIN_STATUS_NSTATUS				BIT(31)
+/************************************************************************/
+
+int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg, u8 urgent,
+		  u32 *resp_buf_len, u32 *resp_buf);
+int mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
+		       u8 urgent, u32 *resp_buf_len, u32 *resp_buf);
+int mbox_send_cmd_only(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg);
+int mbox_send_cmd_only_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg);
+int mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len);
+int mbox_rcv_resp_psci(u32 *resp_buf, u32 resp_buf_max_len);
+int mbox_init(void);
+
+#ifdef CONFIG_CADENCE_QSPI
+int mbox_qspi_close(void);
+int mbox_qspi_open(void);
+#endif
+
+int mbox_reset_cold(void);
+
+#endif /* _MAILBOX_S10_H_ */
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c
new file mode 100644
index 0000000..ed713a9
--- /dev/null
+++ b/arch/arm/mach-socfpga/mailbox_s10.c
@@ -0,0 +1,378 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox_s10.h>
+#include <asm/arch/system_manager.h>
+#include <asm/secure.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static __always_inline int mbox_polling_resp(u32 rout)
+{
+	static const struct socfpga_mailbox *mbox_base =
+					(void *)SOCFPGA_MAILBOX_ADDRESS;
+	u32 rin;
+	unsigned long i = ~0;
+
+	while (i) {
+		rin = readl(&mbox_base->rin);
+		if (rout != rin)
+			return 0;
+
+		i--;
+	}
+
+	return -ETIMEDOUT;
+}
+
+/* Check for available slot and write to circular buffer.
+ * It also update command valid offset (cin) register.
+ */
+static __always_inline int mbox_fill_cmd_circular_buff(u32 header, u32 len,
+						       u32 *arg)
+{
+	static const struct socfpga_mailbox *mbox_base =
+					(void *)SOCFPGA_MAILBOX_ADDRESS;
+	u32 cin;
+	u32 cout;
+	u32 i;
+
+	cin = readl(&mbox_base->cin) % MBOX_CMD_BUFFER_SIZE;
+	cout = readl(&mbox_base->cout) % MBOX_CMD_BUFFER_SIZE;
+
+	/* if command buffer is full or not enough free space
+	 * to fit the data
+	 */
+	if (((cin + 1) % MBOX_CMD_BUFFER_SIZE) == cout ||
+	    ((MBOX_CMD_BUFFER_SIZE - cin + cout - 1) %
+	     MBOX_CMD_BUFFER_SIZE) < len)
+		return -ENOMEM;
+
+	/* write header to circular buffer */
+	writel(header, &mbox_base->cmd_buf[cin++]);
+	/* wrapping around when it reach the buffer size */
+	cin %= MBOX_CMD_BUFFER_SIZE;
+
+	/* write arguments */
+	for (i = 0; i < len; i++) {
+		writel(arg[i], &mbox_base->cmd_buf[cin++]);
+		/* wrapping around when it reach the buffer size */
+		cin %= MBOX_CMD_BUFFER_SIZE;
+	}
+
+	/* write command valid offset */
+	writel(cin, &mbox_base->cin);
+
+	return 0;
+}
+
+/* Check the command and fill it into circular buffer */
+static __always_inline int mbox_prepare_cmd_only(u8 id, u32 cmd,
+						 u8 is_indirect, u32 len,
+						 u32 *arg)
+{
+	u32 header;
+	int ret;
+
+	/* Total length is command + argument length */
+	if ((len + 1) > MBOX_CMD_BUFFER_SIZE)
+		return -EINVAL;
+
+	if (cmd > MBOX_MAX_CMD_INDEX)
+		return -EINVAL;
+
+	header = MBOX_CMD_HEADER(MBOX_CLIENT_ID_UBOOT, id, len,
+				 (is_indirect) ? 1 : 0, cmd);
+
+	ret = mbox_fill_cmd_circular_buff(header, len, arg);
+
+	return ret;
+}
+
+/* Send command only without waiting for responses from SDM */
+static __always_inline int __mbox_send_cmd_only(u8 id, u32 cmd,
+						u8 is_indirect, u32 len,
+						u32 *arg)
+{
+	int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
+	/* write doorbell */
+	writel(1, MBOX_DOORBELL_TO_SDM_REG);
+
+	return ret;
+}
+
+/* Return number of responses received in buffer */
+static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
+{
+	static const struct socfpga_mailbox *mbox_base =
+					(void *)SOCFPGA_MAILBOX_ADDRESS;
+	u32 rin;
+	u32 rout;
+	u32 resp_len = 0;
+
+	/* clear doorbell from SDM if it was SET */
+	if (readl((const u32 *)MBOX_DOORBELL_FROM_SDM_REG) & 1)
+		writel(0, MBOX_DOORBELL_FROM_SDM_REG);
+
+	/* read current response offset */
+	rout = readl(&mbox_base->rout);
+	/* read response valid offset */
+	rin = readl(&mbox_base->rin);
+
+	while (rin != rout && (resp_len < resp_buf_max_len)) {
+		/* Response received */
+		if (resp_buf)
+			resp_buf[resp_len++] =
+				readl(&mbox_base->resp_buf[rout]);
+		rout++;
+		/* wrapping around when it reach the buffer size */
+		rout %= MBOX_RESP_BUFFER_SIZE;
+		/* update next ROUT */
+		writel(rout, &mbox_base->rout);
+	}
+
+	return resp_len;
+}
+
+/* Support one command and up to 31 words argument length only */
+static __always_inline int __mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect,
+					   u32 len, u32 *arg, u8 urgent,
+					   u32 *resp_buf_len, u32 *resp_buf)
+{
+	static const struct socfpga_mailbox *mbox_base =
+					(void *)SOCFPGA_MAILBOX_ADDRESS;
+
+	u32 rin;
+	u32 resp;
+	u32 rout;
+	u32 status;
+	u32 resp_len;
+	u32 buf_len;
+	int ret;
+
+	ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
+	if (ret)
+		return ret;
+
+	if (urgent) {
+		/* Read status because it is toggled */
+		status = readl(&mbox_base->status) & MBOX_STATUS_UA_MSK;
+		/* Send command as urgent command */
+		writel(1, &mbox_base->urg);
+	}
+
+	/* write doorbell */
+	writel(1, MBOX_DOORBELL_TO_SDM_REG);
+
+	while (1) {
+		ret = ~0;
+
+		/* Wait for doorbell from SDM */
+		while (!readl(MBOX_DOORBELL_FROM_SDM_REG) && ret--)
+			;
+		if (!ret)
+			return -ETIMEDOUT;
+
+		/* clear interrupt */
+		writel(0, MBOX_DOORBELL_FROM_SDM_REG);
+
+		if (urgent) {
+			u32 new_status = readl(&mbox_base->status);
+			/* urgent command doesn't have response */
+			writel(0, &mbox_base->urg);
+			/* Urgent ACK is toggled */
+			if ((new_status & MBOX_STATUS_UA_MSK) ^ status)
+				return 0;
+
+			return -ECOMM;
+		}
+
+		/* read current response offset */
+		rout = readl(&mbox_base->rout);
+
+		/* read response valid offset */
+		rin = readl(&mbox_base->rin);
+
+		if (rout != rin) {
+			/* Response received */
+			resp = readl(&mbox_base->resp_buf[rout]);
+			rout++;
+			/* wrapping around when it reach the buffer size */
+			rout %= MBOX_RESP_BUFFER_SIZE;
+			/* update next ROUT */
+			writel(rout, &mbox_base->rout);
+
+			/* check client ID and ID */
+			if ((MBOX_RESP_CLIENT_GET(resp) == MBOX_CLIENT_ID_UBOOT) &&
+			    (MBOX_RESP_ID_GET(resp) == id)) {
+				ret = MBOX_RESP_ERR_GET(resp);
+				if (ret)
+					return ret;
+
+				if (resp_buf_len) {
+					buf_len = *resp_buf_len;
+					*resp_buf_len = 0;
+				} else {
+					buf_len = 0;
+				}
+
+				resp_len = MBOX_RESP_LEN_GET(resp);
+				while (resp_len) {
+					ret = mbox_polling_resp(rout);
+					if (ret)
+						return ret;
+					/* we need to process response buffer
+					 * even caller doesn't need it
+					 */
+					resp = readl(&mbox_base->resp_buf[rout]);
+					rout++;
+					resp_len--;
+					rout %= MBOX_RESP_BUFFER_SIZE;
+					writel(rout, &mbox_base->rout);
+					if (buf_len) {
+						/* copy response to buffer */
+						resp_buf[*resp_buf_len] = resp;
+						(*resp_buf_len)++;
+						buf_len--;
+					}
+				}
+				return ret;
+			}
+		}
+	};
+
+	return -EIO;
+}
+
+int mbox_init(void)
+{
+	static const struct socfpga_mailbox *mbox_base =
+					(void *)SOCFPGA_MAILBOX_ADDRESS;
+	int ret;
+
+	/* enable mailbox interrupts */
+	writel(MBOX_ALL_INTRS, &mbox_base->flags);
+
+	/* Ensure urgent request is cleared */
+	writel(0, &mbox_base->urg);
+
+	/* Ensure the Doorbell Interrupt is cleared */
+	writel(0, MBOX_DOORBELL_FROM_SDM_REG);
+
+	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RESTART, MBOX_CMD_DIRECT, 0,
+			    NULL, 1, 0, NULL);
+	if (ret)
+		return ret;
+
+	/* Renable mailbox interrupts after MBOX_RESTART */
+	writel(MBOX_ALL_INTRS, &mbox_base->flags);
+
+	return 0;
+}
+
+#ifdef CONFIG_CADENCE_QSPI
+int mbox_qspi_close(void)
+{
+	return mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_CLOSE, MBOX_CMD_DIRECT,
+			     0, NULL, 0, 0, NULL);
+}
+
+int mbox_qspi_open(void)
+{
+	static const struct socfpga_system_manager *sysmgr_regs =
+		(struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
+
+	int ret;
+	u32 resp_buf[1];
+	u32 resp_buf_len;
+
+	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN, MBOX_CMD_DIRECT,
+			    0, NULL, 0, 0, NULL);
+	if (ret) {
+		/* retry again by closing and reopen the QSPI again */
+		ret = mbox_qspi_close();
+		if (ret)
+			return ret;
+
+		ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN,
+				    MBOX_CMD_DIRECT, 0, NULL, 0, 0, NULL);
+		if (ret)
+			return ret;
+	}
+
+	/* HPS will directly control the QSPI controller, no longer mailbox */
+	resp_buf_len = 1;
+	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_DIRECT, MBOX_CMD_DIRECT,
+			    0, NULL, 0, (u32 *)&resp_buf_len,
+			    (u32 *)&resp_buf);
+	if (ret)
+		goto error;
+
+	/* We are getting QSPI ref clock and set into sysmgr boot register */
+	printf("QSPI: Reference clock at %d Hz\n", resp_buf[0]);
+	writel(resp_buf[0], &sysmgr_regs->boot_scratch_cold0);
+
+	return 0;
+
+error:
+	mbox_qspi_close();
+
+	return ret;
+}
+#endif /* CONFIG_CADENCE_QSPI */
+
+int mbox_reset_cold(void)
+{
+	int ret;
+
+	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_REBOOT_HPS, MBOX_CMD_DIRECT,
+			    0, NULL, 0, 0, NULL);
+	if (ret) {
+		/* mailbox sent failure, wait for watchdog to kick in */
+		while (1)
+			;
+	}
+	return 0;
+}
+
+int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
+		  u8 urgent, u32 *resp_buf_len, u32 *resp_buf)
+{
+	return __mbox_send_cmd(id, cmd, is_indirect, len, arg, urgent,
+			       resp_buf_len, resp_buf);
+}
+
+int __secure mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len,
+				u32 *arg, u8 urgent, u32 *resp_buf_len,
+				u32 *resp_buf)
+{
+	return __mbox_send_cmd(id, cmd, is_indirect, len, arg, urgent,
+			       resp_buf_len, resp_buf);
+}
+
+int mbox_send_cmd_only(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg)
+{
+	return __mbox_send_cmd_only(id, cmd, is_indirect, len, arg);
+}
+
+int __secure mbox_send_cmd_only_psci(u8 id, u32 cmd, u8 is_indirect, u32 len,
+				     u32 *arg)
+{
+	return __mbox_send_cmd_only(id, cmd, is_indirect, len, arg);
+}
+
+int mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
+{
+	return __mbox_rcv_resp(resp_buf, resp_buf_max_len);
+}
+
+int __secure mbox_rcv_resp_psci(u32 *resp_buf, u32 resp_buf_max_len)
+{
+	return __mbox_rcv_resp(resp_buf, resp_buf_max_len);
+}