1 /*
2 * Copyright (c) 2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <lk/trace.h>
9 #include <lk/err.h>
10 #include <malloc.h>
11 #include <lk/init.h>
12 #include <arch/arm.h>
13 #include <arch/arm/dcc.h>
14 #include <kernel/thread.h>
15 #include <kernel/mutex.h>
16 #include <platform.h>
17 #include <lk/console_cmd.h>
18 #include <string.h>
19
20 struct dcc_state {
21 dcc_rx_callback_t rx_callback;
22 mutex_t lock;
23 thread_t *worker;
24 };
25
26 #define SLOW_POLL_RATE 100
27 #define FAST_POLL_TIMEOUT 5
28
dcc_worker_entry(void * arg)29 static int dcc_worker_entry(void *arg) {
30 struct dcc_state *dcc = (struct dcc_state *)arg;
31 lk_time_t fast_poll_start;
32 bool fast_poll;
33
34 fast_poll = false;
35 for (;;) {
36 // wait for a bit if we're in slow poll mode
37 if (!fast_poll) {
38 thread_sleep(SLOW_POLL_RATE);
39 }
40
41 if (arm_dcc_read_available()) {
42 uint32_t val = arm_read_dbgdtrrxint();
43
44 dcc->rx_callback(val);
45
46 // we just received something, so go to a faster poll rate
47 fast_poll = true;
48 fast_poll_start = current_time();
49 } else {
50 // didn't see anything
51 if (fast_poll && current_time() - fast_poll_start >= FAST_POLL_TIMEOUT) {
52 fast_poll = false; // go back to slow poll
53 }
54 }
55 }
56
57 return 0;
58 }
59
arm_dcc_enable(dcc_rx_callback_t rx_callback)60 status_t arm_dcc_enable(dcc_rx_callback_t rx_callback) {
61 struct dcc_state *state = malloc(sizeof(struct dcc_state));
62 if (!state)
63 return ERR_NO_MEMORY;
64
65 state->rx_callback = rx_callback;
66 mutex_init(&state->lock);
67
68 state->worker = thread_create("dcc worker", dcc_worker_entry, state, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
69 thread_resume(state->worker);
70
71 return NO_ERROR;
72 }
73
arm_dcc_read_available(void)74 bool arm_dcc_read_available(void) {
75 uint32_t dscr = arm_read_dbgdscr();
76 if (dscr & (1<<30)) { // rx full
77 return true;
78 } else {
79 return false;
80 }
81 }
82
arm_dcc_read(uint32_t * buf,size_t len,lk_time_t timeout)83 ssize_t arm_dcc_read(uint32_t *buf, size_t len, lk_time_t timeout) {
84 lk_time_t start = 0;
85
86 if (timeout != 0)
87 start = current_time();
88
89 ssize_t count = 0;
90 while (count < (ssize_t)len) {
91
92 uint32_t dscr = arm_read_dbgdscr();
93 if (dscr & (1<<30)) { // rx full
94 uint32_t val = arm_read_dbgdtrrxint();
95 *buf++ = val;
96
97 count++;
98 } else {
99 if (timeout == 0 || current_time() - start >= timeout) {
100 break;
101 }
102 }
103 }
104
105 return count;
106 }
107
arm_dcc_write(const uint32_t * buf,size_t len,lk_time_t timeout)108 ssize_t arm_dcc_write(const uint32_t *buf, size_t len, lk_time_t timeout) {
109 lk_time_t start = 0;
110
111 if (timeout != 0)
112 start = current_time();
113
114 ssize_t count = 0;
115 while (count < (ssize_t)len) {
116
117 uint32_t dscr = arm_read_dbgdscr();
118 if ((dscr & (1<<29)) == 0) { // tx empty
119 arm_write_dbgdtrrxint(*buf);
120 count++;
121 buf++;
122 } else {
123 if (timeout == 0 || current_time() - start >= timeout) {
124 break;
125 }
126 }
127 }
128
129 return count;
130 }
131
dcc_rx_callback(uint32_t val)132 static void dcc_rx_callback(uint32_t val) {
133 static int count = 0;
134 count += 4;
135 if ((count % 1000) == 0)
136 printf("count %d\n", count);
137 }
138
cmd_dcc(int argc,const console_cmd_args * argv)139 static int cmd_dcc(int argc, const console_cmd_args *argv) {
140 static bool dcc_started = false;
141
142 if (argc < 2) {
143 printf("not enough args\n");
144 return -1;
145 }
146
147 if (!strcmp(argv[1].str, "start")) {
148 if (!dcc_started) {
149 printf("starting dcc\n");
150
151 status_t err = arm_dcc_enable(&dcc_rx_callback);
152 printf("arm_dcc_enable returns %d\n", err);
153 dcc_started = true;
154 }
155 } else if (!strcmp(argv[1].str, "write")) {
156 for (int i = 2; i < argc; i++) {
157 uint32_t buf[128];
158 size_t len = strlen(argv[i].str);
159 for (uint j = 0; j < len; j++) {
160 buf[j] = argv[i].str[j];
161 }
162 arm_dcc_write(buf, strlen(argv[i].str), 1000);
163 }
164 } else if (!strcmp(argv[1].str, "read")) {
165 uint32_t buf[128];
166
167 ssize_t len = arm_dcc_read(buf, sizeof(buf), 1000);
168 printf("arm_dcc_read returns %ld\n", len);
169 if (len > 0) {
170 hexdump(buf, len);
171 }
172 } else {
173 printf("unknown args\n");
174 }
175
176 return 0;
177 }
178
179 STATIC_COMMAND_START
180 #if LK_DEBUGLEVEL > 1
181 STATIC_COMMAND("dcc", "dcc stuff", &cmd_dcc)
182 #endif
183 STATIC_COMMAND_END(dcc);
184
185