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) 2010 Carl-Daniel Hailfinger
5*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2015 Simon Glass
6*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2015 Stefan Tauner
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; version 2 of the License.
11*0d6140beSAndroid Build Coastguard Worker *
12*0d6140beSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
13*0d6140beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*0d6140beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*0d6140beSAndroid Build Coastguard Worker * GNU General Public License for more details.
16*0d6140beSAndroid Build Coastguard Worker */
17*0d6140beSAndroid Build Coastguard Worker
18*0d6140beSAndroid Build Coastguard Worker #include <sys/types.h>
19*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
20*0d6140beSAndroid Build Coastguard Worker #include <stdio.h>
21*0d6140beSAndroid Build Coastguard Worker #include <string.h>
22*0d6140beSAndroid Build Coastguard Worker #include <limits.h>
23*0d6140beSAndroid Build Coastguard Worker #include <errno.h>
24*0d6140beSAndroid Build Coastguard Worker #include <libusb.h>
25*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
26*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
27*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
28*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
29*0d6140beSAndroid Build Coastguard Worker
30*0d6140beSAndroid Build Coastguard Worker /* LIBUSB_CALL ensures the right calling conventions on libusb callbacks.
31*0d6140beSAndroid Build Coastguard Worker * However, the macro is not defined everywhere. m(
32*0d6140beSAndroid Build Coastguard Worker */
33*0d6140beSAndroid Build Coastguard Worker #ifndef LIBUSB_CALL
34*0d6140beSAndroid Build Coastguard Worker #define LIBUSB_CALL
35*0d6140beSAndroid Build Coastguard Worker #endif
36*0d6140beSAndroid Build Coastguard Worker
37*0d6140beSAndroid Build Coastguard Worker #define FIRMWARE_VERSION(x,y,z) ((x << 16) | (y << 8) | z)
38*0d6140beSAndroid Build Coastguard Worker #define DEFAULT_TIMEOUT 3000
39*0d6140beSAndroid Build Coastguard Worker #define DEDIPROG_ASYNC_TRANSFERS 8 /* at most 8 asynchronous transfers */
40*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_OTHER_OUT (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_OTHER) /* 0x43 */
41*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_OTHER_IN (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_OTHER) /* 0xC3 */
42*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_EP_OUT (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT) /* 0x42 */
43*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_EP_IN (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT) /* 0xC2 */
44*0d6140beSAndroid Build Coastguard Worker
45*0d6140beSAndroid Build Coastguard Worker enum dediprog_devtype {
46*0d6140beSAndroid Build Coastguard Worker DEV_UNKNOWN = 0,
47*0d6140beSAndroid Build Coastguard Worker DEV_SF100 = 100,
48*0d6140beSAndroid Build Coastguard Worker DEV_SF200 = 200,
49*0d6140beSAndroid Build Coastguard Worker DEV_SF600 = 600,
50*0d6140beSAndroid Build Coastguard Worker };
51*0d6140beSAndroid Build Coastguard Worker
52*0d6140beSAndroid Build Coastguard Worker enum dediprog_leds {
53*0d6140beSAndroid Build Coastguard Worker LED_INVALID = -1,
54*0d6140beSAndroid Build Coastguard Worker LED_NONE = 0,
55*0d6140beSAndroid Build Coastguard Worker LED_PASS = 1 << 0,
56*0d6140beSAndroid Build Coastguard Worker LED_BUSY = 1 << 1,
57*0d6140beSAndroid Build Coastguard Worker LED_ERROR = 1 << 2,
58*0d6140beSAndroid Build Coastguard Worker LED_ALL = 7,
59*0d6140beSAndroid Build Coastguard Worker };
60*0d6140beSAndroid Build Coastguard Worker
61*0d6140beSAndroid Build Coastguard Worker /* IO bits for CMD_SET_IO_LED message */
62*0d6140beSAndroid Build Coastguard Worker enum dediprog_ios {
63*0d6140beSAndroid Build Coastguard Worker IO1 = 1 << 0,
64*0d6140beSAndroid Build Coastguard Worker IO2 = 1 << 1,
65*0d6140beSAndroid Build Coastguard Worker IO3 = 1 << 2,
66*0d6140beSAndroid Build Coastguard Worker IO4 = 1 << 3,
67*0d6140beSAndroid Build Coastguard Worker };
68*0d6140beSAndroid Build Coastguard Worker
69*0d6140beSAndroid Build Coastguard Worker enum dediprog_cmds {
70*0d6140beSAndroid Build Coastguard Worker CMD_TRANSCEIVE = 0x01,
71*0d6140beSAndroid Build Coastguard Worker CMD_POLL_STATUS_REG = 0x02,
72*0d6140beSAndroid Build Coastguard Worker CMD_SET_VPP = 0x03,
73*0d6140beSAndroid Build Coastguard Worker CMD_SET_TARGET = 0x04,
74*0d6140beSAndroid Build Coastguard Worker CMD_READ_EEPROM = 0x05,
75*0d6140beSAndroid Build Coastguard Worker CMD_WRITE_EEPROM = 0x06,
76*0d6140beSAndroid Build Coastguard Worker CMD_SET_IO_LED = 0x07,
77*0d6140beSAndroid Build Coastguard Worker CMD_READ_PROG_INFO = 0x08,
78*0d6140beSAndroid Build Coastguard Worker CMD_SET_VCC = 0x09,
79*0d6140beSAndroid Build Coastguard Worker CMD_SET_STANDALONE = 0x0A,
80*0d6140beSAndroid Build Coastguard Worker CMD_SET_VOLTAGE = 0x0B, /* Only in firmware older than 6.0.0 */
81*0d6140beSAndroid Build Coastguard Worker CMD_GET_BUTTON = 0x11,
82*0d6140beSAndroid Build Coastguard Worker CMD_GET_UID = 0x12,
83*0d6140beSAndroid Build Coastguard Worker CMD_SET_CS = 0x14,
84*0d6140beSAndroid Build Coastguard Worker CMD_IO_MODE = 0x15,
85*0d6140beSAndroid Build Coastguard Worker CMD_FW_UPDATE = 0x1A,
86*0d6140beSAndroid Build Coastguard Worker CMD_FPGA_UPDATE = 0x1B,
87*0d6140beSAndroid Build Coastguard Worker CMD_READ_FPGA_VERSION = 0x1C,
88*0d6140beSAndroid Build Coastguard Worker CMD_SET_HOLD = 0x1D,
89*0d6140beSAndroid Build Coastguard Worker CMD_READ = 0x20,
90*0d6140beSAndroid Build Coastguard Worker CMD_WRITE = 0x30,
91*0d6140beSAndroid Build Coastguard Worker CMD_WRITE_AT45DB = 0x31,
92*0d6140beSAndroid Build Coastguard Worker CMD_NAND_WRITE = 0x32,
93*0d6140beSAndroid Build Coastguard Worker CMD_NAND_READ = 0x33,
94*0d6140beSAndroid Build Coastguard Worker CMD_SET_SPI_CLK = 0x61,
95*0d6140beSAndroid Build Coastguard Worker CMD_CHECK_SOCKET = 0x62,
96*0d6140beSAndroid Build Coastguard Worker CMD_DOWNLOAD_PRJ = 0x63,
97*0d6140beSAndroid Build Coastguard Worker CMD_READ_PRJ_NAME = 0x64,
98*0d6140beSAndroid Build Coastguard Worker // New protocol/firmware only
99*0d6140beSAndroid Build Coastguard Worker CMD_CHECK_SDCARD = 0x65,
100*0d6140beSAndroid Build Coastguard Worker CMD_READ_PRJ = 0x66,
101*0d6140beSAndroid Build Coastguard Worker };
102*0d6140beSAndroid Build Coastguard Worker
103*0d6140beSAndroid Build Coastguard Worker enum dediprog_target {
104*0d6140beSAndroid Build Coastguard Worker FLASH_TYPE_APPLICATION_FLASH_1 = 0,
105*0d6140beSAndroid Build Coastguard Worker FLASH_TYPE_FLASH_CARD,
106*0d6140beSAndroid Build Coastguard Worker FLASH_TYPE_APPLICATION_FLASH_2,
107*0d6140beSAndroid Build Coastguard Worker FLASH_TYPE_SOCKET,
108*0d6140beSAndroid Build Coastguard Worker };
109*0d6140beSAndroid Build Coastguard Worker
110*0d6140beSAndroid Build Coastguard Worker enum dediprog_readmode {
111*0d6140beSAndroid Build Coastguard Worker READ_MODE_STD = 1,
112*0d6140beSAndroid Build Coastguard Worker READ_MODE_FAST = 2,
113*0d6140beSAndroid Build Coastguard Worker READ_MODE_ATMEL45 = 3,
114*0d6140beSAndroid Build Coastguard Worker READ_MODE_4B_ADDR_FAST = 4,
115*0d6140beSAndroid Build Coastguard Worker READ_MODE_4B_ADDR_FAST_0x0C = 5, /* New protocol only */
116*0d6140beSAndroid Build Coastguard Worker };
117*0d6140beSAndroid Build Coastguard Worker
118*0d6140beSAndroid Build Coastguard Worker enum dediprog_writemode {
119*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_PAGE_PGM = 1,
120*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_PAGE_WRITE = 2,
121*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_1B_AAI = 3,
122*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_2B_AAI = 4,
123*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_128B_PAGE = 5,
124*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_PAGE_AT26DF041 = 6,
125*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_SILICON_BLUE_FPGA = 7,
126*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_64B_PAGE_NUMONYX_PCM = 8, /* unit of 512 bytes */
127*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_4B_ADDR_256B_PAGE_PGM = 9,
128*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_32B_PAGE_PGM_MXIC_512K = 10, /* unit of 512 bytes */
129*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_4B_ADDR_256B_PAGE_PGM_0x12 = 11,
130*0d6140beSAndroid Build Coastguard Worker WRITE_MODE_4B_ADDR_256B_PAGE_PGM_FLAGS = 12,
131*0d6140beSAndroid Build Coastguard Worker };
132*0d6140beSAndroid Build Coastguard Worker
133*0d6140beSAndroid Build Coastguard Worker enum dediprog_standalone_mode {
134*0d6140beSAndroid Build Coastguard Worker ENTER_STANDALONE_MODE = 0,
135*0d6140beSAndroid Build Coastguard Worker LEAVE_STANDALONE_MODE = 1,
136*0d6140beSAndroid Build Coastguard Worker };
137*0d6140beSAndroid Build Coastguard Worker
138*0d6140beSAndroid Build Coastguard Worker /*
139*0d6140beSAndroid Build Coastguard Worker * These are not official designations; they are for use in flashrom only.
140*0d6140beSAndroid Build Coastguard Worker * Order must be preserved so that comparison operators work.
141*0d6140beSAndroid Build Coastguard Worker */
142*0d6140beSAndroid Build Coastguard Worker enum protocol {
143*0d6140beSAndroid Build Coastguard Worker PROTOCOL_UNKNOWN,
144*0d6140beSAndroid Build Coastguard Worker PROTOCOL_V1,
145*0d6140beSAndroid Build Coastguard Worker PROTOCOL_V2,
146*0d6140beSAndroid Build Coastguard Worker PROTOCOL_V3,
147*0d6140beSAndroid Build Coastguard Worker };
148*0d6140beSAndroid Build Coastguard Worker
149*0d6140beSAndroid Build Coastguard Worker static const struct dev_entry devs_dediprog[] = {
150*0d6140beSAndroid Build Coastguard Worker {0x0483, 0xDADA, OK, "Dediprog", "SF100/SF200/SF600"},
151*0d6140beSAndroid Build Coastguard Worker
152*0d6140beSAndroid Build Coastguard Worker {0},
153*0d6140beSAndroid Build Coastguard Worker };
154*0d6140beSAndroid Build Coastguard Worker
155*0d6140beSAndroid Build Coastguard Worker struct dediprog_data {
156*0d6140beSAndroid Build Coastguard Worker struct libusb_context *usb_ctx;
157*0d6140beSAndroid Build Coastguard Worker libusb_device_handle *handle;
158*0d6140beSAndroid Build Coastguard Worker int in_endpoint;
159*0d6140beSAndroid Build Coastguard Worker int out_endpoint;
160*0d6140beSAndroid Build Coastguard Worker int firmwareversion;
161*0d6140beSAndroid Build Coastguard Worker enum dediprog_devtype devicetype;
162*0d6140beSAndroid Build Coastguard Worker };
163*0d6140beSAndroid Build Coastguard Worker
164*0d6140beSAndroid Build Coastguard Worker #if defined(LIBUSB_MAJOR) && defined(LIBUSB_MINOR) && defined(LIBUSB_MICRO) && \
165*0d6140beSAndroid Build Coastguard Worker LIBUSB_MAJOR <= 1 && LIBUSB_MINOR == 0 && LIBUSB_MICRO < 9
166*0d6140beSAndroid Build Coastguard Worker /* Quick and dirty replacement for missing libusb_error_name in libusb < 1.0.9 */
libusb_error_name(int error_code)167*0d6140beSAndroid Build Coastguard Worker const char * LIBUSB_CALL libusb_error_name(int error_code)
168*0d6140beSAndroid Build Coastguard Worker {
169*0d6140beSAndroid Build Coastguard Worker if (error_code >= INT16_MIN && error_code <= INT16_MAX) {
170*0d6140beSAndroid Build Coastguard Worker /* 18 chars for text, rest for number (16 b should be enough), sign, nullbyte. */
171*0d6140beSAndroid Build Coastguard Worker static char my_libusb_error[18 + 5 + 2];
172*0d6140beSAndroid Build Coastguard Worker sprintf(my_libusb_error, "libusb error code %i", error_code);
173*0d6140beSAndroid Build Coastguard Worker return my_libusb_error;
174*0d6140beSAndroid Build Coastguard Worker } else {
175*0d6140beSAndroid Build Coastguard Worker return "UNKNOWN";
176*0d6140beSAndroid Build Coastguard Worker }
177*0d6140beSAndroid Build Coastguard Worker }
178*0d6140beSAndroid Build Coastguard Worker #endif
179*0d6140beSAndroid Build Coastguard Worker
protocol(const struct dediprog_data * dp_data)180*0d6140beSAndroid Build Coastguard Worker static enum protocol protocol(const struct dediprog_data *dp_data)
181*0d6140beSAndroid Build Coastguard Worker {
182*0d6140beSAndroid Build Coastguard Worker /* Firmware version < 5.0.0 is handled explicitly in some cases. */
183*0d6140beSAndroid Build Coastguard Worker switch (dp_data->devicetype) {
184*0d6140beSAndroid Build Coastguard Worker case DEV_SF100:
185*0d6140beSAndroid Build Coastguard Worker case DEV_SF200:
186*0d6140beSAndroid Build Coastguard Worker if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 5, 0))
187*0d6140beSAndroid Build Coastguard Worker return PROTOCOL_V1;
188*0d6140beSAndroid Build Coastguard Worker else
189*0d6140beSAndroid Build Coastguard Worker return PROTOCOL_V2;
190*0d6140beSAndroid Build Coastguard Worker case DEV_SF600:
191*0d6140beSAndroid Build Coastguard Worker if (dp_data->firmwareversion < FIRMWARE_VERSION(6, 9, 0))
192*0d6140beSAndroid Build Coastguard Worker return PROTOCOL_V1;
193*0d6140beSAndroid Build Coastguard Worker else if (dp_data->firmwareversion <= FIRMWARE_VERSION(7, 2, 21))
194*0d6140beSAndroid Build Coastguard Worker return PROTOCOL_V2;
195*0d6140beSAndroid Build Coastguard Worker else
196*0d6140beSAndroid Build Coastguard Worker return PROTOCOL_V3;
197*0d6140beSAndroid Build Coastguard Worker default:
198*0d6140beSAndroid Build Coastguard Worker return PROTOCOL_UNKNOWN;
199*0d6140beSAndroid Build Coastguard Worker }
200*0d6140beSAndroid Build Coastguard Worker }
201*0d6140beSAndroid Build Coastguard Worker
202*0d6140beSAndroid Build Coastguard Worker struct dediprog_transfer_status {
203*0d6140beSAndroid Build Coastguard Worker int error; /* OK if 0, ERROR else */
204*0d6140beSAndroid Build Coastguard Worker unsigned int queued_idx;
205*0d6140beSAndroid Build Coastguard Worker unsigned int finished_idx;
206*0d6140beSAndroid Build Coastguard Worker };
207*0d6140beSAndroid Build Coastguard Worker
dediprog_bulk_read_cb(struct libusb_transfer * const transfer)208*0d6140beSAndroid Build Coastguard Worker static void LIBUSB_CALL dediprog_bulk_read_cb(struct libusb_transfer *const transfer)
209*0d6140beSAndroid Build Coastguard Worker {
210*0d6140beSAndroid Build Coastguard Worker struct dediprog_transfer_status *const status = (struct dediprog_transfer_status *)transfer->user_data;
211*0d6140beSAndroid Build Coastguard Worker if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
212*0d6140beSAndroid Build Coastguard Worker status->error = 1;
213*0d6140beSAndroid Build Coastguard Worker msg_perr("SPI bulk read failed!\n");
214*0d6140beSAndroid Build Coastguard Worker }
215*0d6140beSAndroid Build Coastguard Worker ++status->finished_idx;
216*0d6140beSAndroid Build Coastguard Worker }
217*0d6140beSAndroid Build Coastguard Worker
dediprog_bulk_read_poll(struct libusb_context * usb_ctx,const struct dediprog_transfer_status * const status,const int finish)218*0d6140beSAndroid Build Coastguard Worker static int dediprog_bulk_read_poll(struct libusb_context *usb_ctx,
219*0d6140beSAndroid Build Coastguard Worker const struct dediprog_transfer_status *const status,
220*0d6140beSAndroid Build Coastguard Worker const int finish)
221*0d6140beSAndroid Build Coastguard Worker {
222*0d6140beSAndroid Build Coastguard Worker if (status->finished_idx >= status->queued_idx)
223*0d6140beSAndroid Build Coastguard Worker return 0;
224*0d6140beSAndroid Build Coastguard Worker
225*0d6140beSAndroid Build Coastguard Worker do {
226*0d6140beSAndroid Build Coastguard Worker struct timeval timeout = { 10, 0 };
227*0d6140beSAndroid Build Coastguard Worker const int ret = libusb_handle_events_timeout(usb_ctx, &timeout);
228*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
229*0d6140beSAndroid Build Coastguard Worker msg_perr("Polling read events failed: %i %s!\n", ret, libusb_error_name(ret));
230*0d6140beSAndroid Build Coastguard Worker return 1;
231*0d6140beSAndroid Build Coastguard Worker }
232*0d6140beSAndroid Build Coastguard Worker } while (finish && (status->finished_idx < status->queued_idx));
233*0d6140beSAndroid Build Coastguard Worker return 0;
234*0d6140beSAndroid Build Coastguard Worker }
235*0d6140beSAndroid Build Coastguard Worker
dediprog_read(libusb_device_handle * dediprog_handle,enum dediprog_cmds cmd,unsigned int value,unsigned int idx,uint8_t * bytes,size_t size)236*0d6140beSAndroid Build Coastguard Worker static int dediprog_read(libusb_device_handle *dediprog_handle,
237*0d6140beSAndroid Build Coastguard Worker enum dediprog_cmds cmd, unsigned int value, unsigned int idx,
238*0d6140beSAndroid Build Coastguard Worker uint8_t *bytes, size_t size)
239*0d6140beSAndroid Build Coastguard Worker {
240*0d6140beSAndroid Build Coastguard Worker return libusb_control_transfer(dediprog_handle, REQTYPE_EP_IN, cmd, value, idx,
241*0d6140beSAndroid Build Coastguard Worker (unsigned char *)bytes, size, DEFAULT_TIMEOUT);
242*0d6140beSAndroid Build Coastguard Worker }
243*0d6140beSAndroid Build Coastguard Worker
dediprog_write(libusb_device_handle * dediprog_handle,enum dediprog_cmds cmd,unsigned int value,unsigned int idx,const uint8_t * bytes,size_t size)244*0d6140beSAndroid Build Coastguard Worker static int dediprog_write(libusb_device_handle *dediprog_handle,
245*0d6140beSAndroid Build Coastguard Worker enum dediprog_cmds cmd, unsigned int value, unsigned int idx,
246*0d6140beSAndroid Build Coastguard Worker const uint8_t *bytes, size_t size)
247*0d6140beSAndroid Build Coastguard Worker {
248*0d6140beSAndroid Build Coastguard Worker return libusb_control_transfer(dediprog_handle, REQTYPE_EP_OUT, cmd, value, idx,
249*0d6140beSAndroid Build Coastguard Worker (unsigned char *)bytes, size, DEFAULT_TIMEOUT);
250*0d6140beSAndroid Build Coastguard Worker }
251*0d6140beSAndroid Build Coastguard Worker
252*0d6140beSAndroid Build Coastguard Worker
253*0d6140beSAndroid Build Coastguard Worker /* This function sets the GPIOs connected to the LEDs as well as IO1-IO4. */
dediprog_set_leds(int leds,const struct dediprog_data * dp_data)254*0d6140beSAndroid Build Coastguard Worker static int dediprog_set_leds(int leds, const struct dediprog_data *dp_data)
255*0d6140beSAndroid Build Coastguard Worker {
256*0d6140beSAndroid Build Coastguard Worker if (leds < LED_NONE || leds > LED_ALL)
257*0d6140beSAndroid Build Coastguard Worker leds = LED_ALL;
258*0d6140beSAndroid Build Coastguard Worker
259*0d6140beSAndroid Build Coastguard Worker /* Older Dediprogs with 2.x.x and 3.x.x firmware only had two LEDs, assigned to different bits. So map
260*0d6140beSAndroid Build Coastguard Worker * them around if we have an old device. On those devices the LEDs map as follows:
261*0d6140beSAndroid Build Coastguard Worker * bit 2 == 0: green light is on.
262*0d6140beSAndroid Build Coastguard Worker * bit 0 == 0: red light is on.
263*0d6140beSAndroid Build Coastguard Worker *
264*0d6140beSAndroid Build Coastguard Worker * Additionally, the command structure has changed with the "new" protocol.
265*0d6140beSAndroid Build Coastguard Worker *
266*0d6140beSAndroid Build Coastguard Worker * FIXME: take IO pins into account
267*0d6140beSAndroid Build Coastguard Worker */
268*0d6140beSAndroid Build Coastguard Worker int target_leds, ret;
269*0d6140beSAndroid Build Coastguard Worker if (protocol(dp_data) >= PROTOCOL_V2) {
270*0d6140beSAndroid Build Coastguard Worker target_leds = (leds ^ 7) << 8;
271*0d6140beSAndroid Build Coastguard Worker ret = dediprog_write(dp_data->handle, CMD_SET_IO_LED, target_leds, 0, NULL, 0);
272*0d6140beSAndroid Build Coastguard Worker } else {
273*0d6140beSAndroid Build Coastguard Worker if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 0, 0)) {
274*0d6140beSAndroid Build Coastguard Worker target_leds = ((leds & LED_ERROR) >> 2) | ((leds & LED_PASS) << 2);
275*0d6140beSAndroid Build Coastguard Worker } else {
276*0d6140beSAndroid Build Coastguard Worker target_leds = leds;
277*0d6140beSAndroid Build Coastguard Worker }
278*0d6140beSAndroid Build Coastguard Worker target_leds ^= 7;
279*0d6140beSAndroid Build Coastguard Worker
280*0d6140beSAndroid Build Coastguard Worker ret = dediprog_write(dp_data->handle, CMD_SET_IO_LED, 0x9, target_leds, NULL, 0);
281*0d6140beSAndroid Build Coastguard Worker }
282*0d6140beSAndroid Build Coastguard Worker
283*0d6140beSAndroid Build Coastguard Worker if (ret != 0x0) {
284*0d6140beSAndroid Build Coastguard Worker msg_perr("Command Set LED 0x%x failed (%s)!\n", leds, libusb_error_name(ret));
285*0d6140beSAndroid Build Coastguard Worker return 1;
286*0d6140beSAndroid Build Coastguard Worker }
287*0d6140beSAndroid Build Coastguard Worker
288*0d6140beSAndroid Build Coastguard Worker return 0;
289*0d6140beSAndroid Build Coastguard Worker }
290*0d6140beSAndroid Build Coastguard Worker
dediprog_set_spi_voltage(libusb_device_handle * dediprog_handle,int millivolt)291*0d6140beSAndroid Build Coastguard Worker static int dediprog_set_spi_voltage(libusb_device_handle *dediprog_handle, int millivolt)
292*0d6140beSAndroid Build Coastguard Worker {
293*0d6140beSAndroid Build Coastguard Worker int ret;
294*0d6140beSAndroid Build Coastguard Worker uint16_t voltage_selector;
295*0d6140beSAndroid Build Coastguard Worker
296*0d6140beSAndroid Build Coastguard Worker switch (millivolt) {
297*0d6140beSAndroid Build Coastguard Worker case 0:
298*0d6140beSAndroid Build Coastguard Worker /* Admittedly this one is an assumption. */
299*0d6140beSAndroid Build Coastguard Worker voltage_selector = 0x0;
300*0d6140beSAndroid Build Coastguard Worker break;
301*0d6140beSAndroid Build Coastguard Worker case 1800:
302*0d6140beSAndroid Build Coastguard Worker voltage_selector = 0x12;
303*0d6140beSAndroid Build Coastguard Worker break;
304*0d6140beSAndroid Build Coastguard Worker case 2500:
305*0d6140beSAndroid Build Coastguard Worker voltage_selector = 0x11;
306*0d6140beSAndroid Build Coastguard Worker break;
307*0d6140beSAndroid Build Coastguard Worker case 3500:
308*0d6140beSAndroid Build Coastguard Worker voltage_selector = 0x10;
309*0d6140beSAndroid Build Coastguard Worker break;
310*0d6140beSAndroid Build Coastguard Worker default:
311*0d6140beSAndroid Build Coastguard Worker msg_perr("Unknown voltage %i mV! Aborting.\n", millivolt);
312*0d6140beSAndroid Build Coastguard Worker return 1;
313*0d6140beSAndroid Build Coastguard Worker }
314*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Setting SPI voltage to %u.%03u V\n", millivolt / 1000,
315*0d6140beSAndroid Build Coastguard Worker millivolt % 1000);
316*0d6140beSAndroid Build Coastguard Worker
317*0d6140beSAndroid Build Coastguard Worker if (voltage_selector == 0) {
318*0d6140beSAndroid Build Coastguard Worker /* Wait some time as the original driver does. */
319*0d6140beSAndroid Build Coastguard Worker default_delay(200 * 1000);
320*0d6140beSAndroid Build Coastguard Worker }
321*0d6140beSAndroid Build Coastguard Worker ret = dediprog_write(dediprog_handle, CMD_SET_VCC, voltage_selector, 0, NULL, 0);
322*0d6140beSAndroid Build Coastguard Worker if (ret != 0x0) {
323*0d6140beSAndroid Build Coastguard Worker msg_perr("Command Set SPI Voltage 0x%x failed!\n",
324*0d6140beSAndroid Build Coastguard Worker voltage_selector);
325*0d6140beSAndroid Build Coastguard Worker return 1;
326*0d6140beSAndroid Build Coastguard Worker }
327*0d6140beSAndroid Build Coastguard Worker if (voltage_selector != 0) {
328*0d6140beSAndroid Build Coastguard Worker /* Wait some time as the original driver does. */
329*0d6140beSAndroid Build Coastguard Worker default_delay(200 * 1000);
330*0d6140beSAndroid Build Coastguard Worker }
331*0d6140beSAndroid Build Coastguard Worker return 0;
332*0d6140beSAndroid Build Coastguard Worker }
333*0d6140beSAndroid Build Coastguard Worker
334*0d6140beSAndroid Build Coastguard Worker struct dediprog_spispeeds {
335*0d6140beSAndroid Build Coastguard Worker const char *const name;
336*0d6140beSAndroid Build Coastguard Worker const int speed;
337*0d6140beSAndroid Build Coastguard Worker };
338*0d6140beSAndroid Build Coastguard Worker
339*0d6140beSAndroid Build Coastguard Worker static const struct dediprog_spispeeds spispeeds[] = {
340*0d6140beSAndroid Build Coastguard Worker { "24M", 0x0 },
341*0d6140beSAndroid Build Coastguard Worker { "12M", 0x2 },
342*0d6140beSAndroid Build Coastguard Worker { "8M", 0x1 },
343*0d6140beSAndroid Build Coastguard Worker { "3M", 0x3 },
344*0d6140beSAndroid Build Coastguard Worker { "2.18M", 0x4 },
345*0d6140beSAndroid Build Coastguard Worker { "1.5M", 0x5 },
346*0d6140beSAndroid Build Coastguard Worker { "750k", 0x6 },
347*0d6140beSAndroid Build Coastguard Worker { "375k", 0x7 },
348*0d6140beSAndroid Build Coastguard Worker { NULL, 0x0 },
349*0d6140beSAndroid Build Coastguard Worker };
350*0d6140beSAndroid Build Coastguard Worker
dediprog_set_spi_speed(unsigned int spispeed_idx,const struct dediprog_data * dp_data)351*0d6140beSAndroid Build Coastguard Worker static int dediprog_set_spi_speed(unsigned int spispeed_idx, const struct dediprog_data *dp_data)
352*0d6140beSAndroid Build Coastguard Worker {
353*0d6140beSAndroid Build Coastguard Worker if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 0, 0)) {
354*0d6140beSAndroid Build Coastguard Worker msg_pwarn("Skipping to set SPI speed because firmware is too old.\n");
355*0d6140beSAndroid Build Coastguard Worker return 0;
356*0d6140beSAndroid Build Coastguard Worker }
357*0d6140beSAndroid Build Coastguard Worker
358*0d6140beSAndroid Build Coastguard Worker const struct dediprog_spispeeds *spispeed = &spispeeds[spispeed_idx];
359*0d6140beSAndroid Build Coastguard Worker msg_pdbg("SPI speed is %sHz\n", spispeed->name);
360*0d6140beSAndroid Build Coastguard Worker
361*0d6140beSAndroid Build Coastguard Worker int ret = dediprog_write(dp_data->handle, CMD_SET_SPI_CLK, spispeed->speed, 0, NULL, 0);
362*0d6140beSAndroid Build Coastguard Worker if (ret != 0x0) {
363*0d6140beSAndroid Build Coastguard Worker msg_perr("Command Set SPI Speed 0x%x failed!\n", spispeed->speed);
364*0d6140beSAndroid Build Coastguard Worker return 1;
365*0d6140beSAndroid Build Coastguard Worker }
366*0d6140beSAndroid Build Coastguard Worker return 0;
367*0d6140beSAndroid Build Coastguard Worker }
368*0d6140beSAndroid Build Coastguard Worker
prepare_rw_cmd(struct flashctx * const flash,uint8_t * data_packet,unsigned int count,uint8_t dedi_spi_cmd,unsigned int * value,unsigned int * idx,unsigned int start,int is_read)369*0d6140beSAndroid Build Coastguard Worker static int prepare_rw_cmd(
370*0d6140beSAndroid Build Coastguard Worker struct flashctx *const flash, uint8_t *data_packet, unsigned int count,
371*0d6140beSAndroid Build Coastguard Worker uint8_t dedi_spi_cmd, unsigned int *value, unsigned int *idx, unsigned int start, int is_read)
372*0d6140beSAndroid Build Coastguard Worker {
373*0d6140beSAndroid Build Coastguard Worker const struct dediprog_data *dp_data = flash->mst->spi.data;
374*0d6140beSAndroid Build Coastguard Worker
375*0d6140beSAndroid Build Coastguard Worker if (count >= 1 << 16) {
376*0d6140beSAndroid Build Coastguard Worker msg_perr("%s: Unsupported transfer length of %u blocks! "
377*0d6140beSAndroid Build Coastguard Worker "Please report a bug at [email protected]\n",
378*0d6140beSAndroid Build Coastguard Worker __func__, count);
379*0d6140beSAndroid Build Coastguard Worker return 1;
380*0d6140beSAndroid Build Coastguard Worker }
381*0d6140beSAndroid Build Coastguard Worker
382*0d6140beSAndroid Build Coastguard Worker /* First 5 bytes are common in both generations. */
383*0d6140beSAndroid Build Coastguard Worker data_packet[0] = count & 0xff;
384*0d6140beSAndroid Build Coastguard Worker data_packet[1] = (count >> 8) & 0xff;
385*0d6140beSAndroid Build Coastguard Worker data_packet[2] = 0; /* RFU */
386*0d6140beSAndroid Build Coastguard Worker data_packet[3] = dedi_spi_cmd; /* Read/Write Mode (currently READ_MODE_STD, WRITE_MODE_PAGE_PGM or WRITE_MODE_2B_AAI) */
387*0d6140beSAndroid Build Coastguard Worker data_packet[4] = 0; /* "Opcode". Specs imply necessity only for READ_MODE_4B_ADDR_FAST and WRITE_MODE_4B_ADDR_256B_PAGE_PGM */
388*0d6140beSAndroid Build Coastguard Worker
389*0d6140beSAndroid Build Coastguard Worker if (protocol(dp_data) >= PROTOCOL_V2) {
390*0d6140beSAndroid Build Coastguard Worker if (is_read && flash->chip->feature_bits & FEATURE_4BA_FAST_READ) {
391*0d6140beSAndroid Build Coastguard Worker data_packet[3] = READ_MODE_4B_ADDR_FAST_0x0C;
392*0d6140beSAndroid Build Coastguard Worker data_packet[4] = JEDEC_READ_4BA_FAST;
393*0d6140beSAndroid Build Coastguard Worker } else if (dedi_spi_cmd == WRITE_MODE_PAGE_PGM
394*0d6140beSAndroid Build Coastguard Worker && (flash->chip->feature_bits & FEATURE_4BA_WRITE)) {
395*0d6140beSAndroid Build Coastguard Worker data_packet[3] = WRITE_MODE_4B_ADDR_256B_PAGE_PGM_0x12;
396*0d6140beSAndroid Build Coastguard Worker data_packet[4] = JEDEC_BYTE_PROGRAM_4BA;
397*0d6140beSAndroid Build Coastguard Worker }
398*0d6140beSAndroid Build Coastguard Worker
399*0d6140beSAndroid Build Coastguard Worker *value = *idx = 0;
400*0d6140beSAndroid Build Coastguard Worker data_packet[5] = 0; /* RFU */
401*0d6140beSAndroid Build Coastguard Worker data_packet[6] = (start >> 0) & 0xff;
402*0d6140beSAndroid Build Coastguard Worker data_packet[7] = (start >> 8) & 0xff;
403*0d6140beSAndroid Build Coastguard Worker data_packet[8] = (start >> 16) & 0xff;
404*0d6140beSAndroid Build Coastguard Worker data_packet[9] = (start >> 24) & 0xff;
405*0d6140beSAndroid Build Coastguard Worker if (protocol(dp_data) >= PROTOCOL_V3) {
406*0d6140beSAndroid Build Coastguard Worker if (is_read) {
407*0d6140beSAndroid Build Coastguard Worker data_packet[10] = 0x00; /* address length (3 or 4) */
408*0d6140beSAndroid Build Coastguard Worker data_packet[11] = 0x00; /* dummy cycle / 2 */
409*0d6140beSAndroid Build Coastguard Worker } else {
410*0d6140beSAndroid Build Coastguard Worker /* 16 LSBs and 16 HSBs of page size */
411*0d6140beSAndroid Build Coastguard Worker /* FIXME: This assumes page size of 256. */
412*0d6140beSAndroid Build Coastguard Worker data_packet[10] = 0x00;
413*0d6140beSAndroid Build Coastguard Worker data_packet[11] = 0x01;
414*0d6140beSAndroid Build Coastguard Worker data_packet[12] = 0x00;
415*0d6140beSAndroid Build Coastguard Worker data_packet[13] = 0x00;
416*0d6140beSAndroid Build Coastguard Worker }
417*0d6140beSAndroid Build Coastguard Worker }
418*0d6140beSAndroid Build Coastguard Worker } else {
419*0d6140beSAndroid Build Coastguard Worker if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
420*0d6140beSAndroid Build Coastguard Worker if (spi_set_extended_address(flash, start >> 24))
421*0d6140beSAndroid Build Coastguard Worker return 1;
422*0d6140beSAndroid Build Coastguard Worker } else if (start >> 24) {
423*0d6140beSAndroid Build Coastguard Worker msg_cerr("Can't handle 4-byte address with dediprog.\n");
424*0d6140beSAndroid Build Coastguard Worker return 1;
425*0d6140beSAndroid Build Coastguard Worker }
426*0d6140beSAndroid Build Coastguard Worker /*
427*0d6140beSAndroid Build Coastguard Worker * We don't know how the dediprog firmware handles 4-byte
428*0d6140beSAndroid Build Coastguard Worker * addresses. So let's not tell it what we are doing and
429*0d6140beSAndroid Build Coastguard Worker * only send the lower 3 bytes.
430*0d6140beSAndroid Build Coastguard Worker */
431*0d6140beSAndroid Build Coastguard Worker *value = start & 0xffff;
432*0d6140beSAndroid Build Coastguard Worker *idx = (start >> 16) & 0xff;
433*0d6140beSAndroid Build Coastguard Worker }
434*0d6140beSAndroid Build Coastguard Worker
435*0d6140beSAndroid Build Coastguard Worker return 0;
436*0d6140beSAndroid Build Coastguard Worker }
437*0d6140beSAndroid Build Coastguard Worker
438*0d6140beSAndroid Build Coastguard Worker /* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes.
439*0d6140beSAndroid Build Coastguard Worker * @start start address
440*0d6140beSAndroid Build Coastguard Worker * @len length
441*0d6140beSAndroid Build Coastguard Worker * @return 0 on success, 1 on failure
442*0d6140beSAndroid Build Coastguard Worker */
dediprog_spi_bulk_read(struct flashctx * flash,uint8_t * buf,unsigned int start,unsigned int len)443*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
444*0d6140beSAndroid Build Coastguard Worker {
445*0d6140beSAndroid Build Coastguard Worker int err = 1;
446*0d6140beSAndroid Build Coastguard Worker const struct dediprog_data *dp_data = flash->mst->spi.data;
447*0d6140beSAndroid Build Coastguard Worker
448*0d6140beSAndroid Build Coastguard Worker /* chunksize must be 512, other sizes will NOT work at all. */
449*0d6140beSAndroid Build Coastguard Worker const unsigned int chunksize = 512;
450*0d6140beSAndroid Build Coastguard Worker const unsigned int count = len / chunksize;
451*0d6140beSAndroid Build Coastguard Worker
452*0d6140beSAndroid Build Coastguard Worker struct dediprog_transfer_status status = { 0, 0, 0 };
453*0d6140beSAndroid Build Coastguard Worker struct libusb_transfer *transfers[DEDIPROG_ASYNC_TRANSFERS] = { NULL, };
454*0d6140beSAndroid Build Coastguard Worker struct libusb_transfer *transfer;
455*0d6140beSAndroid Build Coastguard Worker
456*0d6140beSAndroid Build Coastguard Worker if (len == 0)
457*0d6140beSAndroid Build Coastguard Worker return 0;
458*0d6140beSAndroid Build Coastguard Worker
459*0d6140beSAndroid Build Coastguard Worker if ((start % chunksize) || (len % chunksize)) {
460*0d6140beSAndroid Build Coastguard Worker msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug at [email protected]\n",
461*0d6140beSAndroid Build Coastguard Worker __func__, start, len);
462*0d6140beSAndroid Build Coastguard Worker return 1;
463*0d6140beSAndroid Build Coastguard Worker }
464*0d6140beSAndroid Build Coastguard Worker
465*0d6140beSAndroid Build Coastguard Worker int command_packet_size;
466*0d6140beSAndroid Build Coastguard Worker switch (protocol(dp_data)) {
467*0d6140beSAndroid Build Coastguard Worker case PROTOCOL_V1:
468*0d6140beSAndroid Build Coastguard Worker command_packet_size = 5;
469*0d6140beSAndroid Build Coastguard Worker break;
470*0d6140beSAndroid Build Coastguard Worker case PROTOCOL_V2:
471*0d6140beSAndroid Build Coastguard Worker command_packet_size = 10;
472*0d6140beSAndroid Build Coastguard Worker break;
473*0d6140beSAndroid Build Coastguard Worker case PROTOCOL_V3:
474*0d6140beSAndroid Build Coastguard Worker command_packet_size = 12;
475*0d6140beSAndroid Build Coastguard Worker break;
476*0d6140beSAndroid Build Coastguard Worker default:
477*0d6140beSAndroid Build Coastguard Worker return 1;
478*0d6140beSAndroid Build Coastguard Worker }
479*0d6140beSAndroid Build Coastguard Worker
480*0d6140beSAndroid Build Coastguard Worker uint8_t data_packet[command_packet_size];
481*0d6140beSAndroid Build Coastguard Worker unsigned int value, idx;
482*0d6140beSAndroid Build Coastguard Worker if (prepare_rw_cmd(flash, data_packet, count, READ_MODE_STD, &value, &idx, start, 1))
483*0d6140beSAndroid Build Coastguard Worker return 1;
484*0d6140beSAndroid Build Coastguard Worker
485*0d6140beSAndroid Build Coastguard Worker int ret = dediprog_write(dp_data->handle, CMD_READ, value, idx, data_packet, sizeof(data_packet));
486*0d6140beSAndroid Build Coastguard Worker if (ret != (int)sizeof(data_packet)) {
487*0d6140beSAndroid Build Coastguard Worker msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, libusb_error_name(ret));
488*0d6140beSAndroid Build Coastguard Worker return 1;
489*0d6140beSAndroid Build Coastguard Worker }
490*0d6140beSAndroid Build Coastguard Worker
491*0d6140beSAndroid Build Coastguard Worker /*
492*0d6140beSAndroid Build Coastguard Worker * Ring buffer of bulk transfers.
493*0d6140beSAndroid Build Coastguard Worker * Poll until at least one transfer is ready,
494*0d6140beSAndroid Build Coastguard Worker * schedule next transfers until buffer is full.
495*0d6140beSAndroid Build Coastguard Worker */
496*0d6140beSAndroid Build Coastguard Worker
497*0d6140beSAndroid Build Coastguard Worker /* Allocate bulk transfers. */
498*0d6140beSAndroid Build Coastguard Worker unsigned int i;
499*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < MIN(DEDIPROG_ASYNC_TRANSFERS, count); ++i) {
500*0d6140beSAndroid Build Coastguard Worker transfers[i] = libusb_alloc_transfer(0);
501*0d6140beSAndroid Build Coastguard Worker if (!transfers[i]) {
502*0d6140beSAndroid Build Coastguard Worker msg_perr("Allocating libusb transfer %i failed: %s!\n", i, libusb_error_name(ret));
503*0d6140beSAndroid Build Coastguard Worker goto err_free;
504*0d6140beSAndroid Build Coastguard Worker }
505*0d6140beSAndroid Build Coastguard Worker }
506*0d6140beSAndroid Build Coastguard Worker
507*0d6140beSAndroid Build Coastguard Worker /* Now transfer requested chunks using libusb's asynchronous interface. */
508*0d6140beSAndroid Build Coastguard Worker while (!status.error && (status.queued_idx < count)) {
509*0d6140beSAndroid Build Coastguard Worker while ((status.queued_idx < count) &&
510*0d6140beSAndroid Build Coastguard Worker (status.queued_idx - status.finished_idx) < DEDIPROG_ASYNC_TRANSFERS)
511*0d6140beSAndroid Build Coastguard Worker {
512*0d6140beSAndroid Build Coastguard Worker transfer = transfers[status.queued_idx % DEDIPROG_ASYNC_TRANSFERS];
513*0d6140beSAndroid Build Coastguard Worker libusb_fill_bulk_transfer(transfer, dp_data->handle, 0x80 | dp_data->in_endpoint,
514*0d6140beSAndroid Build Coastguard Worker (unsigned char *)buf + status.queued_idx * chunksize, chunksize,
515*0d6140beSAndroid Build Coastguard Worker dediprog_bulk_read_cb, &status, DEFAULT_TIMEOUT);
516*0d6140beSAndroid Build Coastguard Worker transfer->flags |= LIBUSB_TRANSFER_SHORT_NOT_OK;
517*0d6140beSAndroid Build Coastguard Worker ret = libusb_submit_transfer(transfer);
518*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
519*0d6140beSAndroid Build Coastguard Worker msg_perr("Submitting SPI bulk read %i failed: %s!\n",
520*0d6140beSAndroid Build Coastguard Worker status.queued_idx, libusb_error_name(ret));
521*0d6140beSAndroid Build Coastguard Worker goto err_free;
522*0d6140beSAndroid Build Coastguard Worker }
523*0d6140beSAndroid Build Coastguard Worker ++status.queued_idx;
524*0d6140beSAndroid Build Coastguard Worker }
525*0d6140beSAndroid Build Coastguard Worker if (dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 0))
526*0d6140beSAndroid Build Coastguard Worker goto err_free;
527*0d6140beSAndroid Build Coastguard Worker }
528*0d6140beSAndroid Build Coastguard Worker /* Wait for transfers to finish. */
529*0d6140beSAndroid Build Coastguard Worker if (dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 1))
530*0d6140beSAndroid Build Coastguard Worker goto err_free;
531*0d6140beSAndroid Build Coastguard Worker /* Check if everything has been transmitted. */
532*0d6140beSAndroid Build Coastguard Worker if ((status.finished_idx < count) || status.error)
533*0d6140beSAndroid Build Coastguard Worker goto err_free;
534*0d6140beSAndroid Build Coastguard Worker
535*0d6140beSAndroid Build Coastguard Worker err = 0;
536*0d6140beSAndroid Build Coastguard Worker
537*0d6140beSAndroid Build Coastguard Worker err_free:
538*0d6140beSAndroid Build Coastguard Worker dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 1);
539*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < DEDIPROG_ASYNC_TRANSFERS; ++i)
540*0d6140beSAndroid Build Coastguard Worker if (transfers[i]) libusb_free_transfer(transfers[i]);
541*0d6140beSAndroid Build Coastguard Worker return err;
542*0d6140beSAndroid Build Coastguard Worker }
543*0d6140beSAndroid Build Coastguard Worker
dediprog_spi_read(struct flashctx * flash,uint8_t * buf,unsigned int start,unsigned int len)544*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
545*0d6140beSAndroid Build Coastguard Worker {
546*0d6140beSAndroid Build Coastguard Worker int ret;
547*0d6140beSAndroid Build Coastguard Worker /* chunksize must be 512, other sizes will NOT work at all. */
548*0d6140beSAndroid Build Coastguard Worker const unsigned int chunksize = 0x200;
549*0d6140beSAndroid Build Coastguard Worker unsigned int residue = start % chunksize ? min(len, chunksize - start % chunksize) : 0;
550*0d6140beSAndroid Build Coastguard Worker unsigned int bulklen;
551*0d6140beSAndroid Build Coastguard Worker const struct dediprog_data *dp_data = flash->mst->spi.data;
552*0d6140beSAndroid Build Coastguard Worker
553*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_BUSY, dp_data);
554*0d6140beSAndroid Build Coastguard Worker
555*0d6140beSAndroid Build Coastguard Worker if (residue) {
556*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
557*0d6140beSAndroid Build Coastguard Worker start, residue);
558*0d6140beSAndroid Build Coastguard Worker ret = default_spi_read(flash, buf, start, residue);
559*0d6140beSAndroid Build Coastguard Worker if (ret)
560*0d6140beSAndroid Build Coastguard Worker goto err;
561*0d6140beSAndroid Build Coastguard Worker }
562*0d6140beSAndroid Build Coastguard Worker
563*0d6140beSAndroid Build Coastguard Worker /* Round down. */
564*0d6140beSAndroid Build Coastguard Worker bulklen = (len - residue) / chunksize * chunksize;
565*0d6140beSAndroid Build Coastguard Worker ret = dediprog_spi_bulk_read(flash, buf + residue, start + residue, bulklen);
566*0d6140beSAndroid Build Coastguard Worker if (ret)
567*0d6140beSAndroid Build Coastguard Worker goto err;
568*0d6140beSAndroid Build Coastguard Worker
569*0d6140beSAndroid Build Coastguard Worker len -= residue + bulklen;
570*0d6140beSAndroid Build Coastguard Worker if (len != 0) {
571*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
572*0d6140beSAndroid Build Coastguard Worker start, len);
573*0d6140beSAndroid Build Coastguard Worker ret = default_spi_read(flash, buf + residue + bulklen,
574*0d6140beSAndroid Build Coastguard Worker start + residue + bulklen, len);
575*0d6140beSAndroid Build Coastguard Worker if (ret)
576*0d6140beSAndroid Build Coastguard Worker goto err;
577*0d6140beSAndroid Build Coastguard Worker }
578*0d6140beSAndroid Build Coastguard Worker
579*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_PASS, dp_data);
580*0d6140beSAndroid Build Coastguard Worker return 0;
581*0d6140beSAndroid Build Coastguard Worker err:
582*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_ERROR, dp_data);
583*0d6140beSAndroid Build Coastguard Worker return ret;
584*0d6140beSAndroid Build Coastguard Worker }
585*0d6140beSAndroid Build Coastguard Worker
586*0d6140beSAndroid Build Coastguard Worker /* Bulk write interface, will write multiple chunksize byte chunks aligned to chunksize bytes.
587*0d6140beSAndroid Build Coastguard Worker * @chunksize length of data chunks, only 256 supported by now
588*0d6140beSAndroid Build Coastguard Worker * @start start address
589*0d6140beSAndroid Build Coastguard Worker * @len length
590*0d6140beSAndroid Build Coastguard Worker * @dedi_spi_cmd dediprog specific write command for spi bus
591*0d6140beSAndroid Build Coastguard Worker * @return 0 on success, 1 on failure
592*0d6140beSAndroid Build Coastguard Worker */
dediprog_spi_bulk_write(struct flashctx * flash,const uint8_t * buf,unsigned int chunksize,unsigned int start,unsigned int len,uint8_t dedi_spi_cmd)593*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_bulk_write(struct flashctx *flash, const uint8_t *buf, unsigned int chunksize,
594*0d6140beSAndroid Build Coastguard Worker unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
595*0d6140beSAndroid Build Coastguard Worker {
596*0d6140beSAndroid Build Coastguard Worker /* USB transfer size must be 256, other sizes will NOT work at all.
597*0d6140beSAndroid Build Coastguard Worker * chunksize is the real data size per USB bulk transfer. The remaining
598*0d6140beSAndroid Build Coastguard Worker * space in a USB bulk transfer must be filled with 0xff padding.
599*0d6140beSAndroid Build Coastguard Worker */
600*0d6140beSAndroid Build Coastguard Worker const unsigned int count = len / chunksize;
601*0d6140beSAndroid Build Coastguard Worker const struct dediprog_data *dp_data = flash->mst->spi.data;
602*0d6140beSAndroid Build Coastguard Worker
603*0d6140beSAndroid Build Coastguard Worker /*
604*0d6140beSAndroid Build Coastguard Worker * We should change this check to
605*0d6140beSAndroid Build Coastguard Worker * chunksize > 512
606*0d6140beSAndroid Build Coastguard Worker * once we know how to handle different chunk sizes.
607*0d6140beSAndroid Build Coastguard Worker */
608*0d6140beSAndroid Build Coastguard Worker if (chunksize != 256) {
609*0d6140beSAndroid Build Coastguard Worker msg_perr("%s: Chunk sizes other than 256 bytes are unsupported, chunksize=%u!\n"
610*0d6140beSAndroid Build Coastguard Worker "Please report a bug at [email protected]\n", __func__, chunksize);
611*0d6140beSAndroid Build Coastguard Worker return 1;
612*0d6140beSAndroid Build Coastguard Worker }
613*0d6140beSAndroid Build Coastguard Worker
614*0d6140beSAndroid Build Coastguard Worker if ((start % chunksize) || (len % chunksize)) {
615*0d6140beSAndroid Build Coastguard Worker msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug "
616*0d6140beSAndroid Build Coastguard Worker "at [email protected]\n", __func__, start, len);
617*0d6140beSAndroid Build Coastguard Worker return 1;
618*0d6140beSAndroid Build Coastguard Worker }
619*0d6140beSAndroid Build Coastguard Worker
620*0d6140beSAndroid Build Coastguard Worker /* No idea if the hardware can handle empty writes, so chicken out. */
621*0d6140beSAndroid Build Coastguard Worker if (len == 0)
622*0d6140beSAndroid Build Coastguard Worker return 0;
623*0d6140beSAndroid Build Coastguard Worker
624*0d6140beSAndroid Build Coastguard Worker int command_packet_size;
625*0d6140beSAndroid Build Coastguard Worker switch (protocol(dp_data)) {
626*0d6140beSAndroid Build Coastguard Worker case PROTOCOL_V1:
627*0d6140beSAndroid Build Coastguard Worker command_packet_size = 5;
628*0d6140beSAndroid Build Coastguard Worker break;
629*0d6140beSAndroid Build Coastguard Worker case PROTOCOL_V2:
630*0d6140beSAndroid Build Coastguard Worker command_packet_size = 10;
631*0d6140beSAndroid Build Coastguard Worker break;
632*0d6140beSAndroid Build Coastguard Worker case PROTOCOL_V3:
633*0d6140beSAndroid Build Coastguard Worker command_packet_size = 14;
634*0d6140beSAndroid Build Coastguard Worker break;
635*0d6140beSAndroid Build Coastguard Worker default:
636*0d6140beSAndroid Build Coastguard Worker return 1;
637*0d6140beSAndroid Build Coastguard Worker }
638*0d6140beSAndroid Build Coastguard Worker
639*0d6140beSAndroid Build Coastguard Worker uint8_t data_packet[command_packet_size];
640*0d6140beSAndroid Build Coastguard Worker unsigned int value, idx;
641*0d6140beSAndroid Build Coastguard Worker if (prepare_rw_cmd(flash, data_packet, count, dedi_spi_cmd, &value, &idx, start, 0))
642*0d6140beSAndroid Build Coastguard Worker return 1;
643*0d6140beSAndroid Build Coastguard Worker int ret = dediprog_write(dp_data->handle, CMD_WRITE, value, idx, data_packet, sizeof(data_packet));
644*0d6140beSAndroid Build Coastguard Worker if (ret != (int)sizeof(data_packet)) {
645*0d6140beSAndroid Build Coastguard Worker msg_perr("Command Write SPI Bulk failed, %s!\n", libusb_error_name(ret));
646*0d6140beSAndroid Build Coastguard Worker return 1;
647*0d6140beSAndroid Build Coastguard Worker }
648*0d6140beSAndroid Build Coastguard Worker
649*0d6140beSAndroid Build Coastguard Worker unsigned int i;
650*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < count; i++) {
651*0d6140beSAndroid Build Coastguard Worker unsigned char usbbuf[512];
652*0d6140beSAndroid Build Coastguard Worker memcpy(usbbuf, buf + i * chunksize, chunksize);
653*0d6140beSAndroid Build Coastguard Worker memset(usbbuf + chunksize, 0xff, sizeof(usbbuf) - chunksize); // fill up with 0xFF
654*0d6140beSAndroid Build Coastguard Worker int transferred;
655*0d6140beSAndroid Build Coastguard Worker ret = libusb_bulk_transfer(dp_data->handle, dp_data->out_endpoint, usbbuf, 512, &transferred,
656*0d6140beSAndroid Build Coastguard Worker DEFAULT_TIMEOUT);
657*0d6140beSAndroid Build Coastguard Worker if ((ret < 0) || (transferred != 512)) {
658*0d6140beSAndroid Build Coastguard Worker msg_perr("SPI bulk write failed, expected %i, got %s!\n", 512, libusb_error_name(ret));
659*0d6140beSAndroid Build Coastguard Worker return 1;
660*0d6140beSAndroid Build Coastguard Worker }
661*0d6140beSAndroid Build Coastguard Worker update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, count);
662*0d6140beSAndroid Build Coastguard Worker }
663*0d6140beSAndroid Build Coastguard Worker
664*0d6140beSAndroid Build Coastguard Worker return 0;
665*0d6140beSAndroid Build Coastguard Worker }
666*0d6140beSAndroid Build Coastguard Worker
dediprog_spi_write(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len,uint8_t dedi_spi_cmd)667*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_write(struct flashctx *flash, const uint8_t *buf,
668*0d6140beSAndroid Build Coastguard Worker unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
669*0d6140beSAndroid Build Coastguard Worker {
670*0d6140beSAndroid Build Coastguard Worker int ret;
671*0d6140beSAndroid Build Coastguard Worker const unsigned int chunksize = flash->chip->page_size;
672*0d6140beSAndroid Build Coastguard Worker unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0;
673*0d6140beSAndroid Build Coastguard Worker unsigned int bulklen;
674*0d6140beSAndroid Build Coastguard Worker const struct dediprog_data *dp_data = flash->mst->spi.data;
675*0d6140beSAndroid Build Coastguard Worker
676*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_BUSY, dp_data);
677*0d6140beSAndroid Build Coastguard Worker
678*0d6140beSAndroid Build Coastguard Worker if (chunksize != 256) {
679*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Page sizes other than 256 bytes are unsupported as "
680*0d6140beSAndroid Build Coastguard Worker "we don't know how dediprog\nhandles them.\n");
681*0d6140beSAndroid Build Coastguard Worker /* Write everything like it was residue. */
682*0d6140beSAndroid Build Coastguard Worker residue = len;
683*0d6140beSAndroid Build Coastguard Worker }
684*0d6140beSAndroid Build Coastguard Worker
685*0d6140beSAndroid Build Coastguard Worker if (residue) {
686*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
687*0d6140beSAndroid Build Coastguard Worker start, residue);
688*0d6140beSAndroid Build Coastguard Worker /* No idea about the real limit. Maybe 16 including command and address, maybe more. */
689*0d6140beSAndroid Build Coastguard Worker ret = spi_write_chunked(flash, buf, start, residue, 11);
690*0d6140beSAndroid Build Coastguard Worker if (ret) {
691*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_ERROR, dp_data);
692*0d6140beSAndroid Build Coastguard Worker return ret;
693*0d6140beSAndroid Build Coastguard Worker }
694*0d6140beSAndroid Build Coastguard Worker }
695*0d6140beSAndroid Build Coastguard Worker
696*0d6140beSAndroid Build Coastguard Worker /* Round down. */
697*0d6140beSAndroid Build Coastguard Worker bulklen = (len - residue) / chunksize * chunksize;
698*0d6140beSAndroid Build Coastguard Worker ret = dediprog_spi_bulk_write(flash, buf + residue, chunksize, start + residue, bulklen, dedi_spi_cmd);
699*0d6140beSAndroid Build Coastguard Worker if (ret) {
700*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_ERROR, dp_data);
701*0d6140beSAndroid Build Coastguard Worker return ret;
702*0d6140beSAndroid Build Coastguard Worker }
703*0d6140beSAndroid Build Coastguard Worker
704*0d6140beSAndroid Build Coastguard Worker len -= residue + bulklen;
705*0d6140beSAndroid Build Coastguard Worker if (len) {
706*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
707*0d6140beSAndroid Build Coastguard Worker start, len);
708*0d6140beSAndroid Build Coastguard Worker ret = spi_write_chunked(flash, buf + residue + bulklen,
709*0d6140beSAndroid Build Coastguard Worker start + residue + bulklen, len, 11);
710*0d6140beSAndroid Build Coastguard Worker if (ret) {
711*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_ERROR, dp_data);
712*0d6140beSAndroid Build Coastguard Worker return ret;
713*0d6140beSAndroid Build Coastguard Worker }
714*0d6140beSAndroid Build Coastguard Worker }
715*0d6140beSAndroid Build Coastguard Worker
716*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_PASS, dp_data);
717*0d6140beSAndroid Build Coastguard Worker return 0;
718*0d6140beSAndroid Build Coastguard Worker }
719*0d6140beSAndroid Build Coastguard Worker
dediprog_spi_write_256(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)720*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
721*0d6140beSAndroid Build Coastguard Worker {
722*0d6140beSAndroid Build Coastguard Worker return dediprog_spi_write(flash, buf, start, len, WRITE_MODE_PAGE_PGM);
723*0d6140beSAndroid Build Coastguard Worker }
724*0d6140beSAndroid Build Coastguard Worker
dediprog_spi_write_aai(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)725*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
726*0d6140beSAndroid Build Coastguard Worker {
727*0d6140beSAndroid Build Coastguard Worker return dediprog_spi_write(flash, buf, start, len, WRITE_MODE_2B_AAI);
728*0d6140beSAndroid Build Coastguard Worker }
729*0d6140beSAndroid Build Coastguard Worker
dediprog_spi_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)730*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_send_command(const struct flashctx *flash,
731*0d6140beSAndroid Build Coastguard Worker unsigned int writecnt,
732*0d6140beSAndroid Build Coastguard Worker unsigned int readcnt,
733*0d6140beSAndroid Build Coastguard Worker const unsigned char *writearr,
734*0d6140beSAndroid Build Coastguard Worker unsigned char *readarr)
735*0d6140beSAndroid Build Coastguard Worker {
736*0d6140beSAndroid Build Coastguard Worker int ret;
737*0d6140beSAndroid Build Coastguard Worker const struct dediprog_data *dp_data = flash->mst->spi.data;
738*0d6140beSAndroid Build Coastguard Worker
739*0d6140beSAndroid Build Coastguard Worker msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
740*0d6140beSAndroid Build Coastguard Worker if (writecnt > flash->mst->spi.max_data_write) {
741*0d6140beSAndroid Build Coastguard Worker msg_perr("Invalid writecnt=%i, aborting.\n", writecnt);
742*0d6140beSAndroid Build Coastguard Worker return 1;
743*0d6140beSAndroid Build Coastguard Worker }
744*0d6140beSAndroid Build Coastguard Worker if (readcnt > flash->mst->spi.max_data_read) {
745*0d6140beSAndroid Build Coastguard Worker msg_perr("Invalid readcnt=%i, aborting.\n", readcnt);
746*0d6140beSAndroid Build Coastguard Worker return 1;
747*0d6140beSAndroid Build Coastguard Worker }
748*0d6140beSAndroid Build Coastguard Worker
749*0d6140beSAndroid Build Coastguard Worker unsigned int idx, value;
750*0d6140beSAndroid Build Coastguard Worker /* New protocol has options and timeout combined as value while the old one used the value field for
751*0d6140beSAndroid Build Coastguard Worker * timeout and the index field for options. */
752*0d6140beSAndroid Build Coastguard Worker if (protocol(dp_data) >= PROTOCOL_V2) {
753*0d6140beSAndroid Build Coastguard Worker idx = 0;
754*0d6140beSAndroid Build Coastguard Worker value = readcnt ? 0x1 : 0x0; // Indicate if we require a read
755*0d6140beSAndroid Build Coastguard Worker } else {
756*0d6140beSAndroid Build Coastguard Worker idx = readcnt ? 0x1 : 0x0; // Indicate if we require a read
757*0d6140beSAndroid Build Coastguard Worker value = 0;
758*0d6140beSAndroid Build Coastguard Worker }
759*0d6140beSAndroid Build Coastguard Worker ret = dediprog_write(dp_data->handle, CMD_TRANSCEIVE, value, idx, writearr, writecnt);
760*0d6140beSAndroid Build Coastguard Worker if (ret != (int)writecnt) {
761*0d6140beSAndroid Build Coastguard Worker msg_perr("Send SPI failed, expected %i, got %i %s!\n",
762*0d6140beSAndroid Build Coastguard Worker writecnt, ret, libusb_error_name(ret));
763*0d6140beSAndroid Build Coastguard Worker return 1;
764*0d6140beSAndroid Build Coastguard Worker }
765*0d6140beSAndroid Build Coastguard Worker if (readcnt == 0) // If we don't require a response, we are done here
766*0d6140beSAndroid Build Coastguard Worker return 0;
767*0d6140beSAndroid Build Coastguard Worker
768*0d6140beSAndroid Build Coastguard Worker /* The specifications do state the possibility to set a timeout for transceive transactions.
769*0d6140beSAndroid Build Coastguard Worker * Apparently the "timeout" is a delay, and you can use long delays to accelerate writing - in case you
770*0d6140beSAndroid Build Coastguard Worker * can predict the time needed by the previous command or so (untested). In any case, using this
771*0d6140beSAndroid Build Coastguard Worker * "feature" to set sane-looking timouts for the read below will completely trash performance with
772*0d6140beSAndroid Build Coastguard Worker * SF600 and/or firmwares >= 6.0 while they seem to be benign on SF100 with firmwares <= 5.5.2. *shrug*
773*0d6140beSAndroid Build Coastguard Worker *
774*0d6140beSAndroid Build Coastguard Worker * The specification also uses only 0 in its examples, so the lesson to learn here:
775*0d6140beSAndroid Build Coastguard Worker * "Never trust the description of an interface in the documentation but use the example code and pray."
776*0d6140beSAndroid Build Coastguard Worker const uint8_t read_timeout = 10 + readcnt/512;
777*0d6140beSAndroid Build Coastguard Worker if (protocol() >= PROTOCOL_V2) {
778*0d6140beSAndroid Build Coastguard Worker idx = 0;
779*0d6140beSAndroid Build Coastguard Worker value = min(read_timeout, 0xFF) | (0 << 8) ; // Timeout in lower byte, option in upper byte
780*0d6140beSAndroid Build Coastguard Worker } else {
781*0d6140beSAndroid Build Coastguard Worker idx = (0 & 0xFF); // Lower byte is option (0x01 = require SR, 0x02 keep CS low)
782*0d6140beSAndroid Build Coastguard Worker value = min(read_timeout, 0xFF); // Possibly two bytes but we play safe here
783*0d6140beSAndroid Build Coastguard Worker }
784*0d6140beSAndroid Build Coastguard Worker ret = dediprog_read(dp_data->dediprog_handle, CMD_TRANSCEIVE, value, idx, readarr, readcnt);
785*0d6140beSAndroid Build Coastguard Worker */
786*0d6140beSAndroid Build Coastguard Worker ret = dediprog_read(dp_data->handle, CMD_TRANSCEIVE, 0, 0, readarr, readcnt);
787*0d6140beSAndroid Build Coastguard Worker if (ret != (int)readcnt) {
788*0d6140beSAndroid Build Coastguard Worker msg_perr("Receive SPI failed, expected %i, got %i %s!\n", readcnt, ret, libusb_error_name(ret));
789*0d6140beSAndroid Build Coastguard Worker return 1;
790*0d6140beSAndroid Build Coastguard Worker }
791*0d6140beSAndroid Build Coastguard Worker return 0;
792*0d6140beSAndroid Build Coastguard Worker }
793*0d6140beSAndroid Build Coastguard Worker
dediprog_check_devicestring(struct dediprog_data * dp_data)794*0d6140beSAndroid Build Coastguard Worker static int dediprog_check_devicestring(struct dediprog_data *dp_data)
795*0d6140beSAndroid Build Coastguard Worker {
796*0d6140beSAndroid Build Coastguard Worker int ret;
797*0d6140beSAndroid Build Coastguard Worker char buf[0x11];
798*0d6140beSAndroid Build Coastguard Worker
799*0d6140beSAndroid Build Coastguard Worker /* Command Receive Device String. */
800*0d6140beSAndroid Build Coastguard Worker ret = dediprog_read(dp_data->handle, CMD_READ_PROG_INFO, 0, 0, (uint8_t *)buf, 0x10);
801*0d6140beSAndroid Build Coastguard Worker if (ret != 0x10) {
802*0d6140beSAndroid Build Coastguard Worker msg_perr("Incomplete/failed Command Receive Device String!\n");
803*0d6140beSAndroid Build Coastguard Worker return 1;
804*0d6140beSAndroid Build Coastguard Worker }
805*0d6140beSAndroid Build Coastguard Worker buf[0x10] = '\0';
806*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Found a %s\n", buf);
807*0d6140beSAndroid Build Coastguard Worker if (memcmp(buf, "SF100", 0x5) == 0)
808*0d6140beSAndroid Build Coastguard Worker dp_data->devicetype = DEV_SF100;
809*0d6140beSAndroid Build Coastguard Worker else if (memcmp(buf, "SF200", 0x5) == 0)
810*0d6140beSAndroid Build Coastguard Worker dp_data->devicetype = DEV_SF200;
811*0d6140beSAndroid Build Coastguard Worker else if (memcmp(buf, "SF600", 0x5) == 0)
812*0d6140beSAndroid Build Coastguard Worker dp_data->devicetype = DEV_SF600;
813*0d6140beSAndroid Build Coastguard Worker else {
814*0d6140beSAndroid Build Coastguard Worker msg_perr("Device not a SF100, SF200, or SF600!\n");
815*0d6140beSAndroid Build Coastguard Worker return 1;
816*0d6140beSAndroid Build Coastguard Worker }
817*0d6140beSAndroid Build Coastguard Worker
818*0d6140beSAndroid Build Coastguard Worker int sfnum;
819*0d6140beSAndroid Build Coastguard Worker int fw[3];
820*0d6140beSAndroid Build Coastguard Worker if (sscanf(buf, "SF%d V:%d.%d.%d ", &sfnum, &fw[0], &fw[1], &fw[2]) != 4 ||
821*0d6140beSAndroid Build Coastguard Worker sfnum != (int)dp_data->devicetype) {
822*0d6140beSAndroid Build Coastguard Worker msg_perr("Unexpected firmware version string '%s'\n", buf);
823*0d6140beSAndroid Build Coastguard Worker return 1;
824*0d6140beSAndroid Build Coastguard Worker }
825*0d6140beSAndroid Build Coastguard Worker /* Only these major versions were tested. */
826*0d6140beSAndroid Build Coastguard Worker if (fw[0] < 2 || fw[0] > 7) {
827*0d6140beSAndroid Build Coastguard Worker msg_perr("Unexpected firmware version %d.%d.%d!\n", fw[0], fw[1], fw[2]);
828*0d6140beSAndroid Build Coastguard Worker return 1;
829*0d6140beSAndroid Build Coastguard Worker }
830*0d6140beSAndroid Build Coastguard Worker
831*0d6140beSAndroid Build Coastguard Worker dp_data->firmwareversion = FIRMWARE_VERSION(fw[0], fw[1], fw[2]);
832*0d6140beSAndroid Build Coastguard Worker if (protocol(dp_data) == PROTOCOL_UNKNOWN) {
833*0d6140beSAndroid Build Coastguard Worker msg_perr("Internal error: Unable to determine protocol version.\n");
834*0d6140beSAndroid Build Coastguard Worker return 1;
835*0d6140beSAndroid Build Coastguard Worker }
836*0d6140beSAndroid Build Coastguard Worker
837*0d6140beSAndroid Build Coastguard Worker return 0;
838*0d6140beSAndroid Build Coastguard Worker }
839*0d6140beSAndroid Build Coastguard Worker
840*0d6140beSAndroid Build Coastguard Worker /*
841*0d6140beSAndroid Build Coastguard Worker * Read the id from the dediprog. This should return the numeric part of the
842*0d6140beSAndroid Build Coastguard Worker * serial number found on a sticker on the back of the dediprog. Note this
843*0d6140beSAndroid Build Coastguard Worker * number is stored in writable eeprom, so it could get out of sync. Also note,
844*0d6140beSAndroid Build Coastguard Worker * this function only supports SF100 at this time, but SF600 support is not too
845*0d6140beSAndroid Build Coastguard Worker * much different.
846*0d6140beSAndroid Build Coastguard Worker * @return the id on success, -1 on failure
847*0d6140beSAndroid Build Coastguard Worker */
dediprog_read_id(libusb_device_handle * dediprog_handle)848*0d6140beSAndroid Build Coastguard Worker static int dediprog_read_id(libusb_device_handle *dediprog_handle)
849*0d6140beSAndroid Build Coastguard Worker {
850*0d6140beSAndroid Build Coastguard Worker int ret;
851*0d6140beSAndroid Build Coastguard Worker uint8_t buf[3];
852*0d6140beSAndroid Build Coastguard Worker
853*0d6140beSAndroid Build Coastguard Worker ret = libusb_control_transfer(dediprog_handle, REQTYPE_OTHER_IN,
854*0d6140beSAndroid Build Coastguard Worker 0x7, /* request */
855*0d6140beSAndroid Build Coastguard Worker 0, /* value */
856*0d6140beSAndroid Build Coastguard Worker 0xEF00, /* index */
857*0d6140beSAndroid Build Coastguard Worker buf, sizeof(buf),
858*0d6140beSAndroid Build Coastguard Worker DEFAULT_TIMEOUT);
859*0d6140beSAndroid Build Coastguard Worker if (ret != sizeof(buf)) {
860*0d6140beSAndroid Build Coastguard Worker msg_perr("Failed to read dediprog id, error %d!\n", ret);
861*0d6140beSAndroid Build Coastguard Worker return -1;
862*0d6140beSAndroid Build Coastguard Worker }
863*0d6140beSAndroid Build Coastguard Worker
864*0d6140beSAndroid Build Coastguard Worker return buf[0] << 16 | buf[1] << 8 | buf[2];
865*0d6140beSAndroid Build Coastguard Worker }
866*0d6140beSAndroid Build Coastguard Worker
867*0d6140beSAndroid Build Coastguard Worker /*
868*0d6140beSAndroid Build Coastguard Worker * This command presumably sets the voltage for the SF100 itself (not the
869*0d6140beSAndroid Build Coastguard Worker * SPI flash). Only use this command with firmware older than V6.0.0. Newer
870*0d6140beSAndroid Build Coastguard Worker * (including all SF600s) do not support it.
871*0d6140beSAndroid Build Coastguard Worker */
872*0d6140beSAndroid Build Coastguard Worker
873*0d6140beSAndroid Build Coastguard Worker /* This command presumably sets the voltage for the SF100 itself (not the SPI flash).
874*0d6140beSAndroid Build Coastguard Worker * Only use dediprog_set_voltage on SF100 programmers with firmware older
875*0d6140beSAndroid Build Coastguard Worker * than V6.0.0. Newer programmers (including all SF600s) do not support it. */
dediprog_set_voltage(libusb_device_handle * dediprog_handle)876*0d6140beSAndroid Build Coastguard Worker static int dediprog_set_voltage(libusb_device_handle *dediprog_handle)
877*0d6140beSAndroid Build Coastguard Worker {
878*0d6140beSAndroid Build Coastguard Worker unsigned char buf[1] = {0};
879*0d6140beSAndroid Build Coastguard Worker int ret = libusb_control_transfer(dediprog_handle, REQTYPE_OTHER_IN, CMD_SET_VOLTAGE, 0x0, 0x0,
880*0d6140beSAndroid Build Coastguard Worker buf, 0x1, DEFAULT_TIMEOUT);
881*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
882*0d6140beSAndroid Build Coastguard Worker msg_perr("Command Set Voltage failed (%s)!\n", libusb_error_name(ret));
883*0d6140beSAndroid Build Coastguard Worker return 1;
884*0d6140beSAndroid Build Coastguard Worker }
885*0d6140beSAndroid Build Coastguard Worker if ((ret != 1) || (buf[0] != 0x6f)) {
886*0d6140beSAndroid Build Coastguard Worker msg_perr("Unexpected response to init!\n");
887*0d6140beSAndroid Build Coastguard Worker return 1;
888*0d6140beSAndroid Build Coastguard Worker }
889*0d6140beSAndroid Build Coastguard Worker
890*0d6140beSAndroid Build Coastguard Worker return 0;
891*0d6140beSAndroid Build Coastguard Worker }
892*0d6140beSAndroid Build Coastguard Worker
dediprog_standalone_mode(const struct dediprog_data * dp_data)893*0d6140beSAndroid Build Coastguard Worker static int dediprog_standalone_mode(const struct dediprog_data *dp_data)
894*0d6140beSAndroid Build Coastguard Worker {
895*0d6140beSAndroid Build Coastguard Worker int ret;
896*0d6140beSAndroid Build Coastguard Worker
897*0d6140beSAndroid Build Coastguard Worker if (dp_data->devicetype != DEV_SF600)
898*0d6140beSAndroid Build Coastguard Worker return 0;
899*0d6140beSAndroid Build Coastguard Worker
900*0d6140beSAndroid Build Coastguard Worker msg_pdbg2("Disabling standalone mode.\n");
901*0d6140beSAndroid Build Coastguard Worker ret = dediprog_write(dp_data->handle, CMD_SET_STANDALONE, LEAVE_STANDALONE_MODE, 0, NULL, 0);
902*0d6140beSAndroid Build Coastguard Worker if (ret) {
903*0d6140beSAndroid Build Coastguard Worker msg_perr("Failed to disable standalone mode: %s\n", libusb_error_name(ret));
904*0d6140beSAndroid Build Coastguard Worker return 1;
905*0d6140beSAndroid Build Coastguard Worker }
906*0d6140beSAndroid Build Coastguard Worker
907*0d6140beSAndroid Build Coastguard Worker return 0;
908*0d6140beSAndroid Build Coastguard Worker }
909*0d6140beSAndroid Build Coastguard Worker
910*0d6140beSAndroid Build Coastguard Worker #if 0
911*0d6140beSAndroid Build Coastguard Worker /* Something.
912*0d6140beSAndroid Build Coastguard Worker * Present in eng_detect_blink.log with firmware 3.1.8
913*0d6140beSAndroid Build Coastguard Worker * Always preceded by Command Receive Device String
914*0d6140beSAndroid Build Coastguard Worker */
915*0d6140beSAndroid Build Coastguard Worker static int dediprog_command_b(libusb_device_handle *dediprog_handle)
916*0d6140beSAndroid Build Coastguard Worker {
917*0d6140beSAndroid Build Coastguard Worker int ret;
918*0d6140beSAndroid Build Coastguard Worker char buf[0x3];
919*0d6140beSAndroid Build Coastguard Worker
920*0d6140beSAndroid Build Coastguard Worker ret = usb_control_msg(dediprog_handle, REQTYPE_OTHER_IN, 0x7, 0x0, 0xef00,
921*0d6140beSAndroid Build Coastguard Worker buf, 0x3, DEFAULT_TIMEOUT);
922*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
923*0d6140beSAndroid Build Coastguard Worker msg_perr("Command B failed (%s)!\n", libusb_error_name(ret));
924*0d6140beSAndroid Build Coastguard Worker return 1;
925*0d6140beSAndroid Build Coastguard Worker }
926*0d6140beSAndroid Build Coastguard Worker if ((ret != 0x3) || (buf[0] != 0xff) || (buf[1] != 0xff) ||
927*0d6140beSAndroid Build Coastguard Worker (buf[2] != 0xff)) {
928*0d6140beSAndroid Build Coastguard Worker msg_perr("Unexpected response to Command B!\n");
929*0d6140beSAndroid Build Coastguard Worker return 1;
930*0d6140beSAndroid Build Coastguard Worker }
931*0d6140beSAndroid Build Coastguard Worker
932*0d6140beSAndroid Build Coastguard Worker return 0;
933*0d6140beSAndroid Build Coastguard Worker }
934*0d6140beSAndroid Build Coastguard Worker #endif
935*0d6140beSAndroid Build Coastguard Worker
set_target_flash(libusb_device_handle * dediprog_handle,enum dediprog_target target)936*0d6140beSAndroid Build Coastguard Worker static int set_target_flash(libusb_device_handle *dediprog_handle, enum dediprog_target target)
937*0d6140beSAndroid Build Coastguard Worker {
938*0d6140beSAndroid Build Coastguard Worker int ret = dediprog_write(dediprog_handle, CMD_SET_TARGET, target, 0, NULL, 0);
939*0d6140beSAndroid Build Coastguard Worker if (ret != 0) {
940*0d6140beSAndroid Build Coastguard Worker msg_perr("set_target_flash failed (%s)!\n", libusb_error_name(ret));
941*0d6140beSAndroid Build Coastguard Worker return 1;
942*0d6140beSAndroid Build Coastguard Worker }
943*0d6140beSAndroid Build Coastguard Worker return 0;
944*0d6140beSAndroid Build Coastguard Worker }
945*0d6140beSAndroid Build Coastguard Worker
946*0d6140beSAndroid Build Coastguard Worker #if 0
947*0d6140beSAndroid Build Coastguard Worker /* Returns true if the button is currently pressed. */
948*0d6140beSAndroid Build Coastguard Worker static bool dediprog_get_button(libusb_device_handle *dediprog_handle)
949*0d6140beSAndroid Build Coastguard Worker {
950*0d6140beSAndroid Build Coastguard Worker char buf[1];
951*0d6140beSAndroid Build Coastguard Worker int ret = usb_control_msg(dediprog_handle, REQTYPE_EP_IN, CMD_GET_BUTTON, 0, 0,
952*0d6140beSAndroid Build Coastguard Worker buf, 0x1, DEFAULT_TIMEOUT);
953*0d6140beSAndroid Build Coastguard Worker if (ret != 0) {
954*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not get button state (%s)!\n", libusb_error_name(ret));
955*0d6140beSAndroid Build Coastguard Worker return 1;
956*0d6140beSAndroid Build Coastguard Worker }
957*0d6140beSAndroid Build Coastguard Worker return buf[0] != 1;
958*0d6140beSAndroid Build Coastguard Worker }
959*0d6140beSAndroid Build Coastguard Worker #endif
960*0d6140beSAndroid Build Coastguard Worker
parse_voltage(char * voltage)961*0d6140beSAndroid Build Coastguard Worker static int parse_voltage(char *voltage)
962*0d6140beSAndroid Build Coastguard Worker {
963*0d6140beSAndroid Build Coastguard Worker char *tmp = NULL;
964*0d6140beSAndroid Build Coastguard Worker int i;
965*0d6140beSAndroid Build Coastguard Worker int millivolt = 0, fraction = 0;
966*0d6140beSAndroid Build Coastguard Worker
967*0d6140beSAndroid Build Coastguard Worker if (!voltage || !strlen(voltage)) {
968*0d6140beSAndroid Build Coastguard Worker msg_perr("Empty voltage= specified.\n");
969*0d6140beSAndroid Build Coastguard Worker return -1;
970*0d6140beSAndroid Build Coastguard Worker }
971*0d6140beSAndroid Build Coastguard Worker millivolt = (int)strtol(voltage, &tmp, 0);
972*0d6140beSAndroid Build Coastguard Worker voltage = tmp;
973*0d6140beSAndroid Build Coastguard Worker /* Handle "," and "." as decimal point. Everything after it is assumed
974*0d6140beSAndroid Build Coastguard Worker * to be in decimal notation.
975*0d6140beSAndroid Build Coastguard Worker */
976*0d6140beSAndroid Build Coastguard Worker if ((*voltage == '.') || (*voltage == ',')) {
977*0d6140beSAndroid Build Coastguard Worker voltage++;
978*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < 3; i++) {
979*0d6140beSAndroid Build Coastguard Worker fraction *= 10;
980*0d6140beSAndroid Build Coastguard Worker /* Don't advance if the current character is invalid,
981*0d6140beSAndroid Build Coastguard Worker * but continue multiplying.
982*0d6140beSAndroid Build Coastguard Worker */
983*0d6140beSAndroid Build Coastguard Worker if ((*voltage < '0') || (*voltage > '9'))
984*0d6140beSAndroid Build Coastguard Worker continue;
985*0d6140beSAndroid Build Coastguard Worker fraction += *voltage - '0';
986*0d6140beSAndroid Build Coastguard Worker voltage++;
987*0d6140beSAndroid Build Coastguard Worker }
988*0d6140beSAndroid Build Coastguard Worker /* Throw away remaining digits. */
989*0d6140beSAndroid Build Coastguard Worker voltage += strspn(voltage, "0123456789");
990*0d6140beSAndroid Build Coastguard Worker }
991*0d6140beSAndroid Build Coastguard Worker /* The remaining string must be empty or "mV" or "V". */
992*0d6140beSAndroid Build Coastguard Worker tolower_string(voltage);
993*0d6140beSAndroid Build Coastguard Worker
994*0d6140beSAndroid Build Coastguard Worker /* No unit or "V". */
995*0d6140beSAndroid Build Coastguard Worker if ((*voltage == '\0') || !strncmp(voltage, "v", 1)) {
996*0d6140beSAndroid Build Coastguard Worker millivolt *= 1000;
997*0d6140beSAndroid Build Coastguard Worker millivolt += fraction;
998*0d6140beSAndroid Build Coastguard Worker } else if (!strncmp(voltage, "mv", 2) ||
999*0d6140beSAndroid Build Coastguard Worker !strncmp(voltage, "milliv", 6)) {
1000*0d6140beSAndroid Build Coastguard Worker /* No adjustment. fraction is discarded. */
1001*0d6140beSAndroid Build Coastguard Worker } else {
1002*0d6140beSAndroid Build Coastguard Worker /* Garbage at the end of the string. */
1003*0d6140beSAndroid Build Coastguard Worker msg_perr("Garbage voltage= specified.\n");
1004*0d6140beSAndroid Build Coastguard Worker return -1;
1005*0d6140beSAndroid Build Coastguard Worker }
1006*0d6140beSAndroid Build Coastguard Worker return millivolt;
1007*0d6140beSAndroid Build Coastguard Worker }
1008*0d6140beSAndroid Build Coastguard Worker
dediprog_shutdown(void * data)1009*0d6140beSAndroid Build Coastguard Worker static int dediprog_shutdown(void *data)
1010*0d6140beSAndroid Build Coastguard Worker {
1011*0d6140beSAndroid Build Coastguard Worker int ret = 0;
1012*0d6140beSAndroid Build Coastguard Worker struct dediprog_data *dp_data = data;
1013*0d6140beSAndroid Build Coastguard Worker
1014*0d6140beSAndroid Build Coastguard Worker /* URB 28. Command Set SPI Voltage to 0. */
1015*0d6140beSAndroid Build Coastguard Worker if (dediprog_set_spi_voltage(dp_data->handle, 0x0)) {
1016*0d6140beSAndroid Build Coastguard Worker ret = 1;
1017*0d6140beSAndroid Build Coastguard Worker goto out;
1018*0d6140beSAndroid Build Coastguard Worker }
1019*0d6140beSAndroid Build Coastguard Worker
1020*0d6140beSAndroid Build Coastguard Worker if (libusb_release_interface(dp_data->handle, 0)) {
1021*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not release USB interface!\n");
1022*0d6140beSAndroid Build Coastguard Worker ret = 1;
1023*0d6140beSAndroid Build Coastguard Worker goto out;
1024*0d6140beSAndroid Build Coastguard Worker }
1025*0d6140beSAndroid Build Coastguard Worker libusb_close(dp_data->handle);
1026*0d6140beSAndroid Build Coastguard Worker libusb_exit(dp_data->usb_ctx);
1027*0d6140beSAndroid Build Coastguard Worker out:
1028*0d6140beSAndroid Build Coastguard Worker free(data);
1029*0d6140beSAndroid Build Coastguard Worker return ret;
1030*0d6140beSAndroid Build Coastguard Worker }
1031*0d6140beSAndroid Build Coastguard Worker
1032*0d6140beSAndroid Build Coastguard Worker static struct spi_master spi_master_dediprog = {
1033*0d6140beSAndroid Build Coastguard Worker .features = SPI_MASTER_NO_4BA_MODES,
1034*0d6140beSAndroid Build Coastguard Worker .max_data_read = 16, /* 18 seems to work fine as well, but 19 times out sometimes with FW 5.15. */
1035*0d6140beSAndroid Build Coastguard Worker .max_data_write = 16,
1036*0d6140beSAndroid Build Coastguard Worker .command = dediprog_spi_send_command,
1037*0d6140beSAndroid Build Coastguard Worker .read = dediprog_spi_read,
1038*0d6140beSAndroid Build Coastguard Worker .write_256 = dediprog_spi_write_256,
1039*0d6140beSAndroid Build Coastguard Worker .write_aai = dediprog_spi_write_aai,
1040*0d6140beSAndroid Build Coastguard Worker .shutdown = dediprog_shutdown,
1041*0d6140beSAndroid Build Coastguard Worker };
1042*0d6140beSAndroid Build Coastguard Worker
1043*0d6140beSAndroid Build Coastguard Worker /*
1044*0d6140beSAndroid Build Coastguard Worker * Open a dediprog_handle with the USB device at the given index.
1045*0d6140beSAndroid Build Coastguard Worker * @index index of the USB device
1046*0d6140beSAndroid Build Coastguard Worker * @return 0 for success, -1 for error, -2 for busy device
1047*0d6140beSAndroid Build Coastguard Worker */
dediprog_open(int index,struct dediprog_data * dp_data)1048*0d6140beSAndroid Build Coastguard Worker static int dediprog_open(int index, struct dediprog_data *dp_data)
1049*0d6140beSAndroid Build Coastguard Worker {
1050*0d6140beSAndroid Build Coastguard Worker const uint16_t vid = devs_dediprog[0].vendor_id;
1051*0d6140beSAndroid Build Coastguard Worker const uint16_t pid = devs_dediprog[0].device_id;
1052*0d6140beSAndroid Build Coastguard Worker int ret;
1053*0d6140beSAndroid Build Coastguard Worker
1054*0d6140beSAndroid Build Coastguard Worker dp_data->handle = usb_dev_get_by_vid_pid_number(dp_data->usb_ctx, vid, pid, (unsigned int) index);
1055*0d6140beSAndroid Build Coastguard Worker if (!dp_data->handle) {
1056*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not find a Dediprog programmer on USB.\n");
1057*0d6140beSAndroid Build Coastguard Worker libusb_exit(dp_data->usb_ctx);
1058*0d6140beSAndroid Build Coastguard Worker return -1;
1059*0d6140beSAndroid Build Coastguard Worker }
1060*0d6140beSAndroid Build Coastguard Worker ret = libusb_set_configuration(dp_data->handle, 1);
1061*0d6140beSAndroid Build Coastguard Worker if (ret != 0) {
1062*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not set USB device configuration: %i %s\n",
1063*0d6140beSAndroid Build Coastguard Worker ret, libusb_error_name(ret));
1064*0d6140beSAndroid Build Coastguard Worker libusb_close(dp_data->handle);
1065*0d6140beSAndroid Build Coastguard Worker return -2;
1066*0d6140beSAndroid Build Coastguard Worker }
1067*0d6140beSAndroid Build Coastguard Worker ret = libusb_claim_interface(dp_data->handle, 0);
1068*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
1069*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not claim USB device interface %i: %i %s\n",
1070*0d6140beSAndroid Build Coastguard Worker 0, ret, libusb_error_name(ret));
1071*0d6140beSAndroid Build Coastguard Worker libusb_close(dp_data->handle);
1072*0d6140beSAndroid Build Coastguard Worker return -2;
1073*0d6140beSAndroid Build Coastguard Worker }
1074*0d6140beSAndroid Build Coastguard Worker return 0;
1075*0d6140beSAndroid Build Coastguard Worker }
1076*0d6140beSAndroid Build Coastguard Worker
dediprog_init(const struct programmer_cfg * cfg)1077*0d6140beSAndroid Build Coastguard Worker static int dediprog_init(const struct programmer_cfg *cfg)
1078*0d6140beSAndroid Build Coastguard Worker {
1079*0d6140beSAndroid Build Coastguard Worker char *param_str;
1080*0d6140beSAndroid Build Coastguard Worker int spispeed_idx = 1;
1081*0d6140beSAndroid Build Coastguard Worker int millivolt = 3500;
1082*0d6140beSAndroid Build Coastguard Worker int id = -1; /* -1 defaults to enumeration order */
1083*0d6140beSAndroid Build Coastguard Worker int found_id;
1084*0d6140beSAndroid Build Coastguard Worker long usedevice = 0;
1085*0d6140beSAndroid Build Coastguard Worker long target = FLASH_TYPE_APPLICATION_FLASH_1;
1086*0d6140beSAndroid Build Coastguard Worker int i, ret;
1087*0d6140beSAndroid Build Coastguard Worker
1088*0d6140beSAndroid Build Coastguard Worker param_str = extract_programmer_param_str(cfg, "spispeed");
1089*0d6140beSAndroid Build Coastguard Worker if (param_str) {
1090*0d6140beSAndroid Build Coastguard Worker for (i = 0; spispeeds[i].name; ++i) {
1091*0d6140beSAndroid Build Coastguard Worker if (!strcasecmp(spispeeds[i].name, param_str)) {
1092*0d6140beSAndroid Build Coastguard Worker spispeed_idx = i;
1093*0d6140beSAndroid Build Coastguard Worker break;
1094*0d6140beSAndroid Build Coastguard Worker }
1095*0d6140beSAndroid Build Coastguard Worker }
1096*0d6140beSAndroid Build Coastguard Worker if (!spispeeds[i].name) {
1097*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Invalid spispeed value: '%s'.\n", param_str);
1098*0d6140beSAndroid Build Coastguard Worker free(param_str);
1099*0d6140beSAndroid Build Coastguard Worker return 1;
1100*0d6140beSAndroid Build Coastguard Worker }
1101*0d6140beSAndroid Build Coastguard Worker free(param_str);
1102*0d6140beSAndroid Build Coastguard Worker }
1103*0d6140beSAndroid Build Coastguard Worker
1104*0d6140beSAndroid Build Coastguard Worker param_str = extract_programmer_param_str(cfg, "voltage");
1105*0d6140beSAndroid Build Coastguard Worker if (param_str) {
1106*0d6140beSAndroid Build Coastguard Worker millivolt = parse_voltage(param_str);
1107*0d6140beSAndroid Build Coastguard Worker free(param_str);
1108*0d6140beSAndroid Build Coastguard Worker if (millivolt < 0)
1109*0d6140beSAndroid Build Coastguard Worker return 1;
1110*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Setting voltage to %i mV\n", millivolt);
1111*0d6140beSAndroid Build Coastguard Worker }
1112*0d6140beSAndroid Build Coastguard Worker
1113*0d6140beSAndroid Build Coastguard Worker param_str = extract_programmer_param_str(cfg, "id");
1114*0d6140beSAndroid Build Coastguard Worker if (param_str) {
1115*0d6140beSAndroid Build Coastguard Worker char prefix0, prefix1;
1116*0d6140beSAndroid Build Coastguard Worker if (sscanf(param_str, "%c%c%d", &prefix0, &prefix1, &id) != 3) {
1117*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Could not parse dediprog 'id'.\n");
1118*0d6140beSAndroid Build Coastguard Worker msg_perr("Expected a string like SF012345 or DP012345.\n");
1119*0d6140beSAndroid Build Coastguard Worker free(param_str);
1120*0d6140beSAndroid Build Coastguard Worker return 1;
1121*0d6140beSAndroid Build Coastguard Worker }
1122*0d6140beSAndroid Build Coastguard Worker if (id < 0 || id >= 0x1000000) {
1123*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: id %s is out of range!\n", param_str);
1124*0d6140beSAndroid Build Coastguard Worker free(param_str);
1125*0d6140beSAndroid Build Coastguard Worker return 1;
1126*0d6140beSAndroid Build Coastguard Worker }
1127*0d6140beSAndroid Build Coastguard Worker if (!(prefix0 == 'S' && prefix1 == 'F') && !(prefix0 == 'D' && prefix1 == 'P')) {
1128*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: %s is an invalid id!\n", param_str);
1129*0d6140beSAndroid Build Coastguard Worker free(param_str);
1130*0d6140beSAndroid Build Coastguard Worker return 1;
1131*0d6140beSAndroid Build Coastguard Worker }
1132*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Will search for dediprog id %s.\n", param_str);
1133*0d6140beSAndroid Build Coastguard Worker }
1134*0d6140beSAndroid Build Coastguard Worker free(param_str);
1135*0d6140beSAndroid Build Coastguard Worker
1136*0d6140beSAndroid Build Coastguard Worker param_str = extract_programmer_param_str(cfg, "device");
1137*0d6140beSAndroid Build Coastguard Worker if (param_str) {
1138*0d6140beSAndroid Build Coastguard Worker char *dev_suffix;
1139*0d6140beSAndroid Build Coastguard Worker if (id != -1) {
1140*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Cannot use 'id' and 'device'.\n");
1141*0d6140beSAndroid Build Coastguard Worker }
1142*0d6140beSAndroid Build Coastguard Worker errno = 0;
1143*0d6140beSAndroid Build Coastguard Worker usedevice = strtol(param_str, &dev_suffix, 10);
1144*0d6140beSAndroid Build Coastguard Worker if (errno != 0 || param_str == dev_suffix) {
1145*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Could not convert 'device'.\n");
1146*0d6140beSAndroid Build Coastguard Worker free(param_str);
1147*0d6140beSAndroid Build Coastguard Worker return 1;
1148*0d6140beSAndroid Build Coastguard Worker }
1149*0d6140beSAndroid Build Coastguard Worker if (usedevice < 0 || usedevice > INT_MAX) {
1150*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Value for 'device' is out of range.\n");
1151*0d6140beSAndroid Build Coastguard Worker free(param_str);
1152*0d6140beSAndroid Build Coastguard Worker return 1;
1153*0d6140beSAndroid Build Coastguard Worker }
1154*0d6140beSAndroid Build Coastguard Worker if (strlen(dev_suffix) > 0) {
1155*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Garbage following 'device' value.\n");
1156*0d6140beSAndroid Build Coastguard Worker free(param_str);
1157*0d6140beSAndroid Build Coastguard Worker return 1;
1158*0d6140beSAndroid Build Coastguard Worker }
1159*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Using device %li.\n", usedevice);
1160*0d6140beSAndroid Build Coastguard Worker }
1161*0d6140beSAndroid Build Coastguard Worker free(param_str);
1162*0d6140beSAndroid Build Coastguard Worker
1163*0d6140beSAndroid Build Coastguard Worker param_str = extract_programmer_param_str(cfg, "target");
1164*0d6140beSAndroid Build Coastguard Worker if (param_str) {
1165*0d6140beSAndroid Build Coastguard Worker char *target_suffix;
1166*0d6140beSAndroid Build Coastguard Worker errno = 0;
1167*0d6140beSAndroid Build Coastguard Worker target = strtol(param_str, &target_suffix, 10);
1168*0d6140beSAndroid Build Coastguard Worker if (errno != 0 || param_str == target_suffix) {
1169*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Could not convert 'target'.\n");
1170*0d6140beSAndroid Build Coastguard Worker free(param_str);
1171*0d6140beSAndroid Build Coastguard Worker return 1;
1172*0d6140beSAndroid Build Coastguard Worker }
1173*0d6140beSAndroid Build Coastguard Worker if (target < 1 || target > 2) {
1174*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Value for 'target' is out of range.\n");
1175*0d6140beSAndroid Build Coastguard Worker free(param_str);
1176*0d6140beSAndroid Build Coastguard Worker return 1;
1177*0d6140beSAndroid Build Coastguard Worker }
1178*0d6140beSAndroid Build Coastguard Worker if (strlen(target_suffix) > 0) {
1179*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Garbage following 'target' value.\n");
1180*0d6140beSAndroid Build Coastguard Worker free(param_str);
1181*0d6140beSAndroid Build Coastguard Worker return 1;
1182*0d6140beSAndroid Build Coastguard Worker }
1183*0d6140beSAndroid Build Coastguard Worker switch (target) {
1184*0d6140beSAndroid Build Coastguard Worker case 1:
1185*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Using target %s.\n", "FLASH_TYPE_APPLICATION_FLASH_1");
1186*0d6140beSAndroid Build Coastguard Worker target = FLASH_TYPE_APPLICATION_FLASH_1;
1187*0d6140beSAndroid Build Coastguard Worker break;
1188*0d6140beSAndroid Build Coastguard Worker case 2:
1189*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Using target %s.\n", "FLASH_TYPE_APPLICATION_FLASH_2");
1190*0d6140beSAndroid Build Coastguard Worker target = FLASH_TYPE_APPLICATION_FLASH_2;
1191*0d6140beSAndroid Build Coastguard Worker break;
1192*0d6140beSAndroid Build Coastguard Worker default:
1193*0d6140beSAndroid Build Coastguard Worker break;
1194*0d6140beSAndroid Build Coastguard Worker }
1195*0d6140beSAndroid Build Coastguard Worker }
1196*0d6140beSAndroid Build Coastguard Worker free(param_str);
1197*0d6140beSAndroid Build Coastguard Worker
1198*0d6140beSAndroid Build Coastguard Worker struct dediprog_data *dp_data = calloc(1, sizeof(*dp_data));
1199*0d6140beSAndroid Build Coastguard Worker if (!dp_data) {
1200*0d6140beSAndroid Build Coastguard Worker msg_perr("Unable to allocate space for SPI master data\n");
1201*0d6140beSAndroid Build Coastguard Worker return 1;
1202*0d6140beSAndroid Build Coastguard Worker }
1203*0d6140beSAndroid Build Coastguard Worker dp_data->firmwareversion = FIRMWARE_VERSION(0, 0, 0);
1204*0d6140beSAndroid Build Coastguard Worker dp_data->devicetype = DEV_UNKNOWN;
1205*0d6140beSAndroid Build Coastguard Worker
1206*0d6140beSAndroid Build Coastguard Worker /* Here comes the USB stuff. */
1207*0d6140beSAndroid Build Coastguard Worker ret = libusb_init(&dp_data->usb_ctx);
1208*0d6140beSAndroid Build Coastguard Worker if (ret) {
1209*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not initialize libusb!\n");
1210*0d6140beSAndroid Build Coastguard Worker goto init_err_exit;
1211*0d6140beSAndroid Build Coastguard Worker }
1212*0d6140beSAndroid Build Coastguard Worker
1213*0d6140beSAndroid Build Coastguard Worker if (id != -1) {
1214*0d6140beSAndroid Build Coastguard Worker for (i = 0; ; i++) {
1215*0d6140beSAndroid Build Coastguard Worker ret = dediprog_open(i, dp_data);
1216*0d6140beSAndroid Build Coastguard Worker if (ret == -1) {
1217*0d6140beSAndroid Build Coastguard Worker /* no dev */
1218*0d6140beSAndroid Build Coastguard Worker goto init_err_exit;
1219*0d6140beSAndroid Build Coastguard Worker } else if (ret == -2) {
1220*0d6140beSAndroid Build Coastguard Worker /* busy dev */
1221*0d6140beSAndroid Build Coastguard Worker continue;
1222*0d6140beSAndroid Build Coastguard Worker }
1223*0d6140beSAndroid Build Coastguard Worker
1224*0d6140beSAndroid Build Coastguard Worker /* Notice we can only call dediprog_read_id() after
1225*0d6140beSAndroid Build Coastguard Worker * libusb_set_configuration() and
1226*0d6140beSAndroid Build Coastguard Worker * libusb_claim_interface(). When searching by id and
1227*0d6140beSAndroid Build Coastguard Worker * either configuration or claim fails (usually the
1228*0d6140beSAndroid Build Coastguard Worker * device is in use by another instance of flashrom),
1229*0d6140beSAndroid Build Coastguard Worker * the device is skipped and the next device is tried.
1230*0d6140beSAndroid Build Coastguard Worker */
1231*0d6140beSAndroid Build Coastguard Worker found_id = dediprog_read_id(dp_data->handle);
1232*0d6140beSAndroid Build Coastguard Worker if (found_id < 0) {
1233*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not read id.\n");
1234*0d6140beSAndroid Build Coastguard Worker libusb_release_interface(dp_data->handle, 0);
1235*0d6140beSAndroid Build Coastguard Worker libusb_close(dp_data->handle);
1236*0d6140beSAndroid Build Coastguard Worker continue;
1237*0d6140beSAndroid Build Coastguard Worker }
1238*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Found dediprog id SF%06d.\n", found_id);
1239*0d6140beSAndroid Build Coastguard Worker if (found_id != id) {
1240*0d6140beSAndroid Build Coastguard Worker libusb_release_interface(dp_data->handle, 0);
1241*0d6140beSAndroid Build Coastguard Worker libusb_close(dp_data->handle);
1242*0d6140beSAndroid Build Coastguard Worker continue;
1243*0d6140beSAndroid Build Coastguard Worker }
1244*0d6140beSAndroid Build Coastguard Worker break;
1245*0d6140beSAndroid Build Coastguard Worker }
1246*0d6140beSAndroid Build Coastguard Worker } else {
1247*0d6140beSAndroid Build Coastguard Worker if (dediprog_open(usedevice, dp_data)) {
1248*0d6140beSAndroid Build Coastguard Worker goto init_err_exit;
1249*0d6140beSAndroid Build Coastguard Worker }
1250*0d6140beSAndroid Build Coastguard Worker found_id = dediprog_read_id(dp_data->handle);
1251*0d6140beSAndroid Build Coastguard Worker }
1252*0d6140beSAndroid Build Coastguard Worker
1253*0d6140beSAndroid Build Coastguard Worker if (found_id >= 0) {
1254*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Using dediprog id SF%06d.\n", found_id);
1255*0d6140beSAndroid Build Coastguard Worker }
1256*0d6140beSAndroid Build Coastguard Worker
1257*0d6140beSAndroid Build Coastguard Worker /* Try reading the devicestring. If that fails and the device is old (FW < 6.0.0, which we can not know)
1258*0d6140beSAndroid Build Coastguard Worker * then we need to try the "set voltage" command and then attempt to read the devicestring again. */
1259*0d6140beSAndroid Build Coastguard Worker if (dediprog_check_devicestring(dp_data)) {
1260*0d6140beSAndroid Build Coastguard Worker if (dediprog_set_voltage(dp_data->handle))
1261*0d6140beSAndroid Build Coastguard Worker goto init_err_cleanup_exit;
1262*0d6140beSAndroid Build Coastguard Worker if (dediprog_check_devicestring(dp_data))
1263*0d6140beSAndroid Build Coastguard Worker goto init_err_cleanup_exit;
1264*0d6140beSAndroid Build Coastguard Worker }
1265*0d6140beSAndroid Build Coastguard Worker
1266*0d6140beSAndroid Build Coastguard Worker /* SF100/SF200 uses one in/out endpoint, SF600 uses separate in/out endpoints */
1267*0d6140beSAndroid Build Coastguard Worker dp_data->in_endpoint = 2;
1268*0d6140beSAndroid Build Coastguard Worker switch (dp_data->devicetype) {
1269*0d6140beSAndroid Build Coastguard Worker case DEV_SF100:
1270*0d6140beSAndroid Build Coastguard Worker case DEV_SF200:
1271*0d6140beSAndroid Build Coastguard Worker dp_data->out_endpoint = 2;
1272*0d6140beSAndroid Build Coastguard Worker break;
1273*0d6140beSAndroid Build Coastguard Worker default:
1274*0d6140beSAndroid Build Coastguard Worker dp_data->out_endpoint = 1;
1275*0d6140beSAndroid Build Coastguard Worker break;
1276*0d6140beSAndroid Build Coastguard Worker }
1277*0d6140beSAndroid Build Coastguard Worker
1278*0d6140beSAndroid Build Coastguard Worker /* Set all possible LEDs as soon as possible to indicate activity.
1279*0d6140beSAndroid Build Coastguard Worker * Because knowing the firmware version is required to set the LEDs correctly we need to this after
1280*0d6140beSAndroid Build Coastguard Worker * dediprog_check_devicestring() has queried the device. */
1281*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_ALL, dp_data);
1282*0d6140beSAndroid Build Coastguard Worker
1283*0d6140beSAndroid Build Coastguard Worker /* Select target/socket, frequency and VCC. */
1284*0d6140beSAndroid Build Coastguard Worker if (set_target_flash(dp_data->handle, target) ||
1285*0d6140beSAndroid Build Coastguard Worker dediprog_set_spi_speed(spispeed_idx, dp_data) ||
1286*0d6140beSAndroid Build Coastguard Worker dediprog_set_spi_voltage(dp_data->handle, millivolt)) {
1287*0d6140beSAndroid Build Coastguard Worker dediprog_set_leds(LED_ERROR, dp_data);
1288*0d6140beSAndroid Build Coastguard Worker goto init_err_cleanup_exit;
1289*0d6140beSAndroid Build Coastguard Worker }
1290*0d6140beSAndroid Build Coastguard Worker
1291*0d6140beSAndroid Build Coastguard Worker if (dediprog_standalone_mode(dp_data))
1292*0d6140beSAndroid Build Coastguard Worker goto init_err_cleanup_exit;
1293*0d6140beSAndroid Build Coastguard Worker
1294*0d6140beSAndroid Build Coastguard Worker if ((dp_data->devicetype == DEV_SF100) ||
1295*0d6140beSAndroid Build Coastguard Worker (dp_data->devicetype == DEV_SF600 && protocol(dp_data) == PROTOCOL_V3))
1296*0d6140beSAndroid Build Coastguard Worker spi_master_dediprog.features &= ~SPI_MASTER_NO_4BA_MODES;
1297*0d6140beSAndroid Build Coastguard Worker
1298*0d6140beSAndroid Build Coastguard Worker if (protocol(dp_data) >= PROTOCOL_V2)
1299*0d6140beSAndroid Build Coastguard Worker spi_master_dediprog.features |= SPI_MASTER_4BA;
1300*0d6140beSAndroid Build Coastguard Worker
1301*0d6140beSAndroid Build Coastguard Worker if (dediprog_set_leds(LED_NONE, dp_data))
1302*0d6140beSAndroid Build Coastguard Worker goto init_err_cleanup_exit;
1303*0d6140beSAndroid Build Coastguard Worker
1304*0d6140beSAndroid Build Coastguard Worker return register_spi_master(&spi_master_dediprog, dp_data);
1305*0d6140beSAndroid Build Coastguard Worker
1306*0d6140beSAndroid Build Coastguard Worker init_err_cleanup_exit:
1307*0d6140beSAndroid Build Coastguard Worker dediprog_shutdown(dp_data);
1308*0d6140beSAndroid Build Coastguard Worker return 1;
1309*0d6140beSAndroid Build Coastguard Worker
1310*0d6140beSAndroid Build Coastguard Worker init_err_exit:
1311*0d6140beSAndroid Build Coastguard Worker free(dp_data);
1312*0d6140beSAndroid Build Coastguard Worker return 1;
1313*0d6140beSAndroid Build Coastguard Worker }
1314*0d6140beSAndroid Build Coastguard Worker
1315*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_dediprog = {
1316*0d6140beSAndroid Build Coastguard Worker .name = "dediprog",
1317*0d6140beSAndroid Build Coastguard Worker .type = USB,
1318*0d6140beSAndroid Build Coastguard Worker .devs.dev = devs_dediprog,
1319*0d6140beSAndroid Build Coastguard Worker .init = dediprog_init,
1320*0d6140beSAndroid Build Coastguard Worker };
1321