blob: 3c4e6098c4f7bb875b364340fab7db05660869d3 [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];
Urja Rannikkof3196df2009-07-21 13:02:59 +0000200 /* First sends 8 NOPs, then flushes the return data - should cause *
201 * the device serial parser to get to a sane state, unless if it *
202 * is waiting for a real long write-n. */
203 memset(buf, S_CMD_NOP, 8);
Stefan Taunerae3d8372013-04-01 00:45:45 +0000204 if (serialport_write_nonblock(buf, 8, 1, NULL) != 0) {
Niklas Söderlund7145a502012-09-07 07:07:07 +0000205 goto err_out;
206 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000207 /* A second should be enough to get all the answers to the buffer */
Stefan Tauner79587f52013-04-01 00:45:51 +0000208 internal_delay(1000 * 1000);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000209 sp_flush_incoming();
210
Cristian Măgherușan-Stanciu9932c7b2011-07-07 19:56:58 +0000211 /* Then try up to 8 times to send syncnop and get the correct special *
212 * return of NAK+ACK. Timing note: up to 10 characters, 10*50ms = *
213 * up to 500ms per try, 8*0.5s = 4s; +1s (above) = up to 5s sync *
214 * attempt, ~1s if immediate success. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000215 for (i = 0; i < 8; i++) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000216 msg_pdbg(".");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000217 fflush(stdout);
Nico Huberd7318ea2023-02-12 00:30:31 +0100218
219 ret = sp_test_sync();
220 if (ret > 0)
221 continue;
222 if (ret < 0)
223 goto err_out;
224 msg_pdbg("\n");
225 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000226 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000227err_out:
228 msg_perr("Error: cannot synchronize protocol - check communications and reset device?\n");
229 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000230}
231
232static int sp_check_commandavail(uint8_t command)
233{
234 int byteoffs, bitoffs;
235 byteoffs = command / 8;
236 bitoffs = command % 8;
237 return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
238}
239
240static int sp_automatic_cmdcheck(uint8_t cmd)
241{
242 if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000243 msg_pdbg("Warning: Automatic command availability check failed "
Stefan Taunere34e3e82013-01-01 00:06:51 +0000244 "for cmd 0x%02x - won't execute cmd\n", cmd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000245 return 1;
246 }
247 return 0;
248}
249
250static int sp_docommand(uint8_t command, uint32_t parmlen,
Stefan Tauner31019d42011-10-22 21:45:27 +0000251 uint8_t *params, uint32_t retlen, void *retparms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000252{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000253 unsigned char c;
254 if (sp_automatic_cmdcheck(command))
255 return 1;
Stefan Tauner79587f52013-04-01 00:45:51 +0000256 if (serialport_write(&command, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000257 msg_perr("Error: cannot write op code: %s\n", strerror(errno));
258 return 1;
259 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000260 if (serialport_write(params, parmlen) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000261 msg_perr("Error: cannot write parameters: %s\n", strerror(errno));
262 return 1;
263 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000264 if (serialport_read(&c, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000265 msg_perr("Error: cannot read from device: %s\n", strerror(errno));
266 return 1;
267 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000268 if (c == S_NAK)
269 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000270 if (c != S_ACK) {
Stefan Tauner23e10b82016-01-23 16:16:49 +0000271 msg_perr("Error: invalid response 0x%02X from device (to command 0x%02X)\n", c, command);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000272 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000273 }
274 if (retlen) {
Stefan Tauner79587f52013-04-01 00:45:51 +0000275 if (serialport_read(retparms, retlen) != 0) {
276 msg_perr("Error: cannot read return parameters: %s\n", strerror(errno));
277 return 1;
278 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000279 }
280 return 0;
281}
282
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000283static int sp_flush_stream(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000284{
285 if (sp_streamed_transmit_ops)
286 do {
287 unsigned char c;
Stefan Tauner79587f52013-04-01 00:45:51 +0000288 if (serialport_read(&c, 1) != 0) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000289 msg_perr("Error: cannot read from device (flushing stream)");
290 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000291 }
292 if (c == S_NAK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000293 msg_perr("Error: NAK to a stream buffer operation\n");
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000294 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000295 }
296 if (c != S_ACK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000297 msg_perr("Error: Invalid reply 0x%02X from device\n", c);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000298 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000299 }
300 } while (--sp_streamed_transmit_ops);
301 sp_streamed_transmit_ops = 0;
302 sp_streamed_transmit_bytes = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000303 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000304}
305
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000306static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000307{
308 uint8_t *sp;
309 if (sp_automatic_cmdcheck(cmd))
310 return 1;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000311
Urja Rannikkof3196df2009-07-21 13:02:59 +0000312 sp = malloc(1 + parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000313 if (!sp) {
314 msg_perr("Error: cannot malloc command buffer\n");
315 return 1;
316 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000317 sp[0] = cmd;
aarya885917c2022-03-10 09:16:44 +0530318 if (parms)
319 memcpy(&(sp[1]), parms, parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000320
321 if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) {
322 if (sp_flush_stream() != 0) {
323 free(sp);
324 return 1;
325 }
326 }
327 if (serialport_write(sp, 1 + parmlen) != 0) {
328 msg_perr("Error: cannot write command\n");
329 free(sp);
330 return 1;
331 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000332 sp_streamed_transmit_ops += 1;
333 sp_streamed_transmit_bytes += 1 + parmlen;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000334
335 free(sp);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000336 return 0;
337}
338
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000339static int serprog_spi_send_command(const struct flashctx *flash,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000340 unsigned int writecnt, unsigned int readcnt,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000341 const unsigned char *writearr,
342 unsigned char *readarr);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000343static struct spi_master spi_master_serprog = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100344 .features = SPI_MASTER_4BA,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000345 .max_data_read = MAX_DATA_READ_UNLIMITED,
346 .max_data_write = MAX_DATA_WRITE_UNLIMITED,
347 .command = serprog_spi_send_command,
348 .multicommand = default_spi_send_multicommand,
Urja Rannikko731316a2017-06-15 13:32:01 +0300349 .read = default_spi_read,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000350 .write_256 = default_spi_write_256,
Aarya Chaumal0cea7532022-07-04 18:21:50 +0530351 .probe_opcode = default_spi_probe_opcode,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000352};
353
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000354static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
355 chipaddr addr);
356static uint8_t serprog_chip_readb(const struct flashctx *flash,
357 const chipaddr addr);
358static void serprog_chip_readn(const struct flashctx *flash, uint8_t *buf,
359 const chipaddr addr, size_t len);
Nico Huber0e76d992023-01-12 20:22:55 +0100360static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000361static const struct par_master par_master_serprog = {
Thomas Heijligen43040f22022-06-23 14:38:35 +0200362 .chip_readb = serprog_chip_readb,
363 .chip_readw = fallback_chip_readw,
364 .chip_readl = fallback_chip_readl,
365 .chip_readn = serprog_chip_readn,
366 .chip_writeb = serprog_chip_writeb,
367 .chip_writew = fallback_chip_writew,
368 .chip_writel = fallback_chip_writel,
369 .chip_writen = fallback_chip_writen,
Nico Huber0e76d992023-01-12 20:22:55 +0100370 .map_flash = serprog_map,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000371};
372
373static enum chipbustype serprog_buses_supported = BUS_NONE;
374
Nico Hubere3a26882023-01-11 21:45:51 +0100375static int serprog_init(struct flashprog_programmer *const prog)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000376{
377 uint16_t iface;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000378 unsigned char pgmname[17];
379 unsigned char rbuf[3];
380 unsigned char c;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000381 char *device;
Felix Singer815eb792022-08-19 01:02:42 +0200382 bool have_device = false;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000383
Stefan Tauner72587f82016-01-04 03:05:15 +0000384 /* the parameter is either of format "dev=/dev/device[:baud]" or "ip=ip:port" */
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000385 device = extract_programmer_param("dev");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000386 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000387 char *baud_str = strstr(device, ":");
388 if (baud_str != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000389 /* Split device from baudrate. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000390 *baud_str = '\0';
391 baud_str++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000392 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000393 int baud;
394 /* Convert baud string to value.
395 * baud_str is either NULL (if strstr can't find the colon), points to the \0 after the colon
396 * if no characters where given after the colon, or a string to convert... */
397 if (baud_str == NULL || *baud_str == '\0') {
398 baud = -1;
399 msg_pdbg("No baudrate specified, using the hardware's defaults.\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000400 } else {
Stefan Tauner72587f82016-01-04 03:05:15 +0000401 baud = atoi(baud_str); // FIXME: replace atoi with strtoul
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000402 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000403 if (strlen(device) > 0) {
404 sp_fd = sp_openserport(device, baud);
Stefan Tauneracfc4c62012-11-30 16:46:45 +0000405 if (sp_fd == SER_INV_FD) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000406 free(device);
407 return 1;
408 }
Felix Singer815eb792022-08-19 01:02:42 +0200409 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000410 }
411 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000412
413#if !IS_WINDOWS
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000414 if (device && !strlen(device)) {
415 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200416 "Use flashprog -p serprog:dev=/dev/device[:baud]\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000417 free(device);
418 return 1;
419 }
420 free(device);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000421
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000422 device = extract_programmer_param("ip");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000423 if (have_device && device) {
424 msg_perr("Error: Both host and device specified.\n"
425 "Please use either dev= or ip= but not both.\n");
426 free(device);
427 return 1;
428 }
429 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000430 char *port = strstr(device, ":");
431 if (port != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000432 /* Split host from port. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000433 *port = '\0';
434 port++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000435 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000436 if (!port || !strlen(port)) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000437 msg_perr("Error: No port specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200438 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000439 free(device);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000440 return 1;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000441 }
442 if (strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000443 sp_fd = sp_opensocket(device, atoi(port)); // FIXME: replace atoi with strtoul
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000444 if (sp_fd < 0) {
445 free(device);
446 return 1;
447 }
Felix Singer815eb792022-08-19 01:02:42 +0200448 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000449 }
450 }
451 if (device && !strlen(device)) {
452 msg_perr("Error: No host specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200453 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000454 free(device);
455 return 1;
456 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000457#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000458 free(device);
459
460 if (!have_device) {
Urja Rannikko27b431b2016-01-04 03:05:23 +0000461#if IS_WINDOWS
462 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200463 "Use flashprog -p serprog:dev=comN[:baud]\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000464#else
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000465 msg_perr("Error: Neither host nor device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200466 "Use flashprog -p serprog:dev=/dev/device:baud or "
467 "flashprog -p serprog:ip=ipaddr:port\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000468#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000469 return 1;
470 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000471
Sean Nelson74e8af52010-01-10 01:06:23 +0000472 msg_pdbg(MSGHEADER "connected - attempting to synchronize\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000473
474 sp_check_avail_automatic = 0;
475
Niklas Söderlund7145a502012-09-07 07:07:07 +0000476 if (sp_synchronize())
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000477 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000478
Sean Nelson74e8af52010-01-10 01:06:23 +0000479 msg_pdbg(MSGHEADER "Synchronized\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000480
481 if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000482 msg_perr("Error: NAK to query interface version\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000483 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000484 }
485
486 if (iface != 1) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000487 msg_perr("Error: Unknown interface version: %d\n", iface);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000488 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000489 }
490
Sean Nelson74e8af52010-01-10 01:06:23 +0000491 msg_pdbg(MSGHEADER "Interface version ok.\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000492
493 if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000494 msg_perr("Error: query command map not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000495 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000496 }
497
498 sp_check_avail_automatic = 1;
499
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000500 /* FIXME: This assumes that serprog device bustypes are always
Nico Huberc3b02dc2023-08-12 01:13:45 +0200501 * identical with flashprog bustype enums and that they all fit
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000502 * in a single byte.
503 */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000504 if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000505 msg_pwarn("Warning: NAK to query supported buses\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000506 c = BUS_NONSPI; /* A reasonable default for now. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000507 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000508 serprog_buses_supported = c;
509
Stefan Tauner31019d42011-10-22 21:45:27 +0000510 msg_pdbg(MSGHEADER "Bus support: parallel=%s, LPC=%s, FWH=%s, SPI=%s\n",
511 (c & BUS_PARALLEL) ? "on" : "off",
512 (c & BUS_LPC) ? "on" : "off",
513 (c & BUS_FWH) ? "on" : "off",
514 (c & BUS_SPI) ? "on" : "off");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000515 /* Check for the minimum operational set of commands. */
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000516 if (serprog_buses_supported & BUS_SPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000517 uint8_t bt = BUS_SPI;
Riku Viitanenddb6d922024-01-15 19:15:49 +0200518 char *spispeed, *cs;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000519 if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
520 msg_perr("Error: SPI operation not supported while the "
521 "bustype is SPI\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000522 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000523 }
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000524 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000525 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000526 /* Success of any of these commands is optional. We don't need
527 the programmer to tell us its limits, but if it doesn't, we
528 will assume stuff, so it's in the programmers best interest
529 to tell us. */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000530 if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
531 uint32_t v;
532 v = ((unsigned int)(rbuf[0]) << 0);
533 v |= ((unsigned int)(rbuf[1]) << 8);
534 v |= ((unsigned int)(rbuf[2]) << 16);
535 if (v == 0)
536 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000537 spi_master_serprog.max_data_write = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000538 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", v);
539 }
540 if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
541 uint32_t v;
542 v = ((unsigned int)(rbuf[0]) << 0);
543 v |= ((unsigned int)(rbuf[1]) << 8);
544 v |= ((unsigned int)(rbuf[2]) << 16);
545 if (v == 0)
546 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000547 spi_master_serprog.max_data_read = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000548 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
549 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000550 spispeed = extract_programmer_param("spispeed");
551 if (spispeed && strlen(spispeed)) {
552 uint32_t f_spi_req, f_spi;
553 uint8_t buf[4];
554 char *f_spi_suffix;
555
556 errno = 0;
557 f_spi_req = strtol(spispeed, &f_spi_suffix, 0);
558 if (errno != 0 || spispeed == f_spi_suffix) {
559 msg_perr("Error: Could not convert 'spispeed'.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000560 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000561 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000562 }
563 if (strlen(f_spi_suffix) == 1) {
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000564 if (!strcasecmp(f_spi_suffix, "M")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000565 f_spi_req *= 1000000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000566 } else if (!strcasecmp(f_spi_suffix, "k")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000567 f_spi_req *= 1000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000568 } else {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000569 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000570 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000571 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000572 }
573 } else if (strlen(f_spi_suffix) > 1) {
574 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000575 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000576 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000577 }
578
579 buf[0] = (f_spi_req >> (0 * 8)) & 0xFF;
580 buf[1] = (f_spi_req >> (1 * 8)) & 0xFF;
581 buf[2] = (f_spi_req >> (2 * 8)) & 0xFF;
582 buf[3] = (f_spi_req >> (3 * 8)) & 0xFF;
583
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000584 if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000585 msg_pwarn(MSGHEADER "Warning: Setting the SPI clock rate is not supported!\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000586 } else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) == 0) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000587 f_spi = buf[0];
588 f_spi |= buf[1] << (1 * 8);
589 f_spi |= buf[2] << (2 * 8);
590 f_spi |= buf[3] << (3 * 8);
591 msg_pdbg(MSGHEADER "Requested to set SPI clock frequency to %u Hz. "
592 "It was actually set to %u Hz\n", f_spi_req, f_spi);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000593 } else {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000594 msg_pwarn(MSGHEADER "Setting SPI clock rate to %u Hz failed!\n", f_spi_req);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000595 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000596 }
597 free(spispeed);
Riku Viitanenddb6d922024-01-15 19:15:49 +0200598 cs = extract_programmer_param("cs");
599 if (cs) {
600 char *endptr = NULL;
601 errno = 0;
602 unsigned long cs_num = strtoul(cs, &endptr, 0);
603 if (!*cs || errno || *endptr || cs_num > 255) {
604 msg_perr("Error: Invalid chip select requested! "
605 "Only 0-255 are valid.\n");
606 free(cs);
607 goto init_err_cleanup_exit;
608 }
609 free(cs);
610 if (!sp_check_commandavail(S_CMD_S_SPI_CS)) {
611 msg_perr("Error: Setting SPI chip select is not supported!\n");
612 goto init_err_cleanup_exit;
613 }
614 msg_pdbg(MSGHEADER "Requested to use chip select %lu.\n", cs_num);
615 uint8_t cs_num8 = cs_num;
616 if (sp_docommand(S_CMD_S_SPI_CS, 1, &cs_num8, 0, NULL)) {
617 msg_perr("Error: Chip select %u not supported "
618 "by programmer!\n", cs_num8);
619 goto init_err_cleanup_exit;
620 }
621 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000622 bt = serprog_buses_supported;
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000623 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000624 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000625 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000626
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000627 if (serprog_buses_supported & BUS_NONSPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000628 if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
629 msg_perr("Error: Initialize operation buffer "
630 "not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000631 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000632 }
633
634 if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
635 msg_perr("Error: Write to opbuf: "
636 "delay not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000637 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000638 }
639
640 /* S_CMD_O_EXEC availability checked later. */
641
642 if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
643 msg_perr("Error: Single byte read not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000644 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000645 }
646 /* This could be translated to single byte reads (if missing),
647 * but now we don't support that. */
648 if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
649 msg_perr("Error: Read n bytes not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000650 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000651 }
652 if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
653 msg_perr("Error: Write to opbuf: "
654 "write byte 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
658 if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
659 msg_pdbg(MSGHEADER "Write-n not supported");
660 sp_max_write_n = 0;
661 } else {
662 sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
663 sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
664 sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
665 if (!sp_max_write_n) {
666 sp_max_write_n = (1 << 24);
667 }
668 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n",
669 sp_max_write_n);
670 sp_write_n_buf = malloc(sp_max_write_n);
671 if (!sp_write_n_buf) {
672 msg_perr("Error: cannot allocate memory for "
673 "Write-n buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000674 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000675 }
676 sp_write_n_bytes = 0;
677 }
678
679 if (sp_check_commandavail(S_CMD_Q_RDNMAXLEN) &&
680 (sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf) == 0)) {
681 sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
682 sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
683 sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
684 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n",
685 sp_max_read_n ? sp_max_read_n : (1 << 24));
686 } else {
687 msg_pdbg(MSGHEADER "Maximum read-n length "
688 "not reported\n");
689 sp_max_read_n = 0;
690 }
691
Urja Rannikkof3196df2009-07-21 13:02:59 +0000692 }
693
694 if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000695 msg_pwarn("Warning: NAK to query programmer name\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000696 strcpy((char *)pgmname, "(unknown)");
697 }
698 pgmname[16] = 0;
Stefan Tauner31019d42011-10-22 21:45:27 +0000699 msg_pinfo(MSGHEADER "Programmer name is \"%s\"\n", pgmname);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000700
701 if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000702 msg_pwarn("Warning: NAK to query serial buffer size\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000703 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000704 msg_pdbg(MSGHEADER "Serial buffer size is %d\n",
Urja Rannikkof3196df2009-07-21 13:02:59 +0000705 sp_device_serbuf_size);
706
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000707 if (sp_check_commandavail(S_CMD_O_INIT)) {
708 /* This would be inconsistent. */
709 if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
710 msg_perr("Error: Execute operation buffer not "
711 "supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000712 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000713 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000714
715 if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
716 msg_perr("Error: NAK to initialize operation buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000717 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000718 }
719
720 if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
721 &sp_device_opbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000722 msg_pwarn("Warning: NAK to query operation buffer size\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000723 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000724 msg_pdbg(MSGHEADER "operation buffer size is %d\n",
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000725 sp_device_opbuf_size);
Elyes HAOUAS124ef382018-03-27 12:15:09 +0200726 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000727
Stefan Tauner92fefc92012-10-27 00:34:23 +0000728 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
729 uint8_t en = 1;
730 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &en, 0, NULL) != 0) {
731 msg_perr("Error: could not enable output buffers\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000732 goto init_err_cleanup_exit;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000733 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000734 msg_pdbg(MSGHEADER "Output drivers enabled\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000735 }
736 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000737 msg_pdbg(MSGHEADER "Warning: Programmer does not support toggling its output drivers\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000738 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000739 sp_prev_was_write = 0;
740 sp_streamed_transmit_ops = 0;
741 sp_streamed_transmit_bytes = 0;
742 sp_opbuf_usage = 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000743
744 if (register_shutdown(serprog_shutdown, NULL))
745 goto init_err_cleanup_exit;
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000746 if (serprog_buses_supported & BUS_SPI)
Nico Huber89569d62023-01-12 23:31:40 +0100747 register_spi_master(&spi_master_serprog, 0, NULL);
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000748 if (serprog_buses_supported & BUS_NONSPI)
Nico Huber89569d62023-01-12 23:31:40 +0100749 register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI, 0, NULL);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000750 return 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000751
752init_err_cleanup_exit:
753 serprog_shutdown(NULL);
754 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000755}
756
Nico Huberc3b02dc2023-08-12 01:13:45 +0200757/* Move an in flashprog buffer existing write-n operation to the on-device operation buffer. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000758static int sp_pass_writen(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000759{
760 unsigned char header[7];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000761 msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
762 if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
763 if (sp_flush_stream() != 0) {
764 return 1;
765 }
766 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000767 /* In case it's just a single byte send it as a single write. */
768 if (sp_write_n_bytes == 1) {
769 sp_write_n_bytes = 0;
770 header[0] = (sp_write_n_addr >> 0) & 0xFF;
771 header[1] = (sp_write_n_addr >> 8) & 0xFF;
772 header[2] = (sp_write_n_addr >> 16) & 0xFF;
773 header[3] = sp_write_n_buf[0];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000774 if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
775 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000776 sp_opbuf_usage += 5;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000777 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000778 }
779 header[0] = S_CMD_O_WRITEN;
780 header[1] = (sp_write_n_bytes >> 0) & 0xFF;
781 header[2] = (sp_write_n_bytes >> 8) & 0xFF;
782 header[3] = (sp_write_n_bytes >> 16) & 0xFF;
783 header[4] = (sp_write_n_addr >> 0) & 0xFF;
784 header[5] = (sp_write_n_addr >> 8) & 0xFF;
785 header[6] = (sp_write_n_addr >> 16) & 0xFF;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000786 if (serialport_write(header, 7) != 0) {
787 msg_perr(MSGHEADER "Error: cannot write write-n command\n");
788 return 1;
789 }
790 if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
791 msg_perr(MSGHEADER "Error: cannot write write-n data");
792 return 1;
793 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000794 sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
795 sp_streamed_transmit_ops += 1;
796 sp_opbuf_usage += 7 + sp_write_n_bytes;
797 sp_write_n_bytes = 0;
798 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000799 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000800}
801
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000802static int sp_execute_opbuf_noflush(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000803{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000804 if ((sp_max_write_n) && (sp_write_n_bytes)) {
805 if (sp_pass_writen() != 0) {
806 msg_perr("Error: could not transfer write buffer\n");
807 return 1;
808 }
809 }
810 if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
811 msg_perr("Error: could not execute command buffer\n");
812 return 1;
813 }
814 msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000815 sp_opbuf_usage = 0;
816 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000817 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000818}
819
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000820static int sp_execute_opbuf(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000821{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000822 if (sp_execute_opbuf_noflush() != 0)
823 return 1;
824 if (sp_flush_stream() != 0)
825 return 1;
826
827 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000828}
829
David Hendricks8bb20212011-06-14 01:35:36 +0000830static int serprog_shutdown(void *data)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000831{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000832 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000833 if (sp_execute_opbuf() != 0)
834 msg_pwarn("Could not flush command buffer.\n");
Stefan Tauner92fefc92012-10-27 00:34:23 +0000835 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
836 uint8_t dis = 0;
837 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
838 msg_pdbg(MSGHEADER "Output drivers disabled\n");
839 else
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000840 msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
Stefan Tauner92fefc92012-10-27 00:34:23 +0000841 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000842 /* FIXME: fix sockets on windows(?), especially closing */
843 serialport_shutdown(&sp_fd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000844 if (sp_max_write_n)
845 free(sp_write_n_buf);
846 return 0;
847}
848
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000849static int sp_check_opbuf_usage(int bytes_to_be_added)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000850{
851 if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000852 /* If this happens in the middle of a page load the page load will probably fail. */
853 msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
854 if (sp_execute_opbuf() != 0)
855 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000856 }
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000857 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000858}
859
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000860static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
861 chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000862{
Sean Nelson74e8af52010-01-10 01:06:23 +0000863 msg_pspew("%s\n", __func__);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000864 if (sp_max_write_n) {
865 if ((sp_prev_was_write)
866 && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
867 sp_write_n_buf[sp_write_n_bytes++] = val;
868 } else {
869 if ((sp_prev_was_write) && (sp_write_n_bytes))
870 sp_pass_writen();
871 sp_prev_was_write = 1;
872 sp_write_n_addr = addr;
873 sp_write_n_bytes = 1;
874 sp_write_n_buf[0] = val;
875 }
876 sp_check_opbuf_usage(7 + sp_write_n_bytes);
877 if (sp_write_n_bytes >= sp_max_write_n)
878 sp_pass_writen();
879 } else {
880 /* We will have to do single writeb ops. */
881 unsigned char writeb_parm[4];
882 sp_check_opbuf_usage(6);
883 writeb_parm[0] = (addr >> 0) & 0xFF;
884 writeb_parm[1] = (addr >> 8) & 0xFF;
885 writeb_parm[2] = (addr >> 16) & 0xFF;
886 writeb_parm[3] = val;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000887 sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000888 sp_opbuf_usage += 5;
889 }
890}
891
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000892static uint8_t serprog_chip_readb(const struct flashctx *flash,
893 const chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000894{
895 unsigned char c;
896 unsigned char buf[3];
897 /* Will stream the read operation - eg. add it to the stream buffer, *
898 * then flush the buffer, then read the read answer. */
899 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
900 sp_execute_opbuf_noflush();
901 buf[0] = ((addr >> 0) & 0xFF);
902 buf[1] = ((addr >> 8) & 0xFF);
903 buf[2] = ((addr >> 16) & 0xFF);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000904 sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
905 sp_flush_stream(); // FIXME: return error
Stefan Tauner79587f52013-04-01 00:45:51 +0000906 if (serialport_read(&c, 1) != 0)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000907 msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
Stefan Taunerc2333752013-07-13 23:31:37 +0000908 msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000909 return c;
910}
911
Uwe Hermann4e3d0b32010-03-25 23:18:41 +0000912/* Local version that really does the job, doesn't care of max_read_n. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000913static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000914{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000915 unsigned char sbuf[6];
Stefan Tauner0554ca52013-07-25 22:54:25 +0000916 msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000917 /* Stream the read-n -- as above. */
918 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
919 sp_execute_opbuf_noflush();
920 sbuf[0] = ((addr >> 0) & 0xFF);
921 sbuf[1] = ((addr >> 8) & 0xFF);
922 sbuf[2] = ((addr >> 16) & 0xFF);
923 sbuf[3] = ((len >> 0) & 0xFF);
924 sbuf[4] = ((len >> 8) & 0xFF);
925 sbuf[5] = ((len >> 16) & 0xFF);
926 sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000927 if (sp_flush_stream() != 0)
928 return 1;
929 if (serialport_read(buf, len) != 0) {
930 msg_perr(MSGHEADER "Error: cannot read read-n data");
931 return 1;
932 }
933 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000934}
935
936/* The externally called version that makes sure that max_read_n is obeyed. */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000937static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
938 const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000939{
940 size_t lenm = len;
941 chipaddr addrm = addr;
Stefan Tauner31019d42011-10-22 21:45:27 +0000942 while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000943 sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000944 addrm += sp_max_read_n;
945 lenm -= sp_max_read_n;
946 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000947 if (lenm)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000948 sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000949}
950
Thomas Heijligencc853d82021-05-04 15:32:17 +0200951static void serprog_delay(unsigned int usecs)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000952{
953 unsigned char buf[4];
Stefan Tauner31019d42011-10-22 21:45:27 +0000954 msg_pspew("%s usecs=%d\n", __func__, usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000955 if (!sp_check_commandavail(S_CMD_O_DELAY)) {
Stefan Taunerd7d423b2012-10-20 09:13:16 +0000956 msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
Stefan Tauner31019d42011-10-22 21:45:27 +0000957 internal_delay(usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000958 return;
959 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000960 if ((sp_max_write_n) && (sp_write_n_bytes))
961 sp_pass_writen();
962 sp_check_opbuf_usage(5);
Stefan Tauner31019d42011-10-22 21:45:27 +0000963 buf[0] = ((usecs >> 0) & 0xFF);
964 buf[1] = ((usecs >> 8) & 0xFF);
965 buf[2] = ((usecs >> 16) & 0xFF);
966 buf[3] = ((usecs >> 24) & 0xFF);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000967 sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
968 sp_opbuf_usage += 5;
969 sp_prev_was_write = 0;
970}
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000971
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000972static int serprog_spi_send_command(const struct flashctx *flash,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000973 unsigned int writecnt, unsigned int readcnt,
974 const unsigned char *writearr,
975 unsigned char *readarr)
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000976{
977 unsigned char *parmbuf;
978 int ret;
979 msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000980 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
981 if (sp_execute_opbuf() != 0) {
982 msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
983 return 1;
984 }
985 }
986
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000987 parmbuf = malloc(writecnt + 6);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000988 if (!parmbuf) {
989 msg_perr("Error: could not allocate SPI send param buffer.\n");
990 return 1;
991 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000992 parmbuf[0] = (writecnt >> 0) & 0xFF;
993 parmbuf[1] = (writecnt >> 8) & 0xFF;
994 parmbuf[2] = (writecnt >> 16) & 0xFF;
995 parmbuf[3] = (readcnt >> 0) & 0xFF;
996 parmbuf[4] = (readcnt >> 8) & 0xFF;
997 parmbuf[5] = (readcnt >> 16) & 0xFF;
998 memcpy(parmbuf + 6, writearr, writecnt);
999 ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
1000 readarr);
1001 free(parmbuf);
1002 return ret;
1003}
1004
Thomas Heijligencc853d82021-05-04 15:32:17 +02001005static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001006{
1007 /* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
1008 * correctly (usually setting them to one either in software (for FWH/LPC) or relying on the fact that
1009 * the hardware observes a subset of the address bits only). Combined with the standard mapping of
Nico Huberc3b02dc2023-08-12 01:13:45 +02001010 * 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 +00001011 * needed for non-SPI chips). Below we make sure that the requested range is within this window. */
1012 if ((phys_addr & 0xFF000000) == 0xFF000000) {
1013 return (void*)phys_addr;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001014 }
Elyes HAOUASec819d62019-06-09 17:50:51 +02001015 msg_pwarn(MSGHEADER "requested mapping %s is incompatible: 0x%zx bytes at 0x%0*" PRIxPTR ".\n",
1016 descr, len, PRIxPTR_WIDTH, phys_addr);
1017 return NULL;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001018}
Thomas Heijligencc853d82021-05-04 15:32:17 +02001019
1020const struct programmer_entry programmer_serprog = {
1021 .name = "serprog",
1022 .type = OTHER,
1023 /* FIXME */
1024 .devs.note = "All programmer devices speaking the serprog protocol\n",
1025 .init = serprog_init,
Thomas Heijligencc853d82021-05-04 15:32:17 +02001026 .delay = serprog_delay,
1027};