blob: 60e87a42f4ddb8b529e88da8d53399bd9224345d [file] [log] [blame]
Urja Rannikko22915352009-06-23 11:33:43 +00001/*
2 * This file is part of the flashrom project.
3 *
Urja Rannikkoc93f5f12011-09-15 23:38:14 +00004 * Copyright (C) 2009, 2011 Urja Rannikko <urjaman@gmail.com>
Urja Rannikko22915352009-06-23 11:33:43 +00005 * Copyright (C) 2009 Carl-Daniel Hailfinger
Riku Viitanenddb6d922024-01-15 19:15:49 +02006 * Copyright (C) 2024 Riku Viitanen <riku.viitanen@protonmail.com>
Urja Rannikko22915352009-06-23 11:33:43 +00007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Urja Rannikko22915352009-06-23 11:33:43 +000017 */
18
Felix Singer815eb792022-08-19 01:02:42 +020019#include <stdbool.h>
Carl-Daniel Hailfingeref58a9c2009-08-12 13:32:56 +000020#include <stdio.h>
Stefan Taunerb0eee9b2015-01-10 09:32:50 +000021#if ! IS_WINDOWS /* stuff (presumably) needed for sockets only */
Urja Rannikko22915352009-06-23 11:33:43 +000022#include <stdlib.h>
Carl-Daniel Hailfingeref58a9c2009-08-12 13:32:56 +000023#include <unistd.h>
Urja Rannikko22915352009-06-23 11:33:43 +000024#include <fcntl.h>
Urja Rannikko22915352009-06-23 11:33:43 +000025#include <sys/socket.h>
26#include <arpa/inet.h>
27#include <netinet/in.h>
28#include <netinet/tcp.h>
29#include <netdb.h>
Stefan Tauner52b6e9d2013-04-01 00:46:05 +000030#endif
Stefan Taunerb0eee9b2015-01-10 09:32:50 +000031#if IS_WINDOWS
Stefan Tauner52b6e9d2013-04-01 00:46:05 +000032#include <conio.h>
33#else
Urja Rannikko22915352009-06-23 11:33:43 +000034#include <termios.h>
Stefan Tauner52b6e9d2013-04-01 00:46:05 +000035#endif
36#include <string.h>
37#include <errno.h>
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000038#include "flash.h"
39#include "programmer.h"
Urja Rannikkoc93f5f12011-09-15 23:38:14 +000040#include "chipdrivers.h"
Felix Singer100be2c2021-10-13 13:40:07 +020041
42/* According to Serial Flasher Protocol Specification - version 1 */
43#define S_ACK 0x06
44#define S_NAK 0x15
45#define S_CMD_NOP 0x00 /* No operation */
46#define S_CMD_Q_IFACE 0x01 /* Query interface version */
47#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */
48#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */
49#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */
50#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */
51#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */
52#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */
53#define S_CMD_Q_WRNMAXLEN 0x08 /* Query Write to opbuf: Write-N maximum length */
54#define S_CMD_R_BYTE 0x09 /* Read a single byte */
55#define S_CMD_R_NBYTES 0x0A /* Read n bytes */
56#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */
57#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */
58#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */
59#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */
60#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */
61#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */
62#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */
63#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */
64#define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */
65#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */
66#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */
Riku Viitanenddb6d922024-01-15 19:15:49 +020067#define S_CMD_S_SPI_CS 0x16 /* Set SPI chip select to use */
Urja Rannikkof3196df2009-07-21 13:02:59 +000068
Stefan Tauner31019d42011-10-22 21:45:27 +000069#define MSGHEADER "serprog: "
Urja Rannikkof3196df2009-07-21 13:02:59 +000070
David Hendricks8bb20212011-06-14 01:35:36 +000071/*
72 * FIXME: This prototype was added to help reduce diffs for the shutdown
73 * registration patch, which shifted many lines of code to place
74 * serprog_shutdown() before serprog_init(). It should be removed soon.
75 */
76static int serprog_shutdown(void *data);
77
Urja Rannikkof3196df2009-07-21 13:02:59 +000078static uint16_t sp_device_serbuf_size = 16;
79static uint16_t sp_device_opbuf_size = 300;
80/* Bitmap of supported commands */
81static uint8_t sp_cmdmap[32];
82
Uwe Hermann4e3d0b32010-03-25 23:18:41 +000083/* sp_prev_was_write used to detect writes with contiguous addresses
Urja Rannikkof3196df2009-07-21 13:02:59 +000084 and combine them to write-n's */
85static int sp_prev_was_write = 0;
86/* sp_write_n_addr used as the starting addr of the currently
87 combined write-n operation */
88static uint32_t sp_write_n_addr;
89/* The maximum length of an write_n operation; 0 = write-n not supported */
90static uint32_t sp_max_write_n = 0;
91/* The maximum length of a read_n operation; 0 = 2^24 */
92static uint32_t sp_max_read_n = 0;
93
94/* A malloc'd buffer for combining the operation's data
95 and a counter that tells how much data is there. */
96static uint8_t *sp_write_n_buf;
97static uint32_t sp_write_n_bytes = 0;
98
99/* sp_streamed_* used for flow control checking */
Nico Huber519be662018-12-23 20:03:35 +0100100static unsigned int sp_streamed_transmit_ops = 0;
101static unsigned int sp_streamed_transmit_bytes = 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000102
103/* sp_opbuf_usage used for counting the amount of
104 on-device operation buffer used */
105static int sp_opbuf_usage = 0;
106/* if true causes sp_docommand to automatically check
107 whether the command is supported before doing it */
108static int sp_check_avail_automatic = 0;
109
Stefan Taunerb0eee9b2015-01-10 09:32:50 +0000110#if ! IS_WINDOWS
Urja Rannikkof3196df2009-07-21 13:02:59 +0000111static int sp_opensocket(char *ip, unsigned int port)
112{
113 int flag = 1;
114 struct hostent *hostPtr = NULL;
Carl-Daniel Hailfinger6d125602009-09-05 01:10:23 +0000115 union { struct sockaddr_in si; struct sockaddr s; } sp = {};
Urja Rannikkof3196df2009-07-21 13:02:59 +0000116 int sock;
Sean Nelson74e8af52010-01-10 01:06:23 +0000117 msg_pdbg(MSGHEADER "IP %s port %d\n", ip, port);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000118 sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000119 if (sock < 0) {
120 msg_perr("Error: serprog cannot open socket: %s\n", strerror(errno));
121 return -1;
122 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000123 hostPtr = gethostbyname(ip);
124 if (NULL == hostPtr) {
125 hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000126 if (NULL == hostPtr) {
Stefan Reinauerb8792872014-04-26 16:12:03 +0000127 close(sock);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000128 msg_perr("Error: cannot resolve %s\n", ip);
129 return -1;
130 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000131 }
Carl-Daniel Hailfinger6d125602009-09-05 01:10:23 +0000132 sp.si.sin_family = AF_INET;
133 sp.si.sin_port = htons(port);
Carl-Daniel Hailfinger1c6d2ff2012-08-27 00:44:42 +0000134 (void)memcpy(&sp.si.sin_addr, hostPtr->h_addr_list[0], hostPtr->h_length);
Carl-Daniel Hailfinger6d125602009-09-05 01:10:23 +0000135 if (connect(sock, &sp.s, sizeof(sp.si)) < 0) {
Urja Rannikkof3196df2009-07-21 13:02:59 +0000136 close(sock);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000137 msg_perr("Error: serprog cannot connect: %s\n", strerror(errno));
138 return -1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000139 }
140 /* We are latency limited, and sometimes do write-write-read *
141 * (write-n) - so enable TCP_NODELAY. */
Stefan Reinauer907c3eb2014-04-26 16:12:31 +0000142 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) {
143 close(sock);
144 msg_perr("Error: serprog cannot set socket options: %s\n", strerror(errno));
145 return -1;
146 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000147 return sock;
148}
Stefan Tauner52b6e9d2013-04-01 00:46:05 +0000149#endif
Urja Rannikkof3196df2009-07-21 13:02:59 +0000150
Nico Huberd7318ea2023-02-12 00:30:31 +0100151static int sp_test_sync(void)
152{
153 int n;
154
155 unsigned char c = S_CMD_SYNCNOP;
156 if (serialport_write_nonblock(&c, 1, 1, NULL) != 0)
157 return -1;
158
159 for (n = 0; n < 10; n++) {
160 int ret = serialport_read_nonblock(&c, 1, 50, NULL);
161 if (ret < 0)
162 return -1;
163 if (ret > 0 || c != S_NAK)
164 continue;
165 ret = serialport_read_nonblock(&c, 1, 20, NULL);
166 if (ret < 0)
167 return -1;
168 if (ret > 0 || c != S_ACK)
169 continue;
170
171 c = S_CMD_SYNCNOP;
172 if (serialport_write_nonblock(&c, 1, 1, NULL) != 0)
173 return -1;
174 ret = serialport_read_nonblock(&c, 1, 500, NULL);
175 if (ret < 0)
176 return -1;
177 if (ret > 0 || c != S_NAK)
178 return 1; /* soft fail */
179 ret = serialport_read_nonblock(&c, 1, 100, NULL);
180 if (ret > 0 || ret < 0)
181 return -1;
182 if (c != S_ACK)
183 return 1; /* soft fail */
184 return 0;
185 }
186
187 return 1; /* soft fail */
188}
189
Uwe Hermann4e3d0b32010-03-25 23:18:41 +0000190/* Synchronize: a bit tricky algorithm that tries to (and in my tests has *
Urja Rannikkof3196df2009-07-21 13:02:59 +0000191 * always succeeded in) bring the serial protocol to known waiting-for- *
Stefan Taunerae3d8372013-04-01 00:45:45 +0000192 * command state - uses nonblocking I/O - rest of the driver uses *
Urja Rannikkof3196df2009-07-21 13:02:59 +0000193 * blocking read - TODO: add an alarm() timer for the rest of the app on *
194 * serial operations, though not such a big issue as the first thing to *
195 * do is synchronize (eg. check that device is alive). */
Niklas Söderlund7145a502012-09-07 07:07:07 +0000196static int sp_synchronize(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000197{
Nico Huberd7318ea2023-02-12 00:30:31 +0100198 int i, ret;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000199 unsigned char buf[8];
Nico Huber383b7fe2023-02-12 00:38:55 +0100200
201 ret = sp_test_sync();
202 if (ret < 0)
203 goto err_out;
204 if (ret == 0) {
205 msg_pdbg("\n");
206 return 0;
207 }
208
209 msg_pdbg(" - attempting to synchronize\n");
210
Urja Rannikkof3196df2009-07-21 13:02:59 +0000211 /* First sends 8 NOPs, then flushes the return data - should cause *
212 * the device serial parser to get to a sane state, unless if it *
213 * is waiting for a real long write-n. */
214 memset(buf, S_CMD_NOP, 8);
Stefan Taunerae3d8372013-04-01 00:45:45 +0000215 if (serialport_write_nonblock(buf, 8, 1, NULL) != 0) {
Niklas Söderlund7145a502012-09-07 07:07:07 +0000216 goto err_out;
217 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000218 /* A second should be enough to get all the answers to the buffer */
Stefan Tauner79587f52013-04-01 00:45:51 +0000219 internal_delay(1000 * 1000);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000220 sp_flush_incoming();
221
Cristian Măgherușan-Stanciu9932c7b2011-07-07 19:56:58 +0000222 /* Then try up to 8 times to send syncnop and get the correct special *
223 * return of NAK+ACK. Timing note: up to 10 characters, 10*50ms = *
224 * up to 500ms per try, 8*0.5s = 4s; +1s (above) = up to 5s sync *
225 * attempt, ~1s if immediate success. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000226 for (i = 0; i < 8; i++) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000227 msg_pdbg(".");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000228 fflush(stdout);
Nico Huberd7318ea2023-02-12 00:30:31 +0100229
230 ret = sp_test_sync();
231 if (ret > 0)
232 continue;
233 if (ret < 0)
234 goto err_out;
235 msg_pdbg("\n");
236 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000237 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000238err_out:
239 msg_perr("Error: cannot synchronize protocol - check communications and reset device?\n");
240 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000241}
242
243static int sp_check_commandavail(uint8_t command)
244{
245 int byteoffs, bitoffs;
246 byteoffs = command / 8;
247 bitoffs = command % 8;
248 return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
249}
250
251static int sp_automatic_cmdcheck(uint8_t cmd)
252{
253 if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000254 msg_pdbg("Warning: Automatic command availability check failed "
Stefan Taunere34e3e82013-01-01 00:06:51 +0000255 "for cmd 0x%02x - won't execute cmd\n", cmd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000256 return 1;
257 }
258 return 0;
259}
260
261static int sp_docommand(uint8_t command, uint32_t parmlen,
Stefan Tauner31019d42011-10-22 21:45:27 +0000262 uint8_t *params, uint32_t retlen, void *retparms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000263{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000264 unsigned char c;
265 if (sp_automatic_cmdcheck(command))
266 return 1;
Stefan Tauner79587f52013-04-01 00:45:51 +0000267 if (serialport_write(&command, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000268 msg_perr("Error: cannot write op code: %s\n", strerror(errno));
269 return 1;
270 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000271 if (serialport_write(params, parmlen) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000272 msg_perr("Error: cannot write parameters: %s\n", strerror(errno));
273 return 1;
274 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000275 if (serialport_read(&c, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000276 msg_perr("Error: cannot read from device: %s\n", strerror(errno));
277 return 1;
278 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000279 if (c == S_NAK)
280 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000281 if (c != S_ACK) {
Stefan Tauner23e10b82016-01-23 16:16:49 +0000282 msg_perr("Error: invalid response 0x%02X from device (to command 0x%02X)\n", c, command);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000283 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000284 }
285 if (retlen) {
Stefan Tauner79587f52013-04-01 00:45:51 +0000286 if (serialport_read(retparms, retlen) != 0) {
287 msg_perr("Error: cannot read return parameters: %s\n", strerror(errno));
288 return 1;
289 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000290 }
291 return 0;
292}
293
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000294static int sp_flush_stream(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000295{
296 if (sp_streamed_transmit_ops)
297 do {
298 unsigned char c;
Stefan Tauner79587f52013-04-01 00:45:51 +0000299 if (serialport_read(&c, 1) != 0) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000300 msg_perr("Error: cannot read from device (flushing stream)");
301 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000302 }
303 if (c == S_NAK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000304 msg_perr("Error: NAK to a stream buffer operation\n");
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000305 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000306 }
307 if (c != S_ACK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000308 msg_perr("Error: Invalid reply 0x%02X from device\n", c);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000309 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000310 }
311 } while (--sp_streamed_transmit_ops);
312 sp_streamed_transmit_ops = 0;
313 sp_streamed_transmit_bytes = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000314 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000315}
316
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000317static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000318{
319 uint8_t *sp;
320 if (sp_automatic_cmdcheck(cmd))
321 return 1;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000322
Urja Rannikkof3196df2009-07-21 13:02:59 +0000323 sp = malloc(1 + parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000324 if (!sp) {
325 msg_perr("Error: cannot malloc command buffer\n");
326 return 1;
327 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000328 sp[0] = cmd;
aarya885917c2022-03-10 09:16:44 +0530329 if (parms)
330 memcpy(&(sp[1]), parms, parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000331
332 if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) {
333 if (sp_flush_stream() != 0) {
334 free(sp);
335 return 1;
336 }
337 }
338 if (serialport_write(sp, 1 + parmlen) != 0) {
339 msg_perr("Error: cannot write command\n");
340 free(sp);
341 return 1;
342 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000343 sp_streamed_transmit_ops += 1;
344 sp_streamed_transmit_bytes += 1 + parmlen;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000345
346 free(sp);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000347 return 0;
348}
349
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000350static int serprog_spi_send_command(const struct flashctx *flash,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000351 unsigned int writecnt, unsigned int readcnt,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000352 const unsigned char *writearr,
353 unsigned char *readarr);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000354static struct spi_master spi_master_serprog = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100355 .features = SPI_MASTER_4BA,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000356 .max_data_read = MAX_DATA_READ_UNLIMITED,
357 .max_data_write = MAX_DATA_WRITE_UNLIMITED,
358 .command = serprog_spi_send_command,
359 .multicommand = default_spi_send_multicommand,
Urja Rannikko731316a2017-06-15 13:32:01 +0300360 .read = default_spi_read,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000361 .write_256 = default_spi_write_256,
Aarya Chaumal0cea7532022-07-04 18:21:50 +0530362 .probe_opcode = default_spi_probe_opcode,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000363};
364
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000365static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
366 chipaddr addr);
367static uint8_t serprog_chip_readb(const struct flashctx *flash,
368 const chipaddr addr);
369static void serprog_chip_readn(const struct flashctx *flash, uint8_t *buf,
370 const chipaddr addr, size_t len);
Nico Huber0e76d992023-01-12 20:22:55 +0100371static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000372static const struct par_master par_master_serprog = {
Thomas Heijligen43040f22022-06-23 14:38:35 +0200373 .chip_readb = serprog_chip_readb,
374 .chip_readw = fallback_chip_readw,
375 .chip_readl = fallback_chip_readl,
376 .chip_readn = serprog_chip_readn,
377 .chip_writeb = serprog_chip_writeb,
378 .chip_writew = fallback_chip_writew,
379 .chip_writel = fallback_chip_writel,
380 .chip_writen = fallback_chip_writen,
Nico Huber0e76d992023-01-12 20:22:55 +0100381 .map_flash = serprog_map,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000382};
383
384static enum chipbustype serprog_buses_supported = BUS_NONE;
385
Nico Hubere3a26882023-01-11 21:45:51 +0100386static int serprog_init(struct flashprog_programmer *const prog)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000387{
388 uint16_t iface;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000389 unsigned char pgmname[17];
390 unsigned char rbuf[3];
391 unsigned char c;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000392 char *device;
Felix Singer815eb792022-08-19 01:02:42 +0200393 bool have_device = false;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000394
Stefan Tauner72587f82016-01-04 03:05:15 +0000395 /* the parameter is either of format "dev=/dev/device[:baud]" or "ip=ip:port" */
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000396 device = extract_programmer_param("dev");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000397 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000398 char *baud_str = strstr(device, ":");
399 if (baud_str != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000400 /* Split device from baudrate. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000401 *baud_str = '\0';
402 baud_str++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000403 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000404 int baud;
405 /* Convert baud string to value.
406 * baud_str is either NULL (if strstr can't find the colon), points to the \0 after the colon
407 * if no characters where given after the colon, or a string to convert... */
408 if (baud_str == NULL || *baud_str == '\0') {
409 baud = -1;
410 msg_pdbg("No baudrate specified, using the hardware's defaults.\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000411 } else {
Stefan Tauner72587f82016-01-04 03:05:15 +0000412 baud = atoi(baud_str); // FIXME: replace atoi with strtoul
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000413 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000414 if (strlen(device) > 0) {
415 sp_fd = sp_openserport(device, baud);
Stefan Tauneracfc4c62012-11-30 16:46:45 +0000416 if (sp_fd == SER_INV_FD) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000417 free(device);
418 return 1;
419 }
Felix Singer815eb792022-08-19 01:02:42 +0200420 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000421 }
422 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000423
424#if !IS_WINDOWS
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000425 if (device && !strlen(device)) {
426 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200427 "Use flashprog -p serprog:dev=/dev/device[:baud]\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000428 free(device);
429 return 1;
430 }
431 free(device);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000432
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000433 device = extract_programmer_param("ip");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000434 if (have_device && device) {
435 msg_perr("Error: Both host and device specified.\n"
436 "Please use either dev= or ip= but not both.\n");
437 free(device);
438 return 1;
439 }
440 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000441 char *port = strstr(device, ":");
442 if (port != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000443 /* Split host from port. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000444 *port = '\0';
445 port++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000446 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000447 if (!port || !strlen(port)) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000448 msg_perr("Error: No port specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200449 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000450 free(device);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000451 return 1;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000452 }
453 if (strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000454 sp_fd = sp_opensocket(device, atoi(port)); // FIXME: replace atoi with strtoul
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000455 if (sp_fd < 0) {
456 free(device);
457 return 1;
458 }
Felix Singer815eb792022-08-19 01:02:42 +0200459 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000460 }
461 }
462 if (device && !strlen(device)) {
463 msg_perr("Error: No host specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200464 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000465 free(device);
466 return 1;
467 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000468#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000469 free(device);
470
471 if (!have_device) {
Urja Rannikko27b431b2016-01-04 03:05:23 +0000472#if IS_WINDOWS
473 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200474 "Use flashprog -p serprog:dev=comN[:baud]\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000475#else
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000476 msg_perr("Error: Neither host nor device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200477 "Use flashprog -p serprog:dev=/dev/device:baud or "
478 "flashprog -p serprog:ip=ipaddr:port\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000479#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000480 return 1;
481 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000482
Nico Huber383b7fe2023-02-12 00:38:55 +0100483 msg_pdbg(MSGHEADER "connected");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000484
485 sp_check_avail_automatic = 0;
486
Niklas Söderlund7145a502012-09-07 07:07:07 +0000487 if (sp_synchronize())
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000488 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000489
Sean Nelson74e8af52010-01-10 01:06:23 +0000490 msg_pdbg(MSGHEADER "Synchronized\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000491
492 if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000493 msg_perr("Error: NAK to query interface version\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000494 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000495 }
496
497 if (iface != 1) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000498 msg_perr("Error: Unknown interface version: %d\n", iface);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000499 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000500 }
501
Sean Nelson74e8af52010-01-10 01:06:23 +0000502 msg_pdbg(MSGHEADER "Interface version ok.\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000503
504 if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000505 msg_perr("Error: query command map not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000506 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000507 }
508
509 sp_check_avail_automatic = 1;
510
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000511 /* FIXME: This assumes that serprog device bustypes are always
Nico Huberc3b02dc2023-08-12 01:13:45 +0200512 * identical with flashprog bustype enums and that they all fit
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000513 * in a single byte.
514 */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000515 if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000516 msg_pwarn("Warning: NAK to query supported buses\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000517 c = BUS_NONSPI; /* A reasonable default for now. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000518 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000519 serprog_buses_supported = c;
520
Stefan Tauner31019d42011-10-22 21:45:27 +0000521 msg_pdbg(MSGHEADER "Bus support: parallel=%s, LPC=%s, FWH=%s, SPI=%s\n",
522 (c & BUS_PARALLEL) ? "on" : "off",
523 (c & BUS_LPC) ? "on" : "off",
524 (c & BUS_FWH) ? "on" : "off",
525 (c & BUS_SPI) ? "on" : "off");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000526 /* Check for the minimum operational set of commands. */
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000527 if (serprog_buses_supported & BUS_SPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000528 uint8_t bt = BUS_SPI;
Riku Viitanenddb6d922024-01-15 19:15:49 +0200529 char *spispeed, *cs;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000530 if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
531 msg_perr("Error: SPI operation not supported while the "
532 "bustype is SPI\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000533 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000534 }
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000535 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000536 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000537 /* Success of any of these commands is optional. We don't need
538 the programmer to tell us its limits, but if it doesn't, we
539 will assume stuff, so it's in the programmers best interest
540 to tell us. */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000541 if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
542 uint32_t v;
543 v = ((unsigned int)(rbuf[0]) << 0);
544 v |= ((unsigned int)(rbuf[1]) << 8);
545 v |= ((unsigned int)(rbuf[2]) << 16);
546 if (v == 0)
547 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000548 spi_master_serprog.max_data_write = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000549 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", v);
550 }
551 if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
552 uint32_t v;
553 v = ((unsigned int)(rbuf[0]) << 0);
554 v |= ((unsigned int)(rbuf[1]) << 8);
555 v |= ((unsigned int)(rbuf[2]) << 16);
556 if (v == 0)
557 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000558 spi_master_serprog.max_data_read = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000559 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
560 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000561 spispeed = extract_programmer_param("spispeed");
562 if (spispeed && strlen(spispeed)) {
563 uint32_t f_spi_req, f_spi;
564 uint8_t buf[4];
565 char *f_spi_suffix;
566
567 errno = 0;
568 f_spi_req = strtol(spispeed, &f_spi_suffix, 0);
569 if (errno != 0 || spispeed == f_spi_suffix) {
570 msg_perr("Error: Could not convert 'spispeed'.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000571 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000572 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000573 }
574 if (strlen(f_spi_suffix) == 1) {
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000575 if (!strcasecmp(f_spi_suffix, "M")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000576 f_spi_req *= 1000000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000577 } else if (!strcasecmp(f_spi_suffix, "k")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000578 f_spi_req *= 1000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000579 } else {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000580 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000581 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000582 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000583 }
584 } else if (strlen(f_spi_suffix) > 1) {
585 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000586 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000587 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000588 }
589
590 buf[0] = (f_spi_req >> (0 * 8)) & 0xFF;
591 buf[1] = (f_spi_req >> (1 * 8)) & 0xFF;
592 buf[2] = (f_spi_req >> (2 * 8)) & 0xFF;
593 buf[3] = (f_spi_req >> (3 * 8)) & 0xFF;
594
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000595 if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000596 msg_pwarn(MSGHEADER "Warning: Setting the SPI clock rate is not supported!\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000597 } else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) == 0) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000598 f_spi = buf[0];
599 f_spi |= buf[1] << (1 * 8);
600 f_spi |= buf[2] << (2 * 8);
601 f_spi |= buf[3] << (3 * 8);
602 msg_pdbg(MSGHEADER "Requested to set SPI clock frequency to %u Hz. "
603 "It was actually set to %u Hz\n", f_spi_req, f_spi);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000604 } else {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000605 msg_pwarn(MSGHEADER "Setting SPI clock rate to %u Hz failed!\n", f_spi_req);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000606 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000607 }
608 free(spispeed);
Riku Viitanenddb6d922024-01-15 19:15:49 +0200609 cs = extract_programmer_param("cs");
610 if (cs) {
611 char *endptr = NULL;
612 errno = 0;
613 unsigned long cs_num = strtoul(cs, &endptr, 0);
614 if (!*cs || errno || *endptr || cs_num > 255) {
615 msg_perr("Error: Invalid chip select requested! "
616 "Only 0-255 are valid.\n");
617 free(cs);
618 goto init_err_cleanup_exit;
619 }
620 free(cs);
621 if (!sp_check_commandavail(S_CMD_S_SPI_CS)) {
622 msg_perr("Error: Setting SPI chip select is not supported!\n");
623 goto init_err_cleanup_exit;
624 }
625 msg_pdbg(MSGHEADER "Requested to use chip select %lu.\n", cs_num);
626 uint8_t cs_num8 = cs_num;
627 if (sp_docommand(S_CMD_S_SPI_CS, 1, &cs_num8, 0, NULL)) {
628 msg_perr("Error: Chip select %u not supported "
629 "by programmer!\n", cs_num8);
630 goto init_err_cleanup_exit;
631 }
632 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000633 bt = serprog_buses_supported;
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000634 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000635 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000636 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000637
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000638 if (serprog_buses_supported & BUS_NONSPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000639 if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
640 msg_perr("Error: Initialize operation buffer "
641 "not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000642 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000643 }
644
645 if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
646 msg_perr("Error: Write to opbuf: "
647 "delay not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000648 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000649 }
650
651 /* S_CMD_O_EXEC availability checked later. */
652
653 if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
654 msg_perr("Error: Single byte read not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000655 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000656 }
657 /* This could be translated to single byte reads (if missing),
658 * but now we don't support that. */
659 if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
660 msg_perr("Error: Read n bytes not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000661 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000662 }
663 if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
664 msg_perr("Error: Write to opbuf: "
665 "write byte not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000666 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000667 }
668
669 if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
670 msg_pdbg(MSGHEADER "Write-n not supported");
671 sp_max_write_n = 0;
672 } else {
673 sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
674 sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
675 sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
676 if (!sp_max_write_n) {
677 sp_max_write_n = (1 << 24);
678 }
679 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n",
680 sp_max_write_n);
681 sp_write_n_buf = malloc(sp_max_write_n);
682 if (!sp_write_n_buf) {
683 msg_perr("Error: cannot allocate memory for "
684 "Write-n buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000685 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000686 }
687 sp_write_n_bytes = 0;
688 }
689
690 if (sp_check_commandavail(S_CMD_Q_RDNMAXLEN) &&
691 (sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf) == 0)) {
692 sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
693 sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
694 sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
695 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n",
696 sp_max_read_n ? sp_max_read_n : (1 << 24));
697 } else {
698 msg_pdbg(MSGHEADER "Maximum read-n length "
699 "not reported\n");
700 sp_max_read_n = 0;
701 }
702
Urja Rannikkof3196df2009-07-21 13:02:59 +0000703 }
704
705 if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000706 msg_pwarn("Warning: NAK to query programmer name\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000707 strcpy((char *)pgmname, "(unknown)");
708 }
709 pgmname[16] = 0;
Stefan Tauner31019d42011-10-22 21:45:27 +0000710 msg_pinfo(MSGHEADER "Programmer name is \"%s\"\n", pgmname);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000711
712 if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000713 msg_pwarn("Warning: NAK to query serial buffer size\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000714 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000715 msg_pdbg(MSGHEADER "Serial buffer size is %d\n",
Urja Rannikkof3196df2009-07-21 13:02:59 +0000716 sp_device_serbuf_size);
717
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000718 if (sp_check_commandavail(S_CMD_O_INIT)) {
719 /* This would be inconsistent. */
720 if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
721 msg_perr("Error: Execute operation buffer not "
722 "supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000723 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000724 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000725
726 if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
727 msg_perr("Error: NAK to initialize operation buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000728 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000729 }
730
731 if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
732 &sp_device_opbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000733 msg_pwarn("Warning: NAK to query operation buffer size\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000734 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000735 msg_pdbg(MSGHEADER "operation buffer size is %d\n",
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000736 sp_device_opbuf_size);
Elyes HAOUAS124ef382018-03-27 12:15:09 +0200737 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000738
Stefan Tauner92fefc92012-10-27 00:34:23 +0000739 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
740 uint8_t en = 1;
741 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &en, 0, NULL) != 0) {
742 msg_perr("Error: could not enable output buffers\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000743 goto init_err_cleanup_exit;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000744 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000745 msg_pdbg(MSGHEADER "Output drivers enabled\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000746 }
747 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000748 msg_pdbg(MSGHEADER "Warning: Programmer does not support toggling its output drivers\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000749 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000750 sp_prev_was_write = 0;
751 sp_streamed_transmit_ops = 0;
752 sp_streamed_transmit_bytes = 0;
753 sp_opbuf_usage = 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000754
755 if (register_shutdown(serprog_shutdown, NULL))
756 goto init_err_cleanup_exit;
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000757 if (serprog_buses_supported & BUS_SPI)
Nico Huber89569d62023-01-12 23:31:40 +0100758 register_spi_master(&spi_master_serprog, 0, NULL);
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000759 if (serprog_buses_supported & BUS_NONSPI)
Nico Huber89569d62023-01-12 23:31:40 +0100760 register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI, 0, NULL);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000761 return 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000762
763init_err_cleanup_exit:
764 serprog_shutdown(NULL);
765 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000766}
767
Nico Huberc3b02dc2023-08-12 01:13:45 +0200768/* Move an in flashprog buffer existing write-n operation to the on-device operation buffer. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000769static int sp_pass_writen(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000770{
771 unsigned char header[7];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000772 msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
773 if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
774 if (sp_flush_stream() != 0) {
775 return 1;
776 }
777 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000778 /* In case it's just a single byte send it as a single write. */
779 if (sp_write_n_bytes == 1) {
780 sp_write_n_bytes = 0;
781 header[0] = (sp_write_n_addr >> 0) & 0xFF;
782 header[1] = (sp_write_n_addr >> 8) & 0xFF;
783 header[2] = (sp_write_n_addr >> 16) & 0xFF;
784 header[3] = sp_write_n_buf[0];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000785 if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
786 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000787 sp_opbuf_usage += 5;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000788 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000789 }
790 header[0] = S_CMD_O_WRITEN;
791 header[1] = (sp_write_n_bytes >> 0) & 0xFF;
792 header[2] = (sp_write_n_bytes >> 8) & 0xFF;
793 header[3] = (sp_write_n_bytes >> 16) & 0xFF;
794 header[4] = (sp_write_n_addr >> 0) & 0xFF;
795 header[5] = (sp_write_n_addr >> 8) & 0xFF;
796 header[6] = (sp_write_n_addr >> 16) & 0xFF;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000797 if (serialport_write(header, 7) != 0) {
798 msg_perr(MSGHEADER "Error: cannot write write-n command\n");
799 return 1;
800 }
801 if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
802 msg_perr(MSGHEADER "Error: cannot write write-n data");
803 return 1;
804 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000805 sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
806 sp_streamed_transmit_ops += 1;
807 sp_opbuf_usage += 7 + sp_write_n_bytes;
808 sp_write_n_bytes = 0;
809 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000810 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000811}
812
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000813static int sp_execute_opbuf_noflush(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000814{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000815 if ((sp_max_write_n) && (sp_write_n_bytes)) {
816 if (sp_pass_writen() != 0) {
817 msg_perr("Error: could not transfer write buffer\n");
818 return 1;
819 }
820 }
821 if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
822 msg_perr("Error: could not execute command buffer\n");
823 return 1;
824 }
825 msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000826 sp_opbuf_usage = 0;
827 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000828 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000829}
830
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000831static int sp_execute_opbuf(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000832{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000833 if (sp_execute_opbuf_noflush() != 0)
834 return 1;
835 if (sp_flush_stream() != 0)
836 return 1;
837
838 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000839}
840
David Hendricks8bb20212011-06-14 01:35:36 +0000841static int serprog_shutdown(void *data)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000842{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000843 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000844 if (sp_execute_opbuf() != 0)
845 msg_pwarn("Could not flush command buffer.\n");
Stefan Tauner92fefc92012-10-27 00:34:23 +0000846 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
847 uint8_t dis = 0;
848 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
849 msg_pdbg(MSGHEADER "Output drivers disabled\n");
850 else
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000851 msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
Stefan Tauner92fefc92012-10-27 00:34:23 +0000852 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000853 /* FIXME: fix sockets on windows(?), especially closing */
854 serialport_shutdown(&sp_fd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000855 if (sp_max_write_n)
856 free(sp_write_n_buf);
857 return 0;
858}
859
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000860static int sp_check_opbuf_usage(int bytes_to_be_added)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000861{
862 if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000863 /* If this happens in the middle of a page load the page load will probably fail. */
864 msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
865 if (sp_execute_opbuf() != 0)
866 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000867 }
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000868 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000869}
870
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000871static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
872 chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000873{
Sean Nelson74e8af52010-01-10 01:06:23 +0000874 msg_pspew("%s\n", __func__);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000875 if (sp_max_write_n) {
876 if ((sp_prev_was_write)
877 && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
878 sp_write_n_buf[sp_write_n_bytes++] = val;
879 } else {
880 if ((sp_prev_was_write) && (sp_write_n_bytes))
881 sp_pass_writen();
882 sp_prev_was_write = 1;
883 sp_write_n_addr = addr;
884 sp_write_n_bytes = 1;
885 sp_write_n_buf[0] = val;
886 }
887 sp_check_opbuf_usage(7 + sp_write_n_bytes);
888 if (sp_write_n_bytes >= sp_max_write_n)
889 sp_pass_writen();
890 } else {
891 /* We will have to do single writeb ops. */
892 unsigned char writeb_parm[4];
893 sp_check_opbuf_usage(6);
894 writeb_parm[0] = (addr >> 0) & 0xFF;
895 writeb_parm[1] = (addr >> 8) & 0xFF;
896 writeb_parm[2] = (addr >> 16) & 0xFF;
897 writeb_parm[3] = val;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000898 sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000899 sp_opbuf_usage += 5;
900 }
901}
902
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000903static uint8_t serprog_chip_readb(const struct flashctx *flash,
904 const chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000905{
906 unsigned char c;
907 unsigned char buf[3];
908 /* Will stream the read operation - eg. add it to the stream buffer, *
909 * then flush the buffer, then read the read answer. */
910 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
911 sp_execute_opbuf_noflush();
912 buf[0] = ((addr >> 0) & 0xFF);
913 buf[1] = ((addr >> 8) & 0xFF);
914 buf[2] = ((addr >> 16) & 0xFF);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000915 sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
916 sp_flush_stream(); // FIXME: return error
Stefan Tauner79587f52013-04-01 00:45:51 +0000917 if (serialport_read(&c, 1) != 0)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000918 msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
Stefan Taunerc2333752013-07-13 23:31:37 +0000919 msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000920 return c;
921}
922
Uwe Hermann4e3d0b32010-03-25 23:18:41 +0000923/* Local version that really does the job, doesn't care of max_read_n. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000924static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000925{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000926 unsigned char sbuf[6];
Stefan Tauner0554ca52013-07-25 22:54:25 +0000927 msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000928 /* Stream the read-n -- as above. */
929 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
930 sp_execute_opbuf_noflush();
931 sbuf[0] = ((addr >> 0) & 0xFF);
932 sbuf[1] = ((addr >> 8) & 0xFF);
933 sbuf[2] = ((addr >> 16) & 0xFF);
934 sbuf[3] = ((len >> 0) & 0xFF);
935 sbuf[4] = ((len >> 8) & 0xFF);
936 sbuf[5] = ((len >> 16) & 0xFF);
937 sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000938 if (sp_flush_stream() != 0)
939 return 1;
940 if (serialport_read(buf, len) != 0) {
941 msg_perr(MSGHEADER "Error: cannot read read-n data");
942 return 1;
943 }
944 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000945}
946
947/* The externally called version that makes sure that max_read_n is obeyed. */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000948static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
949 const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000950{
951 size_t lenm = len;
952 chipaddr addrm = addr;
Stefan Tauner31019d42011-10-22 21:45:27 +0000953 while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000954 sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000955 addrm += sp_max_read_n;
956 lenm -= sp_max_read_n;
957 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000958 if (lenm)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000959 sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000960}
961
Thomas Heijligencc853d82021-05-04 15:32:17 +0200962static void serprog_delay(unsigned int usecs)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000963{
964 unsigned char buf[4];
Stefan Tauner31019d42011-10-22 21:45:27 +0000965 msg_pspew("%s usecs=%d\n", __func__, usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000966 if (!sp_check_commandavail(S_CMD_O_DELAY)) {
Stefan Taunerd7d423b2012-10-20 09:13:16 +0000967 msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
Stefan Tauner31019d42011-10-22 21:45:27 +0000968 internal_delay(usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000969 return;
970 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000971 if ((sp_max_write_n) && (sp_write_n_bytes))
972 sp_pass_writen();
973 sp_check_opbuf_usage(5);
Stefan Tauner31019d42011-10-22 21:45:27 +0000974 buf[0] = ((usecs >> 0) & 0xFF);
975 buf[1] = ((usecs >> 8) & 0xFF);
976 buf[2] = ((usecs >> 16) & 0xFF);
977 buf[3] = ((usecs >> 24) & 0xFF);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000978 sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
979 sp_opbuf_usage += 5;
980 sp_prev_was_write = 0;
981}
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000982
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000983static int serprog_spi_send_command(const struct flashctx *flash,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000984 unsigned int writecnt, unsigned int readcnt,
985 const unsigned char *writearr,
986 unsigned char *readarr)
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000987{
988 unsigned char *parmbuf;
989 int ret;
990 msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000991 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
992 if (sp_execute_opbuf() != 0) {
993 msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
994 return 1;
995 }
996 }
997
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000998 parmbuf = malloc(writecnt + 6);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000999 if (!parmbuf) {
1000 msg_perr("Error: could not allocate SPI send param buffer.\n");
1001 return 1;
1002 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +00001003 parmbuf[0] = (writecnt >> 0) & 0xFF;
1004 parmbuf[1] = (writecnt >> 8) & 0xFF;
1005 parmbuf[2] = (writecnt >> 16) & 0xFF;
1006 parmbuf[3] = (readcnt >> 0) & 0xFF;
1007 parmbuf[4] = (readcnt >> 8) & 0xFF;
1008 parmbuf[5] = (readcnt >> 16) & 0xFF;
1009 memcpy(parmbuf + 6, writearr, writecnt);
1010 ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
1011 readarr);
1012 free(parmbuf);
1013 return ret;
1014}
1015
Thomas Heijligencc853d82021-05-04 15:32:17 +02001016static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001017{
1018 /* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
1019 * correctly (usually setting them to one either in software (for FWH/LPC) or relying on the fact that
1020 * the hardware observes a subset of the address bits only). Combined with the standard mapping of
Nico Huberc3b02dc2023-08-12 01:13:45 +02001021 * flashprog this creates a 16 MB-wide window just below the 4 GB boundary where serprog can operate (as
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001022 * needed for non-SPI chips). Below we make sure that the requested range is within this window. */
1023 if ((phys_addr & 0xFF000000) == 0xFF000000) {
1024 return (void*)phys_addr;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001025 }
Elyes HAOUASec819d62019-06-09 17:50:51 +02001026 msg_pwarn(MSGHEADER "requested mapping %s is incompatible: 0x%zx bytes at 0x%0*" PRIxPTR ".\n",
1027 descr, len, PRIxPTR_WIDTH, phys_addr);
1028 return NULL;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001029}
Thomas Heijligencc853d82021-05-04 15:32:17 +02001030
1031const struct programmer_entry programmer_serprog = {
1032 .name = "serprog",
1033 .type = OTHER,
1034 /* FIXME */
1035 .devs.note = "All programmer devices speaking the serprog protocol\n",
1036 .init = serprog_init,
Thomas Heijligencc853d82021-05-04 15:32:17 +02001037 .delay = serprog_delay,
1038};