blob: 6cf87f00bd082569ed960c3099682cc431401ef7 [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;
Nico Huber211c6ec2023-02-12 01:05:47 +0100199 unsigned char buf[512];
Nico Huber383b7fe2023-02-12 00:38:55 +0100200
201 ret = sp_test_sync();
202 if (ret < 0)
203 goto err_out;
204 if (ret == 0) {
205 msg_pdbg("\n");
206 return 0;
207 }
208
209 msg_pdbg(" - attempting to synchronize\n");
210
Urja Rannikkof3196df2009-07-21 13:02:59 +0000211 /* First sends 8 NOPs, then flushes the return data - should cause *
212 * the device serial parser to get to a sane state, unless if it *
213 * is waiting for a real long write-n. */
214 memset(buf, S_CMD_NOP, 8);
Stefan Taunerae3d8372013-04-01 00:45:45 +0000215 if (serialport_write_nonblock(buf, 8, 1, NULL) != 0) {
Niklas Söderlund7145a502012-09-07 07:07:07 +0000216 goto err_out;
217 }
Nico Huber211c6ec2023-02-12 01:05:47 +0100218 /* To drain large reading orders that exceed FIFO sizes, we try
219 to read repeatedly until no data is received for 10ms. */
220 const int timeout_ms = 10;
221 /* Limit the loop to guarantee termination within 10s. */
222 const int limit = 1 << 10;
223 for (i = 0, ret = 0; i < limit && ret == 0; ++i) {
224 ret = serialport_read_nonblock(buf, sizeof(buf), timeout_ms, NULL);
225 if (ret < 0)
226 goto err_out;
227 }
228 if (i == limit)
229 goto err_out;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000230
Cristian Măgherușan-Stanciu9932c7b2011-07-07 19:56:58 +0000231 /* Then try up to 8 times to send syncnop and get the correct special *
232 * return of NAK+ACK. Timing note: up to 10 characters, 10*50ms = *
233 * up to 500ms per try, 8*0.5s = 4s; +1s (above) = up to 5s sync *
234 * attempt, ~1s if immediate success. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000235 for (i = 0; i < 8; i++) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000236 msg_pdbg(".");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000237 fflush(stdout);
Nico Huberd7318ea2023-02-12 00:30:31 +0100238
239 ret = sp_test_sync();
240 if (ret > 0)
241 continue;
242 if (ret < 0)
243 goto err_out;
244 msg_pdbg("\n");
245 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000246 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000247err_out:
248 msg_perr("Error: cannot synchronize protocol - check communications and reset device?\n");
249 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000250}
251
252static int sp_check_commandavail(uint8_t command)
253{
254 int byteoffs, bitoffs;
255 byteoffs = command / 8;
256 bitoffs = command % 8;
257 return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
258}
259
260static int sp_automatic_cmdcheck(uint8_t cmd)
261{
262 if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000263 msg_pdbg("Warning: Automatic command availability check failed "
Stefan Taunere34e3e82013-01-01 00:06:51 +0000264 "for cmd 0x%02x - won't execute cmd\n", cmd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000265 return 1;
266 }
267 return 0;
268}
269
270static int sp_docommand(uint8_t command, uint32_t parmlen,
Stefan Tauner31019d42011-10-22 21:45:27 +0000271 uint8_t *params, uint32_t retlen, void *retparms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000272{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000273 unsigned char c;
274 if (sp_automatic_cmdcheck(command))
275 return 1;
Stefan Tauner79587f52013-04-01 00:45:51 +0000276 if (serialport_write(&command, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000277 msg_perr("Error: cannot write op code: %s\n", strerror(errno));
278 return 1;
279 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000280 if (serialport_write(params, parmlen) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000281 msg_perr("Error: cannot write parameters: %s\n", strerror(errno));
282 return 1;
283 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000284 if (serialport_read(&c, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000285 msg_perr("Error: cannot read from device: %s\n", strerror(errno));
286 return 1;
287 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000288 if (c == S_NAK)
289 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000290 if (c != S_ACK) {
Stefan Tauner23e10b82016-01-23 16:16:49 +0000291 msg_perr("Error: invalid response 0x%02X from device (to command 0x%02X)\n", c, command);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000292 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000293 }
294 if (retlen) {
Stefan Tauner79587f52013-04-01 00:45:51 +0000295 if (serialport_read(retparms, retlen) != 0) {
296 msg_perr("Error: cannot read return parameters: %s\n", strerror(errno));
297 return 1;
298 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000299 }
300 return 0;
301}
302
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000303static int sp_flush_stream(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000304{
305 if (sp_streamed_transmit_ops)
306 do {
307 unsigned char c;
Stefan Tauner79587f52013-04-01 00:45:51 +0000308 if (serialport_read(&c, 1) != 0) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000309 msg_perr("Error: cannot read from device (flushing stream)");
310 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000311 }
312 if (c == S_NAK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000313 msg_perr("Error: NAK to a stream buffer operation\n");
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000314 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000315 }
316 if (c != S_ACK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000317 msg_perr("Error: Invalid reply 0x%02X from device\n", c);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000318 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000319 }
320 } while (--sp_streamed_transmit_ops);
321 sp_streamed_transmit_ops = 0;
322 sp_streamed_transmit_bytes = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000323 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000324}
325
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000326static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000327{
328 uint8_t *sp;
329 if (sp_automatic_cmdcheck(cmd))
330 return 1;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000331
Urja Rannikkof3196df2009-07-21 13:02:59 +0000332 sp = malloc(1 + parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000333 if (!sp) {
334 msg_perr("Error: cannot malloc command buffer\n");
335 return 1;
336 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000337 sp[0] = cmd;
aarya885917c2022-03-10 09:16:44 +0530338 if (parms)
339 memcpy(&(sp[1]), parms, parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000340
341 if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) {
342 if (sp_flush_stream() != 0) {
343 free(sp);
344 return 1;
345 }
346 }
347 if (serialport_write(sp, 1 + parmlen) != 0) {
348 msg_perr("Error: cannot write command\n");
349 free(sp);
350 return 1;
351 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000352 sp_streamed_transmit_ops += 1;
353 sp_streamed_transmit_bytes += 1 + parmlen;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000354
355 free(sp);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000356 return 0;
357}
358
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000359static int serprog_spi_send_command(const struct flashctx *flash,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000360 unsigned int writecnt, unsigned int readcnt,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000361 const unsigned char *writearr,
362 unsigned char *readarr);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000363static struct spi_master spi_master_serprog = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100364 .features = SPI_MASTER_4BA,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000365 .max_data_read = MAX_DATA_READ_UNLIMITED,
366 .max_data_write = MAX_DATA_WRITE_UNLIMITED,
367 .command = serprog_spi_send_command,
368 .multicommand = default_spi_send_multicommand,
Urja Rannikko731316a2017-06-15 13:32:01 +0300369 .read = default_spi_read,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000370 .write_256 = default_spi_write_256,
Aarya Chaumal0cea7532022-07-04 18:21:50 +0530371 .probe_opcode = default_spi_probe_opcode,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000372};
373
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000374static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
375 chipaddr addr);
376static uint8_t serprog_chip_readb(const struct flashctx *flash,
377 const chipaddr addr);
378static void serprog_chip_readn(const struct flashctx *flash, uint8_t *buf,
379 const chipaddr addr, size_t len);
Nico Huber0e76d992023-01-12 20:22:55 +0100380static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000381static const struct par_master par_master_serprog = {
Thomas Heijligen43040f22022-06-23 14:38:35 +0200382 .chip_readb = serprog_chip_readb,
383 .chip_readw = fallback_chip_readw,
384 .chip_readl = fallback_chip_readl,
385 .chip_readn = serprog_chip_readn,
386 .chip_writeb = serprog_chip_writeb,
387 .chip_writew = fallback_chip_writew,
388 .chip_writel = fallback_chip_writel,
389 .chip_writen = fallback_chip_writen,
Nico Huber0e76d992023-01-12 20:22:55 +0100390 .map_flash = serprog_map,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000391};
392
393static enum chipbustype serprog_buses_supported = BUS_NONE;
394
Nico Hubere3a26882023-01-11 21:45:51 +0100395static int serprog_init(struct flashprog_programmer *const prog)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000396{
397 uint16_t iface;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000398 unsigned char pgmname[17];
399 unsigned char rbuf[3];
400 unsigned char c;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000401 char *device;
Felix Singer815eb792022-08-19 01:02:42 +0200402 bool have_device = false;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000403
Stefan Tauner72587f82016-01-04 03:05:15 +0000404 /* the parameter is either of format "dev=/dev/device[:baud]" or "ip=ip:port" */
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000405 device = extract_programmer_param("dev");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000406 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000407 char *baud_str = strstr(device, ":");
408 if (baud_str != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000409 /* Split device from baudrate. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000410 *baud_str = '\0';
411 baud_str++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000412 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000413 int baud;
414 /* Convert baud string to value.
415 * baud_str is either NULL (if strstr can't find the colon), points to the \0 after the colon
416 * if no characters where given after the colon, or a string to convert... */
417 if (baud_str == NULL || *baud_str == '\0') {
418 baud = -1;
419 msg_pdbg("No baudrate specified, using the hardware's defaults.\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000420 } else {
Stefan Tauner72587f82016-01-04 03:05:15 +0000421 baud = atoi(baud_str); // FIXME: replace atoi with strtoul
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000422 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000423 if (strlen(device) > 0) {
424 sp_fd = sp_openserport(device, baud);
Stefan Tauneracfc4c62012-11-30 16:46:45 +0000425 if (sp_fd == SER_INV_FD) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000426 free(device);
427 return 1;
428 }
Felix Singer815eb792022-08-19 01:02:42 +0200429 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000430 }
431 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000432
433#if !IS_WINDOWS
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000434 if (device && !strlen(device)) {
435 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200436 "Use flashprog -p serprog:dev=/dev/device[:baud]\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000437 free(device);
438 return 1;
439 }
440 free(device);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000441
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000442 device = extract_programmer_param("ip");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000443 if (have_device && device) {
444 msg_perr("Error: Both host and device specified.\n"
445 "Please use either dev= or ip= but not both.\n");
446 free(device);
447 return 1;
448 }
449 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000450 char *port = strstr(device, ":");
451 if (port != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000452 /* Split host from port. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000453 *port = '\0';
454 port++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000455 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000456 if (!port || !strlen(port)) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000457 msg_perr("Error: No port specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200458 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000459 free(device);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000460 return 1;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000461 }
462 if (strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000463 sp_fd = sp_opensocket(device, atoi(port)); // FIXME: replace atoi with strtoul
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000464 if (sp_fd < 0) {
465 free(device);
466 return 1;
467 }
Felix Singer815eb792022-08-19 01:02:42 +0200468 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000469 }
470 }
471 if (device && !strlen(device)) {
472 msg_perr("Error: No host specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200473 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000474 free(device);
475 return 1;
476 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000477#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000478 free(device);
479
480 if (!have_device) {
Urja Rannikko27b431b2016-01-04 03:05:23 +0000481#if IS_WINDOWS
482 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200483 "Use flashprog -p serprog:dev=comN[:baud]\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000484#else
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000485 msg_perr("Error: Neither host nor device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200486 "Use flashprog -p serprog:dev=/dev/device:baud or "
487 "flashprog -p serprog:ip=ipaddr:port\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000488#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000489 return 1;
490 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000491
Nico Huber383b7fe2023-02-12 00:38:55 +0100492 msg_pdbg(MSGHEADER "connected");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000493
494 sp_check_avail_automatic = 0;
495
Niklas Söderlund7145a502012-09-07 07:07:07 +0000496 if (sp_synchronize())
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000497 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000498
Sean Nelson74e8af52010-01-10 01:06:23 +0000499 msg_pdbg(MSGHEADER "Synchronized\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000500
501 if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000502 msg_perr("Error: NAK to query interface version\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000503 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000504 }
505
506 if (iface != 1) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000507 msg_perr("Error: Unknown interface version: %d\n", iface);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000508 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000509 }
510
Sean Nelson74e8af52010-01-10 01:06:23 +0000511 msg_pdbg(MSGHEADER "Interface version ok.\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000512
513 if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000514 msg_perr("Error: query command map not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000515 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000516 }
517
518 sp_check_avail_automatic = 1;
519
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000520 /* FIXME: This assumes that serprog device bustypes are always
Nico Huberc3b02dc2023-08-12 01:13:45 +0200521 * identical with flashprog bustype enums and that they all fit
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000522 * in a single byte.
523 */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000524 if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000525 msg_pwarn("Warning: NAK to query supported buses\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000526 c = BUS_NONSPI; /* A reasonable default for now. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000527 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000528 serprog_buses_supported = c;
529
Stefan Tauner31019d42011-10-22 21:45:27 +0000530 msg_pdbg(MSGHEADER "Bus support: parallel=%s, LPC=%s, FWH=%s, SPI=%s\n",
531 (c & BUS_PARALLEL) ? "on" : "off",
532 (c & BUS_LPC) ? "on" : "off",
533 (c & BUS_FWH) ? "on" : "off",
534 (c & BUS_SPI) ? "on" : "off");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000535 /* Check for the minimum operational set of commands. */
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000536 if (serprog_buses_supported & BUS_SPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000537 uint8_t bt = BUS_SPI;
Riku Viitanenddb6d922024-01-15 19:15:49 +0200538 char *spispeed, *cs;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000539 if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
540 msg_perr("Error: SPI operation not supported while the "
541 "bustype is SPI\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000542 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000543 }
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000544 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000545 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000546 /* Success of any of these commands is optional. We don't need
547 the programmer to tell us its limits, but if it doesn't, we
548 will assume stuff, so it's in the programmers best interest
549 to tell us. */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000550 if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
551 uint32_t v;
552 v = ((unsigned int)(rbuf[0]) << 0);
553 v |= ((unsigned int)(rbuf[1]) << 8);
554 v |= ((unsigned int)(rbuf[2]) << 16);
555 if (v == 0)
556 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000557 spi_master_serprog.max_data_write = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000558 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", v);
559 }
560 if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
561 uint32_t v;
562 v = ((unsigned int)(rbuf[0]) << 0);
563 v |= ((unsigned int)(rbuf[1]) << 8);
564 v |= ((unsigned int)(rbuf[2]) << 16);
565 if (v == 0)
566 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000567 spi_master_serprog.max_data_read = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000568 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
569 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000570 spispeed = extract_programmer_param("spispeed");
571 if (spispeed && strlen(spispeed)) {
572 uint32_t f_spi_req, f_spi;
573 uint8_t buf[4];
574 char *f_spi_suffix;
575
576 errno = 0;
577 f_spi_req = strtol(spispeed, &f_spi_suffix, 0);
578 if (errno != 0 || spispeed == f_spi_suffix) {
579 msg_perr("Error: Could not convert 'spispeed'.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000580 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000581 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000582 }
583 if (strlen(f_spi_suffix) == 1) {
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000584 if (!strcasecmp(f_spi_suffix, "M")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000585 f_spi_req *= 1000000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000586 } else if (!strcasecmp(f_spi_suffix, "k")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000587 f_spi_req *= 1000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000588 } else {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000589 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 } else if (strlen(f_spi_suffix) > 1) {
594 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000595 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000596 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000597 }
598
599 buf[0] = (f_spi_req >> (0 * 8)) & 0xFF;
600 buf[1] = (f_spi_req >> (1 * 8)) & 0xFF;
601 buf[2] = (f_spi_req >> (2 * 8)) & 0xFF;
602 buf[3] = (f_spi_req >> (3 * 8)) & 0xFF;
603
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000604 if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000605 msg_pwarn(MSGHEADER "Warning: Setting the SPI clock rate is not supported!\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000606 } else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) == 0) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000607 f_spi = buf[0];
608 f_spi |= buf[1] << (1 * 8);
609 f_spi |= buf[2] << (2 * 8);
610 f_spi |= buf[3] << (3 * 8);
611 msg_pdbg(MSGHEADER "Requested to set SPI clock frequency to %u Hz. "
612 "It was actually set to %u Hz\n", f_spi_req, f_spi);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000613 } else {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000614 msg_pwarn(MSGHEADER "Setting SPI clock rate to %u Hz failed!\n", f_spi_req);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000615 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000616 }
617 free(spispeed);
Riku Viitanenddb6d922024-01-15 19:15:49 +0200618 cs = extract_programmer_param("cs");
619 if (cs) {
620 char *endptr = NULL;
621 errno = 0;
622 unsigned long cs_num = strtoul(cs, &endptr, 0);
623 if (!*cs || errno || *endptr || cs_num > 255) {
624 msg_perr("Error: Invalid chip select requested! "
625 "Only 0-255 are valid.\n");
626 free(cs);
627 goto init_err_cleanup_exit;
628 }
629 free(cs);
630 if (!sp_check_commandavail(S_CMD_S_SPI_CS)) {
631 msg_perr("Error: Setting SPI chip select is not supported!\n");
632 goto init_err_cleanup_exit;
633 }
634 msg_pdbg(MSGHEADER "Requested to use chip select %lu.\n", cs_num);
635 uint8_t cs_num8 = cs_num;
636 if (sp_docommand(S_CMD_S_SPI_CS, 1, &cs_num8, 0, NULL)) {
637 msg_perr("Error: Chip select %u not supported "
638 "by programmer!\n", cs_num8);
639 goto init_err_cleanup_exit;
640 }
641 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000642 bt = serprog_buses_supported;
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000643 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000644 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000645 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000646
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000647 if (serprog_buses_supported & BUS_NONSPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000648 if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
649 msg_perr("Error: Initialize operation buffer "
650 "not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000651 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000652 }
653
654 if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
655 msg_perr("Error: Write to opbuf: "
656 "delay not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000657 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000658 }
659
660 /* S_CMD_O_EXEC availability checked later. */
661
662 if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
663 msg_perr("Error: Single byte read not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000664 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000665 }
666 /* This could be translated to single byte reads (if missing),
667 * but now we don't support that. */
668 if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
669 msg_perr("Error: Read n bytes 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 if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
673 msg_perr("Error: Write to opbuf: "
674 "write byte not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000675 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000676 }
677
678 if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
679 msg_pdbg(MSGHEADER "Write-n not supported");
680 sp_max_write_n = 0;
681 } else {
682 sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
683 sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
684 sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
685 if (!sp_max_write_n) {
686 sp_max_write_n = (1 << 24);
687 }
688 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n",
689 sp_max_write_n);
690 sp_write_n_buf = malloc(sp_max_write_n);
691 if (!sp_write_n_buf) {
692 msg_perr("Error: cannot allocate memory for "
693 "Write-n buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000694 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000695 }
696 sp_write_n_bytes = 0;
697 }
698
699 if (sp_check_commandavail(S_CMD_Q_RDNMAXLEN) &&
700 (sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf) == 0)) {
701 sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
702 sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
703 sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
704 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n",
705 sp_max_read_n ? sp_max_read_n : (1 << 24));
706 } else {
707 msg_pdbg(MSGHEADER "Maximum read-n length "
708 "not reported\n");
709 sp_max_read_n = 0;
710 }
711
Urja Rannikkof3196df2009-07-21 13:02:59 +0000712 }
713
714 if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000715 msg_pwarn("Warning: NAK to query programmer name\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000716 strcpy((char *)pgmname, "(unknown)");
717 }
718 pgmname[16] = 0;
Stefan Tauner31019d42011-10-22 21:45:27 +0000719 msg_pinfo(MSGHEADER "Programmer name is \"%s\"\n", pgmname);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000720
721 if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000722 msg_pwarn("Warning: NAK to query serial buffer size\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000723 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000724 msg_pdbg(MSGHEADER "Serial buffer size is %d\n",
Urja Rannikkof3196df2009-07-21 13:02:59 +0000725 sp_device_serbuf_size);
726
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000727 if (sp_check_commandavail(S_CMD_O_INIT)) {
728 /* This would be inconsistent. */
729 if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
730 msg_perr("Error: Execute operation buffer not "
731 "supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000732 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000733 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000734
735 if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
736 msg_perr("Error: NAK to initialize operation buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000737 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000738 }
739
740 if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
741 &sp_device_opbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000742 msg_pwarn("Warning: NAK to query operation buffer size\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000743 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000744 msg_pdbg(MSGHEADER "operation buffer size is %d\n",
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000745 sp_device_opbuf_size);
Elyes HAOUAS124ef382018-03-27 12:15:09 +0200746 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000747
Stefan Tauner92fefc92012-10-27 00:34:23 +0000748 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
749 uint8_t en = 1;
750 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &en, 0, NULL) != 0) {
751 msg_perr("Error: could not enable output buffers\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000752 goto init_err_cleanup_exit;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000753 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000754 msg_pdbg(MSGHEADER "Output drivers enabled\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000755 }
756 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000757 msg_pdbg(MSGHEADER "Warning: Programmer does not support toggling its output drivers\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000758 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000759 sp_prev_was_write = 0;
760 sp_streamed_transmit_ops = 0;
761 sp_streamed_transmit_bytes = 0;
762 sp_opbuf_usage = 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000763
764 if (register_shutdown(serprog_shutdown, NULL))
765 goto init_err_cleanup_exit;
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000766 if (serprog_buses_supported & BUS_SPI)
Nico Huber89569d62023-01-12 23:31:40 +0100767 register_spi_master(&spi_master_serprog, 0, NULL);
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000768 if (serprog_buses_supported & BUS_NONSPI)
Nico Huber89569d62023-01-12 23:31:40 +0100769 register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI, 0, NULL);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000770 return 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000771
772init_err_cleanup_exit:
773 serprog_shutdown(NULL);
774 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000775}
776
Nico Huberc3b02dc2023-08-12 01:13:45 +0200777/* Move an in flashprog buffer existing write-n operation to the on-device operation buffer. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000778static int sp_pass_writen(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000779{
780 unsigned char header[7];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000781 msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
782 if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
783 if (sp_flush_stream() != 0) {
784 return 1;
785 }
786 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000787 /* In case it's just a single byte send it as a single write. */
788 if (sp_write_n_bytes == 1) {
789 sp_write_n_bytes = 0;
790 header[0] = (sp_write_n_addr >> 0) & 0xFF;
791 header[1] = (sp_write_n_addr >> 8) & 0xFF;
792 header[2] = (sp_write_n_addr >> 16) & 0xFF;
793 header[3] = sp_write_n_buf[0];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000794 if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
795 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000796 sp_opbuf_usage += 5;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000797 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000798 }
799 header[0] = S_CMD_O_WRITEN;
800 header[1] = (sp_write_n_bytes >> 0) & 0xFF;
801 header[2] = (sp_write_n_bytes >> 8) & 0xFF;
802 header[3] = (sp_write_n_bytes >> 16) & 0xFF;
803 header[4] = (sp_write_n_addr >> 0) & 0xFF;
804 header[5] = (sp_write_n_addr >> 8) & 0xFF;
805 header[6] = (sp_write_n_addr >> 16) & 0xFF;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000806 if (serialport_write(header, 7) != 0) {
807 msg_perr(MSGHEADER "Error: cannot write write-n command\n");
808 return 1;
809 }
810 if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
811 msg_perr(MSGHEADER "Error: cannot write write-n data");
812 return 1;
813 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000814 sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
815 sp_streamed_transmit_ops += 1;
816 sp_opbuf_usage += 7 + sp_write_n_bytes;
817 sp_write_n_bytes = 0;
818 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000819 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000820}
821
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000822static int sp_execute_opbuf_noflush(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000823{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000824 if ((sp_max_write_n) && (sp_write_n_bytes)) {
825 if (sp_pass_writen() != 0) {
826 msg_perr("Error: could not transfer write buffer\n");
827 return 1;
828 }
829 }
830 if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
831 msg_perr("Error: could not execute command buffer\n");
832 return 1;
833 }
834 msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000835 sp_opbuf_usage = 0;
836 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000837 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000838}
839
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000840static int sp_execute_opbuf(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000841{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000842 if (sp_execute_opbuf_noflush() != 0)
843 return 1;
844 if (sp_flush_stream() != 0)
845 return 1;
846
847 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000848}
849
David Hendricks8bb20212011-06-14 01:35:36 +0000850static int serprog_shutdown(void *data)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000851{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000852 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000853 if (sp_execute_opbuf() != 0)
854 msg_pwarn("Could not flush command buffer.\n");
Stefan Tauner92fefc92012-10-27 00:34:23 +0000855 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
856 uint8_t dis = 0;
857 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
858 msg_pdbg(MSGHEADER "Output drivers disabled\n");
859 else
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000860 msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
Stefan Tauner92fefc92012-10-27 00:34:23 +0000861 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000862 /* FIXME: fix sockets on windows(?), especially closing */
863 serialport_shutdown(&sp_fd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000864 if (sp_max_write_n)
865 free(sp_write_n_buf);
866 return 0;
867}
868
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000869static int sp_check_opbuf_usage(int bytes_to_be_added)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000870{
871 if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000872 /* If this happens in the middle of a page load the page load will probably fail. */
873 msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
874 if (sp_execute_opbuf() != 0)
875 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000876 }
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000877 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000878}
879
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000880static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
881 chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000882{
Sean Nelson74e8af52010-01-10 01:06:23 +0000883 msg_pspew("%s\n", __func__);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000884 if (sp_max_write_n) {
885 if ((sp_prev_was_write)
886 && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
887 sp_write_n_buf[sp_write_n_bytes++] = val;
888 } else {
889 if ((sp_prev_was_write) && (sp_write_n_bytes))
890 sp_pass_writen();
891 sp_prev_was_write = 1;
892 sp_write_n_addr = addr;
893 sp_write_n_bytes = 1;
894 sp_write_n_buf[0] = val;
895 }
896 sp_check_opbuf_usage(7 + sp_write_n_bytes);
897 if (sp_write_n_bytes >= sp_max_write_n)
898 sp_pass_writen();
899 } else {
900 /* We will have to do single writeb ops. */
901 unsigned char writeb_parm[4];
902 sp_check_opbuf_usage(6);
903 writeb_parm[0] = (addr >> 0) & 0xFF;
904 writeb_parm[1] = (addr >> 8) & 0xFF;
905 writeb_parm[2] = (addr >> 16) & 0xFF;
906 writeb_parm[3] = val;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000907 sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000908 sp_opbuf_usage += 5;
909 }
910}
911
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000912static uint8_t serprog_chip_readb(const struct flashctx *flash,
913 const chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000914{
915 unsigned char c;
916 unsigned char buf[3];
917 /* Will stream the read operation - eg. add it to the stream buffer, *
918 * then flush the buffer, then read the read answer. */
919 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
920 sp_execute_opbuf_noflush();
921 buf[0] = ((addr >> 0) & 0xFF);
922 buf[1] = ((addr >> 8) & 0xFF);
923 buf[2] = ((addr >> 16) & 0xFF);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000924 sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
925 sp_flush_stream(); // FIXME: return error
Stefan Tauner79587f52013-04-01 00:45:51 +0000926 if (serialport_read(&c, 1) != 0)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000927 msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
Stefan Taunerc2333752013-07-13 23:31:37 +0000928 msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000929 return c;
930}
931
Uwe Hermann4e3d0b32010-03-25 23:18:41 +0000932/* Local version that really does the job, doesn't care of max_read_n. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000933static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000934{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000935 unsigned char sbuf[6];
Stefan Tauner0554ca52013-07-25 22:54:25 +0000936 msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000937 /* Stream the read-n -- as above. */
938 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
939 sp_execute_opbuf_noflush();
940 sbuf[0] = ((addr >> 0) & 0xFF);
941 sbuf[1] = ((addr >> 8) & 0xFF);
942 sbuf[2] = ((addr >> 16) & 0xFF);
943 sbuf[3] = ((len >> 0) & 0xFF);
944 sbuf[4] = ((len >> 8) & 0xFF);
945 sbuf[5] = ((len >> 16) & 0xFF);
946 sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000947 if (sp_flush_stream() != 0)
948 return 1;
949 if (serialport_read(buf, len) != 0) {
950 msg_perr(MSGHEADER "Error: cannot read read-n data");
951 return 1;
952 }
953 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000954}
955
956/* The externally called version that makes sure that max_read_n is obeyed. */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000957static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
958 const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000959{
960 size_t lenm = len;
961 chipaddr addrm = addr;
Stefan Tauner31019d42011-10-22 21:45:27 +0000962 while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000963 sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000964 addrm += sp_max_read_n;
965 lenm -= sp_max_read_n;
966 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000967 if (lenm)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000968 sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000969}
970
Thomas Heijligencc853d82021-05-04 15:32:17 +0200971static void serprog_delay(unsigned int usecs)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000972{
973 unsigned char buf[4];
Stefan Tauner31019d42011-10-22 21:45:27 +0000974 msg_pspew("%s usecs=%d\n", __func__, usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000975 if (!sp_check_commandavail(S_CMD_O_DELAY)) {
Stefan Taunerd7d423b2012-10-20 09:13:16 +0000976 msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
Stefan Tauner31019d42011-10-22 21:45:27 +0000977 internal_delay(usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000978 return;
979 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000980 if ((sp_max_write_n) && (sp_write_n_bytes))
981 sp_pass_writen();
982 sp_check_opbuf_usage(5);
Stefan Tauner31019d42011-10-22 21:45:27 +0000983 buf[0] = ((usecs >> 0) & 0xFF);
984 buf[1] = ((usecs >> 8) & 0xFF);
985 buf[2] = ((usecs >> 16) & 0xFF);
986 buf[3] = ((usecs >> 24) & 0xFF);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000987 sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
988 sp_opbuf_usage += 5;
989 sp_prev_was_write = 0;
990}
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000991
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000992static int serprog_spi_send_command(const struct flashctx *flash,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000993 unsigned int writecnt, unsigned int readcnt,
994 const unsigned char *writearr,
995 unsigned char *readarr)
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000996{
997 unsigned char *parmbuf;
998 int ret;
999 msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
Stefan Taunerbdead0d2013-08-24 02:10:18 +00001000 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
1001 if (sp_execute_opbuf() != 0) {
1002 msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
1003 return 1;
1004 }
1005 }
1006
Urja Rannikkoc93f5f12011-09-15 23:38:14 +00001007 parmbuf = malloc(writecnt + 6);
Stefan Taunerbdead0d2013-08-24 02:10:18 +00001008 if (!parmbuf) {
1009 msg_perr("Error: could not allocate SPI send param buffer.\n");
1010 return 1;
1011 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +00001012 parmbuf[0] = (writecnt >> 0) & 0xFF;
1013 parmbuf[1] = (writecnt >> 8) & 0xFF;
1014 parmbuf[2] = (writecnt >> 16) & 0xFF;
1015 parmbuf[3] = (readcnt >> 0) & 0xFF;
1016 parmbuf[4] = (readcnt >> 8) & 0xFF;
1017 parmbuf[5] = (readcnt >> 16) & 0xFF;
1018 memcpy(parmbuf + 6, writearr, writecnt);
1019 ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
1020 readarr);
1021 free(parmbuf);
1022 return ret;
1023}
1024
Thomas Heijligencc853d82021-05-04 15:32:17 +02001025static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001026{
1027 /* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
1028 * correctly (usually setting them to one either in software (for FWH/LPC) or relying on the fact that
1029 * the hardware observes a subset of the address bits only). Combined with the standard mapping of
Nico Huberc3b02dc2023-08-12 01:13:45 +02001030 * 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 +00001031 * needed for non-SPI chips). Below we make sure that the requested range is within this window. */
1032 if ((phys_addr & 0xFF000000) == 0xFF000000) {
1033 return (void*)phys_addr;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001034 }
Elyes HAOUASec819d62019-06-09 17:50:51 +02001035 msg_pwarn(MSGHEADER "requested mapping %s is incompatible: 0x%zx bytes at 0x%0*" PRIxPTR ".\n",
1036 descr, len, PRIxPTR_WIDTH, phys_addr);
1037 return NULL;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001038}
Thomas Heijligencc853d82021-05-04 15:32:17 +02001039
1040const struct programmer_entry programmer_serprog = {
1041 .name = "serprog",
1042 .type = OTHER,
1043 /* FIXME */
1044 .devs.note = "All programmer devices speaking the serprog protocol\n",
1045 .init = serprog_init,
Thomas Heijligencc853d82021-05-04 15:32:17 +02001046 .delay = serprog_delay,
1047};