aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/allwinner
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/allwinner')
-rw-r--r--drivers/allwinner/axp/common.c22
-rw-r--r--drivers/allwinner/sunxi_msgbox.c95
2 files changed, 116 insertions, 1 deletions
diff --git a/drivers/allwinner/axp/common.c b/drivers/allwinner/axp/common.c
index 13437fec8..e98b16fdb 100644
--- a/drivers/allwinner/axp/common.c
+++ b/drivers/allwinner/axp/common.c
@@ -105,6 +105,25 @@ static bool should_enable_regulator(const void *fdt, int node)
return false;
}
+static bool board_uses_usb0_host_mode(const void *fdt)
+{
+ int node, length;
+ const char *prop;
+
+ node = fdt_node_offset_by_compatible(fdt, -1,
+ "allwinner,sun8i-a33-musb");
+ if (node < 0) {
+ return false;
+ }
+
+ prop = fdt_getprop(fdt, node, "dr_mode", &length);
+ if (!prop) {
+ return false;
+ }
+
+ return !strncmp(prop, "host", length);
+}
+
void axp_setup_regulators(const void *fdt)
{
int node;
@@ -121,7 +140,8 @@ void axp_setup_regulators(const void *fdt)
}
/* This applies to AXP803 only. */
- if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL)) {
+ if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL) &&
+ board_uses_usb0_host_mode(fdt)) {
axp_clrbits(0x8f, BIT(4));
axp_setbits(0x30, BIT(2));
INFO("PMIC: Enabling DRIVEVBUS\n");
diff --git a/drivers/allwinner/sunxi_msgbox.c b/drivers/allwinner/sunxi_msgbox.c
new file mode 100644
index 000000000..cc4a6ffcb
--- /dev/null
+++ b/drivers/allwinner/sunxi_msgbox.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include <sunxi_mmap.h>
+
+#define REMOTE_IRQ_EN_REG 0x0040
+#define REMOTE_IRQ_STAT_REG 0x0050
+#define LOCAL_IRQ_EN_REG 0x0060
+#define LOCAL_IRQ_STAT_REG 0x0070
+
+#define RX_IRQ(n) BIT(0 + 2 * (n))
+#define TX_IRQ(n) BIT(1 + 2 * (n))
+
+#define FIFO_STAT_REG(n) (0x0100 + 0x4 * (n))
+#define FIFO_STAT_MASK GENMASK(0, 0)
+
+#define MSG_STAT_REG(n) (0x0140 + 0x4 * (n))
+#define MSG_STAT_MASK GENMASK(2, 0)
+
+#define MSG_DATA_REG(n) (0x0180 + 0x4 * (n))
+
+#define RX_CHAN 1
+#define TX_CHAN 0
+
+#define MHU_MAX_SLOT_ID 31
+
+#define MHU_TIMEOUT_DELAY 10
+#define MHU_TIMEOUT_ITERS 10000
+
+static DEFINE_BAKERY_LOCK(mhu_secure_message_lock);
+
+static bool sunxi_msgbox_last_tx_done(unsigned int chan)
+{
+ uint32_t stat = mmio_read_32(SUNXI_MSGBOX_BASE + REMOTE_IRQ_STAT_REG);
+
+ return (stat & RX_IRQ(chan)) == 0U;
+}
+
+static bool sunxi_msgbox_peek_data(unsigned int chan)
+{
+ uint32_t stat = mmio_read_32(SUNXI_MSGBOX_BASE + MSG_STAT_REG(chan));
+
+ return (stat & MSG_STAT_MASK) != 0U;
+}
+
+void mhu_secure_message_start(unsigned int slot_id __unused)
+{
+ uint32_t timeout = MHU_TIMEOUT_ITERS;
+
+ bakery_lock_get(&mhu_secure_message_lock);
+
+ /* Wait for all previous messages to be acknowledged. */
+ while (!sunxi_msgbox_last_tx_done(TX_CHAN) && --timeout)
+ udelay(MHU_TIMEOUT_DELAY);
+}
+
+void mhu_secure_message_send(unsigned int slot_id)
+{
+ mmio_write_32(SUNXI_MSGBOX_BASE + MSG_DATA_REG(TX_CHAN), BIT(slot_id));
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+ uint32_t timeout = MHU_TIMEOUT_ITERS;
+ uint32_t msg = 0;
+
+ /* Wait for a message from the SCP. */
+ while (!sunxi_msgbox_peek_data(RX_CHAN) && --timeout)
+ udelay(MHU_TIMEOUT_DELAY);
+
+ /* Return the most recent message in the FIFO. */
+ while (sunxi_msgbox_peek_data(RX_CHAN))
+ msg = mmio_read_32(SUNXI_MSGBOX_BASE + MSG_DATA_REG(RX_CHAN));
+
+ return msg;
+}
+
+void mhu_secure_message_end(unsigned int slot_id)
+{
+ /* Acknowledge a response by clearing the IRQ status. */
+ mmio_write_32(SUNXI_MSGBOX_BASE + LOCAL_IRQ_STAT_REG, RX_IRQ(RX_CHAN));
+
+ bakery_lock_release(&mhu_secure_message_lock);
+}