blob: 5221387412439a48e80eccbec6c1846b1cc28ab8 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/* swdp-sgpio.c
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#include <app.h>
19#include <debug.h>
20#include <string.h>
21#include <stdlib.h>
22#include <printf.h>
23#include <dev/udc.h>
24
25#include <platform.h>
26#include <arch/arm.h>
27#include <kernel/thread.h>
28
29#include <platform/lpc43xx-gpio.h>
30#include <platform/lpc43xx-sgpio.h>
31#include <platform/lpc43xx-clocks.h>
32
33#define PIN_LED PIN(1,1)
34#define PIN_RESET PIN(2,5)
35#define PIN_RESET_TXEN PIN(2,6)
36#define PIN_SWDIO_TXEN PIN(1,5) // SGPIO15=6
37#define PIN_SWDIO PIN(1,6) // SGPIO14=6
38#define PIN_SWO PIN(1,14) // U1_RXD=1
39#define PIN_SWCLK PIN(1,17) // SGPIO11=6
40
41#define GPIO_LED GPIO(0,8)
42#define GPIO_RESET GPIO(5,5)
43#define GPIO_RESET_TXEN GPIO(5,6)
44#define GPIO_SWDIO_TXEN GPIO(1,8)
45#define GPIO_SWDIO GPIO(1,9)
46#define GPIO_SWCLK GPIO(0,12)
47
48static unsigned sgpio_div = 31; // 6MHz
49
50static void gpio_init(void) {
51 pin_config(PIN_LED, PIN_MODE(0) | PIN_PLAIN);
52 pin_config(PIN_RESET, PIN_MODE(4) | PIN_PLAIN);
53 pin_config(PIN_RESET_TXEN, PIN_MODE(4) | PIN_PLAIN);
54 pin_config(PIN_SWDIO_TXEN, PIN_MODE(0) | PIN_PLAIN);
55 pin_config(PIN_SWDIO, PIN_MODE(0) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
56 pin_config(PIN_SWCLK, PIN_MODE(0) | PIN_PLAIN | PIN_FAST);
57 pin_config(PIN_SWO, PIN_MODE(1) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
58
59 gpio_set(GPIO_LED, 0);
60 gpio_set(GPIO_RESET, 1);
61 gpio_set(GPIO_RESET_TXEN, 0);
62 gpio_set(GPIO_SWDIO, 0);
63 gpio_set(GPIO_SWDIO_TXEN, 1);
64 gpio_set(GPIO_SWCLK, 0);
65
66 gpio_config(GPIO_LED, GPIO_OUTPUT);
67 gpio_config(GPIO_RESET, GPIO_OUTPUT);
68 gpio_config(GPIO_RESET_TXEN, GPIO_OUTPUT);
69 gpio_config(GPIO_SWDIO, GPIO_OUTPUT);
70 gpio_config(GPIO_SWDIO_TXEN, GPIO_OUTPUT);
71 gpio_config(GPIO_SWCLK, GPIO_OUTPUT);
72}
73
74/* returns 1 if the number of bits set in n is odd */
75static unsigned parity(unsigned n) {
76 n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
77 n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
78 n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
79 n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
80 n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
81 return n & 1;
82}
83
84static void sgpio_txn(unsigned slices) {
85 // clear any previous status bits
86 writel(0xFFFF, SLICE_XHG_STS_CLR);
87 // kick the txn
88 writel(slices, SLICE_CTRL_ENABLE);
89 writel(slices, SLICE_CTRL_DISABLE);
90 // wait for all slices to complete
91 while ((readl(SLICE_XHG_STS) & slices) != slices) ;
92 // shut down clocks
93 writel(0, SLICE_CTRL_ENABLE);
94 writel(0, SLICE_CTRL_DISABLE);
95}
96
97// SWDIO SLICE_H SLICE_P SLICE_D SLICE_O SWDIO
98// SGPIO14 -> [31....0] -> [31....0] [31....0] -> [31....0] -> SGPIO14
99//
100// SLICE_M SWDIO_TXEN
101// [31....7] -> SGPIO15
102//
103// SLICE_F SWDIO_OE
104// [31....0] -> SGPIO14_OE
105
106
107// configures all slices, muxes, etc
108// ensures that outputs are enabled and SWDIO and SWCLK are high
109static void sgpio_init(void) {
110 writel(BASE_CLK_SEL(CLK_PLL1), BASE_PERIPH_CLK);
111
112 // make sure everything's shut down
113 writel(0, SLICE_CTRL_ENABLE);
114 writel(0, SLICE_CTRL_DISABLE);
115 writel(0xFFFF, SLICE_XHG_STS_CLR);
116
117 // SWDIO_TXEN (SGPIO15)
118 // M[31..7] -> OUT
119 writel(CFG_OUT_M8B | CFG_OE_GPIO, SGPIO_OUT_CFG(15));
120 writel(CLK_USE_SLICE | QUAL_ENABLE | CONCAT_SLICE, SLICE_CFG1(SLC_M));
121 writel(CLK_GEN_INTERNAL | SHIFT_1BPC, SLICE_CFG2(SLC_M));
122
123 // SWDIO (SGPIO14)
124 // IN -> H[31..0] -> P[31..0]
125 // D[31..0] -> O[31..0] -> OUT
126 // F[31..0] -> OE
127 writel(CFG_OUT_M2C | CFG_OE_M1, SGPIO_OUT_CFG(14));
128 writel(CLK_USE_SLICE | QUAL_ENABLE | CONCAT_PIN, SLICE_CFG1(SLC_H));
129 writel(CLK_GEN_INTERNAL | SHIFT_1BPC, SLICE_CFG2(SLC_H));
130 writel(CLK_USE_SLICE | QUAL_ENABLE | CONCAT_SLICE | CONCAT_2_SLICE, SLICE_CFG1(SLC_P));
131 writel(CLK_GEN_INTERNAL | SHIFT_1BPC, SLICE_CFG2(SLC_P));
132 writel(CLK_USE_SLICE | QUAL_ENABLE | CONCAT_SLICE, SLICE_CFG1(SLC_D));
133 writel(CLK_GEN_INTERNAL | SHIFT_1BPC, SLICE_CFG2(SLC_D));
134 writel(CLK_USE_SLICE | QUAL_ENABLE | CONCAT_SLICE | CONCAT_2_SLICE, SLICE_CFG1(SLC_O));
135 writel(CLK_GEN_INTERNAL | SHIFT_1BPC, SLICE_CFG2(SLC_O));
136 writel(CLK_USE_SLICE | QUAL_ENABLE | CONCAT_SLICE, SLICE_CFG1(SLC_F));
137 writel(CLK_GEN_INTERNAL | SHIFT_1BPC, SLICE_CFG2(SLC_F));
138
139 // SWDCLK (SGPIO11)
140 // SLICE_N CLK -> OUT
141 writel(CFG_OUT_CLK | CFG_OE_GPIO, SGPIO_OUT_CFG(11));
142 writel(CLK_USE_SLICE | QUAL_ENABLE, SLICE_CFG1(SLC_N));
143 writel(CLK_GEN_INTERNAL | SHIFT_1BPC | INV_CLK_OUT, SLICE_CFG2(SLC_N));
144
145 // ensure output and enables idle high
146 writel(1, SLICE_REG(SLC_F));
147 writel(1, SLICE_REG(SLC_O));
148 writel(1 << 7, SLICE_REG(SLC_M));
149
150 // enable all outputs
151 writel((1 << 11) | (1 << 14) | (1 << 15), SGPIO_OEN);
152
153 // select SGPIOs via pin mux
154 pin_config(PIN_SWDIO_TXEN, PIN_MODE(6) | PIN_PLAIN | PIN_FAST);
155 pin_config(PIN_SWDIO, PIN_MODE(6) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
156 pin_config(PIN_SWCLK, PIN_MODE(6) | PIN_PLAIN | PIN_FAST);
157}
158
159static void sgpio_swd_clock_setup(unsigned div) {
160 writel(div, SLICE_PRESET(SLC_D));
161 writel(div, SLICE_PRESET(SLC_F));
162 writel(div, SLICE_PRESET(SLC_H));
163 writel(div, SLICE_PRESET(SLC_M));
164 writel(div, SLICE_PRESET(SLC_N));
165 writel(div, SLICE_PRESET(SLC_O));
166 writel(div, SLICE_PRESET(SLC_P));
167}
168
169static void sgpio_swd_reset(unsigned div) {
170 // shift out 64 clocks while DATA is 1
171 writel(0, SLICE_COUNT(SLC_N));
172 writel(POS_POS(63) | POS_RESET(63), SLICE_POS(SLC_N));
173 sgpio_txn(1 << SLC_N);
174
175 // shift out 16bit jtag->swd escape pattern
176 writel(0, SLICE_COUNT(SLC_N));
177 writel(POS_POS(15) | POS_RESET(15), SLICE_POS(SLC_N));
178
179 writel(0b1110011110011110, SLICE_REG(SLC_O));
180 writel(1, SLICE_SHADOW(SLC_O));
181 writel(div, SLICE_COUNT(SLC_O));
182 writel(POS_POS(15) | POS_RESET(15), SLICE_POS(SLC_O));
183 sgpio_txn((1 << SLC_N) | (1 << SLC_O));
184
185 // shift out 64 clocks while DATA is 1
186 writel(0, SLICE_COUNT(SLC_N));
187 writel(POS_POS(63) | POS_RESET(63), SLICE_POS(SLC_N));
188 sgpio_txn(1 << SLC_N);
189};
190
191// shift out 8 0s then the 8bit header, then disable outputs
192// and shift in the turnaround bit (ignored) and 3 bit ack
193// leaves output enables low
194//
195// todo: make leader optional/adjustable
196static int sgpio_swd_header(unsigned div, uint32_t hdr) {
197 unsigned timeout = 16;
198 unsigned ack;
199
200 for (;;) {
201 // 16 bits tx_en, then stop, disabling tx_en
202 writel(0xFFFF << 7, SLICE_REG(SLC_M));
203 writel(0, SLICE_SHADOW(SLC_M));
204 writel(div, SLICE_COUNT(SLC_M));
205 writel(POS_POS(15) | POS_RESET(15), SLICE_POS(SLC_M));
206
207 // 16 bits output, then stop, disabling OE
208 writel(0xFFFF, SLICE_REG(SLC_F));
209 writel(0, SLICE_SHADOW(SLC_F));
210 writel(div, SLICE_COUNT(SLC_F));
211 writel(POS_POS(15) | POS_RESET(15), SLICE_POS(SLC_F));
212
213 // 16 bits data out
214 writel(hdr << 8, SLICE_REG(SLC_O));
215 writel(1, SLICE_SHADOW(SLC_O));
216 writel(div, SLICE_COUNT(SLC_O));
217 writel(POS_POS(15) | POS_RESET(15), SLICE_POS(SLC_O));
218
219 // 20 bits data in
220 writel(0, SLICE_COUNT(SLC_H));
221 writel(POS_POS(19) | POS_RESET(19), SLICE_POS(SLC_H));
222 writel(0, SLICE_REG(SLC_H));
223
224 // 20 bits clock
225 writel(0, SLICE_COUNT(SLC_N));
226 writel(POS_POS(19) | POS_RESET(19), SLICE_POS(SLC_N));
227
228 sgpio_txn((1<<SLC_M)|(1<<SLC_F)|(1<<SLC_O)|(1<<SLC_H)|(1<<SLC_N));
229
230 if ((ack = readl(SLICE_SHADOW(SLC_H)) >> 29) == 1) {
231 // OKAY
232 if (timeout < 16) printf("[%d]\n",16-timeout);
233 return 0;
234 }
235
236 // re-enable oe, tx_en, and make data high
237 writel(1, SLICE_REG(SLC_O));
238 writel(1 << 7, SLICE_REG(SLC_M));
239 writel(1, SLICE_REG(SLC_F));
240
241 // technically we should do a Turn cycle here,
242 // but we rely on the fact that we prefix all ops
243 // with some leader 0s and can be lazy
244
245 if (ack == 2) {
246 // WAIT
247 if (timeout == 0) {
248 return -1;
249 }
250 timeout--;
251 } else {
252 printf("ERR %d\n", ack);
253 // FAULT or invalid response
254 return -1;
255 }
256 }
257}
258
259static int sgpio_swd_read(unsigned div, uint32_t hdr, uint32_t *_data) {
260 uint32_t data, p;
261
262 //printf("rd(%d,%02x)\n", div, hdr);
263 if (sgpio_swd_header(div, hdr)) {
264 return -1;
265 }
266
267 // 34 bits in -> H -> P
268 writel(0, SLICE_COUNT(SLC_H));
269 writel(POS_POS(33) | POS_RESET(33), SLICE_POS(SLC_H));
270 writel(0, SLICE_REG(SLC_H));
271 writel(0, SLICE_COUNT(SLC_P));
272 writel(POS_POS(33) | POS_RESET(33), SLICE_POS(SLC_P));
273 writel(0, SLICE_REG(SLC_P));
274
275 writel(0, SLICE_COUNT(SLC_N));
276 writel(POS_POS(33) | POS_RESET(33), SLICE_POS(SLC_N));
277 sgpio_txn((1<<SLC_H)|(1<<SLC_P)|(1<<SLC_N));
278
279 // re-enable oe, tx_en, and make data high
280 writel(1, SLICE_REG(SLC_O));
281 writel(1 << 7, SLICE_REG(SLC_M));
282 writel(1, SLICE_REG(SLC_F));
283
284 p = readl(SLICE_SHADOW(SLC_H));
285 data = (p << 2) | (readl(SLICE_SHADOW(SLC_P)) >> 30);
286 p = (p >> 30) & 1;
287
288 //printf("RD %08x %d\n", data, p);
289 if (parity(data) != p) {
290 printf("parity error\n");
291 return -1;
292 }
293 *_data = data;
294 return 0;
295}
296
297static int sgpio_swd_write(unsigned div, uint32_t hdr, uint32_t data) {
298 uint32_t p = parity(data);
299
300 //printf("wr(%d,%02x,%08x) p=%d\n", div, hdr, data, p);
301 if (sgpio_swd_header(div, hdr)) {
302 return -1;
303 }
304
305 // 34 bits D -> O -> out
306 writel(div, SLICE_COUNT(SLC_D));
307 writel(POS_POS(33) | POS_RESET(33), SLICE_POS(SLC_D));
308 writel((p << 1) | (data >> 31), SLICE_REG(SLC_D));
309 writel(div, SLICE_COUNT(SLC_O));
310 writel(POS_POS(33) | POS_RESET(33), SLICE_POS(SLC_O));
311 writel((data << 1) | 1, SLICE_REG(SLC_O));
312
313 writel(0, SLICE_COUNT(SLC_N));
314 writel(POS_POS(33) | POS_RESET(33), SLICE_POS(SLC_N));
315
316 // re-enable oe, tx_en
317 writel(1 << 7, SLICE_REG(SLC_M));
318 writel(1, SLICE_REG(SLC_F));
319
320 sgpio_txn((1<<SLC_D)|(1<<SLC_O)|(1<<SLC_N));
321
322 return 0;
323}
324
325void swd_init(void) {
326 gpio_init();
327 sgpio_init();
328}
329
330void swd_reset(void) {
331 unsigned div = sgpio_div;
332 sgpio_swd_clock_setup(div);
333 sgpio_swd_reset(div);
334}
335
336int swd_read(unsigned reg, unsigned *val) {
337 unsigned div = sgpio_div;
338 sgpio_swd_clock_setup(div);
339 return sgpio_swd_read(div, reg, val);
340}
341
342int swd_write(unsigned reg, unsigned val) {
343 unsigned div = sgpio_div;
344 sgpio_swd_clock_setup(div);
345 return sgpio_swd_write(div, reg, val);
346}
347
348unsigned swd_set_clock(unsigned khz) {
349 unsigned div;
350 if (khz < 2000) khz = 2000;
351 if (khz > 48000) khz = 48000;
352 div = 192000 / khz;
353 sgpio_div = div - 1;
354 return 192000 / div;
355}
356
357void swd_hw_reset(int assert) {
358 if (assert) {
359 gpio_set(GPIO_RESET, 0);
360 gpio_set(GPIO_RESET_TXEN, 1);
361 } else {
362 gpio_set(GPIO_RESET, 1);
363 gpio_set(GPIO_RESET_TXEN, 0);
364 }
365}
366