blob: 63ce42a7e122cc2605d2b94213361c488fdd7781 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/* swdp-m0sub.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
24#include <platform.h>
25#include <arch/arm.h>
26#include <kernel/thread.h>
27
28#include <platform/lpc43xx-gpio.h>
29#include <platform/lpc43xx-sgpio.h>
30#include <platform/lpc43xx-clocks.h>
31
32#include "rswdp.h"
33
34#include "lpclink2.h"
35
36static void gpio_init(void) {
37 pin_config(PIN_LED, PIN_MODE(0) | PIN_PLAIN);
38 pin_config(PIN_RESET, PIN_MODE(4) | PIN_PLAIN);
39 pin_config(PIN_RESET_TXEN, PIN_MODE(4) | PIN_PLAIN);
40
41 pin_config(PIN_SWDIO_TXEN, PIN_MODE(6) | PIN_PLAIN | PIN_FAST);
42 pin_config(PIN_SWDIO, PIN_MODE(6) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
43 pin_config(PIN_SWCLK, PIN_MODE(6) | PIN_PLAIN | PIN_FAST);
44
45 pin_config(PIN_SWO, PIN_MODE(1) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
46
47 gpio_set(GPIO_LED, 0);
48 gpio_set(GPIO_RESET, 1);
49 gpio_set(GPIO_RESET_TXEN, 0);
50
51 gpio_config(GPIO_LED, GPIO_OUTPUT);
52 gpio_config(GPIO_RESET, GPIO_OUTPUT);
53 gpio_config(GPIO_RESET_TXEN, GPIO_OUTPUT);
54}
55
56
57/* returns 1 if the number of bits set in n is odd */
58static unsigned parity(unsigned n) {
59 n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
60 n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
61 n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
62 n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
63 n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
64 return n & 1;
65}
66
67#include "fw-m0sub.h"
68
69#define M0SUB_ZEROMAP 0x40043308
70#define M0SUB_TXEV 0x40043314 // write 0 to clear
71#define M4_TXEV 0x40043130 // write 0 to clear
72
73#define RESET_CTRL0 0x40053100
74#define M0_SUB_RST (1 << 12)
75
76#define COMM_CMD 0x18004000
77#define COMM_ARG1 0x18004004
78#define COMM_ARG2 0x18004008
79#define COMM_RESP 0x1800400C
80
81#define M0_CMD_ERR 0
82#define M0_CMD_NOP 1
83#define M0_CMD_READ 2
84#define M0_CMD_WRITE 3
85#define M0_CMD_RESET 4
86#define M0_CMD_SETCLOCK 5
87
88#define RSP_BUSY 0xFFFFFFFF
89
90void swd_init(void) {
91 gpio_init();
92
93 writel(BASE_CLK_SEL(CLK_PLL1), BASE_PERIPH_CLK);
94 spin(1000);
95
96 // SGPIO15 SWDIO_TXEN
97 writel(CFG_OUT_GPIO | CFG_OE_GPIO, SGPIO_OUT_CFG(15));
98 // SGPIO14 SWDIO
99 writel(CFG_OUT_GPIO | CFG_OE_GPIO, SGPIO_OUT_CFG(14));
100 // SGPIO11 SWCLK
101 writel(CFG_OUT_GPIO | CFG_OE_GPIO, SGPIO_OUT_CFG(11));
102
103 // all outputs enabled and high
104 writel((1 << 11) | (1 << 14) | (1 << 15), SGPIO_OUT);
105 writel((1 << 11) | (1 << 14) | (1 << 15), SGPIO_OEN);
106
107 writel(0, M4_TXEV);
108 writel(M0_SUB_RST, RESET_CTRL0);
109 writel(0x18000000, M0SUB_ZEROMAP);
110 writel(0xffffffff, 0x18004000);
111 memcpy((void*) 0x18000000, zero_bin, sizeof(zero_bin));
112 DSB;
113 writel(0, RESET_CTRL0);
114}
115
116int swd_write(unsigned hdr, unsigned data) {
117 unsigned n;
118 unsigned p = parity(data);
119 writel(M0_CMD_WRITE, COMM_CMD);
120 writel((hdr << 8) | (p << 16), COMM_ARG1);
121 writel(data, COMM_ARG2);
122 writel(RSP_BUSY, COMM_RESP);
123 DSB;
124 asm("sev");
125 while ((n = readl(COMM_RESP)) == RSP_BUSY) ;
126 //printf("wr s=%d\n", n);
127 return n;
128}
129
130int swd_read(unsigned hdr, unsigned *val) {
131 unsigned n, data, p;
132 writel(M0_CMD_READ, COMM_CMD);
133 writel(hdr << 8, COMM_ARG1);
134 writel(RSP_BUSY, COMM_RESP);
135 DSB;
136 asm("sev");
137 while ((n = readl(COMM_RESP)) == RSP_BUSY) ;
138 if (n) {
139 return n;
140 }
141 data = readl(COMM_ARG1);
142 p = readl(COMM_ARG2);
143 if (p != parity(data)) {
144 return ERR_PARITY;
145 }
146 //printf("rd s=%d p=%d d=%08x\n", n, p, data);
147 *val = data;
148 return 0;
149}
150
151void swd_reset(void) {
152 unsigned n;
153 writel(M0_CMD_RESET, COMM_CMD);
154 writel(RSP_BUSY, COMM_RESP);
155 DSB;
156 asm("sev");
157 while ((n = readl(COMM_RESP)) == RSP_BUSY) ;
158}
159
160unsigned swd_set_clock(unsigned khz) {
161 unsigned n;
162 if (khz > 8000) {
163 khz = 8000;
164 }
165 writel(M0_CMD_SETCLOCK, COMM_CMD);
166 writel(khz/1000, COMM_ARG1);
167 writel(RSP_BUSY, COMM_RESP);
168 DSB;
169 asm("sev");
170 while ((n = readl(COMM_RESP)) == RSP_BUSY) ;
171
172 // todo: accurate value
173 return khz;
174}
175
176void swd_hw_reset(int assert) {
177 if (assert) {
178 gpio_set(GPIO_RESET, 0);
179 gpio_set(GPIO_RESET_TXEN, 1);
180 } else {
181 gpio_set(GPIO_RESET, 1);
182 gpio_set(GPIO_RESET_TXEN, 0);
183 }
184}