blob: 0565c92a2bfca5cb60636e61667755043a4ee3e9 [file] [log] [blame]
Kévin Redon9a12d682018-07-08 13:21:16 +02001/* sysmocom quad-modem sysmoQMOD application code
2 *
3 * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
Kévin Redona634c0e2019-05-23 16:31:58 +02004 * (C) 2018-2019, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
Kévin Redon9a12d682018-07-08 13:21:16 +02005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19 */
Harald Welteaa3b8672017-02-10 19:21:10 +010020#include "board.h"
21#include "simtrace.h"
22#include "utils.h"
Kévin Redon1dbcf622018-09-04 16:15:10 +020023#include "led.h"
Harald Welteaa3b8672017-02-10 19:21:10 +010024#include "wwan_led.h"
25#include "wwan_perst.h"
Harald Welte5c583d32017-05-09 06:46:47 +020026#include "sim_switch.h"
Harald Welteaa3b8672017-02-10 19:21:10 +010027#include "boardver_adc.h"
Harald Welte6d1128e2017-05-05 20:23:10 +020028#include "card_pres.h"
Harald Welte9d90d282018-06-29 22:25:42 +020029#include <osmocom/core/timer.h>
Harald Welte8e7fca32017-05-07 16:14:33 +020030#include "usb_buf.h"
Harald Weltebc623352019-06-19 20:35:37 +020031#include "i2c.h"
Harald Welteaa3b8672017-02-10 19:21:10 +010032
33static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE;
34static const Pin pin_hub_rst = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
35static const Pin pin_1234_detect = {PIO_PA14, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP};
36static const Pin pin_peer_rst = {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
37static const Pin pin_peer_erase = {PIO_PA11, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
38
Harald Welte912b1832017-03-06 09:28:13 +010039/* array of generated USB Strings */
40extern unsigned char *usb_strings[];
41
Harald Welteaa3b8672017-02-10 19:21:10 +010042static int qmod_sam3_is_12(void)
43{
44 if (PIO_Get(&pin_1234_detect) == 0)
45 return 1;
46 else
47 return 0;
48}
49
Harald Weltebc623352019-06-19 20:35:37 +020050#if (ALLOW_PEER_ERASE > 0)
Harald Welteaa3b8672017-02-10 19:21:10 +010051const unsigned char __eeprom_bin[256] = {
Harald Weltec6e482d2017-03-05 16:24:29 +010052 USB_VENDOR_OPENMOKO & 0xff,
53 USB_VENDOR_OPENMOKO >> 8,
54 USB_PRODUCT_QMOD_HUB & 0xff,
55 USB_PRODUCT_QMOD_HUB >> 8,
Harald Welte705e8992017-03-05 17:10:26 +010056 0x00, 0x00, 0x9b, 0x20, 0x09, 0x00, 0x00, 0x00, 0x32, 0x32, 0x32, 0x32, /* 0x00 - 0x0f */
Harald Welteaa3b8672017-02-10 19:21:10 +010057 0x32, 0x04, 0x09, 0x18, 0x0d, 0x00, 0x73, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6d, 0x00, 0x6f, 0x00, /* 0x10 - 0x1f */
58 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x73, 0x00, 0x2e, 0x00, /* 0x20 - 0x2f */
59 0x66, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x47, 0x00, /* 0x30 - 0x3f */
60 0x6d, 0x00, 0x62, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 - 0x4f */
61 0x00, 0x00, 0x00, 0x00, 0x71, 0x00, 0x75, 0x00, 0x61, 0x00, 0x64, 0x00, 0x20, 0x00, 0x6d, 0x00, /* 0x50 - 0x5f */
62 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x76, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x60 - 0x6f */
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x7f */
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80 - 0x8f */
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90 - 0x9f */
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0 - 0xaf */
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0 - 0xbf */
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 - 0xcf */
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 - 0xdf */
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0 - 0xef */
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x56, 0x23, 0x71, 0x04, 0x00, /* 0xf0 - 0xff */
72};
73
Harald Welteaa3b8672017-02-10 19:21:10 +010074static int write_hub_eeprom(void)
75{
Harald Welteaa3b8672017-02-10 19:21:10 +010076 int i;
77
78 /* wait */
Harald Welte0e295982017-03-05 16:48:47 +010079 mdelay(100);
Harald Welteaa3b8672017-02-10 19:21:10 +010080
Harald Welteec0837c2017-03-03 01:33:24 +010081 TRACE_INFO("Writing EEPROM...\n\r");
Harald Welteaa3b8672017-02-10 19:21:10 +010082 /* write the EEPROM once */
Kévin Redona71a6f42018-07-24 09:54:12 +020083 for (i = 0; i < ARRAY_SIZE(__eeprom_bin); i++) {
Harald Welteaa3b8672017-02-10 19:21:10 +010084 int rc = eeprom_write_byte(0x50, i, __eeprom_bin[i]);
Kévin Redona71a6f42018-07-24 09:54:12 +020085 if (rc < 0) {
86 TRACE_ERROR("Writing EEPROM failed at byte %u: 0x%02x\n\r",
87 i, __eeprom_bin[i]);
88 return 1;
89 }
Harald Welteaa3b8672017-02-10 19:21:10 +010090 }
91
92 /* then pursue re-reading it again and again */
Harald Welteec0837c2017-03-03 01:33:24 +010093 TRACE_INFO("Verifying EEPROM...\n\r");
Kévin Redona71a6f42018-07-24 09:54:12 +020094 for (i = 0; i < ARRAY_SIZE(__eeprom_bin); i++) {
Harald Welteaa3b8672017-02-10 19:21:10 +010095 int byte = eeprom_read_byte(0x50, i);
Kévin Redona6bd7172018-08-28 19:41:10 +020096 TRACE_DEBUG("0x%02x: %02x\n\r", i, byte);
Harald Welteaa3b8672017-02-10 19:21:10 +010097 if (byte != __eeprom_bin[i])
Harald Welteec0837c2017-03-03 01:33:24 +010098 TRACE_ERROR("Byte %u is wrong, expected 0x%02x, found 0x%02x\n\r",
Harald Welteaa3b8672017-02-10 19:21:10 +010099 i, __eeprom_bin[i], byte);
100 }
Kévin Redona6bd7172018-08-28 19:41:10 +0200101 TRACE_INFO("EEPROM written\n\r");
Harald Welteaa3b8672017-02-10 19:21:10 +0100102
103 /* FIXME: Release PIN_PRTPWR_OVERRIDE after we know the hub is
104 * again powering us up */
105
106 return 0;
107}
108
Harald Welte9547e412018-07-03 22:31:16 +0200109static int erase_hub_eeprom(void)
110{
111 int i;
112
113 /* wait */
114 mdelay(100);
115
116 TRACE_INFO("Erasing EEPROM...\n\r");
117 /* write the EEPROM once */
118 for (i = 0; i < 256; i++) {
119 int rc = eeprom_write_byte(0x50, i, 0xff);
Kévin Redonc4285162018-08-07 12:12:47 +0200120 if (rc < 0) {
121 TRACE_ERROR("Erasing EEPROM failed at byte %u: 0x%02x\n\r",
122 i, __eeprom_bin[i]);
123 return 1;
124 }
Harald Welte9547e412018-07-03 22:31:16 +0200125 }
Kévin Redona6bd7172018-08-28 19:41:10 +0200126 TRACE_INFO("EEPROM erased\n\r");
Harald Welte9547e412018-07-03 22:31:16 +0200127
128 return 0;
129}
Harald Weltebc623352019-06-19 20:35:37 +0200130#endif /* ALLOW_PEER_ERASE */
Harald Welte9547e412018-07-03 22:31:16 +0200131
Harald Welteed1efc52017-05-07 22:49:45 +0200132static void board_exec_dbg_cmd_st12only(int ch)
Harald Welteaa3b8672017-02-10 19:21:10 +0100133{
134 uint32_t addr, val;
135
Harald Welteed1efc52017-05-07 22:49:45 +0200136 /* functions below only work on primary (ST12) */
137 if (!qmod_sam3_is_12())
138 return;
139
140 switch (ch) {
Harald Weltebc623352019-06-19 20:35:37 +0200141#if (ALLOW_PEER_ERASE > 0)
Harald Welteed1efc52017-05-07 22:49:45 +0200142 case 'E':
143 write_hub_eeprom();
144 break;
Harald Welte9547e412018-07-03 22:31:16 +0200145 case 'e':
146 erase_hub_eeprom();
147 break;
Harald Weltebc623352019-06-19 20:35:37 +0200148#endif /* ALLOW_PEER_ERASE */
Harald Welteed1efc52017-05-07 22:49:45 +0200149 case 'O':
150 printf("Setting PRTPWR_OVERRIDE\n\r");
151 PIO_Set(&pin_hubpwr_override);
152 break;
153 case 'o':
154 printf("Clearing PRTPWR_OVERRIDE\n\r");
155 PIO_Clear(&pin_hubpwr_override);
156 break;
Harald Weltebc623352019-06-19 20:35:37 +0200157#if (ALLOW_PEER_ERASE > 0)
Harald Welteed1efc52017-05-07 22:49:45 +0200158 case 'H':
159 printf("Clearing _HUB_RESET -> HUB_RESET high (inactive)\n\r");
160 PIO_Clear(&pin_hub_rst);
161 break;
162 case 'h':
163 /* high level drives transistor -> HUB_RESET low */
164 printf("Asserting _HUB_RESET -> HUB_RESET low (active)\n\r");
165 PIO_Set(&pin_hub_rst);
166 break;
167 case 'w':
168 if (PIO_GetOutputDataStatus(&pin_hub_rst) == 0)
169 printf("WARNING: attempting EEPROM access while HUB not in reset\n\r");
170 printf("Please enter EEPROM offset:\n\r");
171 UART_GetIntegerMinMax(&addr, 0, 255);
172 printf("Please enter EEPROM value:\n\r");
173 UART_GetIntegerMinMax(&val, 0, 255);
Kévin Redone5f891a2018-09-04 13:31:26 +0200174 printf("Writing value 0x%02lx to EEPROM offset 0x%02lx\n\r", val, addr);
Harald Welteed1efc52017-05-07 22:49:45 +0200175 eeprom_write_byte(0x50, addr, val);
176 break;
Harald Weltebc623352019-06-19 20:35:37 +0200177#endif /* ALLOW_PEER_ERASE */
Harald Welteed1efc52017-05-07 22:49:45 +0200178 case 'r':
179 printf("Please enter EEPROM offset:\n\r");
180 UART_GetIntegerMinMax(&addr, 0, 255);
Kévin Redone5f891a2018-09-04 13:31:26 +0200181 printf("EEPROM[0x%02lx] = 0x%02x\n\r", addr, eeprom_read_byte(0x50, addr));
Harald Welteed1efc52017-05-07 22:49:45 +0200182 break;
183 default:
184 printf("Unknown command '%c'\n\r", ch);
185 break;
186 }
187}
188
189/* returns '1' in case we should break any endless loop */
190void board_exec_dbg_cmd(int ch)
191{
Kévin Redon6228d182019-05-23 17:33:45 +0200192#if (ALLOW_PEER_ERASE > 0)
Kévin Redona634c0e2019-05-23 16:31:58 +0200193 /* this variable controls if it is allowed to assert/release the ERASE line.
194 this is done to prevent accidental ERASE on noisy serial input since only one character can trigger the ERASE.
195 */
196 static bool allow_erase = false;
Kévin Redon6228d182019-05-23 17:33:45 +0200197#endif
Kévin Redona634c0e2019-05-23 16:31:58 +0200198
Harald Welteaa3b8672017-02-10 19:21:10 +0100199 switch (ch) {
200 case '?':
Harald Welteec0837c2017-03-03 01:33:24 +0100201 printf("\t?\thelp\n\r");
Harald Welteec0837c2017-03-03 01:33:24 +0100202 printf("\tR\treset SAM3\n\r");
Kévin Redon1dbcf622018-09-04 16:15:10 +0200203 printf("\tl\tswitch off LED 1\n\r");
204 printf("\tL\tswitch off LED 1\n\r");
205 printf("\tg\tswitch off LED 2\n\r");
206 printf("\tG\tswitch off LED 2\n\r");
Harald Welte9164a6d2017-05-05 20:55:21 +0200207 if (qmod_sam3_is_12()) {
208 printf("\tE\tprogram EEPROM\n\r");
Harald Welte9547e412018-07-03 22:31:16 +0200209 printf("\te\tErase EEPROM\n\r");
Harald Welte9164a6d2017-05-05 20:55:21 +0200210 printf("\tO\tEnable PRTPWR_OVERRIDE\n\r");
211 printf("\to\tDisable PRTPWR_OVERRIDE\n\r");
212 printf("\tH\tRelease HUB RESET (high)\n\r");
213 printf("\th\tAssert HUB RESET (low)\n\r");
214 printf("\tw\tWrite single byte in EEPROM\n\r");
215 printf("\tr\tRead single byte from EEPROM\n\r");
216 }
Harald Welteec0837c2017-03-03 01:33:24 +0100217 printf("\tX\tRelease peer SAM3 from reset\n\r");
218 printf("\tx\tAssert peer SAM3 reset\n\r");
Kévin Redon6228d182019-05-23 17:33:45 +0200219#if (ALLOW_PEER_ERASE > 0)
Harald Welteec0837c2017-03-03 01:33:24 +0100220 printf("\tY\tRelease peer SAM3 ERASE signal\n\r");
Kévin Redona634c0e2019-05-23 16:31:58 +0200221 printf("\ta\tAllow asserting peer SAM3 ERASE signal\n\r");
Harald Welteec0837c2017-03-03 01:33:24 +0100222 printf("\ty\tAssert peer SAM3 ERASE signal\n\r");
Kévin Redon6228d182019-05-23 17:33:45 +0200223#endif
Harald Welteec0837c2017-03-03 01:33:24 +0100224 printf("\tU\tProceed to USB Initialization\n\r");
225 printf("\t1\tGenerate 1ms reset pulse on WWAN1\n\r");
226 printf("\t2\tGenerate 1ms reset pulse on WWAN2\n\r");
Harald Welteaa3b8672017-02-10 19:21:10 +0100227 break;
Harald Welteaa3b8672017-02-10 19:21:10 +0100228 case 'R':
Harald Welteec0837c2017-03-03 01:33:24 +0100229 printf("Asking NVIC to reset us\n\r");
Harald Weltef415d712017-03-03 01:51:43 +0100230 USBD_Disconnect();
Harald Welteaa3b8672017-02-10 19:21:10 +0100231 NVIC_SystemReset();
232 break;
Kévin Redon1dbcf622018-09-04 16:15:10 +0200233 case 'l':
234 led_blink(LED_GREEN, BLINK_ALWAYS_OFF);
235 printf("LED 1 switched off\n\r");
236 break;
237 case 'L':
238 led_blink(LED_GREEN, BLINK_ALWAYS_ON);
239 printf("LED 1 switched on\n\r");
240 break;
241 case 'g':
242 led_blink(LED_RED, BLINK_ALWAYS_OFF);
243 printf("LED 2 switched off\n\r");
244 break;
245 case 'G':
246 led_blink(LED_RED, BLINK_ALWAYS_ON);
247 printf("LED 2 switched on\n\r");
248 break;
Harald Welte9164a6d2017-05-05 20:55:21 +0200249 case 'X':
250 printf("Clearing _SIMTRACExx_RST -> SIMTRACExx_RST high (inactive)\n\r");
251 PIO_Clear(&pin_peer_rst);
252 break;
253 case 'x':
254 printf("Setting _SIMTRACExx_RST -> SIMTRACExx_RST low (active)\n\r");
255 PIO_Set(&pin_peer_rst);
256 break;
Kévin Redon6228d182019-05-23 17:33:45 +0200257#if (ALLOW_PEER_ERASE > 0)
Harald Welte9164a6d2017-05-05 20:55:21 +0200258 case 'Y':
259 printf("Clearing SIMTRACExx_ERASE (inactive)\n\r");
260 PIO_Clear(&pin_peer_erase);
261 break;
Kévin Redona634c0e2019-05-23 16:31:58 +0200262 case 'a':
263 printf("Asserting SIMTRACExx_ERASE allowed on next command\n\r");
264 allow_erase = true;
265 break;
Harald Welte9164a6d2017-05-05 20:55:21 +0200266 case 'y':
Kévin Redona634c0e2019-05-23 16:31:58 +0200267 if (allow_erase) {
268 printf("Setting SIMTRACExx_ERASE (active)\n\r");
269 PIO_Set(&pin_peer_erase);
270 } else {
271 printf("Please first allow setting SIMTRACExx_ERASE\n\r");
272 }
Harald Welte9164a6d2017-05-05 20:55:21 +0200273 break;
Kévin Redon6228d182019-05-23 17:33:45 +0200274#endif
Harald Welte9164a6d2017-05-05 20:55:21 +0200275 case '1':
276 printf("Resetting Modem 1 (of this SAM3)\n\r");
Harald Welte44622df2017-05-11 00:04:50 +0200277 wwan_perst_do_reset_pulse(0, 300);
Harald Welte9164a6d2017-05-05 20:55:21 +0200278 break;
279 case '2':
280 printf("Resetting Modem 2 (of this SAM3)\n\r");
Harald Welte44622df2017-05-11 00:04:50 +0200281 wwan_perst_do_reset_pulse(1, 300);
Harald Welte9164a6d2017-05-05 20:55:21 +0200282 break;
283 case '!':
Harald Welte44622df2017-05-11 00:04:50 +0200284 sim_switch_use_physical(0, 0);
Harald Welte9164a6d2017-05-05 20:55:21 +0200285 break;
286 case '@':
Harald Welte44622df2017-05-11 00:04:50 +0200287 sim_switch_use_physical(0, 0);
Harald Welte9164a6d2017-05-05 20:55:21 +0200288 break;
289 default:
Harald Welteed1efc52017-05-07 22:49:45 +0200290 if (!qmod_sam3_is_12())
Harald Welte9164a6d2017-05-05 20:55:21 +0200291 printf("Unknown command '%c'\n\r", ch);
Harald Welteed1efc52017-05-07 22:49:45 +0200292 else
293 board_exec_dbg_cmd_st12only(ch);
Harald Welteaa3b8672017-02-10 19:21:10 +0100294 break;
295 }
Kévin Redona634c0e2019-05-23 16:31:58 +0200296
Kévin Redon6228d182019-05-23 17:33:45 +0200297#if (ALLOW_PEER_ERASE > 0)
Kévin Redona634c0e2019-05-23 16:31:58 +0200298 // set protection back so it can only run for one command
299 if ('a' != ch) {
300 allow_erase = false;
301 }
Kévin Redon6228d182019-05-23 17:33:45 +0200302#endif
Harald Welteaa3b8672017-02-10 19:21:10 +0100303}
304
305void board_main_top(void)
306{
Harald Welte25399172017-05-11 00:47:29 +0200307#ifndef APPLICATION_dfu
Harald Welte8e7fca32017-05-07 16:14:33 +0200308 usb_buf_init();
309
Harald Welteaa3b8672017-02-10 19:21:10 +0100310 wwan_led_init();
311 wwan_perst_init();
Harald Welte5c583d32017-05-09 06:46:47 +0200312 sim_switch_init();
Harald Welte25399172017-05-11 00:47:29 +0200313#endif
Harald Welteaa3b8672017-02-10 19:21:10 +0100314
Harald Welte28174982017-05-07 16:45:10 +0200315 /* make sure we can detect whether running in ST12 or ST34 */
Harald Welteaa3b8672017-02-10 19:21:10 +0100316 PIO_Configure(&pin_1234_detect, 1);
Harald Welte28174982017-05-07 16:45:10 +0200317
318 if (qmod_sam3_is_12()) {
319 /* set PIN_PRTPWR_OVERRIDE to output-low to avoid the internal
320 * pull-up on the input to keep SIMTRACE12 alive */
321 PIO_Configure(&pin_hubpwr_override, 1);
322 PIO_Configure(&pin_hub_rst, 1);
323 }
Harald Welteaa3b8672017-02-10 19:21:10 +0100324 PIO_Configure(&pin_peer_rst, 1);
325 PIO_Configure(&pin_peer_erase, 1);
Harald Welte25399172017-05-11 00:47:29 +0200326
327#ifndef APPLICATION_dfu
Harald Welteaa3b8672017-02-10 19:21:10 +0100328 i2c_pin_init();
Harald Welte25399172017-05-11 00:47:29 +0200329#endif
Harald Welteaa3b8672017-02-10 19:21:10 +0100330
331 if (qmod_sam3_is_12()) {
Harald Welteec0837c2017-03-03 01:33:24 +0100332 TRACE_INFO("Detected Quad-Modem ST12\n\r");
Harald Welteaa3b8672017-02-10 19:21:10 +0100333 } else {
Harald Welteec0837c2017-03-03 01:33:24 +0100334 TRACE_INFO("Detected Quad-Modem ST34\n\r");
Harald Welte912b1832017-03-06 09:28:13 +0100335 /* make sure we use the second set of USB Strings
336 * calling the interfaces "Modem 3" and "Modem 4" rather
337 * than 1+2 */
338 usb_strings[7] = usb_strings[9];
339 usb_strings[8] = usb_strings[10];
Harald Welteaa3b8672017-02-10 19:21:10 +0100340 }
341
342 /* Obtain the circuit board version (currently just prints voltage */
343 get_board_version_adc();
Harald Welte25399172017-05-11 00:47:29 +0200344#ifndef APPLICATION_dfu
Harald Welte6d1128e2017-05-05 20:23:10 +0200345 /* Initialize checking for card insert/remove events */
346 card_present_init();
Harald Welte25399172017-05-11 00:47:29 +0200347#endif
Harald Welteaa3b8672017-02-10 19:21:10 +0100348}
Harald Welte27f5fc62017-11-28 22:15:56 +0100349
350static int uart_has_loopback_jumper(void)
351{
352 unsigned int i;
353 const Pin uart_loopback_pins[] = {
354 {PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT},
355 {PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
356 };
357
358 /* Configure UART pins as I/O */
359 PIO_Configure(uart_loopback_pins, PIO_LISTSIZE(uart_loopback_pins));
360
Kévin Redond24e9bd2018-07-07 14:56:43 +0200361 /* Send pattern over UART TX and check if it is received on RX
362 * If the loop doesn't get interrupted, RxD always follows TxD and thus a
363 * loopback jumper has been placed on RxD/TxD, and we will boot
364 * into DFU unconditionally
365 */
366 int has_loopback_jumper = 1;
Harald Welte27f5fc62017-11-28 22:15:56 +0100367 for (i = 0; i < 10; i++) {
368 /* Set TxD high; abort if RxD doesn't go high either */
369 PIO_Set(&uart_loopback_pins[1]);
Kévin Redond24e9bd2018-07-07 14:56:43 +0200370 if (!PIO_Get(&uart_loopback_pins[0])) {
371 has_loopback_jumper = 0;
372 break;
373 }
Harald Welte27f5fc62017-11-28 22:15:56 +0100374 /* Set TxD low, abort if RxD doesn't go low either */
375 PIO_Clear(&uart_loopback_pins[1]);
Kévin Redond24e9bd2018-07-07 14:56:43 +0200376 if (PIO_Get(&uart_loopback_pins[0])) {
377 has_loopback_jumper = 0;
378 break;
379 }
Harald Welte27f5fc62017-11-28 22:15:56 +0100380 }
Kévin Redond24e9bd2018-07-07 14:56:43 +0200381
382 /* Put pins back to UART mode */
383 const Pin uart_pins[] = {PINS_UART};
384 PIO_Configure(uart_pins, PIO_LISTSIZE(uart_pins));
385
386 return has_loopback_jumper;
Harald Welte27f5fc62017-11-28 22:15:56 +0100387}
388
389int board_override_enter_dfu(void)
390{
391 /* If the loopback jumper is set, we enter DFU mode */
392 if (uart_has_loopback_jumper())
393 return 1;
394
395 return 0;
396}