swdp.c (3861B)
1 /* swdp.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 24 #include <protocol/rswdp.h> 25 #include "swdp.h" 26 27 unsigned swdp_trace = 0; 28 29 void printu(const char *fmt, ...); 30 31 /* NOTES 32 * host -> device: 33 * host writes DATA on falling edge of CLOCK 34 * device reads DATA on rising edge of CLOCK 35 * device -> host 36 * device writes DATA on rising edge of CLOCK 37 * host samples DATA on falling edge of CLOCK 38 * host parks (begins turnaround) by: 39 * releasing bus between falling and rising clock 40 * a turnaround cycle follows, in which the device does its first write on CK+ 41 * host unparks (reclaims bus) by: 42 * reasserting bus between falling and rising clock 43 */ 44 45 #define GPIO_CLK 1 46 #define GPIO_DAT 0 47 48 #define D0 (1 << (GPIO_DAT + 16)) 49 #define D1 (1 << GPIO_DAT) 50 #define C0 (1 << (GPIO_CLK + 16)) 51 #define C1 (1 << (GPIO_CLK)) 52 53 #define GPIOA (GPIOA_BASE + GPIO_BSR) 54 55 #define XMIT(data) writel(data | C0, GPIOA), writel(data | C1, GPIOA) 56 57 #define D_OUT() gpio_config(GPIO_DAT, GPIO_OUTPUT_10MHZ | GPIO_OUT_PUSH_PULL) 58 #define D_IN() gpio_config(GPIO_DAT, GPIO_INPUT | GPIO_PU_PD) 59 60 static unsigned recv(unsigned count) { 61 unsigned n = 0; 62 unsigned bit = 1; 63 64 while (count-- > 0) { 65 writel(D1 | C0, GPIOA); 66 if (readl(GPIOA_BASE + GPIO_IDR) & (1 << GPIO_DAT)) 67 n |= bit; 68 bit <<= 1; 69 writel(D1 | C1, GPIOA); 70 } 71 return n; 72 } 73 74 static void send(unsigned n, unsigned count) { 75 unsigned p = 0; 76 while (count-- > 0) { 77 p ^= (n & 1); 78 if (n & 1) { 79 XMIT(D1); 80 } else { 81 XMIT(D0); 82 } 83 n >>= 1; 84 } 85 if (p) { 86 XMIT(D1); 87 } else { 88 XMIT(D0); 89 } 90 } 91 92 static void clock_high(int n) { 93 while (n-- > 0) 94 XMIT(D1); 95 } 96 static void clock_low(int n) { 97 while (n-- > 0) 98 XMIT(D0); 99 } 100 static void clock_jtag2swdp() { 101 XMIT(D0); XMIT(D1); XMIT(D1); XMIT(D1); 102 XMIT(D1); XMIT(D0); XMIT(D0); XMIT(D1); 103 XMIT(D1); XMIT(D1); XMIT(D1); XMIT(D0); 104 XMIT(D0); XMIT(D1); XMIT(D1); XMIT(D1); 105 } 106 107 static void puth(unsigned hdr, unsigned n, unsigned v) { 108 printu("%s %s %b %s %x\n", 109 (hdr & 0x20) ? "RD" : "WR", 110 (hdr & 0x40) ? "AP" : "DP", 111 (hdr >> 3) & 3, 112 (n == 1) ? "OK" : "XX", 113 v); 114 } 115 116 int swdp_read(unsigned hdr, unsigned *v) { 117 unsigned n,m,o; 118 119 gpio_clr(2); 120 for (n = 0; n < 8; n++) { 121 if (hdr & 0x80) { 122 XMIT(D1); 123 } else { 124 XMIT(D0); 125 } 126 hdr <<= 1; 127 } 128 D_IN(); 129 XMIT(D1); // turnaround 130 131 n = recv(3); 132 m = recv(32); 133 o = recv(1); 134 D_OUT(); 135 XMIT(D1); // turnaround 136 clock_low(8); 137 gpio_set(2); 138 139 if (swdp_trace || (n != 1)) 140 puth(hdr >> 8, n, m); 141 142 *v = m; 143 return (n == 1) ? 0 : -1; 144 } 145 146 int swdp_write(unsigned hdr, unsigned val) { 147 unsigned n; 148 149 for (n = 0; n < 8; n++) { 150 if (hdr & 0x80) { 151 XMIT(D1); 152 } else { 153 XMIT(D0); 154 } 155 hdr <<= 1; 156 } 157 D_IN(); 158 XMIT(D1); // turnaround 159 160 n = recv(3); 161 D_OUT(); 162 XMIT(D1); 163 send(val, 32); 164 clock_low(8); 165 166 if (swdp_trace || (n != 1)) 167 puth(hdr >> 8, n, val); 168 169 return (n == 1) ? 0 : -1; 170 } 171 172 void swdp_reset(void) { 173 gpio_set(GPIO_CLK); 174 gpio_set(GPIO_DAT); 175 gpio_config(GPIO_CLK, GPIO_OUTPUT_10MHZ | GPIO_OUT_PUSH_PULL); 176 gpio_config(GPIO_DAT, GPIO_OUTPUT_10MHZ | GPIO_OUT_PUSH_PULL); 177 178 /* tracing */ 179 gpio_set(2); 180 gpio_config(2, GPIO_OUTPUT_2MHZ | GPIO_OUT_PUSH_PULL); 181 182 clock_high(64); 183 clock_jtag2swdp(); 184 clock_high(64); 185 clock_low(8); 186 } 187