• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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