summaryrefslogtreecommitdiff
path: root/tools/src/asc.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/src/asc.c')
-rw-r--r--tools/src/asc.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/tools/src/asc.c b/tools/src/asc.c
new file mode 100644
index 0000000..67c9d46
--- /dev/null
+++ b/tools/src/asc.c
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: MIT */
+
+#include "adt.h"
+#include "asc.h"
+#include "malloc.h"
+#include "utils.h"
+
+#define ASC_CPU_CONTROL 0x44
+#define ASC_CPU_CONTROL_START 0x10
+
+#define ASC_MBOX_CONTROL_FULL BIT(16)
+#define ASC_MBOX_CONTROL_EMPTY BIT(17)
+
+#define ASC_MBOX_A2I_CONTROL 0x110
+#define ASC_MBOX_A2I_SEND0 0x800
+#define ASC_MBOX_A2I_SEND1 0x808
+#define ASC_MBOX_A2I_RECV0 0x810
+#define ASC_MBOX_A2I_RECV1 0x818
+
+#define ASC_MBOX_I2A_CONTROL 0x114
+#define ASC_MBOX_I2A_SEND0 0x820
+#define ASC_MBOX_I2A_SEND1 0x828
+#define ASC_MBOX_I2A_RECV0 0x830
+#define ASC_MBOX_I2A_RECV1 0x838
+
+struct asc_dev {
+ uintptr_t cpu_base;
+ uintptr_t base;
+ int iop_node;
+};
+
+asc_dev_t *asc_init(const char *path)
+{
+ int asc_path[8];
+ int node = adt_path_offset_trace(adt, path, asc_path);
+ if (node < 0) {
+ printf("asc: Error getting ASC node %s\n", path);
+ return NULL;
+ }
+
+ u64 base;
+ if (adt_get_reg(adt, asc_path, "reg", 0, &base, NULL) < 0) {
+ printf("asc: Error getting ASC %s base address.\n", path);
+ return NULL;
+ }
+
+ asc_dev_t *asc = malloc(sizeof(*asc));
+ if (!asc)
+ return NULL;
+
+ asc->iop_node = adt_first_child_offset(adt, node);
+ asc->cpu_base = base;
+ asc->base = base + 0x8000;
+
+ clear32(base + ASC_CPU_CONTROL, ASC_CPU_CONTROL_START);
+ return asc;
+}
+
+void asc_free(asc_dev_t *asc)
+{
+ free(asc);
+}
+
+int asc_get_iop_node(asc_dev_t *asc)
+{
+ return asc->iop_node;
+}
+
+void asc_cpu_start(asc_dev_t *asc)
+{
+ set32(asc->cpu_base + ASC_CPU_CONTROL, ASC_CPU_CONTROL_START);
+}
+
+void asc_cpu_stop(asc_dev_t *asc)
+{
+ clear32(asc->cpu_base + ASC_CPU_CONTROL, ASC_CPU_CONTROL_START);
+}
+
+bool asc_can_recv(asc_dev_t *asc)
+{
+ return !(read32(asc->base + ASC_MBOX_I2A_CONTROL) & ASC_MBOX_CONTROL_EMPTY);
+}
+
+bool asc_recv(asc_dev_t *asc, struct asc_message *msg)
+{
+ if (!asc_can_recv(asc))
+ return false;
+
+ msg->msg0 = read64(asc->base + ASC_MBOX_I2A_RECV0);
+ msg->msg1 = (u32)read64(asc->base + ASC_MBOX_I2A_RECV1);
+ dma_rmb();
+
+ // printf("received msg: %lx %x\n", msg->msg0, msg->msg1);
+
+ return true;
+}
+
+bool asc_recv_timeout(asc_dev_t *asc, struct asc_message *msg, u32 delay_usec)
+{
+ u64 timeout = timeout_calculate(delay_usec);
+ while (!timeout_expired(timeout)) {
+ if (asc_recv(asc, msg))
+ return true;
+ }
+ return false;
+}
+
+bool asc_can_send(asc_dev_t *asc)
+{
+ return !(read32(asc->base + ASC_MBOX_A2I_CONTROL) & ASC_MBOX_CONTROL_FULL);
+}
+
+bool asc_send(asc_dev_t *asc, const struct asc_message *msg)
+{
+ if (poll32(asc->base + ASC_MBOX_A2I_CONTROL, ASC_MBOX_CONTROL_FULL, 0, 200000)) {
+ printf("asc: A2I mailbox full for 200ms. Is the ASC stuck?");
+ return false;
+ }
+
+ dma_wmb();
+ write64(asc->base + ASC_MBOX_A2I_SEND0, msg->msg0);
+ write64(asc->base + ASC_MBOX_A2I_SEND1, msg->msg1);
+
+ // printf("sent msg: %lx %x\n", msg->msg0, msg->msg1);
+ return true;
+}