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