1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Marek Beh��n <kabel@kernel.org>
4 * Copyright (C) 2021 Pali Roh��r <pali@kernel.org>
5 */
6
7#include <common.h>
8#include <asm/arch/soc.h>
9#include <asm/io.h>
10#include <linux/bitops.h>
11#include <linux/delay.h>
12#include <mach/mbox.h>
13
14#define RWTM_BASE		(MVEBU_REGISTER(0xb0000))
15#define RWTM_CMD_PARAM(i)	(size_t)(RWTM_BASE + (i) * 4)
16#define RWTM_CMD		(RWTM_BASE + 0x40)
17#define RWTM_CMD_RETSTATUS	(RWTM_BASE + 0x80)
18#define RWTM_CMD_STATUS(i)	(size_t)(RWTM_BASE + 0x84 + (i) * 4)
19#define MAX_ARGS		16
20
21#define RWTM_HOST_INT_RESET	(RWTM_BASE + 0xc8)
22#define RWTM_HOST_INT_MASK	(RWTM_BASE + 0xcc)
23#define SP_CMD_COMPLETE		BIT(0)
24
25#define MBOX_STS_SUCCESS		(0x0 << 30)
26#define MBOX_STS_FAIL			(0x1 << 30)
27#define MBOX_STS_BADCMD			(0x2 << 30)
28#define MBOX_STS_LATER			(0x3 << 30)
29#define MBOX_STS_ERROR(s)		((s) & (3 << 30))
30#define MBOX_STS_VALUE(s)		(((s) >> 10) & 0xfffff)
31#define MBOX_STS_CMD(s)			((s) & 0x3ff)
32#define MBOX_STS_MARVELL_ERROR(s)	((s) == 0 ? 0         : \
33					 (s) == 2 ? ETIMEDOUT : \
34					 (s) == 3 ? EINVAL    : \
35					 (s) == 4 ? ENOSYS    : \
36					            EIO)
37
38int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout)
39{
40	const int tries = 50;
41	int i;
42	u32 status;
43
44	if (nin > MAX_ARGS || nout > MAX_ARGS)
45		return -EINVAL;
46
47	clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
48
49	for (i = 0; i < nin; i++)
50		writel(in[i], RWTM_CMD_PARAM(i));
51	for (; i < MAX_ARGS; i++)
52		writel(0x0, RWTM_CMD_PARAM(i));
53	writel(cmd, RWTM_CMD);
54
55	for (i = 0; i < tries; ++i) {
56		mdelay(10);
57		if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE)
58			break;
59	}
60
61	if (i == tries) {
62		/* if timed out, don't read status */
63		setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
64		return -ETIMEDOUT;
65	}
66
67	for (i = 0; i < nout; ++i)
68		out[i] = readl(RWTM_CMD_STATUS(i));
69	status = readl(RWTM_CMD_RETSTATUS);
70
71	setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
72
73	if (MBOX_STS_CMD(status) != cmd)
74		return -MBOX_STS_MARVELL_ERROR(status);
75	else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL)
76		return -(int)MBOX_STS_VALUE(status);
77	else if (MBOX_STS_ERROR(status) == MBOX_STS_BADCMD)
78		return -ENOSYS;
79	else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS)
80		return -EIO;
81	else
82		return MBOX_STS_VALUE(status);
83}
84