summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTzung-Bi Shih <tzungbi@chromium.org>2020-06-30 09:43:23 +0800
committerCommit Bot <commit-bot@chromium.org>2020-07-03 19:35:21 +0000
commite8d3c6227ebb1492d9ad94394a3c6ac9badb4b4e (patch)
tree0a6e4b04adadda23172deb94b1cc1deb5f9d6821
parent6e7f31783acc91e781e93e1712fc9375f8da59eb (diff)
downloadchrome-ec-e8d3c6227ebb1492d9ad94394a3c6ac9badb4b4e.tar.gz
chip/mt8192_scp: support ipi_send()
Supports ipi_send() which sends IPI messages to AP. BRANCH=none BUG=b:146213943 BUG=b:156223050 TEST=make BOARD=asurada_scp Signed-off-by: Tzung-Bi Shih <tzungbi@chromium.org> Change-Id: Ia146b29607bc5bf4150b637368b3a99986de677d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2275709 Reviewed-by: Eric Yilun Lin <yllin@chromium.org>
-rw-r--r--chip/mt8192_scp/build.mk1
-rw-r--r--chip/mt8192_scp/ipi.c121
-rw-r--r--chip/mt8192_scp/ipi_chip.h66
-rw-r--r--chip/mt8192_scp/registers.h5
4 files changed, 193 insertions, 0 deletions
diff --git a/chip/mt8192_scp/build.mk b/chip/mt8192_scp/build.mk
index 19de637af2..966c1a29ef 100644
--- a/chip/mt8192_scp/build.mk
+++ b/chip/mt8192_scp/build.mk
@@ -17,4 +17,5 @@ chip-y+=uart.o
# Optional chip modules
chip-$(CONFIG_COMMON_TIMER)+=hrtimer.o
+chip-$(CONFIG_IPI)+=ipi.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o
diff --git a/chip/mt8192_scp/ipi.c b/chip/mt8192_scp/ipi.c
new file mode 100644
index 0000000000..fdbcde3811
--- /dev/null
+++ b/chip/mt8192_scp/ipi.c
@@ -0,0 +1,121 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "console.h"
+#include "hooks.h"
+#include "ipi_chip.h"
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "util.h"
+
+#define CPRINTF(format, args...) cprintf(CC_IPI, format, ##args)
+#define CPRINTS(format, args...) cprints(CC_IPI, format, ##args)
+
+static uint8_t init_done;
+
+static struct mutex ipi_lock;
+static struct ipc_shared_obj *const ipi_send_buf =
+ (struct ipc_shared_obj *)CONFIG_IPC_SHARED_OBJ_ADDR;
+
+static int ipi_is_busy(void)
+{
+ return SCP_SCP2APMCU_IPC_SET & IPC_SCP2HOST;
+}
+
+static void ipi_wake_ap(int32_t id)
+{
+ if (*ipi_wakeup_table[id])
+ SCP_SCP2SPM_IPC_SET = IPC_SCP2HOST;
+}
+
+int ipi_send(int32_t id, const void *buf, uint32_t len, int wait)
+{
+ int ret;
+
+ if (!init_done) {
+ CPRINTS("IPI has not initialized");
+ return EC_ERROR_BUSY;
+ }
+
+ if (in_interrupt_context()) {
+ CPRINTS("invoke %s() in ISR context", __func__);
+ return EC_ERROR_BUSY;
+ }
+
+ if (len > sizeof(ipi_send_buf->buffer)) {
+ CPRINTS("data length exceeds limitation");
+ return EC_ERROR_INVAL;
+ }
+
+ mutex_lock(&ipi_lock);
+
+ if (ipi_is_busy()) {
+ /*
+ * If the following conditions meet,
+ * 1) There is an IPI pending in AP.
+ * 2) The incoming IPI is a wakeup IPI.
+ * then it assumes that AP is in suspend state.
+ * Send a AP wakeup request to SPM.
+ *
+ * The incoming IPI will be checked if it's a wakeup source.
+ */
+ ipi_wake_ap(id);
+
+ CPRINTS("IPI busy, id=%d", id);
+ ret = EC_ERROR_BUSY;
+ goto error;
+ }
+
+ ipi_send_buf->id = id;
+ ipi_send_buf->len = len;
+ memcpy(ipi_send_buf->buffer, buf, len);
+
+ /* interrupt AP to handle the message */
+ ipi_wake_ap(id);
+ SCP_SCP2APMCU_IPC_SET = IPC_SCP2HOST;
+
+ if (wait)
+ while (ipi_is_busy())
+ ;
+
+ ret = EC_SUCCESS;
+error:
+ mutex_unlock(&ipi_lock);
+ return ret;
+}
+
+static void ipi_enable_deferred(void)
+{
+ struct scp_run_t scp_run;
+ int ret;
+
+ init_done = 1;
+
+ /* inform AP that SCP is up */
+ scp_run.signaled = 1;
+ strncpy(scp_run.fw_ver, system_get_version(EC_IMAGE_RW),
+ SCP_FW_VERSION_LEN);
+ scp_run.dec_capability = VCODEC_CAPABILITY_4K_DISABLED;
+ scp_run.enc_capability = 0;
+
+ ret = ipi_send(SCP_IPI_INIT, (void *)&scp_run, sizeof(scp_run), 1);
+ if (ret) {
+ CPRINTS("failed to send initialization IPC messages");
+ init_done = 0;
+ return;
+ }
+}
+DECLARE_DEFERRED(ipi_enable_deferred);
+
+static void ipi_init(void)
+{
+ memset(ipi_send_buf, 0, sizeof(struct ipc_shared_obj));
+
+ /* enable IRQ after all tasks are up */
+ hook_call_deferred(&ipi_enable_deferred_data, 0);
+}
+DECLARE_HOOK(HOOK_INIT, ipi_init, HOOK_PRIO_DEFAULT);
diff --git a/chip/mt8192_scp/ipi_chip.h b/chip/mt8192_scp/ipi_chip.h
new file mode 100644
index 0000000000..1fa30275d9
--- /dev/null
+++ b/chip/mt8192_scp/ipi_chip.h
@@ -0,0 +1,66 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_IPI_CHIP_H
+#define __CROS_EC_IPI_CHIP_H
+
+/*
+ * Length of EC version string is at most 32 byte (NULL included), which
+ * also aligns SCP fw_version length.
+ */
+#define SCP_FW_VERSION_LEN 32
+
+/*
+ * Video decoder supported capability:
+ * BIT(4): 0 enable 4K
+ * 1 disable 4K
+ */
+#define VCODEC_CAPABILITY_4K_DISABLED BIT(4)
+
+#ifndef SCP_IPI_INIT
+#error If CONFIG_IPI is enabled, SCP_IPI_INIT must be defined.
+#endif
+
+/*
+ * Share buffer layout for SCP_IPI_INIT response. This structure should sync
+ * across kernel and EC.
+ */
+struct scp_run_t {
+ uint32_t signaled;
+ int8_t fw_ver[SCP_FW_VERSION_LEN];
+ uint32_t dec_capability;
+ uint32_t enc_capability;
+};
+
+/*
+ * The layout of the IPC0 AP/SCP shared buffer.
+ * This should sync across kernel and EC.
+ */
+struct ipc_shared_obj {
+ /* IPI ID */
+ int32_t id;
+ /* Length of the contents in buffer. */
+ uint32_t len;
+ /* Shared buffer contents. */
+ uint8_t buffer[CONFIG_IPC_SHARED_OBJ_BUF_SIZE];
+};
+
+/* Send a IPI contents to AP. This shouldn't be used in ISR context. */
+int ipi_send(int32_t id, const void *buf, uint32_t len, int wait);
+
+/*
+ * An IPC IRQ could be shared across many IPI handlers.
+ * Those handlers would usually operate on disabling or enabling the IPC IRQ.
+ * This may disorder the actual timing to on/off the IRQ when there are many
+ * tasks try to operate on it. As a result, any access to the SCP_IRQ_*
+ * should go through ipi_{en,dis}able_irq(), which support a counter to
+ * enable/disable the IRQ at correct timing.
+ */
+/* Disable IPI IRQ. */
+void ipi_disable_irq(void);
+/* Enable IPI IRQ. */
+void ipi_enable_irq(void);
+
+#endif /* __CROS_EC_IPI_CHIP_H */
diff --git a/chip/mt8192_scp/registers.h b/chip/mt8192_scp/registers.h
index 7893a57a67..5620dcb6dc 100644
--- a/chip/mt8192_scp/registers.h
+++ b/chip/mt8192_scp/registers.h
@@ -64,6 +64,11 @@
#define UART_CK_SW_STATUS_32K BIT(1)
#define UART_CK_SW_STATUS_ULPOS BIT(2)
+/* IPC */
+#define SCP_SCP2APMCU_IPC_SET REG32(SCP_REG_BASE + 0x24080)
+#define SCP_SCP2SPM_IPC_SET REG32(SCP_REG_BASE + 0x24090)
+#define IPC_SCP2HOST BIT(0)
+
/* UART */
#define SCP_UART_COUNT 2
#define UART_TX_IRQ(n) CONCAT3(SCP_IRQ_UART, n, _TX)