blob: 458fa912f563833b0b546c7e4ec1d5a08556d385 [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
Uwe Hermann4e3d0b32010-03-25 23:18:41 +0000151/* Synchronize: a bit tricky algorithm that tries to (and in my tests has *
Urja Rannikkof3196df2009-07-21 13:02:59 +0000152 * always succeeded in) bring the serial protocol to known waiting-for- *
Stefan Taunerae3d8372013-04-01 00:45:45 +0000153 * command state - uses nonblocking I/O - rest of the driver uses *
Urja Rannikkof3196df2009-07-21 13:02:59 +0000154 * blocking read - TODO: add an alarm() timer for the rest of the app on *
155 * serial operations, though not such a big issue as the first thing to *
156 * do is synchronize (eg. check that device is alive). */
Niklas Söderlund7145a502012-09-07 07:07:07 +0000157static int sp_synchronize(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000158{
159 int i;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000160 unsigned char buf[8];
Urja Rannikkof3196df2009-07-21 13:02:59 +0000161 /* First sends 8 NOPs, then flushes the return data - should cause *
162 * the device serial parser to get to a sane state, unless if it *
163 * is waiting for a real long write-n. */
164 memset(buf, S_CMD_NOP, 8);
Stefan Taunerae3d8372013-04-01 00:45:45 +0000165 if (serialport_write_nonblock(buf, 8, 1, NULL) != 0) {
Niklas Söderlund7145a502012-09-07 07:07:07 +0000166 goto err_out;
167 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000168 /* A second should be enough to get all the answers to the buffer */
Stefan Tauner79587f52013-04-01 00:45:51 +0000169 internal_delay(1000 * 1000);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000170 sp_flush_incoming();
171
Cristian Măgherușan-Stanciu9932c7b2011-07-07 19:56:58 +0000172 /* Then try up to 8 times to send syncnop and get the correct special *
173 * return of NAK+ACK. Timing note: up to 10 characters, 10*50ms = *
174 * up to 500ms per try, 8*0.5s = 4s; +1s (above) = up to 5s sync *
175 * attempt, ~1s if immediate success. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000176 for (i = 0; i < 8; i++) {
177 int n;
178 unsigned char c = S_CMD_SYNCNOP;
Stefan Taunerae3d8372013-04-01 00:45:45 +0000179 if (serialport_write_nonblock(&c, 1, 1, NULL) != 0) {
Niklas Söderlund7145a502012-09-07 07:07:07 +0000180 goto err_out;
181 }
Sean Nelson74e8af52010-01-10 01:06:23 +0000182 msg_pdbg(".");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000183 fflush(stdout);
184 for (n = 0; n < 10; n++) {
Stefan Tauner00e16082013-04-01 00:45:38 +0000185 int ret = serialport_read_nonblock(&c, 1, 50, NULL);
Niklas Söderlund7145a502012-09-07 07:07:07 +0000186 if (ret < 0)
187 goto err_out;
188 if (ret > 0 || c != S_NAK)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000189 continue;
Stefan Tauner00e16082013-04-01 00:45:38 +0000190 ret = serialport_read_nonblock(&c, 1, 20, NULL);
Niklas Söderlund7145a502012-09-07 07:07:07 +0000191 if (ret < 0)
192 goto err_out;
193 if (ret > 0 || c != S_ACK)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000194 continue;
195 c = S_CMD_SYNCNOP;
Stefan Taunerae3d8372013-04-01 00:45:45 +0000196 if (serialport_write_nonblock(&c, 1, 1, NULL) != 0) {
197 goto err_out;
Niklas Söderlund7145a502012-09-07 07:07:07 +0000198 }
Stefan Tauner00e16082013-04-01 00:45:38 +0000199 ret = serialport_read_nonblock(&c, 1, 500, NULL);
Niklas Söderlund7145a502012-09-07 07:07:07 +0000200 if (ret < 0)
201 goto err_out;
202 if (ret > 0 || c != S_NAK)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000203 break; /* fail */
Stefan Tauner00e16082013-04-01 00:45:38 +0000204 ret = serialport_read_nonblock(&c, 1, 100, NULL);
Niklas Söderlund7145a502012-09-07 07:07:07 +0000205 if (ret > 0 || ret < 0)
206 goto err_out;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000207 if (c != S_ACK)
208 break; /* fail */
Sean Nelson74e8af52010-01-10 01:06:23 +0000209 msg_pdbg("\n");
Niklas Söderlund7145a502012-09-07 07:07:07 +0000210 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000211 }
212 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000213err_out:
214 msg_perr("Error: cannot synchronize protocol - check communications and reset device?\n");
215 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000216}
217
218static int sp_check_commandavail(uint8_t command)
219{
220 int byteoffs, bitoffs;
221 byteoffs = command / 8;
222 bitoffs = command % 8;
223 return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
224}
225
226static int sp_automatic_cmdcheck(uint8_t cmd)
227{
228 if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000229 msg_pdbg("Warning: Automatic command availability check failed "
Stefan Taunere34e3e82013-01-01 00:06:51 +0000230 "for cmd 0x%02x - won't execute cmd\n", cmd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000231 return 1;
232 }
233 return 0;
234}
235
236static int sp_docommand(uint8_t command, uint32_t parmlen,
Stefan Tauner31019d42011-10-22 21:45:27 +0000237 uint8_t *params, uint32_t retlen, void *retparms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000238{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000239 unsigned char c;
240 if (sp_automatic_cmdcheck(command))
241 return 1;
Stefan Tauner79587f52013-04-01 00:45:51 +0000242 if (serialport_write(&command, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000243 msg_perr("Error: cannot write op code: %s\n", strerror(errno));
244 return 1;
245 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000246 if (serialport_write(params, parmlen) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000247 msg_perr("Error: cannot write parameters: %s\n", strerror(errno));
248 return 1;
249 }
Stefan Tauner79587f52013-04-01 00:45:51 +0000250 if (serialport_read(&c, 1) != 0) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000251 msg_perr("Error: cannot read from device: %s\n", strerror(errno));
252 return 1;
253 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000254 if (c == S_NAK)
255 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000256 if (c != S_ACK) {
Stefan Tauner23e10b82016-01-23 16:16:49 +0000257 msg_perr("Error: invalid response 0x%02X from device (to command 0x%02X)\n", c, command);
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000258 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000259 }
260 if (retlen) {
Stefan Tauner79587f52013-04-01 00:45:51 +0000261 if (serialport_read(retparms, retlen) != 0) {
262 msg_perr("Error: cannot read return parameters: %s\n", strerror(errno));
263 return 1;
264 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000265 }
266 return 0;
267}
268
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000269static int sp_flush_stream(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000270{
271 if (sp_streamed_transmit_ops)
272 do {
273 unsigned char c;
Stefan Tauner79587f52013-04-01 00:45:51 +0000274 if (serialport_read(&c, 1) != 0) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000275 msg_perr("Error: cannot read from device (flushing stream)");
276 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000277 }
278 if (c == S_NAK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000279 msg_perr("Error: NAK to a stream buffer operation\n");
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000280 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000281 }
282 if (c != S_ACK) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000283 msg_perr("Error: Invalid reply 0x%02X from device\n", c);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000284 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000285 }
286 } while (--sp_streamed_transmit_ops);
287 sp_streamed_transmit_ops = 0;
288 sp_streamed_transmit_bytes = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000289 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000290}
291
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000292static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000293{
294 uint8_t *sp;
295 if (sp_automatic_cmdcheck(cmd))
296 return 1;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000297
Urja Rannikkof3196df2009-07-21 13:02:59 +0000298 sp = malloc(1 + parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000299 if (!sp) {
300 msg_perr("Error: cannot malloc command buffer\n");
301 return 1;
302 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000303 sp[0] = cmd;
aarya885917c2022-03-10 09:16:44 +0530304 if (parms)
305 memcpy(&(sp[1]), parms, parmlen);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000306
307 if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) {
308 if (sp_flush_stream() != 0) {
309 free(sp);
310 return 1;
311 }
312 }
313 if (serialport_write(sp, 1 + parmlen) != 0) {
314 msg_perr("Error: cannot write command\n");
315 free(sp);
316 return 1;
317 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000318 sp_streamed_transmit_ops += 1;
319 sp_streamed_transmit_bytes += 1 + parmlen;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000320
321 free(sp);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000322 return 0;
323}
324
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000325static int serprog_spi_send_command(const struct flashctx *flash,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000326 unsigned int writecnt, unsigned int readcnt,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000327 const unsigned char *writearr,
328 unsigned char *readarr);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000329static struct spi_master spi_master_serprog = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100330 .features = SPI_MASTER_4BA,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000331 .max_data_read = MAX_DATA_READ_UNLIMITED,
332 .max_data_write = MAX_DATA_WRITE_UNLIMITED,
333 .command = serprog_spi_send_command,
334 .multicommand = default_spi_send_multicommand,
Urja Rannikko731316a2017-06-15 13:32:01 +0300335 .read = default_spi_read,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000336 .write_256 = default_spi_write_256,
Aarya Chaumal0cea7532022-07-04 18:21:50 +0530337 .probe_opcode = default_spi_probe_opcode,
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000338};
339
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000340static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
341 chipaddr addr);
342static uint8_t serprog_chip_readb(const struct flashctx *flash,
343 const chipaddr addr);
344static void serprog_chip_readn(const struct flashctx *flash, uint8_t *buf,
345 const chipaddr addr, size_t len);
Nico Huber0e76d992023-01-12 20:22:55 +0100346static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len);
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000347static const struct par_master par_master_serprog = {
Thomas Heijligen43040f22022-06-23 14:38:35 +0200348 .chip_readb = serprog_chip_readb,
349 .chip_readw = fallback_chip_readw,
350 .chip_readl = fallback_chip_readl,
351 .chip_readn = serprog_chip_readn,
352 .chip_writeb = serprog_chip_writeb,
353 .chip_writew = fallback_chip_writew,
354 .chip_writel = fallback_chip_writel,
355 .chip_writen = fallback_chip_writen,
Nico Huber0e76d992023-01-12 20:22:55 +0100356 .map_flash = serprog_map,
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000357};
358
359static enum chipbustype serprog_buses_supported = BUS_NONE;
360
Thomas Heijligencc853d82021-05-04 15:32:17 +0200361static int serprog_init(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000362{
363 uint16_t iface;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000364 unsigned char pgmname[17];
365 unsigned char rbuf[3];
366 unsigned char c;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000367 char *device;
Felix Singer815eb792022-08-19 01:02:42 +0200368 bool have_device = false;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000369
Stefan Tauner72587f82016-01-04 03:05:15 +0000370 /* the parameter is either of format "dev=/dev/device[:baud]" or "ip=ip:port" */
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000371 device = extract_programmer_param("dev");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000372 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000373 char *baud_str = strstr(device, ":");
374 if (baud_str != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000375 /* Split device from baudrate. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000376 *baud_str = '\0';
377 baud_str++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000378 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000379 int baud;
380 /* Convert baud string to value.
381 * baud_str is either NULL (if strstr can't find the colon), points to the \0 after the colon
382 * if no characters where given after the colon, or a string to convert... */
383 if (baud_str == NULL || *baud_str == '\0') {
384 baud = -1;
385 msg_pdbg("No baudrate specified, using the hardware's defaults.\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000386 } else {
Stefan Tauner72587f82016-01-04 03:05:15 +0000387 baud = atoi(baud_str); // FIXME: replace atoi with strtoul
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000388 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000389 if (strlen(device) > 0) {
390 sp_fd = sp_openserport(device, baud);
Stefan Tauneracfc4c62012-11-30 16:46:45 +0000391 if (sp_fd == SER_INV_FD) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000392 free(device);
393 return 1;
394 }
Felix Singer815eb792022-08-19 01:02:42 +0200395 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000396 }
397 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000398
399#if !IS_WINDOWS
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000400 if (device && !strlen(device)) {
401 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200402 "Use flashprog -p serprog:dev=/dev/device[:baud]\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000403 free(device);
404 return 1;
405 }
406 free(device);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000407
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000408 device = extract_programmer_param("ip");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000409 if (have_device && device) {
410 msg_perr("Error: Both host and device specified.\n"
411 "Please use either dev= or ip= but not both.\n");
412 free(device);
413 return 1;
414 }
415 if (device && strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000416 char *port = strstr(device, ":");
417 if (port != NULL) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000418 /* Split host from port. */
Stefan Tauner72587f82016-01-04 03:05:15 +0000419 *port = '\0';
420 port++;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000421 }
Stefan Tauner72587f82016-01-04 03:05:15 +0000422 if (!port || !strlen(port)) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000423 msg_perr("Error: No port specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200424 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000425 free(device);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000426 return 1;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000427 }
428 if (strlen(device)) {
Stefan Tauner72587f82016-01-04 03:05:15 +0000429 sp_fd = sp_opensocket(device, atoi(port)); // FIXME: replace atoi with strtoul
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000430 if (sp_fd < 0) {
431 free(device);
432 return 1;
433 }
Felix Singer815eb792022-08-19 01:02:42 +0200434 have_device = true;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000435 }
436 }
437 if (device && !strlen(device)) {
438 msg_perr("Error: No host specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200439 "Use flashprog -p serprog:ip=ipaddr:port\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000440 free(device);
441 return 1;
442 }
Urja Rannikko27b431b2016-01-04 03:05:23 +0000443#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000444 free(device);
445
446 if (!have_device) {
Urja Rannikko27b431b2016-01-04 03:05:23 +0000447#if IS_WINDOWS
448 msg_perr("Error: No device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200449 "Use flashprog -p serprog:dev=comN[:baud]\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000450#else
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000451 msg_perr("Error: Neither host nor device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200452 "Use flashprog -p serprog:dev=/dev/device:baud or "
453 "flashprog -p serprog:ip=ipaddr:port\n");
Urja Rannikko27b431b2016-01-04 03:05:23 +0000454#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000455 return 1;
456 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000457
Sean Nelson74e8af52010-01-10 01:06:23 +0000458 msg_pdbg(MSGHEADER "connected - attempting to synchronize\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000459
460 sp_check_avail_automatic = 0;
461
Niklas Söderlund7145a502012-09-07 07:07:07 +0000462 if (sp_synchronize())
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000463 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000464
Sean Nelson74e8af52010-01-10 01:06:23 +0000465 msg_pdbg(MSGHEADER "Synchronized\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000466
467 if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000468 msg_perr("Error: NAK to query interface version\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000469 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000470 }
471
472 if (iface != 1) {
Stefan Tauner31019d42011-10-22 21:45:27 +0000473 msg_perr("Error: Unknown interface version: %d\n", iface);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000474 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000475 }
476
Sean Nelson74e8af52010-01-10 01:06:23 +0000477 msg_pdbg(MSGHEADER "Interface version ok.\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000478
479 if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
Sean Nelson74e8af52010-01-10 01:06:23 +0000480 msg_perr("Error: query command map not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000481 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000482 }
483
484 sp_check_avail_automatic = 1;
485
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000486 /* FIXME: This assumes that serprog device bustypes are always
Nico Huberc3b02dc2023-08-12 01:13:45 +0200487 * identical with flashprog bustype enums and that they all fit
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000488 * in a single byte.
489 */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000490 if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000491 msg_pwarn("Warning: NAK to query supported buses\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000492 c = BUS_NONSPI; /* A reasonable default for now. */
Urja Rannikkof3196df2009-07-21 13:02:59 +0000493 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000494 serprog_buses_supported = c;
495
Stefan Tauner31019d42011-10-22 21:45:27 +0000496 msg_pdbg(MSGHEADER "Bus support: parallel=%s, LPC=%s, FWH=%s, SPI=%s\n",
497 (c & BUS_PARALLEL) ? "on" : "off",
498 (c & BUS_LPC) ? "on" : "off",
499 (c & BUS_FWH) ? "on" : "off",
500 (c & BUS_SPI) ? "on" : "off");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000501 /* Check for the minimum operational set of commands. */
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000502 if (serprog_buses_supported & BUS_SPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000503 uint8_t bt = BUS_SPI;
Riku Viitanenddb6d922024-01-15 19:15:49 +0200504 char *spispeed, *cs;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000505 if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
506 msg_perr("Error: SPI operation not supported while the "
507 "bustype is SPI\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000508 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000509 }
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000510 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000511 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000512 /* Success of any of these commands is optional. We don't need
513 the programmer to tell us its limits, but if it doesn't, we
514 will assume stuff, so it's in the programmers best interest
515 to tell us. */
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000516 if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
517 uint32_t v;
518 v = ((unsigned int)(rbuf[0]) << 0);
519 v |= ((unsigned int)(rbuf[1]) << 8);
520 v |= ((unsigned int)(rbuf[2]) << 16);
521 if (v == 0)
522 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000523 spi_master_serprog.max_data_write = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000524 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", v);
525 }
526 if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
527 uint32_t v;
528 v = ((unsigned int)(rbuf[0]) << 0);
529 v |= ((unsigned int)(rbuf[1]) << 8);
530 v |= ((unsigned int)(rbuf[2]) << 16);
531 if (v == 0)
532 v = (1 << 24) - 1; /* SPI-op maximum. */
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000533 spi_master_serprog.max_data_read = v;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000534 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
535 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000536 spispeed = extract_programmer_param("spispeed");
537 if (spispeed && strlen(spispeed)) {
538 uint32_t f_spi_req, f_spi;
539 uint8_t buf[4];
540 char *f_spi_suffix;
541
542 errno = 0;
543 f_spi_req = strtol(spispeed, &f_spi_suffix, 0);
544 if (errno != 0 || spispeed == f_spi_suffix) {
545 msg_perr("Error: Could not convert 'spispeed'.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000546 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000547 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000548 }
549 if (strlen(f_spi_suffix) == 1) {
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000550 if (!strcasecmp(f_spi_suffix, "M")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000551 f_spi_req *= 1000000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000552 } else if (!strcasecmp(f_spi_suffix, "k")) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000553 f_spi_req *= 1000;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000554 } else {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000555 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000556 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000557 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000558 }
559 } else if (strlen(f_spi_suffix) > 1) {
560 msg_perr("Error: Garbage following 'spispeed' value.\n");
Stefan Taunere34e3e82013-01-01 00:06:51 +0000561 free(spispeed);
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000562 goto init_err_cleanup_exit;
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000563 }
564
565 buf[0] = (f_spi_req >> (0 * 8)) & 0xFF;
566 buf[1] = (f_spi_req >> (1 * 8)) & 0xFF;
567 buf[2] = (f_spi_req >> (2 * 8)) & 0xFF;
568 buf[3] = (f_spi_req >> (3 * 8)) & 0xFF;
569
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000570 if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000571 msg_pwarn(MSGHEADER "Warning: Setting the SPI clock rate is not supported!\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000572 } else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) == 0) {
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000573 f_spi = buf[0];
574 f_spi |= buf[1] << (1 * 8);
575 f_spi |= buf[2] << (2 * 8);
576 f_spi |= buf[3] << (3 * 8);
577 msg_pdbg(MSGHEADER "Requested to set SPI clock frequency to %u Hz. "
578 "It was actually set to %u Hz\n", f_spi_req, f_spi);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000579 } else {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000580 msg_pwarn(MSGHEADER "Setting SPI clock rate to %u Hz failed!\n", f_spi_req);
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000581 }
Stefan Taunerb98f6eb2012-08-13 16:33:04 +0000582 }
583 free(spispeed);
Riku Viitanenddb6d922024-01-15 19:15:49 +0200584 cs = extract_programmer_param("cs");
585 if (cs) {
586 char *endptr = NULL;
587 errno = 0;
588 unsigned long cs_num = strtoul(cs, &endptr, 0);
589 if (!*cs || errno || *endptr || cs_num > 255) {
590 msg_perr("Error: Invalid chip select requested! "
591 "Only 0-255 are valid.\n");
592 free(cs);
593 goto init_err_cleanup_exit;
594 }
595 free(cs);
596 if (!sp_check_commandavail(S_CMD_S_SPI_CS)) {
597 msg_perr("Error: Setting SPI chip select is not supported!\n");
598 goto init_err_cleanup_exit;
599 }
600 msg_pdbg(MSGHEADER "Requested to use chip select %lu.\n", cs_num);
601 uint8_t cs_num8 = cs_num;
602 if (sp_docommand(S_CMD_S_SPI_CS, 1, &cs_num8, 0, NULL)) {
603 msg_perr("Error: Chip select %u not supported "
604 "by programmer!\n", cs_num8);
605 goto init_err_cleanup_exit;
606 }
607 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000608 bt = serprog_buses_supported;
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000609 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000610 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000611 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000612
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000613 if (serprog_buses_supported & BUS_NONSPI) {
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000614 if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
615 msg_perr("Error: Initialize operation buffer "
616 "not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000617 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000618 }
619
620 if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
621 msg_perr("Error: Write to opbuf: "
622 "delay not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000623 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000624 }
625
626 /* S_CMD_O_EXEC availability checked later. */
627
628 if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
629 msg_perr("Error: Single byte read not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000630 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000631 }
632 /* This could be translated to single byte reads (if missing),
633 * but now we don't support that. */
634 if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
635 msg_perr("Error: Read n bytes not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000636 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000637 }
638 if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
639 msg_perr("Error: Write to opbuf: "
640 "write byte not supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000641 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000642 }
643
644 if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
645 msg_pdbg(MSGHEADER "Write-n not supported");
646 sp_max_write_n = 0;
647 } else {
648 sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
649 sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
650 sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
651 if (!sp_max_write_n) {
652 sp_max_write_n = (1 << 24);
653 }
654 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n",
655 sp_max_write_n);
656 sp_write_n_buf = malloc(sp_max_write_n);
657 if (!sp_write_n_buf) {
658 msg_perr("Error: cannot allocate memory for "
659 "Write-n buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000660 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000661 }
662 sp_write_n_bytes = 0;
663 }
664
665 if (sp_check_commandavail(S_CMD_Q_RDNMAXLEN) &&
666 (sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf) == 0)) {
667 sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
668 sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
669 sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
670 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n",
671 sp_max_read_n ? sp_max_read_n : (1 << 24));
672 } else {
673 msg_pdbg(MSGHEADER "Maximum read-n length "
674 "not reported\n");
675 sp_max_read_n = 0;
676 }
677
Urja Rannikkof3196df2009-07-21 13:02:59 +0000678 }
679
680 if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000681 msg_pwarn("Warning: NAK to query programmer name\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000682 strcpy((char *)pgmname, "(unknown)");
683 }
684 pgmname[16] = 0;
Stefan Tauner31019d42011-10-22 21:45:27 +0000685 msg_pinfo(MSGHEADER "Programmer name is \"%s\"\n", pgmname);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000686
687 if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000688 msg_pwarn("Warning: NAK to query serial buffer size\n");
Urja Rannikkof3196df2009-07-21 13:02:59 +0000689 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000690 msg_pdbg(MSGHEADER "Serial buffer size is %d\n",
Urja Rannikkof3196df2009-07-21 13:02:59 +0000691 sp_device_serbuf_size);
692
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000693 if (sp_check_commandavail(S_CMD_O_INIT)) {
694 /* This would be inconsistent. */
695 if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
696 msg_perr("Error: Execute operation buffer not "
697 "supported\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000698 goto init_err_cleanup_exit;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000699 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000700
701 if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
702 msg_perr("Error: NAK to initialize operation buffer\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000703 goto init_err_cleanup_exit;
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000704 }
705
706 if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
707 &sp_device_opbuf_size)) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000708 msg_pwarn("Warning: NAK to query operation buffer size\n");
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000709 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000710 msg_pdbg(MSGHEADER "operation buffer size is %d\n",
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000711 sp_device_opbuf_size);
Elyes HAOUAS124ef382018-03-27 12:15:09 +0200712 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000713
Stefan Tauner92fefc92012-10-27 00:34:23 +0000714 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
715 uint8_t en = 1;
716 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &en, 0, NULL) != 0) {
717 msg_perr("Error: could not enable output buffers\n");
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000718 goto init_err_cleanup_exit;
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000719 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000720 msg_pdbg(MSGHEADER "Output drivers enabled\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000721 }
722 } else {
Stefan Tauner92fefc92012-10-27 00:34:23 +0000723 msg_pdbg(MSGHEADER "Warning: Programmer does not support toggling its output drivers\n");
Anastasia Klimchukf02db802021-05-24 10:07:56 +1000724 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000725 sp_prev_was_write = 0;
726 sp_streamed_transmit_ops = 0;
727 sp_streamed_transmit_bytes = 0;
728 sp_opbuf_usage = 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000729
730 if (register_shutdown(serprog_shutdown, NULL))
731 goto init_err_cleanup_exit;
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000732 if (serprog_buses_supported & BUS_SPI)
Nico Huber5e08e3e2021-05-11 17:38:14 +0200733 register_spi_master(&spi_master_serprog, NULL);
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000734 if (serprog_buses_supported & BUS_NONSPI)
Anastasia Klimchukb91a2032021-05-21 09:40:58 +1000735 register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI, NULL);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000736 return 0;
Anastasia Klimchukc6ff17b2021-05-24 09:55:03 +1000737
738init_err_cleanup_exit:
739 serprog_shutdown(NULL);
740 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000741}
742
Nico Huberc3b02dc2023-08-12 01:13:45 +0200743/* Move an in flashprog buffer existing write-n operation to the on-device operation buffer. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000744static int sp_pass_writen(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000745{
746 unsigned char header[7];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000747 msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
748 if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
749 if (sp_flush_stream() != 0) {
750 return 1;
751 }
752 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000753 /* In case it's just a single byte send it as a single write. */
754 if (sp_write_n_bytes == 1) {
755 sp_write_n_bytes = 0;
756 header[0] = (sp_write_n_addr >> 0) & 0xFF;
757 header[1] = (sp_write_n_addr >> 8) & 0xFF;
758 header[2] = (sp_write_n_addr >> 16) & 0xFF;
759 header[3] = sp_write_n_buf[0];
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000760 if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
761 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000762 sp_opbuf_usage += 5;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000763 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000764 }
765 header[0] = S_CMD_O_WRITEN;
766 header[1] = (sp_write_n_bytes >> 0) & 0xFF;
767 header[2] = (sp_write_n_bytes >> 8) & 0xFF;
768 header[3] = (sp_write_n_bytes >> 16) & 0xFF;
769 header[4] = (sp_write_n_addr >> 0) & 0xFF;
770 header[5] = (sp_write_n_addr >> 8) & 0xFF;
771 header[6] = (sp_write_n_addr >> 16) & 0xFF;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000772 if (serialport_write(header, 7) != 0) {
773 msg_perr(MSGHEADER "Error: cannot write write-n command\n");
774 return 1;
775 }
776 if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
777 msg_perr(MSGHEADER "Error: cannot write write-n data");
778 return 1;
779 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000780 sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
781 sp_streamed_transmit_ops += 1;
782 sp_opbuf_usage += 7 + sp_write_n_bytes;
783 sp_write_n_bytes = 0;
784 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000785 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000786}
787
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000788static int sp_execute_opbuf_noflush(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000789{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000790 if ((sp_max_write_n) && (sp_write_n_bytes)) {
791 if (sp_pass_writen() != 0) {
792 msg_perr("Error: could not transfer write buffer\n");
793 return 1;
794 }
795 }
796 if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
797 msg_perr("Error: could not execute command buffer\n");
798 return 1;
799 }
800 msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000801 sp_opbuf_usage = 0;
802 sp_prev_was_write = 0;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000803 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000804}
805
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000806static int sp_execute_opbuf(void)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000807{
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000808 if (sp_execute_opbuf_noflush() != 0)
809 return 1;
810 if (sp_flush_stream() != 0)
811 return 1;
812
813 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000814}
815
David Hendricks8bb20212011-06-14 01:35:36 +0000816static int serprog_shutdown(void *data)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000817{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000818 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000819 if (sp_execute_opbuf() != 0)
820 msg_pwarn("Could not flush command buffer.\n");
Stefan Tauner92fefc92012-10-27 00:34:23 +0000821 if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
822 uint8_t dis = 0;
823 if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
824 msg_pdbg(MSGHEADER "Output drivers disabled\n");
825 else
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000826 msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
Stefan Tauner92fefc92012-10-27 00:34:23 +0000827 }
Niklas Söderlund7145a502012-09-07 07:07:07 +0000828 /* FIXME: fix sockets on windows(?), especially closing */
829 serialport_shutdown(&sp_fd);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000830 if (sp_max_write_n)
831 free(sp_write_n_buf);
832 return 0;
833}
834
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000835static int sp_check_opbuf_usage(int bytes_to_be_added)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000836{
837 if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000838 /* If this happens in the middle of a page load the page load will probably fail. */
839 msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
840 if (sp_execute_opbuf() != 0)
841 return 1;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000842 }
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000843 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000844}
845
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000846static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
847 chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000848{
Sean Nelson74e8af52010-01-10 01:06:23 +0000849 msg_pspew("%s\n", __func__);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000850 if (sp_max_write_n) {
851 if ((sp_prev_was_write)
852 && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
853 sp_write_n_buf[sp_write_n_bytes++] = val;
854 } else {
855 if ((sp_prev_was_write) && (sp_write_n_bytes))
856 sp_pass_writen();
857 sp_prev_was_write = 1;
858 sp_write_n_addr = addr;
859 sp_write_n_bytes = 1;
860 sp_write_n_buf[0] = val;
861 }
862 sp_check_opbuf_usage(7 + sp_write_n_bytes);
863 if (sp_write_n_bytes >= sp_max_write_n)
864 sp_pass_writen();
865 } else {
866 /* We will have to do single writeb ops. */
867 unsigned char writeb_parm[4];
868 sp_check_opbuf_usage(6);
869 writeb_parm[0] = (addr >> 0) & 0xFF;
870 writeb_parm[1] = (addr >> 8) & 0xFF;
871 writeb_parm[2] = (addr >> 16) & 0xFF;
872 writeb_parm[3] = val;
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000873 sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000874 sp_opbuf_usage += 5;
875 }
876}
877
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000878static uint8_t serprog_chip_readb(const struct flashctx *flash,
879 const chipaddr addr)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000880{
881 unsigned char c;
882 unsigned char buf[3];
883 /* Will stream the read operation - eg. add it to the stream buffer, *
884 * then flush the buffer, then read the read answer. */
885 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
886 sp_execute_opbuf_noflush();
887 buf[0] = ((addr >> 0) & 0xFF);
888 buf[1] = ((addr >> 8) & 0xFF);
889 buf[2] = ((addr >> 16) & 0xFF);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000890 sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
891 sp_flush_stream(); // FIXME: return error
Stefan Tauner79587f52013-04-01 00:45:51 +0000892 if (serialport_read(&c, 1) != 0)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000893 msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
Stefan Taunerc2333752013-07-13 23:31:37 +0000894 msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000895 return c;
896}
897
Uwe Hermann4e3d0b32010-03-25 23:18:41 +0000898/* Local version that really does the job, doesn't care of max_read_n. */
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000899static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000900{
Urja Rannikkof3196df2009-07-21 13:02:59 +0000901 unsigned char sbuf[6];
Stefan Tauner0554ca52013-07-25 22:54:25 +0000902 msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000903 /* Stream the read-n -- as above. */
904 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
905 sp_execute_opbuf_noflush();
906 sbuf[0] = ((addr >> 0) & 0xFF);
907 sbuf[1] = ((addr >> 8) & 0xFF);
908 sbuf[2] = ((addr >> 16) & 0xFF);
909 sbuf[3] = ((len >> 0) & 0xFF);
910 sbuf[4] = ((len >> 8) & 0xFF);
911 sbuf[5] = ((len >> 16) & 0xFF);
912 sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000913 if (sp_flush_stream() != 0)
914 return 1;
915 if (serialport_read(buf, len) != 0) {
916 msg_perr(MSGHEADER "Error: cannot read read-n data");
917 return 1;
918 }
919 return 0;
Urja Rannikkof3196df2009-07-21 13:02:59 +0000920}
921
922/* The externally called version that makes sure that max_read_n is obeyed. */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000923static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
924 const chipaddr addr, size_t len)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000925{
926 size_t lenm = len;
927 chipaddr addrm = addr;
Stefan Tauner31019d42011-10-22 21:45:27 +0000928 while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000929 sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000930 addrm += sp_max_read_n;
931 lenm -= sp_max_read_n;
932 }
Stefan Tauner31019d42011-10-22 21:45:27 +0000933 if (lenm)
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000934 sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
Urja Rannikkof3196df2009-07-21 13:02:59 +0000935}
936
Thomas Heijligencc853d82021-05-04 15:32:17 +0200937static void serprog_delay(unsigned int usecs)
Urja Rannikkof3196df2009-07-21 13:02:59 +0000938{
939 unsigned char buf[4];
Stefan Tauner31019d42011-10-22 21:45:27 +0000940 msg_pspew("%s usecs=%d\n", __func__, usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000941 if (!sp_check_commandavail(S_CMD_O_DELAY)) {
Stefan Taunerd7d423b2012-10-20 09:13:16 +0000942 msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
Stefan Tauner31019d42011-10-22 21:45:27 +0000943 internal_delay(usecs);
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000944 return;
945 }
Urja Rannikkof3196df2009-07-21 13:02:59 +0000946 if ((sp_max_write_n) && (sp_write_n_bytes))
947 sp_pass_writen();
948 sp_check_opbuf_usage(5);
Stefan Tauner31019d42011-10-22 21:45:27 +0000949 buf[0] = ((usecs >> 0) & 0xFF);
950 buf[1] = ((usecs >> 8) & 0xFF);
951 buf[2] = ((usecs >> 16) & 0xFF);
952 buf[3] = ((usecs >> 24) & 0xFF);
Urja Rannikkof3196df2009-07-21 13:02:59 +0000953 sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
954 sp_opbuf_usage += 5;
955 sp_prev_was_write = 0;
956}
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000957
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000958static int serprog_spi_send_command(const struct flashctx *flash,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000959 unsigned int writecnt, unsigned int readcnt,
960 const unsigned char *writearr,
961 unsigned char *readarr)
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000962{
963 unsigned char *parmbuf;
964 int ret;
965 msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000966 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
967 if (sp_execute_opbuf() != 0) {
968 msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
969 return 1;
970 }
971 }
972
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000973 parmbuf = malloc(writecnt + 6);
Stefan Taunerbdead0d2013-08-24 02:10:18 +0000974 if (!parmbuf) {
975 msg_perr("Error: could not allocate SPI send param buffer.\n");
976 return 1;
977 }
Urja Rannikkoc93f5f12011-09-15 23:38:14 +0000978 parmbuf[0] = (writecnt >> 0) & 0xFF;
979 parmbuf[1] = (writecnt >> 8) & 0xFF;
980 parmbuf[2] = (writecnt >> 16) & 0xFF;
981 parmbuf[3] = (readcnt >> 0) & 0xFF;
982 parmbuf[4] = (readcnt >> 8) & 0xFF;
983 parmbuf[5] = (readcnt >> 16) & 0xFF;
984 memcpy(parmbuf + 6, writearr, writecnt);
985 ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
986 readarr);
987 free(parmbuf);
988 return ret;
989}
990
Thomas Heijligencc853d82021-05-04 15:32:17 +0200991static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
Urja Rannikko0b4ffd52015-06-29 23:24:23 +0000992{
993 /* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
994 * correctly (usually setting them to one either in software (for FWH/LPC) or relying on the fact that
995 * the hardware observes a subset of the address bits only). Combined with the standard mapping of
Nico Huberc3b02dc2023-08-12 01:13:45 +0200996 * 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 +0000997 * needed for non-SPI chips). Below we make sure that the requested range is within this window. */
998 if ((phys_addr & 0xFF000000) == 0xFF000000) {
999 return (void*)phys_addr;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001000 }
Elyes HAOUASec819d62019-06-09 17:50:51 +02001001 msg_pwarn(MSGHEADER "requested mapping %s is incompatible: 0x%zx bytes at 0x%0*" PRIxPTR ".\n",
1002 descr, len, PRIxPTR_WIDTH, phys_addr);
1003 return NULL;
Urja Rannikko0b4ffd52015-06-29 23:24:23 +00001004}
Thomas Heijligencc853d82021-05-04 15:32:17 +02001005
1006const struct programmer_entry programmer_serprog = {
1007 .name = "serprog",
1008 .type = OTHER,
1009 /* FIXME */
1010 .devs.note = "All programmer devices speaking the serprog protocol\n",
1011 .init = serprog_init,
Thomas Heijligencc853d82021-05-04 15:32:17 +02001012 .delay = serprog_delay,
1013};