1/* fw-m0sub.S 2 * 3 * Copyright 2015 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.syntax unified 19 20m0_vectors: 21 .word 0x18003FF0 22 .word m0_reset + 1 23 .word m0_fault + 1 24 .word m0_fault + 1 25 .word m0_fault + 1 26 .word m0_fault + 1 27 .word m0_fault + 1 28 .word m0_fault + 1 29 .word m0_fault + 1 30 .word m0_fault + 1 31 .word m0_fault + 1 32 .word m0_fault + 1 33 .word m0_fault + 1 34 .word m0_fault + 1 35 .word m0_fault + 1 36 .word m0_fault + 1 37// external IRQs 38 .word m0_fault + 1 39 .word m0_irq + 1 40 41m0_fault: 42 ldr r0, =0x18000000 43 ldr r1, =0xeeee0000 44 mrs r2, xpsr 45 movs r3, #0xFF 46 ands r2, r2, r3 47 orrs r1, r1, r2 48 str r1, [r0] 49 b . 50 51.ltorg 52 53#define REPORT_DELAY 0 54 55#define COMM_BASE 0x18004000 56 57#define COMM_CMD 0 58#define COMM_ARG0 4 59#define COMM_ARG1 8 60#define COMM_RESP 12 61#define COMM_RETRY 16 62 63 64#define M4_TXEV 0x40043130 // write 0 to clear 65 66#define SGPIO_BASE (0x40101210) 67#define OFF_IN 0 68#define OFF_OUT 4 69#define OFF_OEN 8 70#define SGPIO_IN (0x40101210) 71#define SGPIO_OUT (0x40101214) 72#define SGPIO_OEN (0x40101218) 73 74#define CLK_BIT 11 75#define DIO_BIT 14 76#define TEN_BIT 15 77#define CLK_MSK (1 << CLK_BIT) 78#define DIO_MSK (1 << DIO_BIT) 79#define TEN_MSK (1 << TEN_BIT) 80 81#define CLK1_OUT (CLK_MSK | TEN_MSK) 82#define CLK0_OUT (TEN_MSK) 83#define CLK1_IN (CLK_MSK) 84#define CLK0_IN (0) 85 86#define OEN_IN ((1 << CLK_BIT) | (1 << TEN_BIT)) 87#define OEN_OUT ((1 << CLK_BIT) | (1 << DIO_BIT) | (1 << TEN_BIT)) 88 89#define NOP4 nop ; nop ; nop ; nop 90#define NOP8 NOP4 ; NOP4 91#define NOP16 NOP8 ; NOP8 92 93//#define DELAY nop ; nop 94//#define DELAY NOP8 95 96// r11 CLK1_OUT const 97// r10 CLK0_OUT const 98// r9 delay subroutine 99// r8 comm_base addr 100// r7 SGPIO_BASE addr 101// r6 DIO_MSK const 102// r5 CLK1_IN const 103// r4 CLK0_IN const 104// r3 outbits data 105 106snooze_1m: 107 nop ; nop ; nop ; nop 108 nop ; nop ; nop ; nop 109 nop ; nop ; nop ; nop 110 nop ; nop ; nop ; nop 111 nop ; nop ; nop ; nop 112 nop ; nop ; nop ; nop 113 nop ; nop ; nop ; nop 114 nop ; nop ; nop ; nop 115 nop ; nop ; nop ; nop 116snooze_2m: 117 nop ; nop ; nop ; nop 118 nop ; nop ; nop ; nop 119 nop ; nop ; nop ; nop 120 nop ; nop ; nop ; nop 121snooze_3m: 122 nop ; nop ; nop ; nop 123 nop ; nop ; nop ; nop 124snooze_4m: 125 nop ; nop ; nop ; nop 126 nop ; nop ; nop ; nop 127snooze_6m: 128 nop ; nop ; nop ; nop 129snooze_8m: 130 bx lr 131 132// delay 0 nops 16MHz 133// delay 2 nops 12MHz 134// delay 4 nops 9.6MHz 135#define DELAY blx r9 136 137// 12 cycles + DELAY x 2 138.macro ONE_BIT_OUT 139 lsls r2, r3, #DIO_BIT // shift bit 1 to posn 140 ands r2, r2, r6 // isolate bit 1 141 movs r1, r2 // save bit 1 142 add r2, r2, r10 // combine with CLK1 143 DELAY 144 str r2, [r7, #OFF_OUT] // commit negative edge 145 lsrs r3, r3, #1 // advance to next bit 146 add r1, r1, r11 // combine with CLK1 147 nop 148 nop 149 DELAY 150 str r1, [r7, #OFF_OUT] // commit positive edge 151.endm 152 153.macro ONE_BIT_IN 154 ands r0, r0, r6 // isolate input bit 155 lsls r0, r0, #(31-DIO_BIT) // move to posn 31 156 lsrs r3, r3, #1 // make room 157 orrs r3, r3, r0 // add bit 158 DELAY 159 str r4, [r7, #OFF_OUT] // commit negative edge 160 ldr r0, [r7, #OFF_IN] // sample input 161 nop 162 nop 163 DELAY 164 str r5, [r7, #OFF_OUT] // commit positive edge 165.endm 166 167// used for the final parity and turn bits on input so this 168// actually only reads one bit 169read_2: 170 push {lr} 171 nop 172 nop 173 nop 174 nop 175 DELAY 176 str r4, [r7, #OFF_OUT] 177 ldr r0, [r7, #OFF_IN] 178 nop 179 nop 180 DELAY 181 str r5, [r7, #OFF_OUT] 182 ands r0, r0, r6 // isolate bit 183 lsrs r0, r0, #DIO_BIT // shift to bit0 184 nop 185 nop 186 DELAY 187 str r4, [r7, #OFF_OUT] 188 nop 189 nop 190 nop 191 nop 192 DELAY 193 str r5, [r7, #OFF_OUT] 194 pop {pc} 195 196// w0: <15> <parity:1> <cmd:16> 197// w1: <data:32> 198 199 200write_16: 201 push {lr} 202 b _write_16 203write_32: 204 push {lr} 205 ONE_BIT_OUT 206 ONE_BIT_OUT 207 ONE_BIT_OUT 208 ONE_BIT_OUT 209 ONE_BIT_OUT 210 ONE_BIT_OUT 211 ONE_BIT_OUT 212 ONE_BIT_OUT 213 ONE_BIT_OUT 214 ONE_BIT_OUT 215 ONE_BIT_OUT 216 ONE_BIT_OUT 217 ONE_BIT_OUT 218 ONE_BIT_OUT 219 ONE_BIT_OUT 220 ONE_BIT_OUT 221_write_16: 222 ONE_BIT_OUT 223 ONE_BIT_OUT 224 ONE_BIT_OUT 225 ONE_BIT_OUT 226 ONE_BIT_OUT 227 ONE_BIT_OUT 228 ONE_BIT_OUT 229 ONE_BIT_OUT 230 ONE_BIT_OUT 231 ONE_BIT_OUT 232 ONE_BIT_OUT 233 ONE_BIT_OUT 234 ONE_BIT_OUT 235 ONE_BIT_OUT 236 ONE_BIT_OUT 237 ONE_BIT_OUT 238 pop {pc} 239write_1: 240 push {lr} 241 ONE_BIT_OUT 242 pop {pc} 243 244read_4: 245 push {lr} 246 b _read_4 247read_5: 248 push {lr} 249 b _read_5 250read_32: 251 push {lr} 252 ONE_BIT_IN 253 ONE_BIT_IN 254 ONE_BIT_IN 255 ONE_BIT_IN 256 ONE_BIT_IN 257 ONE_BIT_IN 258 ONE_BIT_IN 259 ONE_BIT_IN 260 ONE_BIT_IN 261 ONE_BIT_IN 262 ONE_BIT_IN 263 ONE_BIT_IN 264 ONE_BIT_IN 265 ONE_BIT_IN 266 ONE_BIT_IN 267 ONE_BIT_IN 268 ONE_BIT_IN 269 ONE_BIT_IN 270 ONE_BIT_IN 271 ONE_BIT_IN 272 ONE_BIT_IN 273 ONE_BIT_IN 274 ONE_BIT_IN 275 ONE_BIT_IN 276 ONE_BIT_IN 277 ONE_BIT_IN 278 ONE_BIT_IN 279_read_5: 280 ONE_BIT_IN 281_read_4: 282 ONE_BIT_IN 283 ONE_BIT_IN 284 ONE_BIT_IN 285 ONE_BIT_IN 286 ands r0, r0, r6 // isolate input bit 287 lsls r0, r0, #(31-DIO_BIT) // move to posn 31 288 lsrs r3, r3, #1 // make room 289 orrs r3, r3, r0 // add bit 290 pop {pc} 291 292init: 293 ldr r0, =CLK1_OUT 294 mov r11, r0 295 ldr r0, =CLK0_OUT 296 mov r10, r0 297 ldr r0, =(snooze_4m + 1) 298 ldr r0, =(snooze_1m + 1) 299 mov r9, r0 300 ldr r0, =COMM_BASE 301 mov r8, r0 302 ldr r7, =SGPIO_BASE 303 ldr r6, =DIO_MSK 304 ldr r5, =CLK1_IN 305 ldr r4, =CLK0_IN 306 bx lr 307 308#define MAX_RETRY 8192 309 310err_fail: 311 movs r0, #3 312 mov r3, r8 313 str r0, [r3, #COMM_RESP]; 314 pop {pc} 315 316err_timeout: 317 movs r0, #2 318 mov r3, r8 319 str r0, [r3, #COMM_RESP]; 320 pop {pc} 321 322cmd_read_txn: 323 push {lr} 324 325 ldr r0, =MAX_RETRY 326 //movs r0, #MAX_RETRY 327 mov r12, r0 328 329rd_retry: 330 ldr r3, [r3, #COMM_ARG0] 331 bl write_16 332 333 ldr r3, =OEN_IN 334 str r3, [r7, #OFF_OEN] 335 bl read_4 336 337 lsrs r3, r3, #29 338 cmp r3, #1 // OK 339 beq rd_okay 340 341 ldr r1, =OEN_OUT 342 str r1, [r7, #OFF_OEN] 343 344 cmp r3, #2 // WAIT 345 bne err_fail 346 347 mov r0, r12 348 subs r0, r0, #1 349 mov r12, r0 350 beq err_timeout 351 mov r3, r8 352 b rd_retry 353 354rd_okay: 355 bl read_32 356 bl read_2 357 ldr r1, =OEN_OUT 358 str r1, [r7, #OFF_OEN] 359 mov r1, r11 360 orrs r1, r1, r6 361 str r1, [r7, #OFF_OUT] 362 363 mov r1, r8 // get COMM_BASE 364 str r3, [r1, #COMM_ARG0] 365 str r0, [r1, #COMM_ARG1] 366 movs r0, #0 367 str r0, [r1, #COMM_RESP] 368#if REPORT_DELAY 369 mov r0, r12 370 str r0, [r1, #COMM_RETRY] 371#endif 372 pop {pc} 373 374 375cmd_write_txn: 376 push {lr} 377 378 ldr r0, =MAX_RETRY 379 mov r12, r0 380 381wr_retry: 382 ldr r3, [r3, #COMM_ARG0] 383 bl write_16 384 push {r3} // stash parity bit 385 386 ldr r3, =OEN_IN 387 str r3, [r7, #OFF_OEN] 388 bl read_4 389 390 lsrs r3, r3, #29 391 cmp r3, #1 // OK 392 beq wr_okay 393 394 pop {r0} // discard saved parity bit 395 396 ldr r1, =OEN_OUT 397 str r1, [r7, #OFF_OEN] 398 399 cmp r3, #2 // WAIT 400 bne err_fail 401 402 mov r0, r12 403 subs r0, r0, #1 404 mov r12, r0 405 beq err_timeout 406 407 mov r3, r8 408 b wr_retry 409 410wr_okay: 411 ldr r3, =OEN_OUT 412 str r3, [r7, #OFF_OEN] 413 bl write_1 414 415 mov r3, r8 416 ldr r3, [r3, #COMM_ARG1] 417 bl write_32 418 419 pop {r3} // recover parity bit 420 bl write_1 421 422 mov r3, r8 // get COMM_BASE 423 movs r0, #0 424 str r0, [r3, #COMM_RESP] 425#if REPORT_DELAY 426 mov r0, r12 427 str r0, [r3, #COMM_RETRY] 428#endif 429 pop {pc} 430 431// write without caring about the response 432cmd_write_blind: 433 push {lr} 434 435 ldr r3, [r3, #COMM_ARG0] 436 bl write_16 437 push {r3} // stash parity bit 438 439 ldr r3, =OEN_IN // ignore Trn/Rsp/Trn 440 str r3, [r7, #OFF_OEN] 441 bl read_5 442 443 ldr r3, =OEN_OUT 444 str r3, [r7, #OFF_OEN] 445 446 mov r3, r8 447 ldr r3, [r3, #COMM_ARG1] 448 bl write_32 449 450 pop {r3} // recover parity bit 451 bl write_1 452 453 mov r3, r8 // get COMM_BASE 454 movs r0, #0 455 str r0, [r3, #COMM_RESP] 456#if REPORT_DELAY 457 mov r0, =MAX_RETRY 458 str r0, [r3, #COMM_RETRY] 459#endif 460 pop {pc} 461 462 463cmd_jtag_to_swd: 464 push {lr} 465 ldr r3, =0xffffffff 466 bl write_32 467 ldr r3, =0xffffffff 468 bl write_32 469 ldr r3, =0b1110011110011110 470 bl write_16 471 472 mov r3, r8 473 movs r0, #0 474 str r0, [r3, #COMM_RESP] 475 pop {pc} 476 477cmd_swd_to_dormant: 478 push {lr} 479 ldr r3, =0xffffffff 480 bl write_32 481 ldr r3, =0xffffffff 482 bl write_32 483 ldr r3, =0xE3BC 484 bl write_16 485 486 mov r3, r8 487 movs r0, #0 488 str r0, [r3, #COMM_RESP] 489 pop {pc} 490 491cmd_dormant_to_swd: 492 push {lr} 493 // at least 8 HI 494 ldr r3, =0xffff 495 bl write_16 496 // activation sequence (128bit) 497 ldr r3, =0x6209F392 498 bl write_32 499 ldr r3, =0x86852D95 500 bl write_32 501 ldr r3, =0xE3DDAFE9 502 bl write_32 503 ldr r3, =0x19BC0EA2 504 bl write_32 505 // 4 LO, selection sequence, 4 HI 506 ldr r3, =0xF1A0 507 bl write_16 508 509 mov r3, r8 510 movs r0, #0 511 str r0, [r3, #COMM_RESP] 512 pop {pc} 513 514cmd_reset: 515 push {lr} 516 // 50+ HI (60 here), 2+ LO (4 here) 517 ldr r3, =0xffffffff 518 bl write_32 519 ldr r3, =0x0fffffff 520 bl write_32 521 522 mov r3, r8 523 movs r0, #0 524 str r0, [r3, #COMM_RESP] 525 pop {pc} 526 527 528m0_irq: 529 push {lr} 530 531 // clear event from m4 532 ldr r0, =M4_TXEV 533 movs r1, #0 534 str r1, [r0] 535 536 mov r3, r8 // get COMM_BASE 537 ldr r0, [r3, #COMM_CMD] 538 cmp r0, #9 539 bls good_cmd 540 movs r0, #0 541good_cmd: 542 lsls r0, r0, #2 543 adr r1, cmd_table 544 ldr r2, [r1, r0] 545 blx r2 546 547 pop {pc} 548 549.align 4 550cmd_table: 551 .word cmd_invalid + 1 552 .word cmd_nop + 1 553 .word cmd_read_txn + 1 554 .word cmd_write_txn + 1 555 .word cmd_reset + 1 556 .word cmd_setclock + 1 557 .word cmd_write_blind + 1 558 .word cmd_jtag_to_swd + 1 559 .word cmd_dormant_to_swd + 1 560 .word cmd_swd_to_dormant + 1 561 562cmd_invalid: 563 movs r0, #9 564 str r0, [r3, #COMM_RESP] 565 bx lr 566 567cmd_nop: 568 movs r0, #0 569 str r0, [r3, #COMM_RESP] 570 bx lr 571 572cmd_setclock: 573 ldr r0, [r3, #COMM_ARG0] 574 cmp r0, #8 575 bls good_clock 576 movs r0, #0 577good_clock: 578 lsls r2, r0, #2 579 adr r1, snooze_table 580 ldr r1, [r1, r2] 581 mov r9, r1 582 583 // return actual clock used 584 str r0, [r3, #COMM_RESP] 585 bx lr 586 587.align 4 588snooze_table: 589 .word snooze_1m + 1 590 .word snooze_1m + 1 591 .word snooze_2m + 1 592 .word snooze_3m + 1 593 .word snooze_4m + 1 594 .word snooze_4m + 1 595 .word snooze_6m + 1 596 .word snooze_6m + 1 597 .word snooze_8m + 1 598 599m0_reset: 600 ldr r0, =0x18000000 601 ldr r1, =0xaaaa0000 602 str r1, [r0] 603 604 bl init 605 606 // enable IRQ1 (Event From M4) 607 ldr r0, =0xE000E100 608 movs r1, #2 609 str r1, [r0] 610 611m0_idle: 612 wfi 613 b m0_idle 614