1 /*
2 * Copyright (c) 2015 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #include <trace.h>
24 #include <err.h>
25 #include <malloc.h>
26 #include <lk/init.h>
27 #include <arch/arm.h>
28 #include <arch/arm/dcc.h>
29 #include <kernel/thread.h>
30 #include <kernel/mutex.h>
31 #include <platform.h>
32
33 struct dcc_state {
34 dcc_rx_callback_t rx_callback;
35 mutex_t lock;
36 thread_t *worker;
37 };
38
39 #define SLOW_POLL_RATE 100
40 #define FAST_POLL_TIMEOUT 5
41
dcc_worker_entry(void * arg)42 static int dcc_worker_entry(void *arg)
43 {
44 struct dcc_state *dcc = (struct dcc_state *)arg;
45 lk_time_t fast_poll_start;
46 bool fast_poll;
47
48 fast_poll = false;
49 for (;;) {
50 // wait for a bit if we're in slow poll mode
51 if (!fast_poll) {
52 thread_sleep(SLOW_POLL_RATE);
53 }
54
55 if (arm_dcc_read_available()) {
56 uint32_t val = arm_read_dbgdtrrxint();
57
58 dcc->rx_callback(val);
59
60 // we just received something, so go to a faster poll rate
61 fast_poll = true;
62 fast_poll_start = current_time();
63 } else {
64 // didn't see anything
65 if (fast_poll && current_time() - fast_poll_start >= FAST_POLL_TIMEOUT) {
66 fast_poll = false; // go back to slow poll
67 }
68 }
69 }
70
71 return 0;
72 }
73
arm_dcc_enable(dcc_rx_callback_t rx_callback)74 status_t arm_dcc_enable(dcc_rx_callback_t rx_callback)
75 {
76 struct dcc_state *state = malloc(sizeof(struct dcc_state));
77 if (!state)
78 return ERR_NO_MEMORY;
79
80 state->rx_callback = rx_callback;
81 mutex_init(&state->lock);
82
83 state->worker = thread_create("dcc worker", dcc_worker_entry, state, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
84 thread_resume(state->worker);
85
86 return NO_ERROR;
87 }
88
arm_dcc_read_available(void)89 bool arm_dcc_read_available(void)
90 {
91 uint32_t dscr = arm_read_dbgdscr();
92 if (dscr & (1<<30)) { // rx full
93 return true;
94 } else {
95 return false;
96 }
97 }
98
arm_dcc_read(uint32_t * buf,size_t len,lk_time_t timeout)99 ssize_t arm_dcc_read(uint32_t *buf, size_t len, lk_time_t timeout)
100 {
101 lk_time_t start = 0;
102
103 if (timeout != 0)
104 start = current_time();
105
106 ssize_t count = 0;
107 while (count < (ssize_t)len) {
108
109 uint32_t dscr = arm_read_dbgdscr();
110 if (dscr & (1<<30)) { // rx full
111 uint32_t val = arm_read_dbgdtrrxint();
112 *buf++ = val;
113
114 count++;
115 } else {
116 if (timeout == 0 || current_time() - start >= timeout) {
117 break;
118 }
119 }
120 }
121
122 return count;
123 }
124
arm_dcc_write(const uint32_t * buf,size_t len,lk_time_t timeout)125 ssize_t arm_dcc_write(const uint32_t *buf, size_t len, lk_time_t timeout)
126 {
127 lk_time_t start = 0;
128
129 if (timeout != 0)
130 start = current_time();
131
132 ssize_t count = 0;
133 while (count < (ssize_t)len) {
134
135 uint32_t dscr = arm_read_dbgdscr();
136 if ((dscr & (1<<29)) == 0) { // tx empty
137 arm_write_dbgdtrrxint(*buf);
138 count++;
139 buf++;
140 } else {
141 if (timeout == 0 || current_time() - start >= timeout) {
142 break;
143 }
144 }
145 }
146
147 return count;
148 }
149
150 #if WITH_LIB_CONSOLE
151 #include <lib/console.h>
152 #include <string.h>
153
dcc_rx_callback(uint32_t val)154 static void dcc_rx_callback(uint32_t val)
155 {
156 static int count = 0;
157 count += 4;
158 if ((count % 1000) == 0)
159 printf("count %d\n", count);
160 }
161
cmd_dcc(int argc,const cmd_args * argv)162 static int cmd_dcc(int argc, const cmd_args *argv)
163 {
164 static bool dcc_started = false;
165
166 if (argc < 2) {
167 printf("not enough args\n");
168 return -1;
169 }
170
171 if (!strcmp(argv[1].str, "start")) {
172 if (!dcc_started) {
173 printf("starting dcc\n");
174
175 status_t err = arm_dcc_enable(&dcc_rx_callback);
176 printf("arm_dcc_enable returns %d\n", err);
177 dcc_started = true;
178 }
179 } else if (!strcmp(argv[1].str, "write")) {
180 for (int i = 2; i < argc; i++) {
181 uint32_t buf[128];
182 size_t len = strlen(argv[i].str);
183 for (uint j = 0; j < len; j++) {
184 buf[j] = argv[i].str[j];
185 }
186 arm_dcc_write(buf, strlen(argv[i].str), 1000);
187 }
188 } else if (!strcmp(argv[1].str, "read")) {
189 uint32_t buf[128];
190
191 ssize_t len = arm_dcc_read(buf, sizeof(buf), 1000);
192 printf("arm_dcc_read returns %ld\n", len);
193 if (len > 0) {
194 hexdump(buf, len);
195 }
196 } else {
197 printf("unknown args\n");
198 }
199
200 return 0;
201 }
202
203 STATIC_COMMAND_START
204 #if LK_DEBUGLEVEL > 1
205 STATIC_COMMAND("dcc", "dcc stuff", &cmd_dcc)
206 #endif
207 STATIC_COMMAND_END(dcc);
208
209 #endif
210
211