blob: a5969669c67c0da51d2958c62cf6d17e9b4a5736 [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 "programmer.h"
Felix Singer100be2c2021-10-13 13:40:07 +020039
40/* According to Serial Flasher Protocol Specification - version 1 */
41#define S_ACK 0x06
42#define S_NAK 0x15
43#define S_CMD_NOP 0x00 /* No operation */
44#define S_CMD_Q_IFACE 0x01 /* Query interface version */
45#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */
46#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */
47#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */
48#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */
49#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */
50#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */
51#define S_CMD_Q_WRNMAXLEN 0x08 /* Query Write to opbuf: Write-N maximum length */
52#define S_CMD_R_BYTE 0x09 /* Read a single byte */
53#define S_CMD_R_NBYTES 0x0A /* Read n bytes */
54#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */
55#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */
56#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */
57#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */
58#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */
59#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */
60#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */
61#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */
62#define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */
63#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */
64#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */
Riku Viitanenddb6d922024-01-15 19:15:49 +020065#define S_CMD_S_SPI_CS 0x16 /* Set SPI chip select to use */
Urja Rannikkof3196df2009-07-21 13:02:59 +000066
Stefan Tauner31019d42011-10-22 21:45:27 +000067#define MSGHEADER "serprog: "
Urja Rannikkof3196df2009-07-21 13:02:59 +000068
David Hendricks8bb20212011-06-14 01:35:36 +000069/*
70 * FIXME: This prototype was added to help reduce diffs for the shutdown
71 * registration patch, which shifted many lines of code to place
72 * serprog_shutdown() before serprog_init(). It should be removed soon.
73 */
74static int serprog_shutdown(void *data);
75
Urja Rannikkof3196df2009-07-21 13:02:59 +000076static uint16_t sp_device_serbuf_size = 16;
77static uint16_t sp_device_opbuf_size = 300;
78/* Bitmap of supported commands */
79static uint8_t sp_cmdmap[32];
80
Uwe Hermann4e3d0b32010-03-25 23:18:41 +000081/* sp_prev_was_write used to detect writes with contiguous addresses
Urja Rannikkof3196df2009-07-21 13:02:59 +000082 and combine them to write-n's */
83static int sp_prev_was_write = 0;
84/* sp_write_n_addr used as the starting addr of the currently
85 combined write-n operation */
86static uint32_t sp_write_n_addr;
87/* The maximum length of an write_n operation; 0 = write-n not supported */
88static uint32_t sp_max_write_n = 0;
89/* The maximum length of a read_n operation; 0 = 2^24 */
90static uint32_t sp_max_read_n = 0;
91
92/* A malloc'd buffer for combining the operation's data
93 and a counter that tells how much data is there. */
94static uint8_t *sp_write_n_buf;
95static uint32_t sp_write_n_bytes = 0;
96
97/* sp_streamed_* used for flow control checking */
Nico Huber519be662018-12-23 20:03:35 +010098static unsigned int sp_streamed_transmit_ops = 0;
99static unsigned int sp_streamed_transmit_bytes = 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000100
101/* sp_opbuf_usage used for counting the amount of
102 on-device operation buffer used */
103static int sp_opbuf_usage = 0;
104/* if true causes sp_docommand to automatically check
105 whether the command is supported before doing it */
106static int sp_check_avail_automatic = 0;
107
Stefan Taunerb0eee9b2015-01-10 09:32:50 +0000108#if ! IS_WINDOWS
Urja Rannikkof3196df2009-07-21 13:02:59 +0000109static int sp_opensocket(char *ip, unsigned int port)
110{
111 int flag = 1;
112 struct hostent *hostPtr = NULL;
Carl-Daniel Hailfinger6d125602009-09-05 01:10:23 +0000113 union { struct sockaddr_in si; struct sockaddr s; } sp = {};
Urja Rannikkof3196df2009-07-21 13:02:59 +0000114 int sock;
Sean Nelson74e8af52010-01-10 01:06:23 +0000115 msg_pdbg(MSGHEADER "IP %s port %d\n", ip, port);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000116 sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000117 if (sock < 0) {
118 msg_perr("Error: serprog cannot open socket: %s\n", strerror(errno));
119 return -1;
120 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000121 hostPtr = gethostbyname(ip);
122 if (NULL == hostPtr) {
123 hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000124 if (NULL == hostPtr) {
Stefan Reinauerb8792872014-04-26 16:12:03 +0000125 close(sock);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000126 msg_perr("Error: cannot resolve %s\n", ip);
127 return -1;
128 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000129 }
Carl-Daniel Hailfinger6d125602009-09-05 01:10:23 +0000130 sp.si.sin_family = AF_INET;
131 sp.si.sin_port = htons(port);
Carl-Daniel Hailfinger1c6d2ff2012-08-27 00:44:42 +0000132 (void)memcpy(&sp.si.sin_addr, hostPtr->h_addr_list[0], hostPtr->h_length);
Carl-Daniel Hailfinger6d125602009-09-05 01:10:23 +0000133 if (connect(sock, &sp.s, sizeof(sp.si)) < 0) {
Urja Rannikkof3196df2009-07-21 13:02:59 +0000134 close(sock);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000135 msg_perr("Error: serprog cannot connect: %s\n", strerror(errno));
136 return -1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000137 }
138 /* We are latency limited, and sometimes do write-write-read *
139 * (write-n) - so enable TCP_NODELAY. */
Stefan Reinauer907c3eb2014-04-26 16:12:31 +0000140 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) {
141 close(sock);
142 msg_perr("Error: serprog cannot set socket options: %s\n", strerror(errno));
143 return -1;
144 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000145 return sock;
146}
Stefan Tauner52b6e9d2013-04-01 00:46:05 +0000147#endif
Urja Rannikkof3196df2009-07-21 13:02:59 +0000148
Nico Huberd7318ea2023-02-12 00:30:31 +0100149static int sp_test_sync(void)
150{
151 int n;
152
153 unsigned char c = S_CMD_SYNCNOP;
154 if (serialport_write_nonblock(&c, 1, 1, NULL) != 0)
155 return -1;
156
157 for (n = 0; n < 10; n++) {
158 int ret = serialport_read_nonblock(&c, 1, 50, NULL);
159 if (ret < 0)
160 return -1;
161 if (ret > 0 || c != S_NAK)
162 continue;
163 ret = serialport_read_nonblock(&c, 1, 20, NULL);
164 if (ret < 0)
165 return -1;
166 if (ret > 0 || c != S_ACK)
167 continue;
168
169 c = S_CMD_SYNCNOP;
170 if (serialport_write_nonblock(&c, 1, 1, NULL) != 0)
171 return -1;
172 ret = serialport_read_nonblock(&c, 1, 500, NULL);
173 if (ret < 0)
174 return -1;
175 if (ret > 0 || c != S_NAK)
176 return 1; /* soft fail */
177 ret = serialport_read_nonblock(&c, 1, 100, NULL);
178 if (ret > 0 || ret < 0)
179 return -1;
180 if (c != S_ACK)
181 return 1; /* soft fail */
182 return 0;
183 }
184
185 return 1; /* soft fail */
186}
187
Uwe Hermann4e3d0b32010-03-25 23:18:41 +0000188/* Synchronize: a bit tricky algorithm that tries to (and in my tests has *
Urja Rannikkof3196df2009-07-21 13:02:59 +0000189 * always succeeded in) bring the serial protocol to known waiting-for- *
Stefan Taunerae3d8372013-04-01 00:45:45 +0000190 * command state - uses nonblocking I/O - rest of the driver uses *
Urja Rannikkof3196df2009-07-21 13:02:59 +0000191 * blocking read - TODO: add an alarm() timer for the rest of the app on *
192 * serial operations, though not such a big issue as the first thing to *
193 * do is synchronize (eg. check that device is alive). */
Niklas Söderlund7145a502012-09-07 07:07:07 +0000194static int sp_synchronize(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000195{
Nico Huberd7318ea2023-02-12 00:30:31 +0100196 int i, ret;
Nico Huber211c6ec2023-02-12 01:05:47 +0100197 unsigned char buf[512];
Nico Huber383b7fe2023-02-12 00:38:55 +0100198
199 ret = sp_test_sync();
200 if (ret < 0)
201 goto err_out;
202 if (ret == 0) {
203 msg_pdbg("\n");
204 return 0;
205 }
206
207 msg_pdbg(" - attempting to synchronize\n");
208
Urja Rannikkof3196df2009-07-21 13:02:59 +0000209 /* First sends 8 NOPs, then flushes the return data - should cause *
210 * the device serial parser to get to a sane state, unless if it *
211 * is waiting for a real long write-n. */
212 memset(buf, S_CMD_NOP, 8);
Stefan Taunerae3d8372013-04-01 00:45:45 +0000213 if (serialport_write_nonblock(buf, 8, 1, NULL) != 0) {
Niklas Söderlund7145a502012-09-07 07:07:07 +0000214 goto err_out;
215 }
Nico Huber211c6ec2023-02-12 01:05:47 +0100216 /* To drain large reading orders that exceed FIFO sizes, we try
217 to read repeatedly until no data is received for 10ms. */
218 const int timeout_ms = 10;
219 /* Limit the loop to guarantee termination within 10s. */
220 const int limit = 1 << 10;
221 for (i = 0, ret = 0; i < limit && ret == 0; ++i) {
222 ret = serialport_read_nonblock(buf, sizeof(buf), timeout_ms, NULL);
223 if (ret < 0)
224 goto err_out;
225 }
226 if (i == limit)
227 goto err_out;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000228
Cristian Măgherușan-Stanciu9932c7b2011-07-07 19:56:58 +0000229 /* Then try up to 8 times to send syncnop and get the correct special *
230 * return of NAK+ACK. Timing note: up to 10 characters, 10*50ms = *
231 * up to 500ms per try, 8*0.5s = 4s; +1s (above) = up to 5s sync *
232 * attempt, ~1s if immediate success. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000233 for (i = 0; i < 8; i++) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000234 msg_pdbg(".");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000235 fflush(stdout);
Nico Huberd7318ea2023-02-12 00:30:31 +0100236
237 ret = sp_test_sync();
238 if (ret > 0)
239 continue;
240 if (ret < 0)
241 goto err_out;
242 msg_pdbg("\n");
243 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000244 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000245err_out:
246 msg_perr("Error: cannot synchronize protocol - check communications and reset device?\n");
247 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000248}
249
250static int sp_check_commandavail(uint8_t command)
251{
252 int byteoffs, bitoffs;
253 byteoffs = command / 8;
254 bitoffs = command % 8;
255 return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
256}
257
258static int sp_automatic_cmdcheck(uint8_t cmd)
259{
260 if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000261 msg_pdbg("Warning: Automatic command availability check failed "
Stefan Taunere34e3e82013-01-01 00:06:51 +0000262 "for cmd 0x%02x - won't execute cmd\n", cmd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000263 return 1;
264 }
265 return 0;
266}
267
268static int sp_docommand(uint8_t command, uint32_t parmlen,
Stefan Tauner31019d42011-10-22 21:45:27 +0000269 uint8_t *params, uint32_t retlen, void *retparms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000270{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000271 unsigned char c;
272 if (sp_automatic_cmdcheck(command))
273 return 1;
Stefan Tauner79587f52013-04-01 00:45:51 +0000274 if (serialport_write(&command, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000275 msg_perr("Error: cannot write op code: %s\n", strerror(errno));
276 return 1;
277 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000278 if (serialport_write(params, parmlen) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000279 msg_perr("Error: cannot write parameters: %s\n", strerror(errno));
280 return 1;
281 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000282 if (serialport_read(&c, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000283 msg_perr("Error: cannot read from device: %s\n", strerror(errno));
284 return 1;
285 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000286 if (c == S_NAK)
287 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000288 if (c != S_ACK) {
Stefan Tauner23e10b82016-01-23 16:16:49 +0000289 msg_perr("Error: invalid response 0x%02X from device (to command 0x%02X)\n", c, command);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000290 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000291 }
292 if (retlen) {
Stefan Tauner79587f52013-04-01 00:45:51 +0000293 if (serialport_read(retparms, retlen) != 0) {
294 msg_perr("Error: cannot read return parameters: %s\n", strerror(errno));
295 return 1;
296 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000297 }
298 return 0;
299}
300
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000301static int sp_flush_stream(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000302{
303 if (sp_streamed_transmit_ops)
304 do {
305 unsigned char c;
Stefan Tauner79587f52013-04-01 00:45:51 +0000306 if (serialport_read(&c, 1) != 0) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000307 msg_perr("Error: cannot read from device (flushing stream)");
308 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000309 }
310 if (c == S_NAK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000311 msg_perr("Error: NAK to a stream buffer operation\n");
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000312 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000313 }
314 if (c != S_ACK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000315 msg_perr("Error: Invalid reply 0x%02X from device\n", c);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000316 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000317 }
318 } while (--sp_streamed_transmit_ops);
319 sp_streamed_transmit_ops = 0;
320 sp_streamed_transmit_bytes = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000321 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000322}
323
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000324static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000325{
326 uint8_t *sp;
327 if (sp_automatic_cmdcheck(cmd))
328 return 1;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000329
Urja Rannikkof3196df2009-07-21 13:02:59 +0000330 sp = malloc(1 + parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000331 if (!sp) {
332 msg_perr("Error: cannot malloc command buffer\n");
333 return 1;
334 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000335 sp[0] = cmd;
aarya885917c2022-03-10 09:16:44 +0530336 if (parms)
337 memcpy(&(sp[1]), parms, parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000338
339 if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) {
340 if (sp_flush_stream() != 0) {
341 free(sp);
342 return 1;
343 }
344 }
345 if (serialport_write(sp, 1 + parmlen) != 0) {
346 msg_perr("Error: cannot write command\n");
347 free(sp);
348 return 1;
349 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000350 sp_streamed_transmit_ops += 1;
351 sp_streamed_transmit_bytes += 1 + parmlen;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000352
353 free(sp);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000354 return 0;
355}
356
Nico Huber610c1aa2023-02-15 02:56:05 +0100357static int serprog_spi_send_command(const struct spi_master *,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000358 unsigned int writecnt, unsigned int readcnt,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000359 const unsigned char *writearr,
360 unsigned char *readarr);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000361static struct spi_master spi_master_serprog = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100362 .features = SPI_MASTER_4BA,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000363 .max_data_read = MAX_DATA_READ_UNLIMITED,
364 .max_data_write = MAX_DATA_WRITE_UNLIMITED,
365 .command = serprog_spi_send_command,
366 .multicommand = default_spi_send_multicommand,
Urja Rannikko731316a2017-06-15 13:32:01 +0300367 .read = default_spi_read,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000368 .write_256 = default_spi_write_256,
Aarya Chaumal0cea7532022-07-04 18:21:50 +0530369 .probe_opcode = default_spi_probe_opcode,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000370};
371
Nico Huberdd6e07a2026-02-21 17:55:26 +0100372static void serprog_chip_writeb(const struct par_master *, uint8_t val, chipaddr);
373static uint8_t serprog_chip_readb(const struct par_master *, chipaddr);
374static void serprog_chip_readn(const struct par_master *, uint8_t *buf, chipaddr, size_t len);
Nico Huber0e76d992023-01-12 20:22:55 +0100375static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000376static const struct par_master par_master_serprog = {
Thomas Heijligen43040f22022-06-23 14:38:35 +0200377 .chip_readb = serprog_chip_readb,
378 .chip_readw = fallback_chip_readw,
379 .chip_readl = fallback_chip_readl,
380 .chip_readn = serprog_chip_readn,
381 .chip_writeb = serprog_chip_writeb,
382 .chip_writew = fallback_chip_writew,
383 .chip_writel = fallback_chip_writel,
384 .chip_writen = fallback_chip_writen,
Nico Huber0e76d992023-01-12 20:22:55 +0100385 .map_flash = serprog_map,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000386};
387
388static enum chipbustype serprog_buses_supported = BUS_NONE;
389
Nico Hubere3a26882023-01-11 21:45:51 +0100390static int serprog_init(struct flashprog_programmer *const prog)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000391{
392 uint16_t iface;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000393 unsigned char pgmname[17];
394 unsigned char rbuf[3];
395 unsigned char c;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000396 char *device;
Felix Singer815eb792022-08-19 01:02:42 +0200397 bool have_device = false;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000398
Stefan Tauner72587f82016-01-04 03:05:15 +0000399 /* the parameter is either of format "dev=/dev/device[:baud]" or "ip=ip:port" */
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000400 device = extract_programmer_param("dev");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000401 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000402 char *baud_str = strstr(device, ":");
403 if (baud_str != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000404 /* Split device from baudrate. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000405 *baud_str = '\0';
406 baud_str++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000407 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000408 int baud;
409 /* Convert baud string to value.
410 * baud_str is either NULL (if strstr can't find the colon), points to the \0 after the colon
411 * if no characters where given after the colon, or a string to convert... */
412 if (baud_str == NULL || *baud_str == '\0') {
413 baud = -1;
414 msg_pdbg("No baudrate specified, using the hardware's defaults.\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000415 } else {
Stefan Tauner72587f82016-01-04 03:05:15 +0000416 baud = atoi(baud_str); // FIXME: replace atoi with strtoul
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000417 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000418 if (strlen(device) > 0) {
419 sp_fd = sp_openserport(device, baud);
Stefan Tauneracfc4c62012-11-30 16:46:45 +0000420 if (sp_fd == SER_INV_FD) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000421 free(device);
422 return 1;
423 }
Felix Singer815eb792022-08-19 01:02:42 +0200424 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000425 }
426 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000427
428#if !IS_WINDOWS
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000429 if (device && !strlen(device)) {
430 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200431 "Use flashprog -p serprog:dev=/dev/device[:baud]\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000432 free(device);
433 return 1;
434 }
435 free(device);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000436
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000437 device = extract_programmer_param("ip");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000438 if (have_device && device) {
439 msg_perr("Error: Both host and device specified.\n"
440 "Please use either dev= or ip= but not both.\n");
441 free(device);
442 return 1;
443 }
444 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000445 char *port = strstr(device, ":");
446 if (port != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000447 /* Split host from port. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000448 *port = '\0';
449 port++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000450 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000451 if (!port || !strlen(port)) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000452 msg_perr("Error: No port 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);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000455 return 1;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000456 }
457 if (strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000458 sp_fd = sp_opensocket(device, atoi(port)); // FIXME: replace atoi with strtoul
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000459 if (sp_fd < 0) {
460 free(device);
461 return 1;
462 }
Felix Singer815eb792022-08-19 01:02:42 +0200463 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000464 }
465 }
466 if (device && !strlen(device)) {
467 msg_perr("Error: No host specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200468 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000469 free(device);
470 return 1;
471 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000472#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000473 free(device);
474
475 if (!have_device) {
Urja Rannikko27b431b2016-01-04 03:05:23 +0000476#if IS_WINDOWS
477 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200478 "Use flashprog -p serprog:dev=comN[:baud]\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000479#else
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000480 msg_perr("Error: Neither host nor device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200481 "Use flashprog -p serprog:dev=/dev/device:baud or "
482 "flashprog -p serprog:ip=ipaddr:port\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000483#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000484 return 1;
485 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000486
Nico Huber383b7fe2023-02-12 00:38:55 +0100487 msg_pdbg(MSGHEADER "connected");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000488
489 sp_check_avail_automatic = 0;
490
Niklas Söderlund7145a502012-09-07 07:07:07 +0000491 if (sp_synchronize())
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000492 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000493
Sean Nelson74e8af52010-01-10 01:06:23 +0000494 msg_pdbg(MSGHEADER "Synchronized\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000495
496 if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000497 msg_perr("Error: NAK to query interface version\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000498 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000499 }
500
501 if (iface != 1) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000502 msg_perr("Error: Unknown interface version: %d\n", iface);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000503 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000504 }
505
Sean Nelson74e8af52010-01-10 01:06:23 +0000506 msg_pdbg(MSGHEADER "Interface version ok.\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000507
508 if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000509 msg_perr("Error: query command map not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000510 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000511 }
512
513 sp_check_avail_automatic = 1;
514
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000515 /* FIXME: This assumes that serprog device bustypes are always
Nico Huberc3b02dc2023-08-12 01:13:45 +0200516 * identical with flashprog bustype enums and that they all fit
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000517 * in a single byte.
518 */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000519 if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000520 msg_pwarn("Warning: NAK to query supported buses\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000521 c = BUS_NONSPI; /* A reasonable default for now. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000522 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000523 serprog_buses_supported = c;
524
Stefan Tauner31019d42011-10-22 21:45:27 +0000525 msg_pdbg(MSGHEADER "Bus support: parallel=%s, LPC=%s, FWH=%s, SPI=%s\n",
526 (c & BUS_PARALLEL) ? "on" : "off",
527 (c & BUS_LPC) ? "on" : "off",
528 (c & BUS_FWH) ? "on" : "off",
529 (c & BUS_SPI) ? "on" : "off");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000530 /* Check for the minimum operational set of commands. */
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000531 if (serprog_buses_supported & BUS_SPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000532 uint8_t bt = BUS_SPI;
Riku Viitanenddb6d922024-01-15 19:15:49 +0200533 char *spispeed, *cs;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000534 if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
535 msg_perr("Error: SPI operation not supported while the "
536 "bustype is SPI\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000537 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000538 }
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000539 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000540 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000541 /* Success of any of these commands is optional. We don't need
542 the programmer to tell us its limits, but if it doesn't, we
543 will assume stuff, so it's in the programmers best interest
544 to tell us. */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000545 if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
546 uint32_t v;
547 v = ((unsigned int)(rbuf[0]) << 0);
548 v |= ((unsigned int)(rbuf[1]) << 8);
549 v |= ((unsigned int)(rbuf[2]) << 16);
550 if (v == 0)
551 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000552 spi_master_serprog.max_data_write = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000553 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", v);
554 }
555 if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
556 uint32_t v;
557 v = ((unsigned int)(rbuf[0]) << 0);
558 v |= ((unsigned int)(rbuf[1]) << 8);
559 v |= ((unsigned int)(rbuf[2]) << 16);
560 if (v == 0)
561 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000562 spi_master_serprog.max_data_read = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000563 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
564 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000565 spispeed = extract_programmer_param("spispeed");
566 if (spispeed && strlen(spispeed)) {
567 uint32_t f_spi_req, f_spi;
568 uint8_t buf[4];
569 char *f_spi_suffix;
570
571 errno = 0;
572 f_spi_req = strtol(spispeed, &f_spi_suffix, 0);
573 if (errno != 0 || spispeed == f_spi_suffix) {
574 msg_perr("Error: Could not convert 'spispeed'.\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 if (strlen(f_spi_suffix) == 1) {
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000579 if (!strcasecmp(f_spi_suffix, "M")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000580 f_spi_req *= 1000000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000581 } else if (!strcasecmp(f_spi_suffix, "k")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000582 f_spi_req *= 1000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000583 } else {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000584 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000585 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000586 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000587 }
588 } else if (strlen(f_spi_suffix) > 1) {
589 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000590 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000591 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000592 }
593
594 buf[0] = (f_spi_req >> (0 * 8)) & 0xFF;
595 buf[1] = (f_spi_req >> (1 * 8)) & 0xFF;
596 buf[2] = (f_spi_req >> (2 * 8)) & 0xFF;
597 buf[3] = (f_spi_req >> (3 * 8)) & 0xFF;
598
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000599 if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000600 msg_pwarn(MSGHEADER "Warning: Setting the SPI clock rate is not supported!\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000601 } else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) == 0) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000602 f_spi = buf[0];
603 f_spi |= buf[1] << (1 * 8);
604 f_spi |= buf[2] << (2 * 8);
605 f_spi |= buf[3] << (3 * 8);
606 msg_pdbg(MSGHEADER "Requested to set SPI clock frequency to %u Hz. "
607 "It was actually set to %u Hz\n", f_spi_req, f_spi);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000608 } else {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000609 msg_pwarn(MSGHEADER "Setting SPI clock rate to %u Hz failed!\n", f_spi_req);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000610 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000611 }
612 free(spispeed);
Riku Viitanenddb6d922024-01-15 19:15:49 +0200613 cs = extract_programmer_param("cs");
614 if (cs) {
615 char *endptr = NULL;
616 errno = 0;
617 unsigned long cs_num = strtoul(cs, &endptr, 0);
618 if (!*cs || errno || *endptr || cs_num > 255) {
619 msg_perr("Error: Invalid chip select requested! "
620 "Only 0-255 are valid.\n");
621 free(cs);
622 goto init_err_cleanup_exit;
623 }
624 free(cs);
625 if (!sp_check_commandavail(S_CMD_S_SPI_CS)) {
626 msg_perr("Error: Setting SPI chip select is not supported!\n");
627 goto init_err_cleanup_exit;
628 }
629 msg_pdbg(MSGHEADER "Requested to use chip select %lu.\n", cs_num);
630 uint8_t cs_num8 = cs_num;
631 if (sp_docommand(S_CMD_S_SPI_CS, 1, &cs_num8, 0, NULL)) {
632 msg_perr("Error: Chip select %u not supported "
633 "by programmer!\n", cs_num8);
634 goto init_err_cleanup_exit;
635 }
636 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000637 bt = serprog_buses_supported;
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000638 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000639 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000640 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000641
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000642 if (serprog_buses_supported & BUS_NONSPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000643 if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
644 msg_perr("Error: Initialize operation buffer "
645 "not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000646 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000647 }
648
649 if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
650 msg_perr("Error: Write to opbuf: "
651 "delay not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000652 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000653 }
654
655 /* S_CMD_O_EXEC availability checked later. */
656
657 if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
658 msg_perr("Error: Single byte read not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000659 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000660 }
661 /* This could be translated to single byte reads (if missing),
662 * but now we don't support that. */
663 if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
664 msg_perr("Error: Read n bytes not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000665 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000666 }
667 if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
668 msg_perr("Error: Write to opbuf: "
669 "write byte not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000670 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000671 }
672
673 if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
674 msg_pdbg(MSGHEADER "Write-n not supported");
675 sp_max_write_n = 0;
676 } else {
677 sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
678 sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
679 sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
680 if (!sp_max_write_n) {
681 sp_max_write_n = (1 << 24);
682 }
683 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n",
684 sp_max_write_n);
685 sp_write_n_buf = malloc(sp_max_write_n);
686 if (!sp_write_n_buf) {
687 msg_perr("Error: cannot allocate memory for "
688 "Write-n buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000689 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000690 }
691 sp_write_n_bytes = 0;
692 }
693
694 if (sp_check_commandavail(S_CMD_Q_RDNMAXLEN) &&
695 (sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf) == 0)) {
696 sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
697 sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
698 sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
699 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n",
700 sp_max_read_n ? sp_max_read_n : (1 << 24));
701 } else {
702 msg_pdbg(MSGHEADER "Maximum read-n length "
703 "not reported\n");
704 sp_max_read_n = 0;
705 }
706
Urja Rannikkof3196df2009-07-21 13:02:59 +0000707 }
708
709 if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000710 msg_pwarn("Warning: NAK to query programmer name\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000711 strcpy((char *)pgmname, "(unknown)");
712 }
713 pgmname[16] = 0;
Stefan Tauner31019d42011-10-22 21:45:27 +0000714 msg_pinfo(MSGHEADER "Programmer name is \"%s\"\n", pgmname);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000715
716 if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000717 msg_pwarn("Warning: NAK to query serial buffer size\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000718 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000719 msg_pdbg(MSGHEADER "Serial buffer size is %d\n",
Urja Rannikkof3196df2009-07-21 13:02:59 +0000720 sp_device_serbuf_size);
721
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000722 if (sp_check_commandavail(S_CMD_O_INIT)) {
723 /* This would be inconsistent. */
724 if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
725 msg_perr("Error: Execute operation buffer not "
726 "supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000727 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000728 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000729
730 if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
731 msg_perr("Error: NAK to initialize operation buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000732 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000733 }
734
735 if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
736 &sp_device_opbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000737 msg_pwarn("Warning: NAK to query operation buffer size\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000738 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000739 msg_pdbg(MSGHEADER "operation buffer size is %d\n",
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000740 sp_device_opbuf_size);
Elyes HAOUAS124ef382018-03-27 12:15:09 +0200741 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000742
Stefan Tauner92fefc92012-10-27 00:34:23 +0000743 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
744 uint8_t en = 1;
745 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &en, 0, NULL) != 0) {
746 msg_perr("Error: could not enable output buffers\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000747 goto init_err_cleanup_exit;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000748 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000749 msg_pdbg(MSGHEADER "Output drivers enabled\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000750 }
751 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000752 msg_pdbg(MSGHEADER "Warning: Programmer does not support toggling its output drivers\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000753 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000754 sp_prev_was_write = 0;
755 sp_streamed_transmit_ops = 0;
756 sp_streamed_transmit_bytes = 0;
757 sp_opbuf_usage = 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000758
759 if (register_shutdown(serprog_shutdown, NULL))
760 goto init_err_cleanup_exit;
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000761 if (serprog_buses_supported & BUS_SPI)
Nico Huber89569d62023-01-12 23:31:40 +0100762 register_spi_master(&spi_master_serprog, 0, NULL);
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000763 if (serprog_buses_supported & BUS_NONSPI)
Nico Huber47aa85c2026-02-21 14:57:20 +0100764 register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI, 0, 0, NULL);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000765 return 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000766
767init_err_cleanup_exit:
768 serprog_shutdown(NULL);
769 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000770}
771
Nico Huberc3b02dc2023-08-12 01:13:45 +0200772/* Move an in flashprog buffer existing write-n operation to the on-device operation buffer. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000773static int sp_pass_writen(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000774{
775 unsigned char header[7];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000776 msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
777 if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
778 if (sp_flush_stream() != 0) {
779 return 1;
780 }
781 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000782 /* In case it's just a single byte send it as a single write. */
783 if (sp_write_n_bytes == 1) {
784 sp_write_n_bytes = 0;
785 header[0] = (sp_write_n_addr >> 0) & 0xFF;
786 header[1] = (sp_write_n_addr >> 8) & 0xFF;
787 header[2] = (sp_write_n_addr >> 16) & 0xFF;
788 header[3] = sp_write_n_buf[0];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000789 if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
790 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000791 sp_opbuf_usage += 5;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000792 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000793 }
794 header[0] = S_CMD_O_WRITEN;
795 header[1] = (sp_write_n_bytes >> 0) & 0xFF;
796 header[2] = (sp_write_n_bytes >> 8) & 0xFF;
797 header[3] = (sp_write_n_bytes >> 16) & 0xFF;
798 header[4] = (sp_write_n_addr >> 0) & 0xFF;
799 header[5] = (sp_write_n_addr >> 8) & 0xFF;
800 header[6] = (sp_write_n_addr >> 16) & 0xFF;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000801 if (serialport_write(header, 7) != 0) {
802 msg_perr(MSGHEADER "Error: cannot write write-n command\n");
803 return 1;
804 }
805 if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
806 msg_perr(MSGHEADER "Error: cannot write write-n data");
807 return 1;
808 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000809 sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
810 sp_streamed_transmit_ops += 1;
811 sp_opbuf_usage += 7 + sp_write_n_bytes;
812 sp_write_n_bytes = 0;
813 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000814 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000815}
816
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000817static int sp_execute_opbuf_noflush(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000818{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000819 if ((sp_max_write_n) && (sp_write_n_bytes)) {
820 if (sp_pass_writen() != 0) {
821 msg_perr("Error: could not transfer write buffer\n");
822 return 1;
823 }
824 }
825 if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
826 msg_perr("Error: could not execute command buffer\n");
827 return 1;
828 }
829 msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000830 sp_opbuf_usage = 0;
831 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000832 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000833}
834
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000835static int sp_execute_opbuf(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000836{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000837 if (sp_execute_opbuf_noflush() != 0)
838 return 1;
839 if (sp_flush_stream() != 0)
840 return 1;
841
842 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000843}
844
David Hendricks8bb20212011-06-14 01:35:36 +0000845static int serprog_shutdown(void *data)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000846{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000847 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000848 if (sp_execute_opbuf() != 0)
849 msg_pwarn("Could not flush command buffer.\n");
Stefan Tauner92fefc92012-10-27 00:34:23 +0000850 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
851 uint8_t dis = 0;
852 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
853 msg_pdbg(MSGHEADER "Output drivers disabled\n");
854 else
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000855 msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
Stefan Tauner92fefc92012-10-27 00:34:23 +0000856 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000857 /* FIXME: fix sockets on windows(?), especially closing */
858 serialport_shutdown(&sp_fd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000859 if (sp_max_write_n)
860 free(sp_write_n_buf);
861 return 0;
862}
863
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000864static int sp_check_opbuf_usage(int bytes_to_be_added)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000865{
866 if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000867 /* If this happens in the middle of a page load the page load will probably fail. */
868 msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
869 if (sp_execute_opbuf() != 0)
870 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000871 }
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000872 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000873}
874
Nico Huberdd6e07a2026-02-21 17:55:26 +0100875static void serprog_chip_writeb(const struct par_master *par, uint8_t val, chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000876{
Sean Nelson74e8af52010-01-10 01:06:23 +0000877 msg_pspew("%s\n", __func__);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000878 if (sp_max_write_n) {
879 if ((sp_prev_was_write)
880 && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
881 sp_write_n_buf[sp_write_n_bytes++] = val;
882 } else {
883 if ((sp_prev_was_write) && (sp_write_n_bytes))
884 sp_pass_writen();
885 sp_prev_was_write = 1;
886 sp_write_n_addr = addr;
887 sp_write_n_bytes = 1;
888 sp_write_n_buf[0] = val;
889 }
890 sp_check_opbuf_usage(7 + sp_write_n_bytes);
891 if (sp_write_n_bytes >= sp_max_write_n)
892 sp_pass_writen();
893 } else {
894 /* We will have to do single writeb ops. */
895 unsigned char writeb_parm[4];
896 sp_check_opbuf_usage(6);
897 writeb_parm[0] = (addr >> 0) & 0xFF;
898 writeb_parm[1] = (addr >> 8) & 0xFF;
899 writeb_parm[2] = (addr >> 16) & 0xFF;
900 writeb_parm[3] = val;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000901 sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000902 sp_opbuf_usage += 5;
903 }
904}
905
Nico Huberdd6e07a2026-02-21 17:55:26 +0100906static uint8_t serprog_chip_readb(const struct par_master *par, const chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000907{
908 unsigned char c;
909 unsigned char buf[3];
910 /* Will stream the read operation - eg. add it to the stream buffer, *
911 * then flush the buffer, then read the read answer. */
912 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
913 sp_execute_opbuf_noflush();
914 buf[0] = ((addr >> 0) & 0xFF);
915 buf[1] = ((addr >> 8) & 0xFF);
916 buf[2] = ((addr >> 16) & 0xFF);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000917 sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
918 sp_flush_stream(); // FIXME: return error
Stefan Tauner79587f52013-04-01 00:45:51 +0000919 if (serialport_read(&c, 1) != 0)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000920 msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
Stefan Taunerc2333752013-07-13 23:31:37 +0000921 msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000922 return c;
923}
924
Uwe Hermann4e3d0b32010-03-25 23:18:41 +0000925/* Local version that really does the job, doesn't care of max_read_n. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000926static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000927{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000928 unsigned char sbuf[6];
Stefan Tauner0554ca52013-07-25 22:54:25 +0000929 msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000930 /* Stream the read-n -- as above. */
931 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
932 sp_execute_opbuf_noflush();
933 sbuf[0] = ((addr >> 0) & 0xFF);
934 sbuf[1] = ((addr >> 8) & 0xFF);
935 sbuf[2] = ((addr >> 16) & 0xFF);
936 sbuf[3] = ((len >> 0) & 0xFF);
937 sbuf[4] = ((len >> 8) & 0xFF);
938 sbuf[5] = ((len >> 16) & 0xFF);
939 sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000940 if (sp_flush_stream() != 0)
941 return 1;
942 if (serialport_read(buf, len) != 0) {
943 msg_perr(MSGHEADER "Error: cannot read read-n data");
944 return 1;
945 }
946 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000947}
948
949/* The externally called version that makes sure that max_read_n is obeyed. */
Nico Huberdd6e07a2026-02-21 17:55:26 +0100950static void serprog_chip_readn(const struct par_master *par, uint8_t * buf, const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000951{
952 size_t lenm = len;
953 chipaddr addrm = addr;
Stefan Tauner31019d42011-10-22 21:45:27 +0000954 while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000955 sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000956 addrm += sp_max_read_n;
957 lenm -= sp_max_read_n;
958 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000959 if (lenm)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000960 sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000961}
962
Thomas Heijligencc853d82021-05-04 15:32:17 +0200963static void serprog_delay(unsigned int usecs)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000964{
965 unsigned char buf[4];
Stefan Tauner31019d42011-10-22 21:45:27 +0000966 msg_pspew("%s usecs=%d\n", __func__, usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000967 if (!sp_check_commandavail(S_CMD_O_DELAY)) {
Stefan Taunerd7d423b2012-10-20 09:13:16 +0000968 msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
Stefan Tauner31019d42011-10-22 21:45:27 +0000969 internal_delay(usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000970 return;
971 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000972 if ((sp_max_write_n) && (sp_write_n_bytes))
973 sp_pass_writen();
974 sp_check_opbuf_usage(5);
Stefan Tauner31019d42011-10-22 21:45:27 +0000975 buf[0] = ((usecs >> 0) & 0xFF);
976 buf[1] = ((usecs >> 8) & 0xFF);
977 buf[2] = ((usecs >> 16) & 0xFF);
978 buf[3] = ((usecs >> 24) & 0xFF);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000979 sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
980 sp_opbuf_usage += 5;
981 sp_prev_was_write = 0;
982}
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000983
Nico Huber610c1aa2023-02-15 02:56:05 +0100984static int serprog_spi_send_command(const struct spi_master *mst,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000985 unsigned int writecnt, unsigned int readcnt,
986 const unsigned char *writearr,
987 unsigned char *readarr)
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000988{
989 unsigned char *parmbuf;
990 int ret;
991 msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000992 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
993 if (sp_execute_opbuf() != 0) {
994 msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
995 return 1;
996 }
997 }
998
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000999 parmbuf = malloc(writecnt + 6);
Stefan Taunerbdead0d2013-08-24 02:10:18 +00001000 if (!parmbuf) {
1001 msg_perr("Error: could not allocate SPI send param buffer.\n");
1002 return 1;
1003 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +00001004 parmbuf[0] = (writecnt >> 0) & 0xFF;
1005 parmbuf[1] = (writecnt >> 8) & 0xFF;
1006 parmbuf[2] = (writecnt >> 16) & 0xFF;
1007 parmbuf[3] = (readcnt >> 0) & 0xFF;
1008 parmbuf[4] = (readcnt >> 8) & 0xFF;
1009 parmbuf[5] = (readcnt >> 16) & 0xFF;
1010 memcpy(parmbuf + 6, writearr, writecnt);
1011 ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
1012 readarr);
1013 free(parmbuf);
1014 return ret;
1015}
1016
Thomas Heijligencc853d82021-05-04 15:32:17 +02001017static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001018{
1019 /* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
1020 * correctly (usually setting them to one either in software (for FWH/LPC) or relying on the fact that
1021 * the hardware observes a subset of the address bits only). Combined with the standard mapping of
Nico Huberc3b02dc2023-08-12 01:13:45 +02001022 * 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 +00001023 * needed for non-SPI chips). Below we make sure that the requested range is within this window. */
1024 if ((phys_addr & 0xFF000000) == 0xFF000000) {
1025 return (void*)phys_addr;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001026 }
Elyes HAOUASec819d62019-06-09 17:50:51 +02001027 msg_pwarn(MSGHEADER "requested mapping %s is incompatible: 0x%zx bytes at 0x%0*" PRIxPTR ".\n",
1028 descr, len, PRIxPTR_WIDTH, phys_addr);
1029 return NULL;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001030}
Thomas Heijligencc853d82021-05-04 15:32:17 +02001031
1032const struct programmer_entry programmer_serprog = {
1033 .name = "serprog",
1034 .type = OTHER,
1035 /* FIXME */
1036 .devs.note = "All programmer devices speaking the serprog protocol\n",
1037 .init = serprog_init,
Thomas Heijligencc853d82021-05-04 15:32:17 +02001038 .delay = serprog_delay,
1039};