aboutsummaryrefslogtreecommitdiff
path: root/app/mdebug/swd-m0sub.c
blob: de3ec9d2cd2f1654ae174098c547c6d4c98a6bf3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/* swdp-m0sub.c
 *
 * Copyright 2015 Brian Swetland <swetland@frotz.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <app.h>
#include <debug.h>
#include <string.h>
#include <stdlib.h>
#include <printf.h>

#include <platform.h>
#include <arch/arm.h>
#include <kernel/thread.h>

#include <platform/lpc43xx-gpio.h>
#include <platform/lpc43xx-sgpio.h>
#include <platform/lpc43xx-clocks.h>

#include "rswdp.h"

#define PIN_LED		PIN(1,1)
#define PIN_RESET	PIN(2,5)
#define PIN_RESET_TXEN	PIN(2,6)
#define PIN_SWDIO_TXEN	PIN(1,5)	// SGPIO15=6
#define PIN_SWDIO	PIN(1,6)	// SGPIO14=6
#define PIN_SWO		PIN(1,14)	// U1_RXD=1
#define PIN_SWCLK	PIN(1,17)	// SGPIO11=6

#define GPIO_LED	GPIO(0,8)
#define GPIO_RESET	GPIO(5,5)
#define GPIO_RESET_TXEN	GPIO(5,6)
#define GPIO_SWDIO_TXEN	GPIO(1,8)
#define GPIO_SWDIO	GPIO(1,9)
#define GPIO_SWCLK	GPIO(0,12)

static void gpio_init(void) {
	pin_config(PIN_LED, PIN_MODE(0) | PIN_PLAIN);
	pin_config(PIN_RESET, PIN_MODE(4) | PIN_PLAIN);
	pin_config(PIN_RESET_TXEN, PIN_MODE(4) | PIN_PLAIN);

	pin_config(PIN_SWDIO_TXEN, PIN_MODE(6) | PIN_PLAIN | PIN_FAST);
	pin_config(PIN_SWDIO, PIN_MODE(6) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
	pin_config(PIN_SWCLK, PIN_MODE(6) | PIN_PLAIN | PIN_FAST);

	pin_config(PIN_SWO, PIN_MODE(1) | PIN_PLAIN | PIN_INPUT | PIN_FAST);

	gpio_set(GPIO_LED, 0);
	gpio_set(GPIO_RESET, 1);
	gpio_set(GPIO_RESET_TXEN, 0);

	gpio_config(GPIO_LED, GPIO_OUTPUT);
	gpio_config(GPIO_RESET, GPIO_OUTPUT);
	gpio_config(GPIO_RESET_TXEN, GPIO_OUTPUT);
}


/* returns 1 if the number of bits set in n is odd */
static unsigned parity(unsigned n) {
        n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
        n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
        n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
        n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
        n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
        return n & 1;
}

#include "fw-m0sub.h"

#define M0SUB_ZEROMAP		0x40043308
#define M0SUB_TXEV		0x40043314 // write 0 to clear
#define M4_TXEV			0x40043130 // write 0 to clear

#define RESET_CTRL0		0x40053100
#define M0_SUB_RST		(1 << 12)

#define COMM_CMD	0x18004000
#define COMM_ARG1	0x18004004
#define COMM_ARG2	0x18004008
#define COMM_RESP	0x1800400C

#define CMD_ERR		0
#define CMD_NOP		1
#define CMD_READ	2
#define CMD_WRITE	3
#define CMD_RESET	4
#define CMD_SETCLOCK	5

#define RSP_BUSY	0xFFFFFFFF

void swd_init(void) {
	gpio_init();

	writel(BASE_CLK_SEL(CLK_PLL1), BASE_PERIPH_CLK);
	spin(1000);

	// SGPIO15 SWDIO_TXEN
	writel(CFG_OUT_GPIO | CFG_OE_GPIO, SGPIO_OUT_CFG(15));
	// SGPIO14 SWDIO
	writel(CFG_OUT_GPIO | CFG_OE_GPIO, SGPIO_OUT_CFG(14));
	// SGPIO11 SWCLK
	writel(CFG_OUT_GPIO | CFG_OE_GPIO, SGPIO_OUT_CFG(11));

	// all outputs enabled and high
	writel((1 << 11) | (1 << 14) | (1 << 15), SGPIO_OUT);
	writel((1 << 11) | (1 << 14) | (1 << 15), SGPIO_OEN);

	writel(0, M4_TXEV);
	writel(M0_SUB_RST, RESET_CTRL0);
	writel(0x18000000, M0SUB_ZEROMAP);
	writel(0xffffffff, 0x18004000);
	memcpy((void*) 0x18000000, zero_bin, sizeof(zero_bin));
	DSB;
	writel(0, RESET_CTRL0);
}

int swd_write(unsigned hdr, unsigned data) {
	unsigned n;
	unsigned p = parity(data);
	writel(CMD_WRITE, COMM_CMD);
	writel((hdr << 8) | (p << 16), COMM_ARG1);
	writel(data, COMM_ARG2);
	writel(RSP_BUSY, COMM_RESP);
	DSB;
	asm("sev");
	while ((n = readl(COMM_RESP)) == RSP_BUSY) ;
	//printf("wr s=%d\n", n);
	return n;
}

int swd_read(unsigned hdr, unsigned *val) {
	unsigned n, data, p;
	writel(CMD_READ, COMM_CMD);
	writel(hdr << 8, COMM_ARG1);
	writel(RSP_BUSY, COMM_RESP);
	DSB;
	asm("sev");
	while ((n = readl(COMM_RESP)) == RSP_BUSY) ;
	if (n) {
		return n;
	}
	data = readl(COMM_ARG1);
	p = readl(COMM_ARG2);
	if (p != parity(data)) {
		return ERR_PARITY;
	}
	//printf("rd s=%d p=%d d=%08x\n", n, p, data);
	*val = data;
	return 0;
}

void swd_reset(void) {
	unsigned n;
	writel(CMD_RESET, COMM_CMD);
	writel(RSP_BUSY, COMM_RESP);
	DSB;
	asm("sev");
	while ((n = readl(COMM_RESP)) == RSP_BUSY) ;
}

unsigned swd_set_clock(unsigned khz) {
	unsigned n;
	if (khz > 8000) {
		khz = 8000;
	}
	writel(CMD_SETCLOCK, COMM_CMD);
	writel(khz/1000, COMM_ARG1);
	writel(RSP_BUSY, COMM_RESP);
	DSB;
	asm("sev");
	while ((n = readl(COMM_RESP)) == RSP_BUSY) ;

	// todo: accurate value
	return khz;
}

void swd_hw_reset(int assert) {
	if (assert) {
		gpio_set(GPIO_RESET, 0);
		gpio_set(GPIO_RESET_TXEN, 1);
	} else {
		gpio_set(GPIO_RESET, 1);
		gpio_set(GPIO_RESET_TXEN, 0);
	}
}