xref: /aosp_15_r20/external/flashrom/serprog.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker  * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker  *
4*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2009, 2011 Urja Rannikko <[email protected]>
5*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2009 Carl-Daniel Hailfinger
6*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2024 Riku Viitanen <[email protected]>
7*0d6140beSAndroid Build Coastguard Worker  *
8*0d6140beSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
9*0d6140beSAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License as published by
10*0d6140beSAndroid Build Coastguard Worker  * the Free Software Foundation; either version 2 of the License, or
11*0d6140beSAndroid Build Coastguard Worker  * (at your option) any later version.
12*0d6140beSAndroid Build Coastguard Worker  *
13*0d6140beSAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
14*0d6140beSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*0d6140beSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*0d6140beSAndroid Build Coastguard Worker  * GNU General Public License for more details.
17*0d6140beSAndroid Build Coastguard Worker  */
18*0d6140beSAndroid Build Coastguard Worker 
19*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
20*0d6140beSAndroid Build Coastguard Worker #include <stdio.h>
21*0d6140beSAndroid Build Coastguard Worker #if ! IS_WINDOWS /* stuff (presumably) needed for sockets only */
22*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
23*0d6140beSAndroid Build Coastguard Worker #include <unistd.h>
24*0d6140beSAndroid Build Coastguard Worker #include <fcntl.h>
25*0d6140beSAndroid Build Coastguard Worker #include <sys/socket.h>
26*0d6140beSAndroid Build Coastguard Worker #include <arpa/inet.h>
27*0d6140beSAndroid Build Coastguard Worker #include <netinet/in.h>
28*0d6140beSAndroid Build Coastguard Worker #include <netinet/tcp.h>
29*0d6140beSAndroid Build Coastguard Worker #include <netdb.h>
30*0d6140beSAndroid Build Coastguard Worker #endif
31*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
32*0d6140beSAndroid Build Coastguard Worker #include <conio.h>
33*0d6140beSAndroid Build Coastguard Worker #else
34*0d6140beSAndroid Build Coastguard Worker #include <termios.h>
35*0d6140beSAndroid Build Coastguard Worker #endif
36*0d6140beSAndroid Build Coastguard Worker #include <string.h>
37*0d6140beSAndroid Build Coastguard Worker #include <errno.h>
38*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
39*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
40*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
41*0d6140beSAndroid Build Coastguard Worker 
42*0d6140beSAndroid Build Coastguard Worker /* According to Serial Flasher Protocol Specification - version 1 */
43*0d6140beSAndroid Build Coastguard Worker #define S_ACK			0x06
44*0d6140beSAndroid Build Coastguard Worker #define S_NAK			0x15
45*0d6140beSAndroid Build Coastguard Worker #define S_CMD_NOP		0x00	/* No operation					*/
46*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_IFACE		0x01	/* Query interface version			*/
47*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_CMDMAP		0x02	/* Query supported commands bitmap		*/
48*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_PGMNAME		0x03	/* Query programmer name			*/
49*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_SERBUF		0x04	/* Query Serial Buffer Size			*/
50*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_BUSTYPE		0x05	/* Query supported bustypes			*/
51*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_CHIPSIZE	0x06	/* Query supported chipsize (2^n format)	*/
52*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_OPBUF		0x07	/* Query operation buffer size			*/
53*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_WRNMAXLEN	0x08	/* Query Write to opbuf: Write-N maximum length */
54*0d6140beSAndroid Build Coastguard Worker #define S_CMD_R_BYTE		0x09	/* Read a single byte				*/
55*0d6140beSAndroid Build Coastguard Worker #define S_CMD_R_NBYTES		0x0A	/* Read n bytes					*/
56*0d6140beSAndroid Build Coastguard Worker #define S_CMD_O_INIT		0x0B	/* Initialize operation buffer			*/
57*0d6140beSAndroid Build Coastguard Worker #define S_CMD_O_WRITEB		0x0C	/* Write opbuf: Write byte with address		*/
58*0d6140beSAndroid Build Coastguard Worker #define S_CMD_O_WRITEN		0x0D	/* Write to opbuf: Write-N			*/
59*0d6140beSAndroid Build Coastguard Worker #define S_CMD_O_DELAY		0x0E	/* Write opbuf: udelay				*/
60*0d6140beSAndroid Build Coastguard Worker #define S_CMD_O_EXEC		0x0F	/* Execute operation buffer			*/
61*0d6140beSAndroid Build Coastguard Worker #define S_CMD_SYNCNOP		0x10	/* Special no-operation that returns NAK+ACK	*/
62*0d6140beSAndroid Build Coastguard Worker #define S_CMD_Q_RDNMAXLEN	0x11	/* Query read-n maximum length			*/
63*0d6140beSAndroid Build Coastguard Worker #define S_CMD_S_BUSTYPE		0x12	/* Set used bustype(s).				*/
64*0d6140beSAndroid Build Coastguard Worker #define S_CMD_O_SPIOP		0x13	/* Perform SPI operation.			*/
65*0d6140beSAndroid Build Coastguard Worker #define S_CMD_S_SPI_FREQ	0x14	/* Set SPI clock frequency			*/
66*0d6140beSAndroid Build Coastguard Worker #define S_CMD_S_PIN_STATE	0x15	/* Enable/disable output drivers		*/
67*0d6140beSAndroid Build Coastguard Worker #define S_CMD_S_SPI_CS		0x16	/* Set SPI chip select to use			*/
68*0d6140beSAndroid Build Coastguard Worker 
69*0d6140beSAndroid Build Coastguard Worker #define MSGHEADER "serprog: "
70*0d6140beSAndroid Build Coastguard Worker 
71*0d6140beSAndroid Build Coastguard Worker static uint16_t sp_device_serbuf_size = 16;
72*0d6140beSAndroid Build Coastguard Worker static uint16_t sp_device_opbuf_size = 300;
73*0d6140beSAndroid Build Coastguard Worker /* Bitmap of supported commands */
74*0d6140beSAndroid Build Coastguard Worker static uint8_t sp_cmdmap[32];
75*0d6140beSAndroid Build Coastguard Worker 
76*0d6140beSAndroid Build Coastguard Worker /* sp_prev_was_write used to detect writes with contiguous addresses
77*0d6140beSAndroid Build Coastguard Worker 	and combine them to write-n's */
78*0d6140beSAndroid Build Coastguard Worker static int sp_prev_was_write = 0;
79*0d6140beSAndroid Build Coastguard Worker /* sp_write_n_addr used as the starting addr of the currently
80*0d6140beSAndroid Build Coastguard Worker 	combined write-n operation */
81*0d6140beSAndroid Build Coastguard Worker static uint32_t sp_write_n_addr;
82*0d6140beSAndroid Build Coastguard Worker /* The maximum length of an write_n operation; 0 = write-n not supported */
83*0d6140beSAndroid Build Coastguard Worker static uint32_t sp_max_write_n = 0;
84*0d6140beSAndroid Build Coastguard Worker /* The maximum length of a read_n operation; 0 = 2^24 */
85*0d6140beSAndroid Build Coastguard Worker static uint32_t sp_max_read_n = 0;
86*0d6140beSAndroid Build Coastguard Worker 
87*0d6140beSAndroid Build Coastguard Worker /* A malloc'd buffer for combining the operation's data
88*0d6140beSAndroid Build Coastguard Worker 	and a counter that tells how much data is there. */
89*0d6140beSAndroid Build Coastguard Worker static uint8_t *sp_write_n_buf;
90*0d6140beSAndroid Build Coastguard Worker static uint32_t sp_write_n_bytes = 0;
91*0d6140beSAndroid Build Coastguard Worker 
92*0d6140beSAndroid Build Coastguard Worker /* sp_streamed_* used for flow control checking */
93*0d6140beSAndroid Build Coastguard Worker static unsigned int sp_streamed_transmit_ops = 0;
94*0d6140beSAndroid Build Coastguard Worker static unsigned int sp_streamed_transmit_bytes = 0;
95*0d6140beSAndroid Build Coastguard Worker 
96*0d6140beSAndroid Build Coastguard Worker /* sp_opbuf_usage used for counting the amount of
97*0d6140beSAndroid Build Coastguard Worker 	on-device operation buffer used */
98*0d6140beSAndroid Build Coastguard Worker static int sp_opbuf_usage = 0;
99*0d6140beSAndroid Build Coastguard Worker /* if true causes sp_docommand to automatically check
100*0d6140beSAndroid Build Coastguard Worker 	whether the command is supported before doing it */
101*0d6140beSAndroid Build Coastguard Worker static int sp_check_avail_automatic = 0;
102*0d6140beSAndroid Build Coastguard Worker 
103*0d6140beSAndroid Build Coastguard Worker #if ! IS_WINDOWS
sp_opensocket(char * ip,unsigned int port)104*0d6140beSAndroid Build Coastguard Worker static int sp_opensocket(char *ip, unsigned int port)
105*0d6140beSAndroid Build Coastguard Worker {
106*0d6140beSAndroid Build Coastguard Worker 	int flag = 1;
107*0d6140beSAndroid Build Coastguard Worker 	struct hostent *hostPtr = NULL;
108*0d6140beSAndroid Build Coastguard Worker 	union { struct sockaddr_in si; struct sockaddr s; } sp = {};
109*0d6140beSAndroid Build Coastguard Worker 	int sock;
110*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg(MSGHEADER "IP %s port %d\n", ip, port);
111*0d6140beSAndroid Build Coastguard Worker 	sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
112*0d6140beSAndroid Build Coastguard Worker 	if (sock < 0) {
113*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: serprog cannot open socket: %s\n", strerror(errno));
114*0d6140beSAndroid Build Coastguard Worker 		return -1;
115*0d6140beSAndroid Build Coastguard Worker 	}
116*0d6140beSAndroid Build Coastguard Worker 	hostPtr = gethostbyname(ip);
117*0d6140beSAndroid Build Coastguard Worker 	if (NULL == hostPtr) {
118*0d6140beSAndroid Build Coastguard Worker 		hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET);
119*0d6140beSAndroid Build Coastguard Worker 		if (NULL == hostPtr) {
120*0d6140beSAndroid Build Coastguard Worker 			close(sock);
121*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: cannot resolve %s\n", ip);
122*0d6140beSAndroid Build Coastguard Worker 			return -1;
123*0d6140beSAndroid Build Coastguard Worker 		}
124*0d6140beSAndroid Build Coastguard Worker 	}
125*0d6140beSAndroid Build Coastguard Worker 	sp.si.sin_family = AF_INET;
126*0d6140beSAndroid Build Coastguard Worker 	sp.si.sin_port = htons(port);
127*0d6140beSAndroid Build Coastguard Worker 	(void)memcpy(&sp.si.sin_addr, hostPtr->h_addr_list[0], hostPtr->h_length);
128*0d6140beSAndroid Build Coastguard Worker 	if (connect(sock, &sp.s, sizeof(sp.si)) < 0) {
129*0d6140beSAndroid Build Coastguard Worker 		close(sock);
130*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: serprog cannot connect: %s\n", strerror(errno));
131*0d6140beSAndroid Build Coastguard Worker 		return -1;
132*0d6140beSAndroid Build Coastguard Worker 	}
133*0d6140beSAndroid Build Coastguard Worker 	/* We are latency limited, and sometimes do write-write-read    *
134*0d6140beSAndroid Build Coastguard Worker 	 * (write-n) - so enable TCP_NODELAY.				*/
135*0d6140beSAndroid Build Coastguard Worker 	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) {
136*0d6140beSAndroid Build Coastguard Worker 		close(sock);
137*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: serprog cannot set socket options: %s\n", strerror(errno));
138*0d6140beSAndroid Build Coastguard Worker 		return -1;
139*0d6140beSAndroid Build Coastguard Worker 	}
140*0d6140beSAndroid Build Coastguard Worker 	return sock;
141*0d6140beSAndroid Build Coastguard Worker }
142*0d6140beSAndroid Build Coastguard Worker #endif
143*0d6140beSAndroid Build Coastguard Worker 
144*0d6140beSAndroid Build Coastguard Worker /* Synchronize: a bit tricky algorithm that tries to (and in my tests has *
145*0d6140beSAndroid Build Coastguard Worker  * always succeeded in) bring the serial protocol to known waiting-for-   *
146*0d6140beSAndroid Build Coastguard Worker  * command state - uses nonblocking I/O - rest of the driver uses         *
147*0d6140beSAndroid Build Coastguard Worker  * blocking read - TODO: add an alarm() timer for the rest of the app on  *
148*0d6140beSAndroid Build Coastguard Worker  * serial operations, though not such a big issue as the first thing to   *
149*0d6140beSAndroid Build Coastguard Worker  * do is synchronize (eg. check that device is alive).			  */
sp_synchronize(void)150*0d6140beSAndroid Build Coastguard Worker static int sp_synchronize(void)
151*0d6140beSAndroid Build Coastguard Worker {
152*0d6140beSAndroid Build Coastguard Worker 	int i;
153*0d6140beSAndroid Build Coastguard Worker 	unsigned char buf[8];
154*0d6140beSAndroid Build Coastguard Worker 	/* First sends 8 NOPs, then flushes the return data - should cause *
155*0d6140beSAndroid Build Coastguard Worker 	 * the device serial parser to get to a sane state, unless if it   *
156*0d6140beSAndroid Build Coastguard Worker 	 * is waiting for a real long write-n.                             */
157*0d6140beSAndroid Build Coastguard Worker 	memset(buf, S_CMD_NOP, 8);
158*0d6140beSAndroid Build Coastguard Worker 	if (serialport_write_nonblock(buf, 8, 1, NULL) != 0) {
159*0d6140beSAndroid Build Coastguard Worker 		goto err_out;
160*0d6140beSAndroid Build Coastguard Worker 	}
161*0d6140beSAndroid Build Coastguard Worker 	/* A second should be enough to get all the answers to the buffer */
162*0d6140beSAndroid Build Coastguard Worker 	default_delay(1000 * 1000);
163*0d6140beSAndroid Build Coastguard Worker 	sp_flush_incoming();
164*0d6140beSAndroid Build Coastguard Worker 
165*0d6140beSAndroid Build Coastguard Worker 	/* Then try up to 8 times to send syncnop and get the correct special *
166*0d6140beSAndroid Build Coastguard Worker 	 * return of NAK+ACK. Timing note: up to 10 characters, 10*50ms =     *
167*0d6140beSAndroid Build Coastguard Worker 	 * up to 500ms per try, 8*0.5s = 4s; +1s (above) = up to 5s sync      *
168*0d6140beSAndroid Build Coastguard Worker 	 * attempt, ~1s if immediate success.                                 */
169*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < 8; i++) {
170*0d6140beSAndroid Build Coastguard Worker 		int n;
171*0d6140beSAndroid Build Coastguard Worker 		unsigned char c = S_CMD_SYNCNOP;
172*0d6140beSAndroid Build Coastguard Worker 		if (serialport_write_nonblock(&c, 1, 1, NULL) != 0) {
173*0d6140beSAndroid Build Coastguard Worker 			goto err_out;
174*0d6140beSAndroid Build Coastguard Worker 		}
175*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg(".");
176*0d6140beSAndroid Build Coastguard Worker 		fflush(stdout);
177*0d6140beSAndroid Build Coastguard Worker 		for (n = 0; n < 10; n++) {
178*0d6140beSAndroid Build Coastguard Worker 			int ret = serialport_read_nonblock(&c, 1, 50, NULL);
179*0d6140beSAndroid Build Coastguard Worker 			if (ret < 0)
180*0d6140beSAndroid Build Coastguard Worker 				goto err_out;
181*0d6140beSAndroid Build Coastguard Worker 			if (ret > 0 || c != S_NAK)
182*0d6140beSAndroid Build Coastguard Worker 				continue;
183*0d6140beSAndroid Build Coastguard Worker 			ret = serialport_read_nonblock(&c, 1, 20, NULL);
184*0d6140beSAndroid Build Coastguard Worker 			if (ret < 0)
185*0d6140beSAndroid Build Coastguard Worker 				goto err_out;
186*0d6140beSAndroid Build Coastguard Worker 			if (ret > 0 || c != S_ACK)
187*0d6140beSAndroid Build Coastguard Worker 				continue;
188*0d6140beSAndroid Build Coastguard Worker 			c = S_CMD_SYNCNOP;
189*0d6140beSAndroid Build Coastguard Worker 			if (serialport_write_nonblock(&c, 1, 1, NULL) != 0) {
190*0d6140beSAndroid Build Coastguard Worker 				goto err_out;
191*0d6140beSAndroid Build Coastguard Worker 			}
192*0d6140beSAndroid Build Coastguard Worker 			ret = serialport_read_nonblock(&c, 1, 500, NULL);
193*0d6140beSAndroid Build Coastguard Worker 			if (ret < 0)
194*0d6140beSAndroid Build Coastguard Worker 				goto err_out;
195*0d6140beSAndroid Build Coastguard Worker 			if (ret > 0 || c != S_NAK)
196*0d6140beSAndroid Build Coastguard Worker 				break;	/* fail */
197*0d6140beSAndroid Build Coastguard Worker 			ret = serialport_read_nonblock(&c, 1, 100, NULL);
198*0d6140beSAndroid Build Coastguard Worker 			if (ret > 0 || ret < 0)
199*0d6140beSAndroid Build Coastguard Worker 				goto err_out;
200*0d6140beSAndroid Build Coastguard Worker 			if (c != S_ACK)
201*0d6140beSAndroid Build Coastguard Worker 				break;	/* fail */
202*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("\n");
203*0d6140beSAndroid Build Coastguard Worker 			return 0;
204*0d6140beSAndroid Build Coastguard Worker 		}
205*0d6140beSAndroid Build Coastguard Worker 	}
206*0d6140beSAndroid Build Coastguard Worker err_out:
207*0d6140beSAndroid Build Coastguard Worker 	msg_perr("Error: cannot synchronize protocol - check communications and reset device?\n");
208*0d6140beSAndroid Build Coastguard Worker 	return 1;
209*0d6140beSAndroid Build Coastguard Worker }
210*0d6140beSAndroid Build Coastguard Worker 
sp_check_commandavail(uint8_t command)211*0d6140beSAndroid Build Coastguard Worker static int sp_check_commandavail(uint8_t command)
212*0d6140beSAndroid Build Coastguard Worker {
213*0d6140beSAndroid Build Coastguard Worker 	int byteoffs, bitoffs;
214*0d6140beSAndroid Build Coastguard Worker 	byteoffs = command / 8;
215*0d6140beSAndroid Build Coastguard Worker 	bitoffs = command % 8;
216*0d6140beSAndroid Build Coastguard Worker 	return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
217*0d6140beSAndroid Build Coastguard Worker }
218*0d6140beSAndroid Build Coastguard Worker 
sp_automatic_cmdcheck(uint8_t cmd)219*0d6140beSAndroid Build Coastguard Worker static int sp_automatic_cmdcheck(uint8_t cmd)
220*0d6140beSAndroid Build Coastguard Worker {
221*0d6140beSAndroid Build Coastguard Worker 	if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
222*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Warning: Automatic command availability check failed "
223*0d6140beSAndroid Build Coastguard Worker 			 "for cmd 0x%02x - won't execute cmd\n", cmd);
224*0d6140beSAndroid Build Coastguard Worker 		return 1;
225*0d6140beSAndroid Build Coastguard Worker 		}
226*0d6140beSAndroid Build Coastguard Worker 	return 0;
227*0d6140beSAndroid Build Coastguard Worker }
228*0d6140beSAndroid Build Coastguard Worker 
sp_docommand(uint8_t command,uint32_t parmlen,uint8_t * params,uint32_t retlen,void * retparms)229*0d6140beSAndroid Build Coastguard Worker static int sp_docommand(uint8_t command, uint32_t parmlen,
230*0d6140beSAndroid Build Coastguard Worker 			uint8_t *params, uint32_t retlen, void *retparms)
231*0d6140beSAndroid Build Coastguard Worker {
232*0d6140beSAndroid Build Coastguard Worker 	unsigned char c;
233*0d6140beSAndroid Build Coastguard Worker 	if (sp_automatic_cmdcheck(command))
234*0d6140beSAndroid Build Coastguard Worker 		return 1;
235*0d6140beSAndroid Build Coastguard Worker 	if (serialport_write(&command, 1) != 0) {
236*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: cannot write op code: %s\n", strerror(errno));
237*0d6140beSAndroid Build Coastguard Worker 		return 1;
238*0d6140beSAndroid Build Coastguard Worker 	}
239*0d6140beSAndroid Build Coastguard Worker 	if (serialport_write(params, parmlen) != 0) {
240*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: cannot write parameters: %s\n", strerror(errno));
241*0d6140beSAndroid Build Coastguard Worker 		return 1;
242*0d6140beSAndroid Build Coastguard Worker 	}
243*0d6140beSAndroid Build Coastguard Worker 	if (serialport_read(&c, 1) != 0) {
244*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: cannot read from device: %s\n", strerror(errno));
245*0d6140beSAndroid Build Coastguard Worker 		return 1;
246*0d6140beSAndroid Build Coastguard Worker 	}
247*0d6140beSAndroid Build Coastguard Worker 	if (c == S_NAK)
248*0d6140beSAndroid Build Coastguard Worker 		return 1;
249*0d6140beSAndroid Build Coastguard Worker 	if (c != S_ACK) {
250*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: invalid response 0x%02X from device (to command 0x%02X)\n", c, command);
251*0d6140beSAndroid Build Coastguard Worker 		return 1;
252*0d6140beSAndroid Build Coastguard Worker 	}
253*0d6140beSAndroid Build Coastguard Worker 	if (retlen) {
254*0d6140beSAndroid Build Coastguard Worker 		if (serialport_read(retparms, retlen) != 0) {
255*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: cannot read return parameters: %s\n", strerror(errno));
256*0d6140beSAndroid Build Coastguard Worker 			return 1;
257*0d6140beSAndroid Build Coastguard Worker 		}
258*0d6140beSAndroid Build Coastguard Worker 	}
259*0d6140beSAndroid Build Coastguard Worker 	return 0;
260*0d6140beSAndroid Build Coastguard Worker }
261*0d6140beSAndroid Build Coastguard Worker 
sp_flush_stream(void)262*0d6140beSAndroid Build Coastguard Worker static int sp_flush_stream(void)
263*0d6140beSAndroid Build Coastguard Worker {
264*0d6140beSAndroid Build Coastguard Worker 	if (sp_streamed_transmit_ops)
265*0d6140beSAndroid Build Coastguard Worker 		do {
266*0d6140beSAndroid Build Coastguard Worker 			unsigned char c;
267*0d6140beSAndroid Build Coastguard Worker 			if (serialport_read(&c, 1) != 0) {
268*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: cannot read from device (flushing stream)");
269*0d6140beSAndroid Build Coastguard Worker 				return 1;
270*0d6140beSAndroid Build Coastguard Worker 			}
271*0d6140beSAndroid Build Coastguard Worker 			if (c == S_NAK) {
272*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: NAK to a stream buffer operation\n");
273*0d6140beSAndroid Build Coastguard Worker 				return 1;
274*0d6140beSAndroid Build Coastguard Worker 			}
275*0d6140beSAndroid Build Coastguard Worker 			if (c != S_ACK) {
276*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: Invalid reply 0x%02X from device\n", c);
277*0d6140beSAndroid Build Coastguard Worker 				return 1;
278*0d6140beSAndroid Build Coastguard Worker 			}
279*0d6140beSAndroid Build Coastguard Worker 		} while (--sp_streamed_transmit_ops);
280*0d6140beSAndroid Build Coastguard Worker 	sp_streamed_transmit_ops = 0;
281*0d6140beSAndroid Build Coastguard Worker 	sp_streamed_transmit_bytes = 0;
282*0d6140beSAndroid Build Coastguard Worker 	return 0;
283*0d6140beSAndroid Build Coastguard Worker }
284*0d6140beSAndroid Build Coastguard Worker 
sp_stream_buffer_op(uint8_t cmd,uint32_t parmlen,uint8_t * parms)285*0d6140beSAndroid Build Coastguard Worker static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
286*0d6140beSAndroid Build Coastguard Worker {
287*0d6140beSAndroid Build Coastguard Worker 	uint8_t *sp;
288*0d6140beSAndroid Build Coastguard Worker 	if (sp_automatic_cmdcheck(cmd))
289*0d6140beSAndroid Build Coastguard Worker 		return 1;
290*0d6140beSAndroid Build Coastguard Worker 
291*0d6140beSAndroid Build Coastguard Worker 	sp = malloc(1 + parmlen);
292*0d6140beSAndroid Build Coastguard Worker 	if (!sp) {
293*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: cannot malloc command buffer\n");
294*0d6140beSAndroid Build Coastguard Worker 		return 1;
295*0d6140beSAndroid Build Coastguard Worker 	}
296*0d6140beSAndroid Build Coastguard Worker 	sp[0] = cmd;
297*0d6140beSAndroid Build Coastguard Worker 	if (parms)
298*0d6140beSAndroid Build Coastguard Worker 		memcpy(&(sp[1]), parms, parmlen);
299*0d6140beSAndroid Build Coastguard Worker 
300*0d6140beSAndroid Build Coastguard Worker 	if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) {
301*0d6140beSAndroid Build Coastguard Worker 		if (sp_flush_stream() != 0) {
302*0d6140beSAndroid Build Coastguard Worker 			free(sp);
303*0d6140beSAndroid Build Coastguard Worker 			return 1;
304*0d6140beSAndroid Build Coastguard Worker 		}
305*0d6140beSAndroid Build Coastguard Worker 	}
306*0d6140beSAndroid Build Coastguard Worker 	if (serialport_write(sp, 1 + parmlen) != 0) {
307*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: cannot write command\n");
308*0d6140beSAndroid Build Coastguard Worker 		free(sp);
309*0d6140beSAndroid Build Coastguard Worker 		return 1;
310*0d6140beSAndroid Build Coastguard Worker 	}
311*0d6140beSAndroid Build Coastguard Worker 	sp_streamed_transmit_ops += 1;
312*0d6140beSAndroid Build Coastguard Worker 	sp_streamed_transmit_bytes += 1 + parmlen;
313*0d6140beSAndroid Build Coastguard Worker 
314*0d6140beSAndroid Build Coastguard Worker 	free(sp);
315*0d6140beSAndroid Build Coastguard Worker 	return 0;
316*0d6140beSAndroid Build Coastguard Worker }
317*0d6140beSAndroid Build Coastguard Worker 
318*0d6140beSAndroid Build Coastguard Worker /* Move an in flashrom buffer existing write-n operation to the on-device operation buffer. */
sp_pass_writen(void)319*0d6140beSAndroid Build Coastguard Worker static int sp_pass_writen(void)
320*0d6140beSAndroid Build Coastguard Worker {
321*0d6140beSAndroid Build Coastguard Worker 	unsigned char header[7];
322*0d6140beSAndroid Build Coastguard Worker 	msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
323*0d6140beSAndroid Build Coastguard Worker 	if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
324*0d6140beSAndroid Build Coastguard Worker 		if (sp_flush_stream() != 0) {
325*0d6140beSAndroid Build Coastguard Worker 			return 1;
326*0d6140beSAndroid Build Coastguard Worker 		}
327*0d6140beSAndroid Build Coastguard Worker 	}
328*0d6140beSAndroid Build Coastguard Worker 	/* In case it's just a single byte send it as a single write. */
329*0d6140beSAndroid Build Coastguard Worker 	if (sp_write_n_bytes == 1) {
330*0d6140beSAndroid Build Coastguard Worker 		sp_write_n_bytes = 0;
331*0d6140beSAndroid Build Coastguard Worker 		header[0] = (sp_write_n_addr >> 0) & 0xFF;
332*0d6140beSAndroid Build Coastguard Worker 		header[1] = (sp_write_n_addr >> 8) & 0xFF;
333*0d6140beSAndroid Build Coastguard Worker 		header[2] = (sp_write_n_addr >> 16) & 0xFF;
334*0d6140beSAndroid Build Coastguard Worker 		header[3] = sp_write_n_buf[0];
335*0d6140beSAndroid Build Coastguard Worker 		if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
336*0d6140beSAndroid Build Coastguard Worker 			return 1;
337*0d6140beSAndroid Build Coastguard Worker 		sp_opbuf_usage += 5;
338*0d6140beSAndroid Build Coastguard Worker 		return 0;
339*0d6140beSAndroid Build Coastguard Worker 	}
340*0d6140beSAndroid Build Coastguard Worker 	header[0] = S_CMD_O_WRITEN;
341*0d6140beSAndroid Build Coastguard Worker 	header[1] = (sp_write_n_bytes >> 0) & 0xFF;
342*0d6140beSAndroid Build Coastguard Worker 	header[2] = (sp_write_n_bytes >> 8) & 0xFF;
343*0d6140beSAndroid Build Coastguard Worker 	header[3] = (sp_write_n_bytes >> 16) & 0xFF;
344*0d6140beSAndroid Build Coastguard Worker 	header[4] = (sp_write_n_addr >> 0) & 0xFF;
345*0d6140beSAndroid Build Coastguard Worker 	header[5] = (sp_write_n_addr >> 8) & 0xFF;
346*0d6140beSAndroid Build Coastguard Worker 	header[6] = (sp_write_n_addr >> 16) & 0xFF;
347*0d6140beSAndroid Build Coastguard Worker 	if (serialport_write(header, 7) != 0) {
348*0d6140beSAndroid Build Coastguard Worker 		msg_perr(MSGHEADER "Error: cannot write write-n command\n");
349*0d6140beSAndroid Build Coastguard Worker 		return 1;
350*0d6140beSAndroid Build Coastguard Worker 	}
351*0d6140beSAndroid Build Coastguard Worker 	if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
352*0d6140beSAndroid Build Coastguard Worker 		msg_perr(MSGHEADER "Error: cannot write write-n data");
353*0d6140beSAndroid Build Coastguard Worker 		return 1;
354*0d6140beSAndroid Build Coastguard Worker 	}
355*0d6140beSAndroid Build Coastguard Worker 	sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
356*0d6140beSAndroid Build Coastguard Worker 	sp_streamed_transmit_ops += 1;
357*0d6140beSAndroid Build Coastguard Worker 	sp_opbuf_usage += 7 + sp_write_n_bytes;
358*0d6140beSAndroid Build Coastguard Worker 	sp_write_n_bytes = 0;
359*0d6140beSAndroid Build Coastguard Worker 	sp_prev_was_write = 0;
360*0d6140beSAndroid Build Coastguard Worker 	return 0;
361*0d6140beSAndroid Build Coastguard Worker }
362*0d6140beSAndroid Build Coastguard Worker 
sp_execute_opbuf_noflush(void)363*0d6140beSAndroid Build Coastguard Worker static int sp_execute_opbuf_noflush(void)
364*0d6140beSAndroid Build Coastguard Worker {
365*0d6140beSAndroid Build Coastguard Worker 	if ((sp_max_write_n) && (sp_write_n_bytes)) {
366*0d6140beSAndroid Build Coastguard Worker 		if (sp_pass_writen() != 0) {
367*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: could not transfer write buffer\n");
368*0d6140beSAndroid Build Coastguard Worker 			return 1;
369*0d6140beSAndroid Build Coastguard Worker 		}
370*0d6140beSAndroid Build Coastguard Worker 	}
371*0d6140beSAndroid Build Coastguard Worker 	if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
372*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: could not execute command buffer\n");
373*0d6140beSAndroid Build Coastguard Worker 		return 1;
374*0d6140beSAndroid Build Coastguard Worker 	}
375*0d6140beSAndroid Build Coastguard Worker 	msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
376*0d6140beSAndroid Build Coastguard Worker 	sp_opbuf_usage = 0;
377*0d6140beSAndroid Build Coastguard Worker 	sp_prev_was_write = 0;
378*0d6140beSAndroid Build Coastguard Worker 	return 0;
379*0d6140beSAndroid Build Coastguard Worker }
380*0d6140beSAndroid Build Coastguard Worker 
sp_execute_opbuf(void)381*0d6140beSAndroid Build Coastguard Worker static int sp_execute_opbuf(void)
382*0d6140beSAndroid Build Coastguard Worker {
383*0d6140beSAndroid Build Coastguard Worker 	if (sp_execute_opbuf_noflush() != 0)
384*0d6140beSAndroid Build Coastguard Worker 		return 1;
385*0d6140beSAndroid Build Coastguard Worker 	if (sp_flush_stream() != 0)
386*0d6140beSAndroid Build Coastguard Worker 		return 1;
387*0d6140beSAndroid Build Coastguard Worker 
388*0d6140beSAndroid Build Coastguard Worker 	return 0;
389*0d6140beSAndroid Build Coastguard Worker }
390*0d6140beSAndroid Build Coastguard Worker 
serprog_spi_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)391*0d6140beSAndroid Build Coastguard Worker static int serprog_spi_send_command(const struct flashctx *flash,
392*0d6140beSAndroid Build Coastguard Worker 				    unsigned int writecnt, unsigned int readcnt,
393*0d6140beSAndroid Build Coastguard Worker 				    const unsigned char *writearr,
394*0d6140beSAndroid Build Coastguard Worker 				    unsigned char *readarr)
395*0d6140beSAndroid Build Coastguard Worker {
396*0d6140beSAndroid Build Coastguard Worker 	unsigned char *parmbuf;
397*0d6140beSAndroid Build Coastguard Worker 	int ret;
398*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
399*0d6140beSAndroid Build Coastguard Worker 	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
400*0d6140beSAndroid Build Coastguard Worker 		if (sp_execute_opbuf() != 0) {
401*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
402*0d6140beSAndroid Build Coastguard Worker 			return 1;
403*0d6140beSAndroid Build Coastguard Worker 		}
404*0d6140beSAndroid Build Coastguard Worker 	}
405*0d6140beSAndroid Build Coastguard Worker 
406*0d6140beSAndroid Build Coastguard Worker 	parmbuf = malloc(writecnt + 6);
407*0d6140beSAndroid Build Coastguard Worker 	if (!parmbuf) {
408*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: could not allocate SPI send param buffer.\n");
409*0d6140beSAndroid Build Coastguard Worker 		return 1;
410*0d6140beSAndroid Build Coastguard Worker 	}
411*0d6140beSAndroid Build Coastguard Worker 	parmbuf[0] = (writecnt >> 0) & 0xFF;
412*0d6140beSAndroid Build Coastguard Worker 	parmbuf[1] = (writecnt >> 8) & 0xFF;
413*0d6140beSAndroid Build Coastguard Worker 	parmbuf[2] = (writecnt >> 16) & 0xFF;
414*0d6140beSAndroid Build Coastguard Worker 	parmbuf[3] = (readcnt >> 0) & 0xFF;
415*0d6140beSAndroid Build Coastguard Worker 	parmbuf[4] = (readcnt >> 8) & 0xFF;
416*0d6140beSAndroid Build Coastguard Worker 	parmbuf[5] = (readcnt >> 16) & 0xFF;
417*0d6140beSAndroid Build Coastguard Worker 	memcpy(parmbuf + 6, writearr, writecnt);
418*0d6140beSAndroid Build Coastguard Worker 	ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
419*0d6140beSAndroid Build Coastguard Worker 			   readarr);
420*0d6140beSAndroid Build Coastguard Worker 	free(parmbuf);
421*0d6140beSAndroid Build Coastguard Worker 	return ret;
422*0d6140beSAndroid Build Coastguard Worker }
423*0d6140beSAndroid Build Coastguard Worker 
serprog_shutdown(void * data)424*0d6140beSAndroid Build Coastguard Worker static int serprog_shutdown(void *data)
425*0d6140beSAndroid Build Coastguard Worker {
426*0d6140beSAndroid Build Coastguard Worker 	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
427*0d6140beSAndroid Build Coastguard Worker 	if (sp_execute_opbuf() != 0)
428*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("Could not flush command buffer.\n");
429*0d6140beSAndroid Build Coastguard Worker 	if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
430*0d6140beSAndroid Build Coastguard Worker 		uint8_t dis = 0;
431*0d6140beSAndroid Build Coastguard Worker 		if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
432*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Output drivers disabled\n");
433*0d6140beSAndroid Build Coastguard Worker 		else
434*0d6140beSAndroid Build Coastguard Worker 			msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
435*0d6140beSAndroid Build Coastguard Worker 	}
436*0d6140beSAndroid Build Coastguard Worker 	/* FIXME: fix sockets on windows(?), especially closing */
437*0d6140beSAndroid Build Coastguard Worker 	serialport_shutdown(&sp_fd);
438*0d6140beSAndroid Build Coastguard Worker 	if (sp_max_write_n)
439*0d6140beSAndroid Build Coastguard Worker 		free(sp_write_n_buf);
440*0d6140beSAndroid Build Coastguard Worker 	return 0;
441*0d6140beSAndroid Build Coastguard Worker }
442*0d6140beSAndroid Build Coastguard Worker 
serprog_map(const char * descr,uintptr_t phys_addr,size_t len)443*0d6140beSAndroid Build Coastguard Worker static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
444*0d6140beSAndroid Build Coastguard Worker {
445*0d6140beSAndroid Build Coastguard Worker 	/* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
446*0d6140beSAndroid Build Coastguard Worker 	 * correctly (usually setting them to one either in software (for FWH/LPC) or relying on the fact that
447*0d6140beSAndroid Build Coastguard Worker 	 * the hardware observes a subset of the address bits only). Combined with the standard mapping of
448*0d6140beSAndroid Build Coastguard Worker 	 * flashrom this creates a 16 MB-wide window just below the 4 GB boundary where serprog can operate (as
449*0d6140beSAndroid Build Coastguard Worker 	 * needed for non-SPI chips). Below we make sure that the requested range is within this window. */
450*0d6140beSAndroid Build Coastguard Worker 	if ((phys_addr & 0xFF000000) == 0xFF000000) {
451*0d6140beSAndroid Build Coastguard Worker 		return (void*)phys_addr;
452*0d6140beSAndroid Build Coastguard Worker 	}
453*0d6140beSAndroid Build Coastguard Worker 	msg_pwarn(MSGHEADER "requested mapping %s is incompatible: 0x%zx bytes at 0x%0*" PRIxPTR ".\n",
454*0d6140beSAndroid Build Coastguard Worker 		  descr, len, PRIxPTR_WIDTH, phys_addr);
455*0d6140beSAndroid Build Coastguard Worker 	return NULL;
456*0d6140beSAndroid Build Coastguard Worker }
457*0d6140beSAndroid Build Coastguard Worker 
458*0d6140beSAndroid Build Coastguard Worker static void serprog_delay(const struct flashctx *flash, unsigned int usecs);
459*0d6140beSAndroid Build Coastguard Worker 
460*0d6140beSAndroid Build Coastguard Worker static struct spi_master spi_master_serprog = {
461*0d6140beSAndroid Build Coastguard Worker 	.map_flash_region	= serprog_map,
462*0d6140beSAndroid Build Coastguard Worker 	.features	= SPI_MASTER_4BA,
463*0d6140beSAndroid Build Coastguard Worker 	.max_data_read	= MAX_DATA_READ_UNLIMITED,
464*0d6140beSAndroid Build Coastguard Worker 	.max_data_write	= MAX_DATA_WRITE_UNLIMITED,
465*0d6140beSAndroid Build Coastguard Worker 	.command	= serprog_spi_send_command,
466*0d6140beSAndroid Build Coastguard Worker 	.read		= default_spi_read,
467*0d6140beSAndroid Build Coastguard Worker 	.write_256	= default_spi_write_256,
468*0d6140beSAndroid Build Coastguard Worker 	.delay		= serprog_delay,
469*0d6140beSAndroid Build Coastguard Worker };
470*0d6140beSAndroid Build Coastguard Worker 
sp_check_opbuf_usage(int bytes_to_be_added)471*0d6140beSAndroid Build Coastguard Worker static int sp_check_opbuf_usage(int bytes_to_be_added)
472*0d6140beSAndroid Build Coastguard Worker {
473*0d6140beSAndroid Build Coastguard Worker 	if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
474*0d6140beSAndroid Build Coastguard Worker 		/* If this happens in the middle of a page load the page load will probably fail. */
475*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
476*0d6140beSAndroid Build Coastguard Worker 		if (sp_execute_opbuf() != 0)
477*0d6140beSAndroid Build Coastguard Worker 			return 1;
478*0d6140beSAndroid Build Coastguard Worker 	}
479*0d6140beSAndroid Build Coastguard Worker 	return 0;
480*0d6140beSAndroid Build Coastguard Worker }
481*0d6140beSAndroid Build Coastguard Worker 
serprog_chip_writeb(const struct flashctx * flash,uint8_t val,chipaddr addr)482*0d6140beSAndroid Build Coastguard Worker static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
483*0d6140beSAndroid Build Coastguard Worker 				chipaddr addr)
484*0d6140beSAndroid Build Coastguard Worker {
485*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s\n", __func__);
486*0d6140beSAndroid Build Coastguard Worker 	if (sp_max_write_n) {
487*0d6140beSAndroid Build Coastguard Worker 		if ((sp_prev_was_write)
488*0d6140beSAndroid Build Coastguard Worker 		    && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
489*0d6140beSAndroid Build Coastguard Worker 			sp_write_n_buf[sp_write_n_bytes++] = val;
490*0d6140beSAndroid Build Coastguard Worker 		} else {
491*0d6140beSAndroid Build Coastguard Worker 			if ((sp_prev_was_write) && (sp_write_n_bytes))
492*0d6140beSAndroid Build Coastguard Worker 				sp_pass_writen();
493*0d6140beSAndroid Build Coastguard Worker 			sp_prev_was_write = 1;
494*0d6140beSAndroid Build Coastguard Worker 			sp_write_n_addr = addr;
495*0d6140beSAndroid Build Coastguard Worker 			sp_write_n_bytes = 1;
496*0d6140beSAndroid Build Coastguard Worker 			sp_write_n_buf[0] = val;
497*0d6140beSAndroid Build Coastguard Worker 		}
498*0d6140beSAndroid Build Coastguard Worker 		sp_check_opbuf_usage(7 + sp_write_n_bytes);
499*0d6140beSAndroid Build Coastguard Worker 		if (sp_write_n_bytes >= sp_max_write_n)
500*0d6140beSAndroid Build Coastguard Worker 			sp_pass_writen();
501*0d6140beSAndroid Build Coastguard Worker 	} else {
502*0d6140beSAndroid Build Coastguard Worker 		/* We will have to do single writeb ops. */
503*0d6140beSAndroid Build Coastguard Worker 		unsigned char writeb_parm[4];
504*0d6140beSAndroid Build Coastguard Worker 		sp_check_opbuf_usage(6);
505*0d6140beSAndroid Build Coastguard Worker 		writeb_parm[0] = (addr >> 0) & 0xFF;
506*0d6140beSAndroid Build Coastguard Worker 		writeb_parm[1] = (addr >> 8) & 0xFF;
507*0d6140beSAndroid Build Coastguard Worker 		writeb_parm[2] = (addr >> 16) & 0xFF;
508*0d6140beSAndroid Build Coastguard Worker 		writeb_parm[3] = val;
509*0d6140beSAndroid Build Coastguard Worker 		sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
510*0d6140beSAndroid Build Coastguard Worker 		sp_opbuf_usage += 5;
511*0d6140beSAndroid Build Coastguard Worker 	}
512*0d6140beSAndroid Build Coastguard Worker }
513*0d6140beSAndroid Build Coastguard Worker 
serprog_chip_readb(const struct flashctx * flash,const chipaddr addr)514*0d6140beSAndroid Build Coastguard Worker static uint8_t serprog_chip_readb(const struct flashctx *flash,
515*0d6140beSAndroid Build Coastguard Worker 				  const chipaddr addr)
516*0d6140beSAndroid Build Coastguard Worker {
517*0d6140beSAndroid Build Coastguard Worker 	unsigned char c;
518*0d6140beSAndroid Build Coastguard Worker 	unsigned char buf[3];
519*0d6140beSAndroid Build Coastguard Worker 	/* Will stream the read operation - eg. add it to the stream buffer, *
520*0d6140beSAndroid Build Coastguard Worker 	 * then flush the buffer, then read the read answer.		     */
521*0d6140beSAndroid Build Coastguard Worker 	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
522*0d6140beSAndroid Build Coastguard Worker 		sp_execute_opbuf_noflush();
523*0d6140beSAndroid Build Coastguard Worker 	buf[0] = ((addr >> 0) & 0xFF);
524*0d6140beSAndroid Build Coastguard Worker 	buf[1] = ((addr >> 8) & 0xFF);
525*0d6140beSAndroid Build Coastguard Worker 	buf[2] = ((addr >> 16) & 0xFF);
526*0d6140beSAndroid Build Coastguard Worker 	sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
527*0d6140beSAndroid Build Coastguard Worker 	sp_flush_stream(); // FIXME: return error
528*0d6140beSAndroid Build Coastguard Worker 	if (serialport_read(&c, 1) != 0)
529*0d6140beSAndroid Build Coastguard Worker 		msg_perr(MSGHEADER "readb byteread");  // FIXME: return error
530*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
531*0d6140beSAndroid Build Coastguard Worker 	return c;
532*0d6140beSAndroid Build Coastguard Worker }
533*0d6140beSAndroid Build Coastguard Worker 
534*0d6140beSAndroid Build Coastguard Worker /* Local version that really does the job, doesn't care of max_read_n. */
sp_do_read_n(uint8_t * buf,const chipaddr addr,size_t len)535*0d6140beSAndroid Build Coastguard Worker static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
536*0d6140beSAndroid Build Coastguard Worker {
537*0d6140beSAndroid Build Coastguard Worker 	unsigned char sbuf[6];
538*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
539*0d6140beSAndroid Build Coastguard Worker 	/* Stream the read-n -- as above. */
540*0d6140beSAndroid Build Coastguard Worker 	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
541*0d6140beSAndroid Build Coastguard Worker 		sp_execute_opbuf_noflush();
542*0d6140beSAndroid Build Coastguard Worker 	sbuf[0] = ((addr >> 0) & 0xFF);
543*0d6140beSAndroid Build Coastguard Worker 	sbuf[1] = ((addr >> 8) & 0xFF);
544*0d6140beSAndroid Build Coastguard Worker 	sbuf[2] = ((addr >> 16) & 0xFF);
545*0d6140beSAndroid Build Coastguard Worker 	sbuf[3] = ((len >> 0) & 0xFF);
546*0d6140beSAndroid Build Coastguard Worker 	sbuf[4] = ((len >> 8) & 0xFF);
547*0d6140beSAndroid Build Coastguard Worker 	sbuf[5] = ((len >> 16) & 0xFF);
548*0d6140beSAndroid Build Coastguard Worker 	sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
549*0d6140beSAndroid Build Coastguard Worker 	if (sp_flush_stream() != 0)
550*0d6140beSAndroid Build Coastguard Worker 		return 1;
551*0d6140beSAndroid Build Coastguard Worker 	if (serialport_read(buf, len) != 0) {
552*0d6140beSAndroid Build Coastguard Worker 		msg_perr(MSGHEADER "Error: cannot read read-n data");
553*0d6140beSAndroid Build Coastguard Worker 		return 1;
554*0d6140beSAndroid Build Coastguard Worker 	}
555*0d6140beSAndroid Build Coastguard Worker 	return 0;
556*0d6140beSAndroid Build Coastguard Worker }
557*0d6140beSAndroid Build Coastguard Worker 
558*0d6140beSAndroid Build Coastguard Worker /* The externally called version that makes sure that max_read_n is obeyed. */
serprog_chip_readn(const struct flashctx * flash,uint8_t * buf,const chipaddr addr,size_t len)559*0d6140beSAndroid Build Coastguard Worker static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
560*0d6140beSAndroid Build Coastguard Worker 			       const chipaddr addr, size_t len)
561*0d6140beSAndroid Build Coastguard Worker {
562*0d6140beSAndroid Build Coastguard Worker 	size_t lenm = len;
563*0d6140beSAndroid Build Coastguard Worker 	chipaddr addrm = addr;
564*0d6140beSAndroid Build Coastguard Worker 	while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
565*0d6140beSAndroid Build Coastguard Worker 		sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
566*0d6140beSAndroid Build Coastguard Worker 		addrm += sp_max_read_n;
567*0d6140beSAndroid Build Coastguard Worker 		lenm -= sp_max_read_n;
568*0d6140beSAndroid Build Coastguard Worker 	}
569*0d6140beSAndroid Build Coastguard Worker 	if (lenm)
570*0d6140beSAndroid Build Coastguard Worker 		sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
571*0d6140beSAndroid Build Coastguard Worker }
572*0d6140beSAndroid Build Coastguard Worker 
serprog_delay(const struct flashctx * flash,unsigned int usecs)573*0d6140beSAndroid Build Coastguard Worker static void serprog_delay(const struct flashctx *flash, unsigned int usecs)
574*0d6140beSAndroid Build Coastguard Worker {
575*0d6140beSAndroid Build Coastguard Worker 	unsigned char buf[4];
576*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s usecs=%d\n", __func__, usecs);
577*0d6140beSAndroid Build Coastguard Worker 	if (!sp_check_commandavail(S_CMD_O_DELAY)) {
578*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
579*0d6140beSAndroid Build Coastguard Worker 		default_delay(usecs);
580*0d6140beSAndroid Build Coastguard Worker 		return;
581*0d6140beSAndroid Build Coastguard Worker 	}
582*0d6140beSAndroid Build Coastguard Worker 	if ((sp_max_write_n) && (sp_write_n_bytes))
583*0d6140beSAndroid Build Coastguard Worker 		sp_pass_writen();
584*0d6140beSAndroid Build Coastguard Worker 	sp_check_opbuf_usage(5);
585*0d6140beSAndroid Build Coastguard Worker 	buf[0] = ((usecs >> 0) & 0xFF);
586*0d6140beSAndroid Build Coastguard Worker 	buf[1] = ((usecs >> 8) & 0xFF);
587*0d6140beSAndroid Build Coastguard Worker 	buf[2] = ((usecs >> 16) & 0xFF);
588*0d6140beSAndroid Build Coastguard Worker 	buf[3] = ((usecs >> 24) & 0xFF);
589*0d6140beSAndroid Build Coastguard Worker 	sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
590*0d6140beSAndroid Build Coastguard Worker 	sp_opbuf_usage += 5;
591*0d6140beSAndroid Build Coastguard Worker 	sp_prev_was_write = 0;
592*0d6140beSAndroid Build Coastguard Worker }
593*0d6140beSAndroid Build Coastguard Worker 
594*0d6140beSAndroid Build Coastguard Worker static const struct par_master par_master_serprog = {
595*0d6140beSAndroid Build Coastguard Worker 	.map_flash_region	= serprog_map,
596*0d6140beSAndroid Build Coastguard Worker 	.chip_readb	= serprog_chip_readb,
597*0d6140beSAndroid Build Coastguard Worker 	.chip_readn	= serprog_chip_readn,
598*0d6140beSAndroid Build Coastguard Worker 	.chip_writeb	= serprog_chip_writeb,
599*0d6140beSAndroid Build Coastguard Worker 	.delay		= serprog_delay,
600*0d6140beSAndroid Build Coastguard Worker };
601*0d6140beSAndroid Build Coastguard Worker 
602*0d6140beSAndroid Build Coastguard Worker static enum chipbustype serprog_buses_supported = BUS_NONE;
603*0d6140beSAndroid Build Coastguard Worker 
serprog_init(const struct programmer_cfg * cfg)604*0d6140beSAndroid Build Coastguard Worker static int serprog_init(const struct programmer_cfg *cfg)
605*0d6140beSAndroid Build Coastguard Worker {
606*0d6140beSAndroid Build Coastguard Worker 	uint16_t iface;
607*0d6140beSAndroid Build Coastguard Worker 	unsigned char pgmname[17];
608*0d6140beSAndroid Build Coastguard Worker 	unsigned char rbuf[3];
609*0d6140beSAndroid Build Coastguard Worker 	unsigned char c;
610*0d6140beSAndroid Build Coastguard Worker 	char *device;
611*0d6140beSAndroid Build Coastguard Worker 	bool have_device = false;
612*0d6140beSAndroid Build Coastguard Worker 
613*0d6140beSAndroid Build Coastguard Worker 	/* the parameter is either of format "dev=/dev/device[:baud]" or "ip=ip:port" */
614*0d6140beSAndroid Build Coastguard Worker 	device = extract_programmer_param_str(cfg, "dev");
615*0d6140beSAndroid Build Coastguard Worker 	if (device && strlen(device)) {
616*0d6140beSAndroid Build Coastguard Worker 		char *baud_str = strstr(device, ":");
617*0d6140beSAndroid Build Coastguard Worker 		if (baud_str != NULL) {
618*0d6140beSAndroid Build Coastguard Worker 			/* Split device from baudrate. */
619*0d6140beSAndroid Build Coastguard Worker 			*baud_str = '\0';
620*0d6140beSAndroid Build Coastguard Worker 			baud_str++;
621*0d6140beSAndroid Build Coastguard Worker 		}
622*0d6140beSAndroid Build Coastguard Worker 		int baud;
623*0d6140beSAndroid Build Coastguard Worker 		/* Convert baud string to value.
624*0d6140beSAndroid Build Coastguard Worker 		 * baud_str is either NULL (if strstr can't find the colon), points to the \0 after the colon
625*0d6140beSAndroid Build Coastguard Worker 		 * if no characters where given after the colon, or a string to convert... */
626*0d6140beSAndroid Build Coastguard Worker 		if (baud_str == NULL || *baud_str == '\0') {
627*0d6140beSAndroid Build Coastguard Worker 			baud = -1;
628*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("No baudrate specified, using the hardware's defaults.\n");
629*0d6140beSAndroid Build Coastguard Worker 		} else {
630*0d6140beSAndroid Build Coastguard Worker 			baud = atoi(baud_str); // FIXME: replace atoi with strtoul
631*0d6140beSAndroid Build Coastguard Worker 		}
632*0d6140beSAndroid Build Coastguard Worker 		if (strlen(device) > 0) {
633*0d6140beSAndroid Build Coastguard Worker 			sp_fd = sp_openserport(device, baud);
634*0d6140beSAndroid Build Coastguard Worker 			if (sp_fd == SER_INV_FD) {
635*0d6140beSAndroid Build Coastguard Worker 				free(device);
636*0d6140beSAndroid Build Coastguard Worker 				return 1;
637*0d6140beSAndroid Build Coastguard Worker 			}
638*0d6140beSAndroid Build Coastguard Worker 			have_device = true;
639*0d6140beSAndroid Build Coastguard Worker 		}
640*0d6140beSAndroid Build Coastguard Worker 	}
641*0d6140beSAndroid Build Coastguard Worker 
642*0d6140beSAndroid Build Coastguard Worker #if !IS_WINDOWS
643*0d6140beSAndroid Build Coastguard Worker 	if (device && !strlen(device)) {
644*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: No device specified.\n"
645*0d6140beSAndroid Build Coastguard Worker 			 "Use flashrom -p serprog:dev=/dev/device[:baud]\n");
646*0d6140beSAndroid Build Coastguard Worker 		free(device);
647*0d6140beSAndroid Build Coastguard Worker 		return 1;
648*0d6140beSAndroid Build Coastguard Worker 	}
649*0d6140beSAndroid Build Coastguard Worker 	free(device);
650*0d6140beSAndroid Build Coastguard Worker 
651*0d6140beSAndroid Build Coastguard Worker 	device = extract_programmer_param_str(cfg, "ip");
652*0d6140beSAndroid Build Coastguard Worker 	if (have_device && device) {
653*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: Both host and device specified.\n"
654*0d6140beSAndroid Build Coastguard Worker 			 "Please use either dev= or ip= but not both.\n");
655*0d6140beSAndroid Build Coastguard Worker 		free(device);
656*0d6140beSAndroid Build Coastguard Worker 		return 1;
657*0d6140beSAndroid Build Coastguard Worker 	}
658*0d6140beSAndroid Build Coastguard Worker 	if (device && strlen(device)) {
659*0d6140beSAndroid Build Coastguard Worker 		char *port = strstr(device, ":");
660*0d6140beSAndroid Build Coastguard Worker 		if (port != NULL) {
661*0d6140beSAndroid Build Coastguard Worker 			/* Split host from port. */
662*0d6140beSAndroid Build Coastguard Worker 			*port = '\0';
663*0d6140beSAndroid Build Coastguard Worker 			port++;
664*0d6140beSAndroid Build Coastguard Worker 		}
665*0d6140beSAndroid Build Coastguard Worker 		if (!port || !strlen(port)) {
666*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: No port specified.\n"
667*0d6140beSAndroid Build Coastguard Worker 				 "Use flashrom -p serprog:ip=ipaddr:port\n");
668*0d6140beSAndroid Build Coastguard Worker 			free(device);
669*0d6140beSAndroid Build Coastguard Worker 			return 1;
670*0d6140beSAndroid Build Coastguard Worker 		}
671*0d6140beSAndroid Build Coastguard Worker 		if (strlen(device)) {
672*0d6140beSAndroid Build Coastguard Worker 			sp_fd = sp_opensocket(device, atoi(port)); // FIXME: replace atoi with strtoul
673*0d6140beSAndroid Build Coastguard Worker 			if (sp_fd < 0) {
674*0d6140beSAndroid Build Coastguard Worker 				free(device);
675*0d6140beSAndroid Build Coastguard Worker 				return 1;
676*0d6140beSAndroid Build Coastguard Worker 			}
677*0d6140beSAndroid Build Coastguard Worker 			have_device = true;
678*0d6140beSAndroid Build Coastguard Worker 		}
679*0d6140beSAndroid Build Coastguard Worker 	}
680*0d6140beSAndroid Build Coastguard Worker 	if (device && !strlen(device)) {
681*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: No host specified.\n"
682*0d6140beSAndroid Build Coastguard Worker 			 "Use flashrom -p serprog:ip=ipaddr:port\n");
683*0d6140beSAndroid Build Coastguard Worker 		free(device);
684*0d6140beSAndroid Build Coastguard Worker 		return 1;
685*0d6140beSAndroid Build Coastguard Worker 	}
686*0d6140beSAndroid Build Coastguard Worker #endif
687*0d6140beSAndroid Build Coastguard Worker 	free(device);
688*0d6140beSAndroid Build Coastguard Worker 
689*0d6140beSAndroid Build Coastguard Worker 	if (!have_device) {
690*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
691*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: No device specified.\n"
692*0d6140beSAndroid Build Coastguard Worker 			 "Use flashrom -p serprog:dev=comN[:baud]\n");
693*0d6140beSAndroid Build Coastguard Worker #else
694*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: Neither host nor device specified.\n"
695*0d6140beSAndroid Build Coastguard Worker 			 "Use flashrom -p serprog:dev=/dev/device:baud or "
696*0d6140beSAndroid Build Coastguard Worker 			 "flashrom -p serprog:ip=ipaddr:port\n");
697*0d6140beSAndroid Build Coastguard Worker #endif
698*0d6140beSAndroid Build Coastguard Worker 		return 1;
699*0d6140beSAndroid Build Coastguard Worker 	}
700*0d6140beSAndroid Build Coastguard Worker 
701*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg(MSGHEADER "connected - attempting to synchronize\n");
702*0d6140beSAndroid Build Coastguard Worker 
703*0d6140beSAndroid Build Coastguard Worker 	sp_check_avail_automatic = 0;
704*0d6140beSAndroid Build Coastguard Worker 
705*0d6140beSAndroid Build Coastguard Worker 	if (sp_synchronize())
706*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
707*0d6140beSAndroid Build Coastguard Worker 
708*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg(MSGHEADER "Synchronized\n");
709*0d6140beSAndroid Build Coastguard Worker 
710*0d6140beSAndroid Build Coastguard Worker 	if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
711*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: NAK to query interface version\n");
712*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
713*0d6140beSAndroid Build Coastguard Worker 	}
714*0d6140beSAndroid Build Coastguard Worker 
715*0d6140beSAndroid Build Coastguard Worker 	if (iface != 1) {
716*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: Unknown interface version: %d\n", iface);
717*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
718*0d6140beSAndroid Build Coastguard Worker 	}
719*0d6140beSAndroid Build Coastguard Worker 
720*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg(MSGHEADER "Interface version ok.\n");
721*0d6140beSAndroid Build Coastguard Worker 
722*0d6140beSAndroid Build Coastguard Worker 	if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
723*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: query command map not supported\n");
724*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
725*0d6140beSAndroid Build Coastguard Worker 	}
726*0d6140beSAndroid Build Coastguard Worker 
727*0d6140beSAndroid Build Coastguard Worker 	sp_check_avail_automatic = 1;
728*0d6140beSAndroid Build Coastguard Worker 
729*0d6140beSAndroid Build Coastguard Worker 	/* FIXME: This assumes that serprog device bustypes are always
730*0d6140beSAndroid Build Coastguard Worker 	 * identical with flashrom bustype enums and that they all fit
731*0d6140beSAndroid Build Coastguard Worker 	 * in a single byte.
732*0d6140beSAndroid Build Coastguard Worker 	 */
733*0d6140beSAndroid Build Coastguard Worker 	if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
734*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("Warning: NAK to query supported buses\n");
735*0d6140beSAndroid Build Coastguard Worker 		c = BUS_NONSPI;	/* A reasonable default for now. */
736*0d6140beSAndroid Build Coastguard Worker 	}
737*0d6140beSAndroid Build Coastguard Worker 	serprog_buses_supported = c;
738*0d6140beSAndroid Build Coastguard Worker 
739*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg(MSGHEADER "Bus support: parallel=%s, LPC=%s, FWH=%s, SPI=%s\n",
740*0d6140beSAndroid Build Coastguard Worker 		 (c & BUS_PARALLEL) ? "on" : "off",
741*0d6140beSAndroid Build Coastguard Worker 		 (c & BUS_LPC) ? "on" : "off",
742*0d6140beSAndroid Build Coastguard Worker 		 (c & BUS_FWH) ? "on" : "off",
743*0d6140beSAndroid Build Coastguard Worker 		 (c & BUS_SPI) ? "on" : "off");
744*0d6140beSAndroid Build Coastguard Worker 	/* Check for the minimum operational set of commands. */
745*0d6140beSAndroid Build Coastguard Worker 	if (serprog_buses_supported & BUS_SPI) {
746*0d6140beSAndroid Build Coastguard Worker 		uint8_t bt = BUS_SPI;
747*0d6140beSAndroid Build Coastguard Worker 		char *spispeed, *cs;
748*0d6140beSAndroid Build Coastguard Worker 		if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
749*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: SPI operation not supported while the "
750*0d6140beSAndroid Build Coastguard Worker 				 "bustype is SPI\n");
751*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
752*0d6140beSAndroid Build Coastguard Worker 		}
753*0d6140beSAndroid Build Coastguard Worker 		if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
754*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
755*0d6140beSAndroid Build Coastguard Worker 		/* Success of any of these commands is optional. We don't need
756*0d6140beSAndroid Build Coastguard Worker 		   the programmer to tell us its limits, but if it doesn't, we
757*0d6140beSAndroid Build Coastguard Worker 		   will assume stuff, so it's in the programmers best interest
758*0d6140beSAndroid Build Coastguard Worker 		   to tell us. */
759*0d6140beSAndroid Build Coastguard Worker 		if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
760*0d6140beSAndroid Build Coastguard Worker 			uint32_t v;
761*0d6140beSAndroid Build Coastguard Worker 			v = ((unsigned int)(rbuf[0]) << 0);
762*0d6140beSAndroid Build Coastguard Worker 			v |= ((unsigned int)(rbuf[1]) << 8);
763*0d6140beSAndroid Build Coastguard Worker 			v |= ((unsigned int)(rbuf[2]) << 16);
764*0d6140beSAndroid Build Coastguard Worker 			if (v == 0)
765*0d6140beSAndroid Build Coastguard Worker 				v = (1 << 24) - 1; /* SPI-op maximum. */
766*0d6140beSAndroid Build Coastguard Worker 			spi_master_serprog.max_data_write = v;
767*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", v);
768*0d6140beSAndroid Build Coastguard Worker 		}
769*0d6140beSAndroid Build Coastguard Worker 		if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
770*0d6140beSAndroid Build Coastguard Worker 			uint32_t v;
771*0d6140beSAndroid Build Coastguard Worker 			v = ((unsigned int)(rbuf[0]) << 0);
772*0d6140beSAndroid Build Coastguard Worker 			v |= ((unsigned int)(rbuf[1]) << 8);
773*0d6140beSAndroid Build Coastguard Worker 			v |= ((unsigned int)(rbuf[2]) << 16);
774*0d6140beSAndroid Build Coastguard Worker 			if (v == 0)
775*0d6140beSAndroid Build Coastguard Worker 				v = (1 << 24) - 1; /* SPI-op maximum. */
776*0d6140beSAndroid Build Coastguard Worker 			spi_master_serprog.max_data_read = v;
777*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
778*0d6140beSAndroid Build Coastguard Worker 		}
779*0d6140beSAndroid Build Coastguard Worker 		spispeed = extract_programmer_param_str(cfg, "spispeed");
780*0d6140beSAndroid Build Coastguard Worker 		if (spispeed && strlen(spispeed)) {
781*0d6140beSAndroid Build Coastguard Worker 			uint32_t f_spi_req, f_spi;
782*0d6140beSAndroid Build Coastguard Worker 			uint8_t buf[4];
783*0d6140beSAndroid Build Coastguard Worker 			char *f_spi_suffix;
784*0d6140beSAndroid Build Coastguard Worker 
785*0d6140beSAndroid Build Coastguard Worker 			errno = 0;
786*0d6140beSAndroid Build Coastguard Worker 			f_spi_req = strtol(spispeed, &f_spi_suffix, 0);
787*0d6140beSAndroid Build Coastguard Worker 			if (errno != 0 || spispeed == f_spi_suffix) {
788*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: Could not convert 'spispeed'.\n");
789*0d6140beSAndroid Build Coastguard Worker 				free(spispeed);
790*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
791*0d6140beSAndroid Build Coastguard Worker 			}
792*0d6140beSAndroid Build Coastguard Worker 			if (strlen(f_spi_suffix) == 1) {
793*0d6140beSAndroid Build Coastguard Worker 				if (!strcasecmp(f_spi_suffix, "M")) {
794*0d6140beSAndroid Build Coastguard Worker 					f_spi_req *= 1000000;
795*0d6140beSAndroid Build Coastguard Worker 				} else if (!strcasecmp(f_spi_suffix, "k")) {
796*0d6140beSAndroid Build Coastguard Worker 					f_spi_req *= 1000;
797*0d6140beSAndroid Build Coastguard Worker 				} else {
798*0d6140beSAndroid Build Coastguard Worker 					msg_perr("Error: Garbage following 'spispeed' value.\n");
799*0d6140beSAndroid Build Coastguard Worker 					free(spispeed);
800*0d6140beSAndroid Build Coastguard Worker 					goto init_err_cleanup_exit;
801*0d6140beSAndroid Build Coastguard Worker 				}
802*0d6140beSAndroid Build Coastguard Worker 			} else if (strlen(f_spi_suffix) > 1) {
803*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: Garbage following 'spispeed' value.\n");
804*0d6140beSAndroid Build Coastguard Worker 				free(spispeed);
805*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
806*0d6140beSAndroid Build Coastguard Worker 			}
807*0d6140beSAndroid Build Coastguard Worker 
808*0d6140beSAndroid Build Coastguard Worker 			buf[0] = (f_spi_req >> (0 * 8)) & 0xFF;
809*0d6140beSAndroid Build Coastguard Worker 			buf[1] = (f_spi_req >> (1 * 8)) & 0xFF;
810*0d6140beSAndroid Build Coastguard Worker 			buf[2] = (f_spi_req >> (2 * 8)) & 0xFF;
811*0d6140beSAndroid Build Coastguard Worker 			buf[3] = (f_spi_req >> (3 * 8)) & 0xFF;
812*0d6140beSAndroid Build Coastguard Worker 
813*0d6140beSAndroid Build Coastguard Worker 			if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0) {
814*0d6140beSAndroid Build Coastguard Worker 				msg_pwarn(MSGHEADER "Warning: Setting the SPI clock rate is not supported!\n");
815*0d6140beSAndroid Build Coastguard Worker 			} else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) == 0) {
816*0d6140beSAndroid Build Coastguard Worker 				f_spi = buf[0];
817*0d6140beSAndroid Build Coastguard Worker 				f_spi |= buf[1] << (1 * 8);
818*0d6140beSAndroid Build Coastguard Worker 				f_spi |= buf[2] << (2 * 8);
819*0d6140beSAndroid Build Coastguard Worker 				f_spi |= buf[3] << (3 * 8);
820*0d6140beSAndroid Build Coastguard Worker 				msg_pdbg(MSGHEADER "Requested to set SPI clock frequency to %u Hz. "
821*0d6140beSAndroid Build Coastguard Worker 					 "It was actually set to %u Hz\n", f_spi_req, f_spi);
822*0d6140beSAndroid Build Coastguard Worker 			} else {
823*0d6140beSAndroid Build Coastguard Worker 				msg_pwarn(MSGHEADER "Setting SPI clock rate to %u Hz failed!\n", f_spi_req);
824*0d6140beSAndroid Build Coastguard Worker 			}
825*0d6140beSAndroid Build Coastguard Worker 		}
826*0d6140beSAndroid Build Coastguard Worker 		free(spispeed);
827*0d6140beSAndroid Build Coastguard Worker 		cs = extract_programmer_param_str(cfg, "cs");
828*0d6140beSAndroid Build Coastguard Worker 		if (cs && strlen(cs)) {
829*0d6140beSAndroid Build Coastguard Worker 			char *endptr = NULL;
830*0d6140beSAndroid Build Coastguard Worker 			errno = 0;
831*0d6140beSAndroid Build Coastguard Worker 			unsigned long cs_num = strtoul(cs, &endptr, 0);
832*0d6140beSAndroid Build Coastguard Worker 			if (errno || *endptr || cs_num > 255) {
833*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: Invalid chip select requested! "
834*0d6140beSAndroid Build Coastguard Worker 				         "Only 0-255 are valid.\n");
835*0d6140beSAndroid Build Coastguard Worker 				free(cs);
836*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
837*0d6140beSAndroid Build Coastguard Worker 			}
838*0d6140beSAndroid Build Coastguard Worker 			if (!sp_check_commandavail(S_CMD_S_SPI_CS)) {
839*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: Setting SPI chip select is not supported!\n");
840*0d6140beSAndroid Build Coastguard Worker 				free(cs);
841*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
842*0d6140beSAndroid Build Coastguard Worker 			}
843*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Requested to use chip select %lu.\n", cs_num);
844*0d6140beSAndroid Build Coastguard Worker 			uint8_t cs_num8 = cs_num;
845*0d6140beSAndroid Build Coastguard Worker 			if (sp_docommand(S_CMD_S_SPI_CS, 1, &cs_num8, 0, NULL)) {
846*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: Chip select %u not supported "
847*0d6140beSAndroid Build Coastguard Worker 				         "by programmer!\n", cs_num8);
848*0d6140beSAndroid Build Coastguard Worker 				free(cs);
849*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
850*0d6140beSAndroid Build Coastguard Worker 			}
851*0d6140beSAndroid Build Coastguard Worker 		}
852*0d6140beSAndroid Build Coastguard Worker 		free(cs);
853*0d6140beSAndroid Build Coastguard Worker 
854*0d6140beSAndroid Build Coastguard Worker 		bt = serprog_buses_supported;
855*0d6140beSAndroid Build Coastguard Worker 		if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
856*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
857*0d6140beSAndroid Build Coastguard Worker 	}
858*0d6140beSAndroid Build Coastguard Worker 
859*0d6140beSAndroid Build Coastguard Worker 	if (serprog_buses_supported & BUS_NONSPI) {
860*0d6140beSAndroid Build Coastguard Worker 		if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
861*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Initialize operation buffer "
862*0d6140beSAndroid Build Coastguard Worker 				 "not supported\n");
863*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
864*0d6140beSAndroid Build Coastguard Worker 		}
865*0d6140beSAndroid Build Coastguard Worker 
866*0d6140beSAndroid Build Coastguard Worker 		if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
867*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Write to opbuf: "
868*0d6140beSAndroid Build Coastguard Worker 				 "delay not supported\n");
869*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
870*0d6140beSAndroid Build Coastguard Worker 		}
871*0d6140beSAndroid Build Coastguard Worker 
872*0d6140beSAndroid Build Coastguard Worker 		/* S_CMD_O_EXEC availability checked later. */
873*0d6140beSAndroid Build Coastguard Worker 
874*0d6140beSAndroid Build Coastguard Worker 		if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
875*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Single byte read not supported\n");
876*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
877*0d6140beSAndroid Build Coastguard Worker 		}
878*0d6140beSAndroid Build Coastguard Worker 		/* This could be translated to single byte reads (if missing),
879*0d6140beSAndroid Build Coastguard Worker 		 * but now we don't support that. */
880*0d6140beSAndroid Build Coastguard Worker 		if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
881*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Read n bytes not supported\n");
882*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
883*0d6140beSAndroid Build Coastguard Worker 		}
884*0d6140beSAndroid Build Coastguard Worker 		if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
885*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Write to opbuf: "
886*0d6140beSAndroid Build Coastguard Worker 				 "write byte not supported\n");
887*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
888*0d6140beSAndroid Build Coastguard Worker 		}
889*0d6140beSAndroid Build Coastguard Worker 
890*0d6140beSAndroid Build Coastguard Worker 		if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
891*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Write-n not supported");
892*0d6140beSAndroid Build Coastguard Worker 			sp_max_write_n = 0;
893*0d6140beSAndroid Build Coastguard Worker 		} else {
894*0d6140beSAndroid Build Coastguard Worker 			sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
895*0d6140beSAndroid Build Coastguard Worker 			sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
896*0d6140beSAndroid Build Coastguard Worker 			sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
897*0d6140beSAndroid Build Coastguard Worker 			if (!sp_max_write_n) {
898*0d6140beSAndroid Build Coastguard Worker 				sp_max_write_n = (1 << 24);
899*0d6140beSAndroid Build Coastguard Worker 			}
900*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Maximum write-n length is %d\n",
901*0d6140beSAndroid Build Coastguard Worker 				 sp_max_write_n);
902*0d6140beSAndroid Build Coastguard Worker 			sp_write_n_buf = malloc(sp_max_write_n);
903*0d6140beSAndroid Build Coastguard Worker 			if (!sp_write_n_buf) {
904*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Error: cannot allocate memory for "
905*0d6140beSAndroid Build Coastguard Worker 					 "Write-n buffer\n");
906*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
907*0d6140beSAndroid Build Coastguard Worker 			}
908*0d6140beSAndroid Build Coastguard Worker 			sp_write_n_bytes = 0;
909*0d6140beSAndroid Build Coastguard Worker 		}
910*0d6140beSAndroid Build Coastguard Worker 
911*0d6140beSAndroid Build Coastguard Worker 		if (sp_check_commandavail(S_CMD_Q_RDNMAXLEN) &&
912*0d6140beSAndroid Build Coastguard Worker 		    (sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf) == 0)) {
913*0d6140beSAndroid Build Coastguard Worker 			sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
914*0d6140beSAndroid Build Coastguard Worker 			sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
915*0d6140beSAndroid Build Coastguard Worker 			sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
916*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Maximum read-n length is %d\n",
917*0d6140beSAndroid Build Coastguard Worker 				 sp_max_read_n ? sp_max_read_n : (1 << 24));
918*0d6140beSAndroid Build Coastguard Worker 		} else {
919*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Maximum read-n length "
920*0d6140beSAndroid Build Coastguard Worker 				 "not reported\n");
921*0d6140beSAndroid Build Coastguard Worker 			sp_max_read_n = 0;
922*0d6140beSAndroid Build Coastguard Worker 		}
923*0d6140beSAndroid Build Coastguard Worker 
924*0d6140beSAndroid Build Coastguard Worker 	}
925*0d6140beSAndroid Build Coastguard Worker 
926*0d6140beSAndroid Build Coastguard Worker 	if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
927*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("Warning: NAK to query programmer name\n");
928*0d6140beSAndroid Build Coastguard Worker 		strcpy((char *)pgmname, "(unknown)");
929*0d6140beSAndroid Build Coastguard Worker 	}
930*0d6140beSAndroid Build Coastguard Worker 	pgmname[16] = 0;
931*0d6140beSAndroid Build Coastguard Worker 	msg_pinfo(MSGHEADER "Programmer name is \"%s\"\n", pgmname);
932*0d6140beSAndroid Build Coastguard Worker 
933*0d6140beSAndroid Build Coastguard Worker 	if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
934*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("Warning: NAK to query serial buffer size\n");
935*0d6140beSAndroid Build Coastguard Worker 	}
936*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg(MSGHEADER "Serial buffer size is %d\n",
937*0d6140beSAndroid Build Coastguard Worker 		     sp_device_serbuf_size);
938*0d6140beSAndroid Build Coastguard Worker 
939*0d6140beSAndroid Build Coastguard Worker 	if (sp_check_commandavail(S_CMD_O_INIT)) {
940*0d6140beSAndroid Build Coastguard Worker 		/* This would be inconsistent. */
941*0d6140beSAndroid Build Coastguard Worker 		if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
942*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Execute operation buffer not "
943*0d6140beSAndroid Build Coastguard Worker 				 "supported\n");
944*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
945*0d6140beSAndroid Build Coastguard Worker 		}
946*0d6140beSAndroid Build Coastguard Worker 
947*0d6140beSAndroid Build Coastguard Worker 		if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
948*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: NAK to initialize operation buffer\n");
949*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
950*0d6140beSAndroid Build Coastguard Worker 		}
951*0d6140beSAndroid Build Coastguard Worker 
952*0d6140beSAndroid Build Coastguard Worker 		if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
953*0d6140beSAndroid Build Coastguard Worker 		    &sp_device_opbuf_size)) {
954*0d6140beSAndroid Build Coastguard Worker 			msg_pwarn("Warning: NAK to query operation buffer size\n");
955*0d6140beSAndroid Build Coastguard Worker 		}
956*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg(MSGHEADER "operation buffer size is %d\n",
957*0d6140beSAndroid Build Coastguard Worker 			 sp_device_opbuf_size);
958*0d6140beSAndroid Build Coastguard Worker 	}
959*0d6140beSAndroid Build Coastguard Worker 
960*0d6140beSAndroid Build Coastguard Worker 	if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
961*0d6140beSAndroid Build Coastguard Worker 		uint8_t en = 1;
962*0d6140beSAndroid Build Coastguard Worker 		if (sp_docommand(S_CMD_S_PIN_STATE, 1, &en, 0, NULL) != 0) {
963*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: could not enable output buffers\n");
964*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
965*0d6140beSAndroid Build Coastguard Worker 		} else {
966*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg(MSGHEADER "Output drivers enabled\n");
967*0d6140beSAndroid Build Coastguard Worker 		}
968*0d6140beSAndroid Build Coastguard Worker 	} else {
969*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg(MSGHEADER "Warning: Programmer does not support toggling its output drivers\n");
970*0d6140beSAndroid Build Coastguard Worker 	}
971*0d6140beSAndroid Build Coastguard Worker 
972*0d6140beSAndroid Build Coastguard Worker 	sp_prev_was_write = 0;
973*0d6140beSAndroid Build Coastguard Worker 	sp_streamed_transmit_ops = 0;
974*0d6140beSAndroid Build Coastguard Worker 	sp_streamed_transmit_bytes = 0;
975*0d6140beSAndroid Build Coastguard Worker 	sp_opbuf_usage = 0;
976*0d6140beSAndroid Build Coastguard Worker 
977*0d6140beSAndroid Build Coastguard Worker 	if (register_shutdown(serprog_shutdown, NULL))
978*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
979*0d6140beSAndroid Build Coastguard Worker 	if (serprog_buses_supported & BUS_SPI)
980*0d6140beSAndroid Build Coastguard Worker 		register_spi_master(&spi_master_serprog, NULL);
981*0d6140beSAndroid Build Coastguard Worker 	if (serprog_buses_supported & BUS_NONSPI)
982*0d6140beSAndroid Build Coastguard Worker 		register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI, NULL);
983*0d6140beSAndroid Build Coastguard Worker 	return 0;
984*0d6140beSAndroid Build Coastguard Worker 
985*0d6140beSAndroid Build Coastguard Worker init_err_cleanup_exit:
986*0d6140beSAndroid Build Coastguard Worker 	serprog_shutdown(NULL);
987*0d6140beSAndroid Build Coastguard Worker 	return 1;
988*0d6140beSAndroid Build Coastguard Worker }
989*0d6140beSAndroid Build Coastguard Worker 
990*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_serprog = {
991*0d6140beSAndroid Build Coastguard Worker 	.name			= "serprog",
992*0d6140beSAndroid Build Coastguard Worker 	.type			= OTHER,
993*0d6140beSAndroid Build Coastguard Worker 				/* FIXME */
994*0d6140beSAndroid Build Coastguard Worker 	.devs.note		= "All programmer devices speaking the serprog protocol\n",
995*0d6140beSAndroid Build Coastguard Worker 	.init			= serprog_init,
996*0d6140beSAndroid Build Coastguard Worker };
997