blob: 2a4aa4d1658774757221d8f75c2366f25295b19b [file] [log] [blame]
hailfinger37b4fbf2009-06-23 11:33:43 +00001/*
2 * This file is part of the flashrom project.
3 *
stefanct69965b62011-09-15 23:38:14 +00004 * Copyright (C) 2009, 2011 Urja Rannikko <urjaman@gmail.com>
hailfinger37b4fbf2009-06-23 11:33:43 +00005 * Copyright (C) 2009 Carl-Daniel Hailfinger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
hailfinger37b4fbf2009-06-23 11:33:43 +000016 */
17
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +110018#include "platform.h"
19
hailfinger4f45a4f2009-08-12 13:32:56 +000020#include <stdio.h>
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +110021#if ! IS_WINDOWS /* stuff (presumably) needed for sockets only */
hailfinger37b4fbf2009-06-23 11:33:43 +000022#include <stdlib.h>
hailfinger4f45a4f2009-08-12 13:32:56 +000023#include <unistd.h>
hailfinger37b4fbf2009-06-23 11:33:43 +000024#include <fcntl.h>
hailfinger37b4fbf2009-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>
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +110030#endif
31#if IS_WINDOWS
32#include <conio.h>
33#else
34#include <termios.h>
35#endif
36#include <string.h>
hailfinger37b4fbf2009-06-23 11:33:43 +000037#include <errno.h>
hailfinger37b4fbf2009-06-23 11:33:43 +000038#include <inttypes.h>
hailfinger428f6852010-07-27 22:41:39 +000039#include "flash.h"
40#include "programmer.h"
stefanct69965b62011-09-15 23:38:14 +000041#include "chipdrivers.h"
Patrick Georgib9fe7f12017-04-11 20:35:19 +020042#include "serprog.h"
hailfingerbacbc8b2009-07-21 13:02:59 +000043
stefanctd9ac2212011-10-22 21:45:27 +000044#define MSGHEADER "serprog: "
hailfingerbacbc8b2009-07-21 13:02:59 +000045
dhendrix0ffc2eb2011-06-14 01:35:36 +000046/*
47 * FIXME: This prototype was added to help reduce diffs for the shutdown
48 * registration patch, which shifted many lines of code to place
49 * serprog_shutdown() before serprog_init(). It should be removed soon.
50 */
David Hendricks93784b42016-08-09 17:00:38 -070051static int serprog_shutdown(void *data);
dhendrix0ffc2eb2011-06-14 01:35:36 +000052
hailfingerbacbc8b2009-07-21 13:02:59 +000053static uint16_t sp_device_serbuf_size = 16;
54static uint16_t sp_device_opbuf_size = 300;
55/* Bitmap of supported commands */
56static uint8_t sp_cmdmap[32];
57
uwe3a3ab2f2010-03-25 23:18:41 +000058/* sp_prev_was_write used to detect writes with contiguous addresses
hailfingerbacbc8b2009-07-21 13:02:59 +000059 and combine them to write-n's */
60static int sp_prev_was_write = 0;
61/* sp_write_n_addr used as the starting addr of the currently
62 combined write-n operation */
63static uint32_t sp_write_n_addr;
64/* The maximum length of an write_n operation; 0 = write-n not supported */
65static uint32_t sp_max_write_n = 0;
66/* The maximum length of a read_n operation; 0 = 2^24 */
67static uint32_t sp_max_read_n = 0;
68
69/* A malloc'd buffer for combining the operation's data
70 and a counter that tells how much data is there. */
71static uint8_t *sp_write_n_buf;
72static uint32_t sp_write_n_bytes = 0;
73
74/* sp_streamed_* used for flow control checking */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +110075static unsigned int sp_streamed_transmit_ops = 0;
76static unsigned int sp_streamed_transmit_bytes = 0;
hailfingerbacbc8b2009-07-21 13:02:59 +000077
78/* sp_opbuf_usage used for counting the amount of
79 on-device operation buffer used */
80static int sp_opbuf_usage = 0;
81/* if true causes sp_docommand to automatically check
82 whether the command is supported before doing it */
83static int sp_check_avail_automatic = 0;
84
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +110085#if ! IS_WINDOWS
hailfingerbacbc8b2009-07-21 13:02:59 +000086static int sp_opensocket(char *ip, unsigned int port)
87{
88 int flag = 1;
89 struct hostent *hostPtr = NULL;
hailfinger3e454f32009-09-05 01:10:23 +000090 union { struct sockaddr_in si; struct sockaddr s; } sp = {};
hailfingerbacbc8b2009-07-21 13:02:59 +000091 int sock;
snelson0afd28b2010-01-10 01:06:23 +000092 msg_pdbg(MSGHEADER "IP %s port %d\n", ip, port);
hailfingerbacbc8b2009-07-21 13:02:59 +000093 sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +110094 if (sock < 0) {
95 msg_perr("Error: serprog cannot open socket: %s\n", strerror(errno));
96 return -1;
97 }
hailfingerbacbc8b2009-07-21 13:02:59 +000098 hostPtr = gethostbyname(ip);
99 if (NULL == hostPtr) {
100 hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100101 if (NULL == hostPtr) {
102 close(sock);
103 msg_perr("Error: cannot resolve %s\n", ip);
104 return -1;
105 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000106 }
hailfinger3e454f32009-09-05 01:10:23 +0000107 sp.si.sin_family = AF_INET;
108 sp.si.sin_port = htons(port);
Edward O'Callaghan9987ad42019-09-03 15:58:56 +1000109 (void)memcpy(&sp.si.sin_addr, hostPtr->h_addr_list[0], hostPtr->h_length);
hailfinger3e454f32009-09-05 01:10:23 +0000110 if (connect(sock, &sp.s, sizeof(sp.si)) < 0) {
hailfingerbacbc8b2009-07-21 13:02:59 +0000111 close(sock);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100112 msg_perr("Error: serprog cannot connect: %s\n", strerror(errno));
113 return -1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000114 }
115 /* We are latency limited, and sometimes do write-write-read *
116 * (write-n) - so enable TCP_NODELAY. */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100117 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) {
118 close(sock);
119 msg_perr("Error: serprog cannot set socket options: %s\n", strerror(errno));
120 return -1;
121 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000122 return sock;
123}
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100124#endif
hailfingerbacbc8b2009-07-21 13:02:59 +0000125
uwe3a3ab2f2010-03-25 23:18:41 +0000126/* Synchronize: a bit tricky algorithm that tries to (and in my tests has *
hailfingerbacbc8b2009-07-21 13:02:59 +0000127 * always succeeded in) bring the serial protocol to known waiting-for- *
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100128 * command state - uses nonblocking I/O - rest of the driver uses *
hailfingerbacbc8b2009-07-21 13:02:59 +0000129 * blocking read - TODO: add an alarm() timer for the rest of the app on *
130 * serial operations, though not such a big issue as the first thing to *
131 * do is synchronize (eg. check that device is alive). */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100132static int sp_synchronize(void)
hailfingerbacbc8b2009-07-21 13:02:59 +0000133{
134 int i;
hailfingerbacbc8b2009-07-21 13:02:59 +0000135 unsigned char buf[8];
hailfingerbacbc8b2009-07-21 13:02:59 +0000136 /* First sends 8 NOPs, then flushes the return data - should cause *
137 * the device serial parser to get to a sane state, unless if it *
138 * is waiting for a real long write-n. */
139 memset(buf, S_CMD_NOP, 8);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100140 if (serialport_write_nonblock(buf, 8, 1, NULL) != 0) {
141 goto err_out;
142 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000143 /* A second should be enough to get all the answers to the buffer */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100144 internal_delay(1000 * 1000);
hailfingerbacbc8b2009-07-21 13:02:59 +0000145 sp_flush_incoming();
146
stefanct371e7e82011-07-07 19:56:58 +0000147 /* Then try up to 8 times to send syncnop and get the correct special *
148 * return of NAK+ACK. Timing note: up to 10 characters, 10*50ms = *
149 * up to 500ms per try, 8*0.5s = 4s; +1s (above) = up to 5s sync *
150 * attempt, ~1s if immediate success. */
hailfingerbacbc8b2009-07-21 13:02:59 +0000151 for (i = 0; i < 8; i++) {
152 int n;
153 unsigned char c = S_CMD_SYNCNOP;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100154 if (serialport_write_nonblock(&c, 1, 1, NULL) != 0) {
155 goto err_out;
156 }
snelson0afd28b2010-01-10 01:06:23 +0000157 msg_pdbg(".");
hailfingerbacbc8b2009-07-21 13:02:59 +0000158 fflush(stdout);
159 for (n = 0; n < 10; n++) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100160 int ret = serialport_read_nonblock(&c, 1, 50, NULL);
161 if (ret < 0)
162 goto err_out;
163 if (ret > 0 || c != S_NAK)
hailfingerbacbc8b2009-07-21 13:02:59 +0000164 continue;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100165 ret = serialport_read_nonblock(&c, 1, 20, NULL);
166 if (ret < 0)
167 goto err_out;
168 if (ret > 0 || c != S_ACK)
hailfingerbacbc8b2009-07-21 13:02:59 +0000169 continue;
170 c = S_CMD_SYNCNOP;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100171 if (serialport_write_nonblock(&c, 1, 1, NULL) != 0) {
172 goto err_out;
173 }
174 ret = serialport_read_nonblock(&c, 1, 500, NULL);
175 if (ret < 0)
176 goto err_out;
177 if (ret > 0 || c != S_NAK)
hailfingerbacbc8b2009-07-21 13:02:59 +0000178 break; /* fail */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100179 ret = serialport_read_nonblock(&c, 1, 100, NULL);
180 if (ret > 0 || ret < 0)
181 goto err_out;
hailfingerbacbc8b2009-07-21 13:02:59 +0000182 if (c != S_ACK)
183 break; /* fail */
snelson0afd28b2010-01-10 01:06:23 +0000184 msg_pdbg("\n");
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100185 return 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000186 }
187 }
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100188err_out:
189 msg_perr("Error: cannot synchronize protocol - check communications and reset device?\n");
190 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000191}
192
193static int sp_check_commandavail(uint8_t command)
194{
195 int byteoffs, bitoffs;
196 byteoffs = command / 8;
197 bitoffs = command % 8;
198 return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
199}
200
201static int sp_automatic_cmdcheck(uint8_t cmd)
202{
203 if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
stefanctd9ac2212011-10-22 21:45:27 +0000204 msg_pdbg("Warning: Automatic command availability check failed "
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100205 "for cmd 0x%02x - won't execute cmd\n", cmd);
hailfingerbacbc8b2009-07-21 13:02:59 +0000206 return 1;
207 }
208 return 0;
209}
210
211static int sp_docommand(uint8_t command, uint32_t parmlen,
stefanctd9ac2212011-10-22 21:45:27 +0000212 uint8_t *params, uint32_t retlen, void *retparms)
hailfingerbacbc8b2009-07-21 13:02:59 +0000213{
hailfingerbacbc8b2009-07-21 13:02:59 +0000214 unsigned char c;
215 if (sp_automatic_cmdcheck(command))
216 return 1;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100217 if (serialport_write(&command, 1) != 0) {
218 msg_perr("Error: cannot write op code: %s\n", strerror(errno));
219 return 1;
220 }
221 if (serialport_write(params, parmlen) != 0) {
222 msg_perr("Error: cannot write parameters: %s\n", strerror(errno));
223 return 1;
224 }
225 if (serialport_read(&c, 1) != 0) {
226 msg_perr("Error: cannot read from device: %s\n", strerror(errno));
227 return 1;
228 }
stefanctd9ac2212011-10-22 21:45:27 +0000229 if (c == S_NAK)
230 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000231 if (c != S_ACK) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100232 msg_perr("Error: invalid response 0x%02X from device (to command 0x%02X)\n", c, command);
233 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000234 }
235 if (retlen) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100236 if (serialport_read(retparms, retlen) != 0) {
237 msg_perr("Error: cannot read return parameters: %s\n", strerror(errno));
238 return 1;
239 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000240 }
241 return 0;
242}
243
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100244static int sp_flush_stream(void)
hailfingerbacbc8b2009-07-21 13:02:59 +0000245{
246 if (sp_streamed_transmit_ops)
247 do {
248 unsigned char c;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100249 if (serialport_read(&c, 1) != 0) {
250 msg_perr("Error: cannot read from device (flushing stream)");
251 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000252 }
253 if (c == S_NAK) {
snelson0afd28b2010-01-10 01:06:23 +0000254 msg_perr("Error: NAK to a stream buffer operation\n");
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100255 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000256 }
257 if (c != S_ACK) {
snelson0afd28b2010-01-10 01:06:23 +0000258 msg_perr("Error: Invalid reply 0x%02X from device\n", c);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100259 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000260 }
261 } while (--sp_streamed_transmit_ops);
262 sp_streamed_transmit_ops = 0;
263 sp_streamed_transmit_bytes = 0;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100264 return 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000265}
266
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100267static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
hailfingerbacbc8b2009-07-21 13:02:59 +0000268{
269 uint8_t *sp;
270 if (sp_automatic_cmdcheck(cmd))
271 return 1;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100272
hailfingerbacbc8b2009-07-21 13:02:59 +0000273 sp = malloc(1 + parmlen);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100274 if (!sp) {
275 msg_perr("Error: cannot malloc command buffer\n");
276 return 1;
277 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000278 sp[0] = cmd;
279 memcpy(&(sp[1]), parms, parmlen);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100280
281 if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) {
282 if (sp_flush_stream() != 0) {
283 free(sp);
284 return 1;
285 }
286 }
287 if (serialport_write(sp, 1 + parmlen) != 0) {
288 msg_perr("Error: cannot write command\n");
289 free(sp);
290 return 1;
291 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000292 sp_streamed_transmit_ops += 1;
293 sp_streamed_transmit_bytes += 1 + parmlen;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100294
295 free(sp);
hailfingerbacbc8b2009-07-21 13:02:59 +0000296 return 0;
297}
298
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100299static int serprog_spi_send_command(const struct flashctx *flash,
300 unsigned int writecnt, unsigned int readcnt,
hailfinger76bb7e92011-11-09 23:40:00 +0000301 const unsigned char *writearr,
302 unsigned char *readarr);
Patrick Georgif4f1e2f2017-03-10 17:38:40 +0100303static struct spi_master spi_master_serprog = {
Edward O'Callaghana6673bd2019-06-24 15:22:28 +1000304 .features = SPI_MASTER_4BA,
stefanct69965b62011-09-15 23:38:14 +0000305 .max_data_read = MAX_DATA_READ_UNLIMITED,
306 .max_data_write = MAX_DATA_WRITE_UNLIMITED,
307 .command = serprog_spi_send_command,
308 .multicommand = default_spi_send_multicommand,
Edward O'Callaghand825ac02019-07-26 21:36:16 +1000309 .read = default_spi_read,
stefanct69965b62011-09-15 23:38:14 +0000310 .write_256 = default_spi_write_256,
311};
312
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700313static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
314 chipaddr addr);
315static uint8_t serprog_chip_readb(const struct flashctx *flash,
316 const chipaddr addr);
317static void serprog_chip_readn(const struct flashctx *flash, uint8_t *buf,
318 const chipaddr addr, size_t len);
Patrick Georgi0a9533a2017-02-03 19:28:38 +0100319static const struct par_master par_master_serprog = {
hailfinger76bb7e92011-11-09 23:40:00 +0000320 .chip_readb = serprog_chip_readb,
321 .chip_readw = fallback_chip_readw,
322 .chip_readl = fallback_chip_readl,
323 .chip_readn = serprog_chip_readn,
324 .chip_writeb = serprog_chip_writeb,
325 .chip_writew = fallback_chip_writew,
326 .chip_writel = fallback_chip_writel,
327 .chip_writen = fallback_chip_writen,
328};
329
330static enum chipbustype serprog_buses_supported = BUS_NONE;
331
David Hendricksac1d25c2016-08-09 17:00:58 -0700332int serprog_init(void)
hailfingerbacbc8b2009-07-21 13:02:59 +0000333{
334 uint16_t iface;
hailfingerbacbc8b2009-07-21 13:02:59 +0000335 unsigned char pgmname[17];
336 unsigned char rbuf[3];
337 unsigned char c;
hailfinger1ef766d2010-07-06 09:55:48 +0000338 char *device;
hailfinger1ef766d2010-07-06 09:55:48 +0000339 int have_device = 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000340
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100341 /* the parameter is either of format "dev=/dev/device[:baud]" or "ip=ip:port" */
hailfingerddeb4ac2010-07-08 10:13:37 +0000342 device = extract_programmer_param("dev");
hailfinger1ef766d2010-07-06 09:55:48 +0000343 if (device && strlen(device)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100344 char *baud_str = strstr(device, ":");
345 if (baud_str != NULL) {
hailfinger1ef766d2010-07-06 09:55:48 +0000346 /* Split device from baudrate. */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100347 *baud_str = '\0';
348 baud_str++;
hailfinger1ef766d2010-07-06 09:55:48 +0000349 }
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100350 int baud;
351 /* Convert baud string to value.
352 * baud_str is either NULL (if strstr can't find the colon), points to the \0 after the colon
353 * if no characters where given after the colon, or a string to convert... */
354 if (baud_str == NULL || *baud_str == '\0') {
355 baud = -1;
356 msg_pdbg("No baudrate specified, using the hardware's defaults.\n");
357 } else
358 baud = atoi(baud_str); // FIXME: replace atoi with strtoul
359 if (strlen(device) > 0) {
360 sp_fd = sp_openserport(device, baud);
361 if (sp_fd == SER_INV_FD) {
362 free(device);
363 return 1;
364 }
hailfinger1ef766d2010-07-06 09:55:48 +0000365 have_device++;
366 }
367 }
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100368
369#if !IS_WINDOWS
hailfinger1ef766d2010-07-06 09:55:48 +0000370 if (device && !strlen(device)) {
371 msg_perr("Error: No device specified.\n"
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100372 "Use flashrom -p serprog:dev=/dev/device[:baud]\n");
hailfinger1ef766d2010-07-06 09:55:48 +0000373 free(device);
374 return 1;
375 }
376 free(device);
hailfingerbacbc8b2009-07-21 13:02:59 +0000377
hailfingerddeb4ac2010-07-08 10:13:37 +0000378 device = extract_programmer_param("ip");
hailfinger1ef766d2010-07-06 09:55:48 +0000379 if (have_device && device) {
380 msg_perr("Error: Both host and device specified.\n"
381 "Please use either dev= or ip= but not both.\n");
382 free(device);
383 return 1;
384 }
385 if (device && strlen(device)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100386 char *port = strstr(device, ":");
387 if (port != NULL) {
hailfinger1ef766d2010-07-06 09:55:48 +0000388 /* Split host from port. */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100389 *port = '\0';
390 port++;
hailfinger1ef766d2010-07-06 09:55:48 +0000391 }
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100392 if (!port || !strlen(port)) {
hailfinger1ef766d2010-07-06 09:55:48 +0000393 msg_perr("Error: No port specified.\n"
394 "Use flashrom -p serprog:ip=ipaddr:port\n");
395 free(device);
stefanct69965b62011-09-15 23:38:14 +0000396 return 1;
hailfinger1ef766d2010-07-06 09:55:48 +0000397 }
398 if (strlen(device)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100399 sp_fd = sp_opensocket(device, atoi(port)); // FIXME: replace atoi with strtoul
400 if (sp_fd < 0) {
401 free(device);
402 return 1;
403 }
hailfinger1ef766d2010-07-06 09:55:48 +0000404 have_device++;
405 }
406 }
407 if (device && !strlen(device)) {
408 msg_perr("Error: No host specified.\n"
409 "Use flashrom -p serprog:ip=ipaddr:port\n");
410 free(device);
411 return 1;
412 }
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100413#endif
hailfinger1ef766d2010-07-06 09:55:48 +0000414 free(device);
415
416 if (!have_device) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100417#if IS_WINDOWS
418 msg_perr("Error: No device specified.\n"
419 "Use flashrom -p serprog:dev=comN[:baud]\n");
420#else
hailfinger1ef766d2010-07-06 09:55:48 +0000421 msg_perr("Error: Neither host nor device specified.\n"
422 "Use flashrom -p serprog:dev=/dev/device:baud or "
423 "flashrom -p serprog:ip=ipaddr:port\n");
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100424#endif
hailfinger1ef766d2010-07-06 09:55:48 +0000425 return 1;
426 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000427
dhendrix0ffc2eb2011-06-14 01:35:36 +0000428 if (register_shutdown(serprog_shutdown, NULL))
429 return 1;
430
snelson0afd28b2010-01-10 01:06:23 +0000431 msg_pdbg(MSGHEADER "connected - attempting to synchronize\n");
hailfingerbacbc8b2009-07-21 13:02:59 +0000432
433 sp_check_avail_automatic = 0;
434
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100435 if (sp_synchronize())
436 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000437
snelson0afd28b2010-01-10 01:06:23 +0000438 msg_pdbg(MSGHEADER "Synchronized\n");
hailfingerbacbc8b2009-07-21 13:02:59 +0000439
440 if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
stefanctd9ac2212011-10-22 21:45:27 +0000441 msg_perr("Error: NAK to query interface version\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000442 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000443 }
444
445 if (iface != 1) {
stefanctd9ac2212011-10-22 21:45:27 +0000446 msg_perr("Error: Unknown interface version: %d\n", iface);
hailfinger76bb7e92011-11-09 23:40:00 +0000447 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000448 }
449
snelson0afd28b2010-01-10 01:06:23 +0000450 msg_pdbg(MSGHEADER "Interface version ok.\n");
hailfingerbacbc8b2009-07-21 13:02:59 +0000451
452 if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
snelson0afd28b2010-01-10 01:06:23 +0000453 msg_perr("Error: query command map not supported\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000454 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000455 }
456
457 sp_check_avail_automatic = 1;
458
hailfinger76bb7e92011-11-09 23:40:00 +0000459 /* FIXME: This assumes that serprog device bustypes are always
460 * identical with flashrom bustype enums and that they all fit
461 * in a single byte.
462 */
stefanct69965b62011-09-15 23:38:14 +0000463 if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100464 msg_pwarn("Warning: NAK to query supported buses\n");
stefanct69965b62011-09-15 23:38:14 +0000465 c = BUS_NONSPI; /* A reasonable default for now. */
hailfingerbacbc8b2009-07-21 13:02:59 +0000466 }
hailfinger76bb7e92011-11-09 23:40:00 +0000467 serprog_buses_supported = c;
468
stefanctd9ac2212011-10-22 21:45:27 +0000469 msg_pdbg(MSGHEADER "Bus support: parallel=%s, LPC=%s, FWH=%s, SPI=%s\n",
470 (c & BUS_PARALLEL) ? "on" : "off",
471 (c & BUS_LPC) ? "on" : "off",
472 (c & BUS_FWH) ? "on" : "off",
473 (c & BUS_SPI) ? "on" : "off");
stefanct69965b62011-09-15 23:38:14 +0000474 /* Check for the minimum operational set of commands. */
hailfinger76bb7e92011-11-09 23:40:00 +0000475 if (serprog_buses_supported & BUS_SPI) {
stefanct69965b62011-09-15 23:38:14 +0000476 uint8_t bt = BUS_SPI;
477 if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
478 msg_perr("Error: SPI operation not supported while the "
479 "bustype is SPI\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000480 return 1;
stefanct69965b62011-09-15 23:38:14 +0000481 }
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100482 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
483 return 1;
stefanct69965b62011-09-15 23:38:14 +0000484 /* Success of any of these commands is optional. We don't need
485 the programmer to tell us its limits, but if it doesn't, we
486 will assume stuff, so it's in the programmers best interest
487 to tell us. */
stefanct69965b62011-09-15 23:38:14 +0000488 if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
489 uint32_t v;
490 v = ((unsigned int)(rbuf[0]) << 0);
491 v |= ((unsigned int)(rbuf[1]) << 8);
492 v |= ((unsigned int)(rbuf[2]) << 16);
493 if (v == 0)
494 v = (1 << 24) - 1; /* SPI-op maximum. */
Patrick Georgif4f1e2f2017-03-10 17:38:40 +0100495 spi_master_serprog.max_data_write = v;
stefanct69965b62011-09-15 23:38:14 +0000496 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", v);
497 }
498 if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
499 uint32_t v;
500 v = ((unsigned int)(rbuf[0]) << 0);
501 v |= ((unsigned int)(rbuf[1]) << 8);
502 v |= ((unsigned int)(rbuf[2]) << 16);
503 if (v == 0)
504 v = (1 << 24) - 1; /* SPI-op maximum. */
Patrick Georgif4f1e2f2017-03-10 17:38:40 +0100505 spi_master_serprog.max_data_read = v;
stefanct69965b62011-09-15 23:38:14 +0000506 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
507 }
hailfinger76bb7e92011-11-09 23:40:00 +0000508 bt = serprog_buses_supported;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100509 if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
510 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000511 }
stefanct69965b62011-09-15 23:38:14 +0000512
hailfinger76bb7e92011-11-09 23:40:00 +0000513 if (serprog_buses_supported & BUS_NONSPI) {
stefanct69965b62011-09-15 23:38:14 +0000514 if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
515 msg_perr("Error: Initialize operation buffer "
516 "not supported\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000517 return 1;
stefanct69965b62011-09-15 23:38:14 +0000518 }
519
520 if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
521 msg_perr("Error: Write to opbuf: "
522 "delay not supported\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000523 return 1;
stefanct69965b62011-09-15 23:38:14 +0000524 }
525
526 /* S_CMD_O_EXEC availability checked later. */
527
528 if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
529 msg_perr("Error: Single byte read not supported\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000530 return 1;
stefanct69965b62011-09-15 23:38:14 +0000531 }
532 /* This could be translated to single byte reads (if missing),
533 * but now we don't support that. */
534 if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
535 msg_perr("Error: Read n bytes not supported\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000536 return 1;
stefanct69965b62011-09-15 23:38:14 +0000537 }
538 if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
539 msg_perr("Error: Write to opbuf: "
540 "write byte not supported\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000541 return 1;
stefanct69965b62011-09-15 23:38:14 +0000542 }
543
544 if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
545 msg_pdbg(MSGHEADER "Write-n not supported");
546 sp_max_write_n = 0;
547 } else {
548 sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
549 sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
550 sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
551 if (!sp_max_write_n) {
552 sp_max_write_n = (1 << 24);
553 }
554 msg_pdbg(MSGHEADER "Maximum write-n length is %d\n",
555 sp_max_write_n);
556 sp_write_n_buf = malloc(sp_max_write_n);
557 if (!sp_write_n_buf) {
558 msg_perr("Error: cannot allocate memory for "
559 "Write-n buffer\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000560 return 1;
stefanct69965b62011-09-15 23:38:14 +0000561 }
562 sp_write_n_bytes = 0;
563 }
564
565 if (sp_check_commandavail(S_CMD_Q_RDNMAXLEN) &&
566 (sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf) == 0)) {
567 sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
568 sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
569 sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
570 msg_pdbg(MSGHEADER "Maximum read-n length is %d\n",
571 sp_max_read_n ? sp_max_read_n : (1 << 24));
572 } else {
573 msg_pdbg(MSGHEADER "Maximum read-n length "
574 "not reported\n");
575 sp_max_read_n = 0;
576 }
577
hailfingerbacbc8b2009-07-21 13:02:59 +0000578 }
579
580 if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100581 msg_pwarn("Warning: NAK to query programmer name\n");
hailfingerbacbc8b2009-07-21 13:02:59 +0000582 strcpy((char *)pgmname, "(unknown)");
583 }
584 pgmname[16] = 0;
stefanctd9ac2212011-10-22 21:45:27 +0000585 msg_pinfo(MSGHEADER "Programmer name is \"%s\"\n", pgmname);
hailfingerbacbc8b2009-07-21 13:02:59 +0000586
587 if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100588 msg_pwarn("Warning: NAK to query serial buffer size\n");
hailfingerbacbc8b2009-07-21 13:02:59 +0000589 }
stefanctd9ac2212011-10-22 21:45:27 +0000590 msg_pdbg(MSGHEADER "Serial buffer size is %d\n",
hailfingerbacbc8b2009-07-21 13:02:59 +0000591 sp_device_serbuf_size);
592
stefanct69965b62011-09-15 23:38:14 +0000593 if (sp_check_commandavail(S_CMD_O_INIT)) {
594 /* This would be inconsistent. */
595 if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
596 msg_perr("Error: Execute operation buffer not "
597 "supported\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000598 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000599 }
stefanct69965b62011-09-15 23:38:14 +0000600
601 if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
602 msg_perr("Error: NAK to initialize operation buffer\n");
hailfinger76bb7e92011-11-09 23:40:00 +0000603 return 1;
stefanct69965b62011-09-15 23:38:14 +0000604 }
605
606 if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
607 &sp_device_opbuf_size)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100608 msg_pwarn("Warning: NAK to query operation buffer size\n");
stefanct69965b62011-09-15 23:38:14 +0000609 }
stefanctd9ac2212011-10-22 21:45:27 +0000610 msg_pdbg(MSGHEADER "operation buffer size is %d\n",
stefanct69965b62011-09-15 23:38:14 +0000611 sp_device_opbuf_size);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100612 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000613
614 sp_prev_was_write = 0;
615 sp_streamed_transmit_ops = 0;
616 sp_streamed_transmit_bytes = 0;
617 sp_opbuf_usage = 0;
hailfinger76bb7e92011-11-09 23:40:00 +0000618 if (serprog_buses_supported & BUS_SPI)
Patrick Georgif4f1e2f2017-03-10 17:38:40 +0100619 register_spi_master(&spi_master_serprog);
hailfinger76bb7e92011-11-09 23:40:00 +0000620 if (serprog_buses_supported & BUS_NONSPI)
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100621 register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI);
hailfingerbacbc8b2009-07-21 13:02:59 +0000622 return 0;
623}
624
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100625/* Move an in flashrom buffer existing write-n operation to the on-device operation buffer. */
626static int sp_pass_writen(void)
hailfingerbacbc8b2009-07-21 13:02:59 +0000627{
628 unsigned char header[7];
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100629 msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
630 if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
631 if (sp_flush_stream() != 0) {
632 return 1;
633 }
634 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000635 /* In case it's just a single byte send it as a single write. */
636 if (sp_write_n_bytes == 1) {
637 sp_write_n_bytes = 0;
638 header[0] = (sp_write_n_addr >> 0) & 0xFF;
639 header[1] = (sp_write_n_addr >> 8) & 0xFF;
640 header[2] = (sp_write_n_addr >> 16) & 0xFF;
641 header[3] = sp_write_n_buf[0];
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100642 if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
643 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000644 sp_opbuf_usage += 5;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100645 return 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000646 }
647 header[0] = S_CMD_O_WRITEN;
648 header[1] = (sp_write_n_bytes >> 0) & 0xFF;
649 header[2] = (sp_write_n_bytes >> 8) & 0xFF;
650 header[3] = (sp_write_n_bytes >> 16) & 0xFF;
651 header[4] = (sp_write_n_addr >> 0) & 0xFF;
652 header[5] = (sp_write_n_addr >> 8) & 0xFF;
653 header[6] = (sp_write_n_addr >> 16) & 0xFF;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100654 if (serialport_write(header, 7) != 0) {
655 msg_perr(MSGHEADER "Error: cannot write write-n command\n");
656 return 1;
657 }
658 if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
659 msg_perr(MSGHEADER "Error: cannot write write-n data");
660 return 1;
661 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000662 sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
663 sp_streamed_transmit_ops += 1;
664 sp_opbuf_usage += 7 + sp_write_n_bytes;
665 sp_write_n_bytes = 0;
666 sp_prev_was_write = 0;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100667 return 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000668}
669
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100670static int sp_execute_opbuf_noflush(void)
hailfingerbacbc8b2009-07-21 13:02:59 +0000671{
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100672 if ((sp_max_write_n) && (sp_write_n_bytes)) {
673 if (sp_pass_writen() != 0) {
674 msg_perr("Error: could not transfer write buffer\n");
675 return 1;
676 }
677 }
678 if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
679 msg_perr("Error: could not execute command buffer\n");
680 return 1;
681 }
682 msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
hailfingerbacbc8b2009-07-21 13:02:59 +0000683 sp_opbuf_usage = 0;
684 sp_prev_was_write = 0;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100685 return 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000686}
687
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100688static int sp_execute_opbuf(void)
hailfingerbacbc8b2009-07-21 13:02:59 +0000689{
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100690 if (sp_execute_opbuf_noflush() != 0)
691 return 1;
692 if (sp_flush_stream() != 0)
693 return 1;
694
695 return 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000696}
697
David Hendricks93784b42016-08-09 17:00:38 -0700698static int serprog_shutdown(void *data)
hailfingerbacbc8b2009-07-21 13:02:59 +0000699{
hailfingerbacbc8b2009-07-21 13:02:59 +0000700 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100701 if (sp_execute_opbuf() != 0)
702 msg_pwarn("Could not flush command buffer.\n");
703 /* FIXME: fix sockets on windows(?), especially closing */
704 serialport_shutdown(&sp_fd);
hailfingerbacbc8b2009-07-21 13:02:59 +0000705 if (sp_max_write_n)
706 free(sp_write_n_buf);
707 return 0;
708}
709
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100710static int sp_check_opbuf_usage(int bytes_to_be_added)
hailfingerbacbc8b2009-07-21 13:02:59 +0000711{
712 if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100713 /* If this happens in the middle of a page load the page load will probably fail. */
714 msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
715 if (sp_execute_opbuf() != 0)
716 return 1;
hailfingerbacbc8b2009-07-21 13:02:59 +0000717 }
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100718 return 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000719}
720
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100721static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
722 chipaddr addr)
hailfingerbacbc8b2009-07-21 13:02:59 +0000723{
snelson0afd28b2010-01-10 01:06:23 +0000724 msg_pspew("%s\n", __func__);
hailfingerbacbc8b2009-07-21 13:02:59 +0000725 if (sp_max_write_n) {
726 if ((sp_prev_was_write)
727 && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
728 sp_write_n_buf[sp_write_n_bytes++] = val;
729 } else {
730 if ((sp_prev_was_write) && (sp_write_n_bytes))
731 sp_pass_writen();
732 sp_prev_was_write = 1;
733 sp_write_n_addr = addr;
734 sp_write_n_bytes = 1;
735 sp_write_n_buf[0] = val;
736 }
737 sp_check_opbuf_usage(7 + sp_write_n_bytes);
738 if (sp_write_n_bytes >= sp_max_write_n)
739 sp_pass_writen();
740 } else {
741 /* We will have to do single writeb ops. */
742 unsigned char writeb_parm[4];
743 sp_check_opbuf_usage(6);
744 writeb_parm[0] = (addr >> 0) & 0xFF;
745 writeb_parm[1] = (addr >> 8) & 0xFF;
746 writeb_parm[2] = (addr >> 16) & 0xFF;
747 writeb_parm[3] = val;
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100748 sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
hailfingerbacbc8b2009-07-21 13:02:59 +0000749 sp_opbuf_usage += 5;
750 }
751}
752
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100753static uint8_t serprog_chip_readb(const struct flashctx *flash,
754 const chipaddr addr)
hailfingerbacbc8b2009-07-21 13:02:59 +0000755{
756 unsigned char c;
757 unsigned char buf[3];
758 /* Will stream the read operation - eg. add it to the stream buffer, *
759 * then flush the buffer, then read the read answer. */
760 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
761 sp_execute_opbuf_noflush();
762 buf[0] = ((addr >> 0) & 0xFF);
763 buf[1] = ((addr >> 8) & 0xFF);
764 buf[2] = ((addr >> 16) & 0xFF);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100765 sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
766 sp_flush_stream(); // FIXME: return error
767 if (serialport_read(&c, 1) != 0)
768 msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
Kangheui Won4974cc12019-10-18 12:59:01 +1100769 msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
hailfingerbacbc8b2009-07-21 13:02:59 +0000770 return c;
771}
772
uwe3a3ab2f2010-03-25 23:18:41 +0000773/* Local version that really does the job, doesn't care of max_read_n. */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100774static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
hailfingerbacbc8b2009-07-21 13:02:59 +0000775{
hailfingerbacbc8b2009-07-21 13:02:59 +0000776 unsigned char sbuf[6];
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100777 msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
hailfingerbacbc8b2009-07-21 13:02:59 +0000778 /* Stream the read-n -- as above. */
779 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
780 sp_execute_opbuf_noflush();
781 sbuf[0] = ((addr >> 0) & 0xFF);
782 sbuf[1] = ((addr >> 8) & 0xFF);
783 sbuf[2] = ((addr >> 16) & 0xFF);
784 sbuf[3] = ((len >> 0) & 0xFF);
785 sbuf[4] = ((len >> 8) & 0xFF);
786 sbuf[5] = ((len >> 16) & 0xFF);
787 sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100788 if (sp_flush_stream() != 0)
789 return 1;
790 if (serialport_read(buf, len) != 0) {
791 msg_perr(MSGHEADER "Error: cannot read read-n data");
792 return 1;
793 }
794 return 0;
hailfingerbacbc8b2009-07-21 13:02:59 +0000795}
796
797/* The externally called version that makes sure that max_read_n is obeyed. */
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100798static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
799 const chipaddr addr, size_t len)
hailfingerbacbc8b2009-07-21 13:02:59 +0000800{
801 size_t lenm = len;
802 chipaddr addrm = addr;
stefanctd9ac2212011-10-22 21:45:27 +0000803 while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100804 sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
hailfingerbacbc8b2009-07-21 13:02:59 +0000805 addrm += sp_max_read_n;
806 lenm -= sp_max_read_n;
807 }
stefanctd9ac2212011-10-22 21:45:27 +0000808 if (lenm)
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100809 sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
hailfingerbacbc8b2009-07-21 13:02:59 +0000810}
811
Edward O'Callaghan8ebbd502019-09-03 15:11:02 +1000812void serprog_delay(unsigned int usecs)
hailfingerbacbc8b2009-07-21 13:02:59 +0000813{
814 unsigned char buf[4];
stefanctd9ac2212011-10-22 21:45:27 +0000815 msg_pspew("%s usecs=%d\n", __func__, usecs);
stefanct69965b62011-09-15 23:38:14 +0000816 if (!sp_check_commandavail(S_CMD_O_DELAY)) {
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100817 msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
stefanctd9ac2212011-10-22 21:45:27 +0000818 internal_delay(usecs);
stefanct69965b62011-09-15 23:38:14 +0000819 return;
820 }
hailfingerbacbc8b2009-07-21 13:02:59 +0000821 if ((sp_max_write_n) && (sp_write_n_bytes))
822 sp_pass_writen();
823 sp_check_opbuf_usage(5);
stefanctd9ac2212011-10-22 21:45:27 +0000824 buf[0] = ((usecs >> 0) & 0xFF);
825 buf[1] = ((usecs >> 8) & 0xFF);
826 buf[2] = ((usecs >> 16) & 0xFF);
827 buf[3] = ((usecs >> 24) & 0xFF);
hailfingerbacbc8b2009-07-21 13:02:59 +0000828 sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
829 sp_opbuf_usage += 5;
830 sp_prev_was_write = 0;
831}
stefanct69965b62011-09-15 23:38:14 +0000832
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100833static int serprog_spi_send_command(const struct flashctx *flash,
834 unsigned int writecnt, unsigned int readcnt,
835 const unsigned char *writearr,
836 unsigned char *readarr)
stefanct69965b62011-09-15 23:38:14 +0000837{
838 unsigned char *parmbuf;
839 int ret;
840 msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100841 if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
842 if (sp_execute_opbuf() != 0) {
843 msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
844 return 1;
845 }
846 }
847
stefanct69965b62011-09-15 23:38:14 +0000848 parmbuf = malloc(writecnt + 6);
Kangheui Wonb1e8c3b2019-10-20 16:07:32 +1100849 if (!parmbuf) {
850 msg_perr("Error: could not allocate SPI send param buffer.\n");
851 return 1;
852 }
stefanct69965b62011-09-15 23:38:14 +0000853 parmbuf[0] = (writecnt >> 0) & 0xFF;
854 parmbuf[1] = (writecnt >> 8) & 0xFF;
855 parmbuf[2] = (writecnt >> 16) & 0xFF;
856 parmbuf[3] = (readcnt >> 0) & 0xFF;
857 parmbuf[4] = (readcnt >> 8) & 0xFF;
858 parmbuf[5] = (readcnt >> 16) & 0xFF;
859 memcpy(parmbuf + 6, writearr, writecnt);
860 ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
861 readarr);
862 free(parmbuf);
863 return ret;
864}