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) 2018 Linaro Limited
5*0d6140beSAndroid Build Coastguard Worker *
6*0d6140beSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
7*0d6140beSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
8*0d6140beSAndroid Build Coastguard Worker * the Free Software Foundation; either version 2 of the License, or
9*0d6140beSAndroid Build Coastguard Worker * (at your option) any later version.
10*0d6140beSAndroid Build Coastguard Worker *
11*0d6140beSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
12*0d6140beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*0d6140beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*0d6140beSAndroid Build Coastguard Worker * GNU General Public License for more details.
15*0d6140beSAndroid Build Coastguard Worker */
16*0d6140beSAndroid Build Coastguard Worker
17*0d6140beSAndroid Build Coastguard Worker /*
18*0d6140beSAndroid Build Coastguard Worker * Bit bang driver for the 96Boards Developerbox (a.k.a. Synquacer E-series)
19*0d6140beSAndroid Build Coastguard Worker * on-board debug UART. The Developerbox implements its debug UART using a
20*0d6140beSAndroid Build Coastguard Worker * CP2102N, a USB to UART bridge which also provides four GPIO pins. On
21*0d6140beSAndroid Build Coastguard Worker * Developerbox these can be hooked up to the onboard SPI NOR FLASH and used
22*0d6140beSAndroid Build Coastguard Worker * for emergency de-brick without any additional hardware programmer. Bit
23*0d6140beSAndroid Build Coastguard Worker * banging over USB is extremely slow compared to a proper SPI programmer so
24*0d6140beSAndroid Build Coastguard Worker * this is only practical as a de-brick tool.
25*0d6140beSAndroid Build Coastguard Worker *
26*0d6140beSAndroid Build Coastguard Worker * Schematic is available here:
27*0d6140beSAndroid Build Coastguard Worker * https://www.96boards.org/documentation/enterprise/developerbox/hardware-docs/
28*0d6140beSAndroid Build Coastguard Worker *
29*0d6140beSAndroid Build Coastguard Worker * To prepare a Developerbox for programming via the debug UART, DSW4 must be
30*0d6140beSAndroid Build Coastguard Worker * changed from the default 00000000 to 10001000 (i.e. DSW4-1 and DSW4-5
31*0d6140beSAndroid Build Coastguard Worker * should be turned on).
32*0d6140beSAndroid Build Coastguard Worker */
33*0d6140beSAndroid Build Coastguard Worker
34*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
35*0d6140beSAndroid Build Coastguard Worker #include <libusb.h>
36*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
37*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
38*0d6140beSAndroid Build Coastguard Worker
39*0d6140beSAndroid Build Coastguard Worker /* Bit positions for each pin. */
40*0d6140beSAndroid Build Coastguard Worker #define DEVELOPERBOX_SPI_SCK 0
41*0d6140beSAndroid Build Coastguard Worker #define DEVELOPERBOX_SPI_CS 1
42*0d6140beSAndroid Build Coastguard Worker #define DEVELOPERBOX_SPI_MISO 2
43*0d6140beSAndroid Build Coastguard Worker #define DEVELOPERBOX_SPI_MOSI 3
44*0d6140beSAndroid Build Coastguard Worker
45*0d6140beSAndroid Build Coastguard Worker /* Config request types */
46*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_HOST_TO_DEVICE 0x40
47*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_DEVICE_TO_HOST 0xc0
48*0d6140beSAndroid Build Coastguard Worker
49*0d6140beSAndroid Build Coastguard Worker /* Config request codes */
50*0d6140beSAndroid Build Coastguard Worker #define CP210X_VENDOR_SPECIFIC 0xff
51*0d6140beSAndroid Build Coastguard Worker
52*0d6140beSAndroid Build Coastguard Worker /* CP210X_VENDOR_SPECIFIC */
53*0d6140beSAndroid Build Coastguard Worker #define CP210X_WRITE_LATCH 0x37e1
54*0d6140beSAndroid Build Coastguard Worker #define CP210X_READ_LATCH 0x00c2
55*0d6140beSAndroid Build Coastguard Worker
56*0d6140beSAndroid Build Coastguard Worker static const struct dev_entry devs_developerbox_spi[] = {
57*0d6140beSAndroid Build Coastguard Worker {0x10c4, 0xea60, OK, "Silicon Labs", "CP2102N USB to UART Bridge Controller"},
58*0d6140beSAndroid Build Coastguard Worker {0},
59*0d6140beSAndroid Build Coastguard Worker };
60*0d6140beSAndroid Build Coastguard Worker
61*0d6140beSAndroid Build Coastguard Worker struct devbox_spi_data {
62*0d6140beSAndroid Build Coastguard Worker struct libusb_context *usb_ctx;
63*0d6140beSAndroid Build Coastguard Worker libusb_device_handle *cp210x_handle;
64*0d6140beSAndroid Build Coastguard Worker };
65*0d6140beSAndroid Build Coastguard Worker
cp210x_gpio_get(void * spi_data)66*0d6140beSAndroid Build Coastguard Worker static int cp210x_gpio_get(void *spi_data)
67*0d6140beSAndroid Build Coastguard Worker {
68*0d6140beSAndroid Build Coastguard Worker int res;
69*0d6140beSAndroid Build Coastguard Worker uint8_t gpio;
70*0d6140beSAndroid Build Coastguard Worker struct devbox_spi_data *data = spi_data;
71*0d6140beSAndroid Build Coastguard Worker
72*0d6140beSAndroid Build Coastguard Worker res = libusb_control_transfer(data->cp210x_handle, REQTYPE_DEVICE_TO_HOST,
73*0d6140beSAndroid Build Coastguard Worker CP210X_VENDOR_SPECIFIC, CP210X_READ_LATCH,
74*0d6140beSAndroid Build Coastguard Worker 0, &gpio, 1, 0);
75*0d6140beSAndroid Build Coastguard Worker if (res < 0) {
76*0d6140beSAndroid Build Coastguard Worker msg_perr("Failed to read GPIO pins (%s)\n", libusb_error_name(res));
77*0d6140beSAndroid Build Coastguard Worker return 0;
78*0d6140beSAndroid Build Coastguard Worker }
79*0d6140beSAndroid Build Coastguard Worker
80*0d6140beSAndroid Build Coastguard Worker return gpio;
81*0d6140beSAndroid Build Coastguard Worker }
82*0d6140beSAndroid Build Coastguard Worker
cp210x_gpio_set(uint8_t val,uint8_t mask,void * spi_data)83*0d6140beSAndroid Build Coastguard Worker static void cp210x_gpio_set(uint8_t val, uint8_t mask, void *spi_data)
84*0d6140beSAndroid Build Coastguard Worker {
85*0d6140beSAndroid Build Coastguard Worker int res;
86*0d6140beSAndroid Build Coastguard Worker uint16_t gpio;
87*0d6140beSAndroid Build Coastguard Worker struct devbox_spi_data *data = spi_data;
88*0d6140beSAndroid Build Coastguard Worker
89*0d6140beSAndroid Build Coastguard Worker gpio = ((val & 0xf) << 8) | (mask & 0xf);
90*0d6140beSAndroid Build Coastguard Worker
91*0d6140beSAndroid Build Coastguard Worker /* Set relay state on the card */
92*0d6140beSAndroid Build Coastguard Worker res = libusb_control_transfer(data->cp210x_handle, REQTYPE_HOST_TO_DEVICE,
93*0d6140beSAndroid Build Coastguard Worker CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH,
94*0d6140beSAndroid Build Coastguard Worker gpio, NULL, 0, 0);
95*0d6140beSAndroid Build Coastguard Worker if (res < 0)
96*0d6140beSAndroid Build Coastguard Worker msg_perr("Failed to read GPIO pins (%s)\n", libusb_error_name(res));
97*0d6140beSAndroid Build Coastguard Worker }
98*0d6140beSAndroid Build Coastguard Worker
cp210x_bitbang_set_cs(int val,void * spi_data)99*0d6140beSAndroid Build Coastguard Worker static void cp210x_bitbang_set_cs(int val, void *spi_data)
100*0d6140beSAndroid Build Coastguard Worker {
101*0d6140beSAndroid Build Coastguard Worker cp210x_gpio_set(val << DEVELOPERBOX_SPI_CS, 1 << DEVELOPERBOX_SPI_CS, spi_data);
102*0d6140beSAndroid Build Coastguard Worker }
103*0d6140beSAndroid Build Coastguard Worker
cp210x_bitbang_set_sck(int val,void * spi_data)104*0d6140beSAndroid Build Coastguard Worker static void cp210x_bitbang_set_sck(int val, void *spi_data)
105*0d6140beSAndroid Build Coastguard Worker {
106*0d6140beSAndroid Build Coastguard Worker cp210x_gpio_set(val << DEVELOPERBOX_SPI_SCK, 1 << DEVELOPERBOX_SPI_SCK, spi_data);
107*0d6140beSAndroid Build Coastguard Worker }
108*0d6140beSAndroid Build Coastguard Worker
cp210x_bitbang_set_mosi(int val,void * spi_data)109*0d6140beSAndroid Build Coastguard Worker static void cp210x_bitbang_set_mosi(int val, void *spi_data)
110*0d6140beSAndroid Build Coastguard Worker {
111*0d6140beSAndroid Build Coastguard Worker cp210x_gpio_set(val << DEVELOPERBOX_SPI_MOSI, 1 << DEVELOPERBOX_SPI_MOSI, spi_data);
112*0d6140beSAndroid Build Coastguard Worker }
113*0d6140beSAndroid Build Coastguard Worker
cp210x_bitbang_get_miso(void * spi_data)114*0d6140beSAndroid Build Coastguard Worker static int cp210x_bitbang_get_miso(void *spi_data)
115*0d6140beSAndroid Build Coastguard Worker {
116*0d6140beSAndroid Build Coastguard Worker return !!(cp210x_gpio_get(spi_data) & (1 << DEVELOPERBOX_SPI_MISO));
117*0d6140beSAndroid Build Coastguard Worker }
118*0d6140beSAndroid Build Coastguard Worker
cp210x_bitbang_set_sck_set_mosi(int sck,int mosi,void * spi_data)119*0d6140beSAndroid Build Coastguard Worker static void cp210x_bitbang_set_sck_set_mosi(int sck, int mosi, void *spi_data)
120*0d6140beSAndroid Build Coastguard Worker {
121*0d6140beSAndroid Build Coastguard Worker cp210x_gpio_set(sck << DEVELOPERBOX_SPI_SCK | mosi << DEVELOPERBOX_SPI_MOSI,
122*0d6140beSAndroid Build Coastguard Worker 1 << DEVELOPERBOX_SPI_SCK | 1 << DEVELOPERBOX_SPI_MOSI,
123*0d6140beSAndroid Build Coastguard Worker spi_data);
124*0d6140beSAndroid Build Coastguard Worker }
125*0d6140beSAndroid Build Coastguard Worker
126*0d6140beSAndroid Build Coastguard Worker static const struct bitbang_spi_master bitbang_spi_master_cp210x = {
127*0d6140beSAndroid Build Coastguard Worker .set_cs = cp210x_bitbang_set_cs,
128*0d6140beSAndroid Build Coastguard Worker .set_sck = cp210x_bitbang_set_sck,
129*0d6140beSAndroid Build Coastguard Worker .set_mosi = cp210x_bitbang_set_mosi,
130*0d6140beSAndroid Build Coastguard Worker .get_miso = cp210x_bitbang_get_miso,
131*0d6140beSAndroid Build Coastguard Worker .set_sck_set_mosi = cp210x_bitbang_set_sck_set_mosi,
132*0d6140beSAndroid Build Coastguard Worker };
133*0d6140beSAndroid Build Coastguard Worker
developerbox_spi_shutdown(void * spi_data)134*0d6140beSAndroid Build Coastguard Worker static int developerbox_spi_shutdown(void *spi_data)
135*0d6140beSAndroid Build Coastguard Worker {
136*0d6140beSAndroid Build Coastguard Worker struct devbox_spi_data *data = spi_data;
137*0d6140beSAndroid Build Coastguard Worker
138*0d6140beSAndroid Build Coastguard Worker libusb_close(data->cp210x_handle);
139*0d6140beSAndroid Build Coastguard Worker libusb_exit(data->usb_ctx);
140*0d6140beSAndroid Build Coastguard Worker
141*0d6140beSAndroid Build Coastguard Worker free(data);
142*0d6140beSAndroid Build Coastguard Worker return 0;
143*0d6140beSAndroid Build Coastguard Worker }
144*0d6140beSAndroid Build Coastguard Worker
developerbox_spi_init(const struct programmer_cfg * cfg)145*0d6140beSAndroid Build Coastguard Worker static int developerbox_spi_init(const struct programmer_cfg *cfg)
146*0d6140beSAndroid Build Coastguard Worker {
147*0d6140beSAndroid Build Coastguard Worker struct libusb_context *usb_ctx;
148*0d6140beSAndroid Build Coastguard Worker libusb_device_handle *cp210x_handle;
149*0d6140beSAndroid Build Coastguard Worker
150*0d6140beSAndroid Build Coastguard Worker if (libusb_init(&usb_ctx)) {
151*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not initialize libusb!\n");
152*0d6140beSAndroid Build Coastguard Worker return 1;
153*0d6140beSAndroid Build Coastguard Worker }
154*0d6140beSAndroid Build Coastguard Worker
155*0d6140beSAndroid Build Coastguard Worker char *serialno = extract_programmer_param_str(cfg, "serial");
156*0d6140beSAndroid Build Coastguard Worker if (serialno)
157*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Looking for serial number commencing %s\n", serialno);
158*0d6140beSAndroid Build Coastguard Worker cp210x_handle = usb_dev_get_by_vid_pid_serial(usb_ctx,
159*0d6140beSAndroid Build Coastguard Worker devs_developerbox_spi[0].vendor_id, devs_developerbox_spi[0].device_id, serialno);
160*0d6140beSAndroid Build Coastguard Worker free(serialno);
161*0d6140beSAndroid Build Coastguard Worker if (!cp210x_handle) {
162*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not find a Developerbox programmer on USB.\n");
163*0d6140beSAndroid Build Coastguard Worker goto err_exit;
164*0d6140beSAndroid Build Coastguard Worker }
165*0d6140beSAndroid Build Coastguard Worker
166*0d6140beSAndroid Build Coastguard Worker struct devbox_spi_data *data = calloc(1, sizeof(*data));
167*0d6140beSAndroid Build Coastguard Worker if (!data) {
168*0d6140beSAndroid Build Coastguard Worker msg_perr("Unable to allocate space for SPI master data\n");
169*0d6140beSAndroid Build Coastguard Worker goto err_exit;
170*0d6140beSAndroid Build Coastguard Worker }
171*0d6140beSAndroid Build Coastguard Worker data->usb_ctx = usb_ctx;
172*0d6140beSAndroid Build Coastguard Worker data->cp210x_handle = cp210x_handle;
173*0d6140beSAndroid Build Coastguard Worker
174*0d6140beSAndroid Build Coastguard Worker if (register_shutdown(developerbox_spi_shutdown, data)) {
175*0d6140beSAndroid Build Coastguard Worker free(data);
176*0d6140beSAndroid Build Coastguard Worker goto err_exit;
177*0d6140beSAndroid Build Coastguard Worker }
178*0d6140beSAndroid Build Coastguard Worker
179*0d6140beSAndroid Build Coastguard Worker if (register_spi_bitbang_master(&bitbang_spi_master_cp210x, data))
180*0d6140beSAndroid Build Coastguard Worker return 1; /* shutdown function does the cleanup */
181*0d6140beSAndroid Build Coastguard Worker
182*0d6140beSAndroid Build Coastguard Worker return 0;
183*0d6140beSAndroid Build Coastguard Worker
184*0d6140beSAndroid Build Coastguard Worker err_exit:
185*0d6140beSAndroid Build Coastguard Worker if (cp210x_handle)
186*0d6140beSAndroid Build Coastguard Worker libusb_close(cp210x_handle);
187*0d6140beSAndroid Build Coastguard Worker libusb_exit(usb_ctx);
188*0d6140beSAndroid Build Coastguard Worker return 1;
189*0d6140beSAndroid Build Coastguard Worker }
190*0d6140beSAndroid Build Coastguard Worker
191*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_developerbox = {
192*0d6140beSAndroid Build Coastguard Worker .name = "developerbox",
193*0d6140beSAndroid Build Coastguard Worker .type = USB,
194*0d6140beSAndroid Build Coastguard Worker .devs.dev = devs_developerbox_spi,
195*0d6140beSAndroid Build Coastguard Worker .init = developerbox_spi_init,
196*0d6140beSAndroid Build Coastguard Worker };
197