blob: dd6e616624b23fca5433c3318fb2f1021dca8630 [file] [log] [blame]
Harald Welteaa3b8672017-02-10 19:21:10 +01001/* Quad-modem speciic application code */
2/* (C) 2016-2016 by Harald Welte <laforge@gnumonks.org> */
3
4#include "board.h"
5#include "simtrace.h"
6#include "utils.h"
Harald Welteaa3b8672017-02-10 19:21:10 +01007#include "wwan_led.h"
8#include "wwan_perst.h"
Harald Welte5c583d32017-05-09 06:46:47 +02009#include "sim_switch.h"
Harald Welteaa3b8672017-02-10 19:21:10 +010010#include "boardver_adc.h"
Harald Welte6d1128e2017-05-05 20:23:10 +020011#include "card_pres.h"
Harald Welte9d90d282018-06-29 22:25:42 +020012#include <osmocom/core/timer.h>
Harald Welte8e7fca32017-05-07 16:14:33 +020013#include "usb_buf.h"
Harald Welteaa3b8672017-02-10 19:21:10 +010014
15static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE;
16static const Pin pin_hub_rst = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
17static const Pin pin_1234_detect = {PIO_PA14, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP};
18static const Pin pin_peer_rst = {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
19static const Pin pin_peer_erase = {PIO_PA11, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
20
Harald Welte912b1832017-03-06 09:28:13 +010021/* array of generated USB Strings */
22extern unsigned char *usb_strings[];
23
Harald Welteaa3b8672017-02-10 19:21:10 +010024static int qmod_sam3_is_12(void)
25{
26 if (PIO_Get(&pin_1234_detect) == 0)
27 return 1;
28 else
29 return 0;
30}
31
32const unsigned char __eeprom_bin[256] = {
Harald Weltec6e482d2017-03-05 16:24:29 +010033 USB_VENDOR_OPENMOKO & 0xff,
34 USB_VENDOR_OPENMOKO >> 8,
35 USB_PRODUCT_QMOD_HUB & 0xff,
36 USB_PRODUCT_QMOD_HUB >> 8,
Harald Welte705e8992017-03-05 17:10:26 +010037 0x00, 0x00, 0x9b, 0x20, 0x09, 0x00, 0x00, 0x00, 0x32, 0x32, 0x32, 0x32, /* 0x00 - 0x0f */
Harald Welteaa3b8672017-02-10 19:21:10 +010038 0x32, 0x04, 0x09, 0x18, 0x0d, 0x00, 0x73, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6d, 0x00, 0x6f, 0x00, /* 0x10 - 0x1f */
39 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x73, 0x00, 0x2e, 0x00, /* 0x20 - 0x2f */
40 0x66, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x47, 0x00, /* 0x30 - 0x3f */
41 0x6d, 0x00, 0x62, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 - 0x4f */
42 0x00, 0x00, 0x00, 0x00, 0x71, 0x00, 0x75, 0x00, 0x61, 0x00, 0x64, 0x00, 0x20, 0x00, 0x6d, 0x00, /* 0x50 - 0x5f */
43 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x76, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x60 - 0x6f */
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x7f */
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80 - 0x8f */
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90 - 0x9f */
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0 - 0xaf */
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0 - 0xbf */
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 - 0xcf */
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 - 0xdf */
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0 - 0xef */
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x56, 0x23, 0x71, 0x04, 0x00, /* 0xf0 - 0xff */
53};
54
55#include "i2c.h"
56static int write_hub_eeprom(void)
57{
58 const unsigned int __eeprom_bin_len = 256;
59
60 int i;
61
62 /* wait */
Harald Welte0e295982017-03-05 16:48:47 +010063 mdelay(100);
Harald Welteaa3b8672017-02-10 19:21:10 +010064
Harald Welteec0837c2017-03-03 01:33:24 +010065 TRACE_INFO("Writing EEPROM...\n\r");
Harald Welteaa3b8672017-02-10 19:21:10 +010066 /* write the EEPROM once */
67 for (i = 0; i < 256; i++) {
68 int rc = eeprom_write_byte(0x50, i, __eeprom_bin[i]);
69 /* if the result was negative, repeat that write */
70 if (rc < 0)
71 i--;
72 }
73
74 /* then pursue re-reading it again and again */
Harald Welteec0837c2017-03-03 01:33:24 +010075 TRACE_INFO("Verifying EEPROM...\n\r");
Harald Welteaa3b8672017-02-10 19:21:10 +010076 for (i = 0; i < 256; i++) {
77 int byte = eeprom_read_byte(0x50, i);
Harald Welteec0837c2017-03-03 01:33:24 +010078 TRACE_INFO("0x%02x: %02x\n\r", i, byte);
Harald Welteaa3b8672017-02-10 19:21:10 +010079 if (byte != __eeprom_bin[i])
Harald Welteec0837c2017-03-03 01:33:24 +010080 TRACE_ERROR("Byte %u is wrong, expected 0x%02x, found 0x%02x\n\r",
Harald Welteaa3b8672017-02-10 19:21:10 +010081 i, __eeprom_bin[i], byte);
82 }
83
84 /* FIXME: Release PIN_PRTPWR_OVERRIDE after we know the hub is
85 * again powering us up */
86
87 return 0;
88}
89
Harald Welteed1efc52017-05-07 22:49:45 +020090static void board_exec_dbg_cmd_st12only(int ch)
Harald Welteaa3b8672017-02-10 19:21:10 +010091{
92 uint32_t addr, val;
93
Harald Welteed1efc52017-05-07 22:49:45 +020094 /* functions below only work on primary (ST12) */
95 if (!qmod_sam3_is_12())
96 return;
97
98 switch (ch) {
99 case 'E':
100 write_hub_eeprom();
101 break;
102 case 'O':
103 printf("Setting PRTPWR_OVERRIDE\n\r");
104 PIO_Set(&pin_hubpwr_override);
105 break;
106 case 'o':
107 printf("Clearing PRTPWR_OVERRIDE\n\r");
108 PIO_Clear(&pin_hubpwr_override);
109 break;
110 case 'H':
111 printf("Clearing _HUB_RESET -> HUB_RESET high (inactive)\n\r");
112 PIO_Clear(&pin_hub_rst);
113 break;
114 case 'h':
115 /* high level drives transistor -> HUB_RESET low */
116 printf("Asserting _HUB_RESET -> HUB_RESET low (active)\n\r");
117 PIO_Set(&pin_hub_rst);
118 break;
119 case 'w':
120 if (PIO_GetOutputDataStatus(&pin_hub_rst) == 0)
121 printf("WARNING: attempting EEPROM access while HUB not in reset\n\r");
122 printf("Please enter EEPROM offset:\n\r");
123 UART_GetIntegerMinMax(&addr, 0, 255);
124 printf("Please enter EEPROM value:\n\r");
125 UART_GetIntegerMinMax(&val, 0, 255);
126 printf("Writing value 0x%02x to EEPROM offset 0x%02x\n\r", val, addr);
127 eeprom_write_byte(0x50, addr, val);
128 break;
129 case 'r':
130 printf("Please enter EEPROM offset:\n\r");
131 UART_GetIntegerMinMax(&addr, 0, 255);
132 printf("EEPROM[0x%02x] = 0x%02x\n\r", addr, eeprom_read_byte(0x50, addr));
133 break;
134 default:
135 printf("Unknown command '%c'\n\r", ch);
136 break;
137 }
138}
139
140/* returns '1' in case we should break any endless loop */
141void board_exec_dbg_cmd(int ch)
142{
Harald Welteaa3b8672017-02-10 19:21:10 +0100143 switch (ch) {
144 case '?':
Harald Welteec0837c2017-03-03 01:33:24 +0100145 printf("\t?\thelp\n\r");
Harald Welteec0837c2017-03-03 01:33:24 +0100146 printf("\tR\treset SAM3\n\r");
Harald Welte9164a6d2017-05-05 20:55:21 +0200147 if (qmod_sam3_is_12()) {
148 printf("\tE\tprogram EEPROM\n\r");
149 printf("\tO\tEnable PRTPWR_OVERRIDE\n\r");
150 printf("\to\tDisable PRTPWR_OVERRIDE\n\r");
151 printf("\tH\tRelease HUB RESET (high)\n\r");
152 printf("\th\tAssert HUB RESET (low)\n\r");
153 printf("\tw\tWrite single byte in EEPROM\n\r");
154 printf("\tr\tRead single byte from EEPROM\n\r");
155 }
Harald Welteec0837c2017-03-03 01:33:24 +0100156 printf("\tX\tRelease peer SAM3 from reset\n\r");
157 printf("\tx\tAssert peer SAM3 reset\n\r");
158 printf("\tY\tRelease peer SAM3 ERASE signal\n\r");
159 printf("\ty\tAssert peer SAM3 ERASE signal\n\r");
160 printf("\tU\tProceed to USB Initialization\n\r");
161 printf("\t1\tGenerate 1ms reset pulse on WWAN1\n\r");
162 printf("\t2\tGenerate 1ms reset pulse on WWAN2\n\r");
Harald Welteaa3b8672017-02-10 19:21:10 +0100163 break;
Harald Welteaa3b8672017-02-10 19:21:10 +0100164 case 'R':
Harald Welteec0837c2017-03-03 01:33:24 +0100165 printf("Asking NVIC to reset us\n\r");
Harald Weltef415d712017-03-03 01:51:43 +0100166 USBD_Disconnect();
Harald Welteaa3b8672017-02-10 19:21:10 +0100167 NVIC_SystemReset();
168 break;
Harald Welte9164a6d2017-05-05 20:55:21 +0200169 case 'X':
170 printf("Clearing _SIMTRACExx_RST -> SIMTRACExx_RST high (inactive)\n\r");
171 PIO_Clear(&pin_peer_rst);
172 break;
173 case 'x':
174 printf("Setting _SIMTRACExx_RST -> SIMTRACExx_RST low (active)\n\r");
175 PIO_Set(&pin_peer_rst);
176 break;
177 case 'Y':
178 printf("Clearing SIMTRACExx_ERASE (inactive)\n\r");
179 PIO_Clear(&pin_peer_erase);
180 break;
181 case 'y':
182 printf("Seetting SIMTRACExx_ERASE (active)\n\r");
183 PIO_Set(&pin_peer_erase);
184 break;
185 case '1':
186 printf("Resetting Modem 1 (of this SAM3)\n\r");
Harald Welte44622df2017-05-11 00:04:50 +0200187 wwan_perst_do_reset_pulse(0, 300);
Harald Welte9164a6d2017-05-05 20:55:21 +0200188 break;
189 case '2':
190 printf("Resetting Modem 2 (of this SAM3)\n\r");
Harald Welte44622df2017-05-11 00:04:50 +0200191 wwan_perst_do_reset_pulse(1, 300);
Harald Welte9164a6d2017-05-05 20:55:21 +0200192 break;
193 case '!':
Harald Welte44622df2017-05-11 00:04:50 +0200194 sim_switch_use_physical(0, 0);
Harald Welte9164a6d2017-05-05 20:55:21 +0200195 break;
196 case '@':
Harald Welte44622df2017-05-11 00:04:50 +0200197 sim_switch_use_physical(0, 0);
Harald Welte9164a6d2017-05-05 20:55:21 +0200198 break;
199 default:
Harald Welteed1efc52017-05-07 22:49:45 +0200200 if (!qmod_sam3_is_12())
Harald Welte9164a6d2017-05-05 20:55:21 +0200201 printf("Unknown command '%c'\n\r", ch);
Harald Welteed1efc52017-05-07 22:49:45 +0200202 else
203 board_exec_dbg_cmd_st12only(ch);
Harald Welteaa3b8672017-02-10 19:21:10 +0100204 break;
205 }
206}
207
208void board_main_top(void)
209{
Harald Welte25399172017-05-11 00:47:29 +0200210#ifndef APPLICATION_dfu
Harald Welte8e7fca32017-05-07 16:14:33 +0200211 usb_buf_init();
212
Harald Welteaa3b8672017-02-10 19:21:10 +0100213 wwan_led_init();
214 wwan_perst_init();
Harald Welte5c583d32017-05-09 06:46:47 +0200215 sim_switch_init();
Harald Welte25399172017-05-11 00:47:29 +0200216#endif
Harald Welteaa3b8672017-02-10 19:21:10 +0100217
Harald Welte28174982017-05-07 16:45:10 +0200218 /* make sure we can detect whether running in ST12 or ST34 */
Harald Welteaa3b8672017-02-10 19:21:10 +0100219 PIO_Configure(&pin_1234_detect, 1);
Harald Welte28174982017-05-07 16:45:10 +0200220
221 if (qmod_sam3_is_12()) {
222 /* set PIN_PRTPWR_OVERRIDE to output-low to avoid the internal
223 * pull-up on the input to keep SIMTRACE12 alive */
224 PIO_Configure(&pin_hubpwr_override, 1);
225 PIO_Configure(&pin_hub_rst, 1);
226 }
Harald Welteaa3b8672017-02-10 19:21:10 +0100227 PIO_Configure(&pin_peer_rst, 1);
228 PIO_Configure(&pin_peer_erase, 1);
Harald Welte25399172017-05-11 00:47:29 +0200229
230#ifndef APPLICATION_dfu
Harald Welteaa3b8672017-02-10 19:21:10 +0100231 i2c_pin_init();
Harald Welte25399172017-05-11 00:47:29 +0200232#endif
Harald Welteaa3b8672017-02-10 19:21:10 +0100233
234 if (qmod_sam3_is_12()) {
Harald Welteec0837c2017-03-03 01:33:24 +0100235 TRACE_INFO("Detected Quad-Modem ST12\n\r");
Harald Welteaa3b8672017-02-10 19:21:10 +0100236 } else {
Harald Welteec0837c2017-03-03 01:33:24 +0100237 TRACE_INFO("Detected Quad-Modem ST34\n\r");
Harald Welte912b1832017-03-06 09:28:13 +0100238 /* make sure we use the second set of USB Strings
239 * calling the interfaces "Modem 3" and "Modem 4" rather
240 * than 1+2 */
241 usb_strings[7] = usb_strings[9];
242 usb_strings[8] = usb_strings[10];
Harald Welteaa3b8672017-02-10 19:21:10 +0100243 }
244
245 /* Obtain the circuit board version (currently just prints voltage */
246 get_board_version_adc();
Harald Welte25399172017-05-11 00:47:29 +0200247#ifndef APPLICATION_dfu
Harald Welte6d1128e2017-05-05 20:23:10 +0200248 /* Initialize checking for card insert/remove events */
249 card_present_init();
Harald Welte25399172017-05-11 00:47:29 +0200250#endif
Harald Welteaa3b8672017-02-10 19:21:10 +0100251}
Harald Welte27f5fc62017-11-28 22:15:56 +0100252
253static int uart_has_loopback_jumper(void)
254{
255 unsigned int i;
256 const Pin uart_loopback_pins[] = {
257 {PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT},
258 {PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
259 };
260
261 /* Configure UART pins as I/O */
262 PIO_Configure(uart_loopback_pins, PIO_LISTSIZE(uart_loopback_pins));
263
264 for (i = 0; i < 10; i++) {
265 /* Set TxD high; abort if RxD doesn't go high either */
266 PIO_Set(&uart_loopback_pins[1]);
267 if (!PIO_Get(&uart_loopback_pins[0]))
268 return 0;
269 /* Set TxD low, abort if RxD doesn't go low either */
270 PIO_Clear(&uart_loopback_pins[1]);
271 if (PIO_Get(&uart_loopback_pins[0]))
272 return 0;
273 }
274 /* if we reached here, RxD always follows TxD and thus a
275 * loopback jumper has been placed on RxD/TxD, and we will boot
276 * into DFU unconditionally */
277 return 1;
278}
279
280int board_override_enter_dfu(void)
281{
282 /* If the loopback jumper is set, we enter DFU mode */
283 if (uart_has_loopback_jumper())
284 return 1;
285
286 return 0;
287}