forked from AsahiLinux/m1n1
-
Notifications
You must be signed in to change notification settings - Fork 0
/
asc.c
131 lines (105 loc) · 3.02 KB
/
asc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* 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 = calloc(1, 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_cpu_running(asc_dev_t *asc)
{
return read32(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;
}