main.c (7060B)
1 /* main.c 2 * 3 * Copyright 2011 Brian Swetland <swetland@frotz.net> 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <fw/types.h> 19 #include <fw/lib.h> 20 #include <fw/io.h> 21 22 #include <arch/hardware.h> 23 #include <arch/cpu.h> 24 #include <arch/interrupts.h> 25 26 #include <protocol/rswdp.h> 27 #include "swdp.h" 28 29 extern u32 gpio_led0; 30 extern u32 gpio_led1; 31 extern u32 gpio_led2; 32 extern u32 gpio_led3; 33 extern u32 gpio_reset_n; 34 35 unsigned swdp_trace = 0; 36 37 void reboot_bootloader(void) { 38 usb_stop(); 39 writel(0x12345678, GPREG0); 40 writel(0xA5A50000, GPREG1); 41 reboot(); 42 } 43 44 #define DEBUG_MAX 52 45 static struct { 46 u32 txn; 47 u32 cmd; 48 u8 data[DEBUG_MAX]; 49 } pmsg = { 50 .txn = RSWD_TXN_ASYNC, 51 .cmd = RSWD_MSG(CMD_DEBUG_PRINT, 0, DEBUG_MAX/4), 52 }; 53 static unsigned poff = 0; 54 55 void flushu(void) { 56 while (poff < DEBUG_MAX) 57 pmsg.data[poff++] = 0; 58 usb_xmit(&pmsg, sizeof(pmsg)); 59 poff = 0; 60 } 61 62 void _putu(unsigned c) { 63 pmsg.data[poff++] = c; 64 if (poff == DEBUG_MAX) 65 flushu(); 66 } 67 68 void printu(const char *fmt, ...) { 69 va_list ap; 70 va_start(ap, fmt); 71 vprintx(_putu, fmt, ap); 72 va_end(ap); 73 if (poff) 74 flushu(); 75 } 76 77 static u8 optable[16] = { 78 [OP_RD | OP_DP | OP_X0] = RD_IDCODE, 79 [OP_RD | OP_DP | OP_X4] = RD_DPCTRL, 80 [OP_RD | OP_DP | OP_X8] = RD_RESEND, 81 [OP_RD | OP_DP | OP_XC] = RD_BUFFER, 82 [OP_WR | OP_DP | OP_X0] = WR_ABORT, 83 [OP_WR | OP_DP | OP_X4] = WR_DPCTRL, 84 [OP_WR | OP_DP | OP_X8] = WR_SELECT, 85 [OP_WR | OP_DP | OP_XC] = WR_BUFFER, 86 [OP_RD | OP_AP | OP_X0] = RD_AP0, 87 [OP_RD | OP_AP | OP_X4] = RD_AP1, 88 [OP_RD | OP_AP | OP_X8] = RD_AP2, 89 [OP_RD | OP_AP | OP_XC] = RD_AP3, 90 [OP_WR | OP_AP | OP_X0] = WR_AP0, 91 [OP_WR | OP_AP | OP_X4] = WR_AP1, 92 [OP_WR | OP_AP | OP_X8] = WR_AP2, 93 [OP_WR | OP_AP | OP_XC] = WR_AP3, 94 }; 95 96 /* TODO bounds checking -- we trust the host far too much */ 97 void process_txn(u32 txnid, u32 *rx, int rxc, u32 *tx) { 98 unsigned msg, op, n; 99 unsigned txc = 1; 100 unsigned count = 0; 101 unsigned status = 0; 102 void (*func)(void) = 0; 103 104 tx[0] = txnid; 105 106 while (rxc-- > 0) { 107 count++; 108 msg = *rx++; 109 op = RSWD_MSG_OP(msg); 110 n = RSWD_MSG_ARG(msg); 111 #if CONFIG_M3DEBUG_TRACE 112 printx("> %b %b %h <\n", RSWD_MSG_CMD(msg), op, n); 113 #endif 114 switch (RSWD_MSG_CMD(msg)) { 115 case CMD_NULL: 116 continue; 117 case CMD_SWD_WRITE: 118 while (n-- > 0) { 119 rxc--; 120 if (swdp_write(optable[op], *rx++)) { 121 status = 3; 122 goto done; 123 } 124 } 125 continue; 126 case CMD_SWD_READ: 127 tx[txc++] = RSWD_MSG(CMD_SWD_DATA, 0, n); 128 while (n-- > 0) { 129 if (swdp_read(optable[op], tx + txc)) { 130 txc++; 131 while (n-- > 0) 132 tx[txc++] = 0xfefefefe; 133 status = 3; 134 goto done; 135 } 136 txc++; 137 } 138 continue; 139 case CMD_SWD_DISCARD: 140 while (n-- > 0) { 141 u32 tmp; 142 if (swdp_read(optable[op], &tmp)) { 143 status = 3; 144 goto done; 145 } 146 } 147 continue; 148 case CMD_ATTACH: 149 swdp_reset(); 150 continue; 151 case CMD_RESET: 152 if (n == 0) { 153 /* deassert RESET */ 154 gpio_cfg_dir(gpio_reset_n, GPIO_CFG_IN); 155 } else { 156 /* assert RESET */ 157 gpio_cfg_dir(gpio_reset_n, GPIO_CFG_OUT); 158 gpio_clr(gpio_reset_n); 159 } 160 continue; 161 case CMD_DOWNLOAD: { 162 u32 *addr = (void*) *rx++; 163 rxc--; 164 while (n) { 165 *addr++ = *rx++; 166 rxc--; 167 } 168 continue; 169 } 170 case CMD_EXECUTE: 171 func = (void*) *rx++; 172 rxc--; 173 continue; 174 case CMD_TRACE: 175 swdp_trace = op; 176 continue; 177 case CMD_BOOTLOADER: 178 func = reboot_bootloader; 179 continue; 180 case CMD_SET_CLOCK: 181 n = ssp0_set_clock(n); 182 printu("swdp clock is now 0x%x KHz\n", n); 183 continue; 184 default: 185 printx("unknown command %b\n", RSWD_MSG_CMD(msg)); 186 status = 1; 187 goto done; 188 } 189 } 190 191 done: 192 tx[txc++] = RSWD_MSG(CMD_STATUS, status, count); 193 194 /* if we're about to send an even multiple of the packet size 195 * (64), add a NULL op on the end to create a short packet at 196 * the end. 197 */ 198 if ((txc & 0xf) == 0) 199 tx[txc++] = RSWD_MSG(CMD_NULL, 0, 0); 200 201 #if CONFIG_M3DEBUG_TRACE 202 printx("[ send %x words ]\n", txc); 203 for (n = 0; n < txc; n+=4) { 204 printx("%x %x %x %x\n", 205 tx[n], tx[n+1], tx[n+2], tx[n+3]); 206 } 207 #endif 208 usb_xmit(tx, txc * 4); 209 210 if (func) { 211 for (n = 0; n < 1000000; n++) asm("nop"); 212 func(); 213 for (;;) ; 214 } 215 } 216 217 static u32 rxbuffer[512]; 218 static u32 txbuffer[512+1]; 219 220 #if CONFIG_M3DEBUG_SERIAL_IFC 221 extern void _start(void); 222 223 static void ep2_rx_full_cb(void) 224 { 225 int i; 226 227 static char buf[64]; 228 int len = usb_ep2_read(buf, sizeof(buf)); 229 for (i = 0; i < len; i++) { 230 serial_putc(buf[i]); 231 } 232 } 233 234 static char outbuf[64]; 235 static volatile int outbufpos = 0; 236 static volatile int ep2_tx_active = 0; 237 238 static void queue_ep2_tx(void) 239 { 240 if (outbufpos > 0 && !ep2_tx_active) { 241 ep2_tx_active = 1; 242 int oldbufpos = outbufpos; 243 outbufpos = 0; 244 245 // side effect of this routine is enabling interrupts 246 usb_ep2_write(outbuf, oldbufpos); 247 } 248 } 249 250 static void ep2_tx_empty_cb(void) 251 { 252 // printx("tx empty\n"); 253 disable_interrupts(); 254 255 ep2_tx_active = 0; 256 queue_ep2_tx(); 257 258 enable_interrupts(); 259 } 260 261 static void serial_async_cb(char c) 262 { 263 if (outbufpos >= sizeof(outbuf)) 264 return; 265 266 disable_interrupts(); 267 268 outbuf[outbufpos++] = c; 269 270 // serial_putc(c); 271 queue_ep2_tx(); 272 273 enable_interrupts(); 274 } 275 #endif 276 277 int main() { 278 int rxc; 279 280 board_init(); 281 282 #if CONFIG_M3DEBUG_SERIAL_IFC 283 #ifndef CONFIG_USB_2ND_IFC 284 #error CONFIG_M3DEBUG_SERIAL_IFC requires CONFIG_USB_2ND_IFC 285 #endif 286 #ifndef CONFIG_USB_USE_IRQS 287 #error CONFIG_M3DEBUG_SERIAL_IFC requires CONFIG_USB_USE_IRQS 288 #endif 289 irq_set_base((unsigned) _start); 290 enable_interrupts(); 291 #endif 292 293 serial_init(48000000, 115200); 294 ssp0_init(); 295 296 #if CONFIG_M3DEBUG_TRACE 297 printx("[ rswdp agent v0.9 ]\n"); 298 printx("[ built " __DATE__ " " __TIME__ " ]\n"); 299 #endif 300 301 #if CONFIG_M3DEBUG_SERIAL_IFC 302 usb_init(0x18d1, 0xdb04, "m3dev", "super-m3debug"); 303 304 usb_ep2_rx_full_cb = &ep2_rx_full_cb; 305 usb_ep2_tx_empty_cb = &ep2_tx_empty_cb; 306 usb_unmask_ep2_rx_full(); 307 usb_unmask_ep2_tx_empty(); 308 309 serial_start_async_rx(&serial_async_cb); 310 irq_enable(v_uart); 311 #else 312 usb_init(0x18d1, 0xdb03, "m3dev", "m3debug"); 313 #endif 314 315 for (;;) { 316 gpio_clr(gpio_led0); 317 rxc = usb_recv(rxbuffer, sizeof(rxbuffer)); 318 gpio_set(gpio_led0); 319 320 #if CONFIG_M3DEBUG_TRACE 321 int n; 322 printx("[ recv %x words ]\n", rxc/4); 323 for (n = 0; n < (rxc/4); n+=4) { 324 printx("%x %x %x %x\n", 325 rxbuffer[n], rxbuffer[n+1], rxbuffer[n+2], rxbuffer[n+3]); 326 } 327 #endif 328 329 if ((rxc < 4) || (rxc & 3)) { 330 printx("error, runt frame, or strange frame... %x\n", rxc); 331 continue; 332 } 333 334 rxc = rxc / 4; 335 336 if ((rxbuffer[0] & 0xFFFF0000) != 0xAA770000) { 337 printx("invalid frame %x\n", rxbuffer[0]); 338 continue; 339 } 340 341 process_txn(rxbuffer[0], rxbuffer + 1, rxc - 1, txbuffer); 342 } 343 }