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) 2012 Virgil-Adrian Teaca
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; version 2 of the License.
9*0d6140beSAndroid Build Coastguard Worker *
10*0d6140beSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
11*0d6140beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*0d6140beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*0d6140beSAndroid Build Coastguard Worker * GNU General Public License for more details.
14*0d6140beSAndroid Build Coastguard Worker */
15*0d6140beSAndroid Build Coastguard Worker
16*0d6140beSAndroid Build Coastguard Worker /* Driver for serial programmers compatible with SI-Prog or AJAWe.
17*0d6140beSAndroid Build Coastguard Worker *
18*0d6140beSAndroid Build Coastguard Worker * See http://www.lancos.com/siprogsch.html for SI-Prog schematics and instructions.
19*0d6140beSAndroid Build Coastguard Worker * See http://www.ajawe.pl/ajawe0208.htm for AJAWe serial programmer documentation.
20*0d6140beSAndroid Build Coastguard Worker *
21*0d6140beSAndroid Build Coastguard Worker * Pin layout for SI-Prog-like hardware:
22*0d6140beSAndroid Build Coastguard Worker *
23*0d6140beSAndroid Build Coastguard Worker * MOSI <-------< DTR
24*0d6140beSAndroid Build Coastguard Worker * MISO >-------> CTS
25*0d6140beSAndroid Build Coastguard Worker * SCK <---+---< RTS
26*0d6140beSAndroid Build Coastguard Worker * +---> DSR
27*0d6140beSAndroid Build Coastguard Worker * CS# <-------< TXD
28*0d6140beSAndroid Build Coastguard Worker *
29*0d6140beSAndroid Build Coastguard Worker * and for the AJAWe serial programmer:
30*0d6140beSAndroid Build Coastguard Worker *
31*0d6140beSAndroid Build Coastguard Worker * MOSI <-------< DTR
32*0d6140beSAndroid Build Coastguard Worker * MISO >-------> CTS
33*0d6140beSAndroid Build Coastguard Worker * SCK <-------< RTS
34*0d6140beSAndroid Build Coastguard Worker * CS# <-------< TXD
35*0d6140beSAndroid Build Coastguard Worker *
36*0d6140beSAndroid Build Coastguard Worker * DCE >-------> DSR
37*0d6140beSAndroid Build Coastguard Worker */
38*0d6140beSAndroid Build Coastguard Worker
39*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
40*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
41*0d6140beSAndroid Build Coastguard Worker #include <strings.h>
42*0d6140beSAndroid Build Coastguard Worker #include <string.h>
43*0d6140beSAndroid Build Coastguard Worker
44*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
45*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
46*0d6140beSAndroid Build Coastguard Worker
47*0d6140beSAndroid Build Coastguard Worker enum pony_type {
48*0d6140beSAndroid Build Coastguard Worker TYPE_SI_PROG,
49*0d6140beSAndroid Build Coastguard Worker TYPE_SERBANG,
50*0d6140beSAndroid Build Coastguard Worker TYPE_AJAWE
51*0d6140beSAndroid Build Coastguard Worker };
52*0d6140beSAndroid Build Coastguard Worker
53*0d6140beSAndroid Build Coastguard Worker struct pony_spi_data {
54*0d6140beSAndroid Build Coastguard Worker /* Pins for master->slave direction */
55*0d6140beSAndroid Build Coastguard Worker bool negate_cs;
56*0d6140beSAndroid Build Coastguard Worker bool negate_sck;
57*0d6140beSAndroid Build Coastguard Worker bool negate_mosi;
58*0d6140beSAndroid Build Coastguard Worker /* Pins for slave->master direction */
59*0d6140beSAndroid Build Coastguard Worker bool negate_miso;
60*0d6140beSAndroid Build Coastguard Worker };
61*0d6140beSAndroid Build Coastguard Worker
pony_bitbang_set_cs(int val,void * spi_data)62*0d6140beSAndroid Build Coastguard Worker static void pony_bitbang_set_cs(int val, void *spi_data)
63*0d6140beSAndroid Build Coastguard Worker {
64*0d6140beSAndroid Build Coastguard Worker struct pony_spi_data *data = spi_data;
65*0d6140beSAndroid Build Coastguard Worker
66*0d6140beSAndroid Build Coastguard Worker if (data->negate_cs)
67*0d6140beSAndroid Build Coastguard Worker val ^= 1;
68*0d6140beSAndroid Build Coastguard Worker
69*0d6140beSAndroid Build Coastguard Worker sp_set_pin(PIN_TXD, val);
70*0d6140beSAndroid Build Coastguard Worker }
71*0d6140beSAndroid Build Coastguard Worker
pony_bitbang_set_sck(int val,void * spi_data)72*0d6140beSAndroid Build Coastguard Worker static void pony_bitbang_set_sck(int val, void *spi_data)
73*0d6140beSAndroid Build Coastguard Worker {
74*0d6140beSAndroid Build Coastguard Worker struct pony_spi_data *data = spi_data;
75*0d6140beSAndroid Build Coastguard Worker
76*0d6140beSAndroid Build Coastguard Worker if (data->negate_sck)
77*0d6140beSAndroid Build Coastguard Worker val ^= 1;
78*0d6140beSAndroid Build Coastguard Worker
79*0d6140beSAndroid Build Coastguard Worker sp_set_pin(PIN_RTS, val);
80*0d6140beSAndroid Build Coastguard Worker }
81*0d6140beSAndroid Build Coastguard Worker
pony_bitbang_set_mosi(int val,void * spi_data)82*0d6140beSAndroid Build Coastguard Worker static void pony_bitbang_set_mosi(int val, void *spi_data)
83*0d6140beSAndroid Build Coastguard Worker {
84*0d6140beSAndroid Build Coastguard Worker struct pony_spi_data *data = spi_data;
85*0d6140beSAndroid Build Coastguard Worker
86*0d6140beSAndroid Build Coastguard Worker if (data->negate_mosi)
87*0d6140beSAndroid Build Coastguard Worker val ^= 1;
88*0d6140beSAndroid Build Coastguard Worker
89*0d6140beSAndroid Build Coastguard Worker sp_set_pin(PIN_DTR, val);
90*0d6140beSAndroid Build Coastguard Worker }
91*0d6140beSAndroid Build Coastguard Worker
pony_bitbang_get_miso(void * spi_data)92*0d6140beSAndroid Build Coastguard Worker static int pony_bitbang_get_miso(void *spi_data)
93*0d6140beSAndroid Build Coastguard Worker {
94*0d6140beSAndroid Build Coastguard Worker struct pony_spi_data *data = spi_data;
95*0d6140beSAndroid Build Coastguard Worker int tmp = sp_get_pin(PIN_CTS);
96*0d6140beSAndroid Build Coastguard Worker
97*0d6140beSAndroid Build Coastguard Worker if (data->negate_miso)
98*0d6140beSAndroid Build Coastguard Worker tmp ^= 1;
99*0d6140beSAndroid Build Coastguard Worker
100*0d6140beSAndroid Build Coastguard Worker return tmp;
101*0d6140beSAndroid Build Coastguard Worker }
102*0d6140beSAndroid Build Coastguard Worker
103*0d6140beSAndroid Build Coastguard Worker static const struct bitbang_spi_master bitbang_spi_master_pony = {
104*0d6140beSAndroid Build Coastguard Worker .set_cs = pony_bitbang_set_cs,
105*0d6140beSAndroid Build Coastguard Worker .set_sck = pony_bitbang_set_sck,
106*0d6140beSAndroid Build Coastguard Worker .set_mosi = pony_bitbang_set_mosi,
107*0d6140beSAndroid Build Coastguard Worker .get_miso = pony_bitbang_get_miso,
108*0d6140beSAndroid Build Coastguard Worker .half_period = 0,
109*0d6140beSAndroid Build Coastguard Worker };
110*0d6140beSAndroid Build Coastguard Worker
pony_spi_shutdown(void * data)111*0d6140beSAndroid Build Coastguard Worker static int pony_spi_shutdown(void *data)
112*0d6140beSAndroid Build Coastguard Worker {
113*0d6140beSAndroid Build Coastguard Worker /* Shut down serial port communication */
114*0d6140beSAndroid Build Coastguard Worker int ret = serialport_shutdown(NULL);
115*0d6140beSAndroid Build Coastguard Worker if (ret)
116*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Pony SPI shutdown failed.\n");
117*0d6140beSAndroid Build Coastguard Worker else
118*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Pony SPI shutdown completed.\n");
119*0d6140beSAndroid Build Coastguard Worker
120*0d6140beSAndroid Build Coastguard Worker free(data);
121*0d6140beSAndroid Build Coastguard Worker return ret;
122*0d6140beSAndroid Build Coastguard Worker }
123*0d6140beSAndroid Build Coastguard Worker
get_params(const struct programmer_cfg * cfg,enum pony_type * type,bool * have_device)124*0d6140beSAndroid Build Coastguard Worker static int get_params(const struct programmer_cfg *cfg, enum pony_type *type, bool *have_device)
125*0d6140beSAndroid Build Coastguard Worker {
126*0d6140beSAndroid Build Coastguard Worker char *arg = NULL;
127*0d6140beSAndroid Build Coastguard Worker int ret = 0;
128*0d6140beSAndroid Build Coastguard Worker
129*0d6140beSAndroid Build Coastguard Worker /* defaults */
130*0d6140beSAndroid Build Coastguard Worker *type = TYPE_SI_PROG;
131*0d6140beSAndroid Build Coastguard Worker *have_device = false;
132*0d6140beSAndroid Build Coastguard Worker
133*0d6140beSAndroid Build Coastguard Worker /* The parameter is in format "dev=/dev/device,type=serbang" */
134*0d6140beSAndroid Build Coastguard Worker arg = extract_programmer_param_str(cfg, "dev");
135*0d6140beSAndroid Build Coastguard Worker if (arg && strlen(arg)) {
136*0d6140beSAndroid Build Coastguard Worker sp_fd = sp_openserport(arg, 9600);
137*0d6140beSAndroid Build Coastguard Worker if (sp_fd == SER_INV_FD)
138*0d6140beSAndroid Build Coastguard Worker ret = 1;
139*0d6140beSAndroid Build Coastguard Worker else
140*0d6140beSAndroid Build Coastguard Worker *have_device = true;
141*0d6140beSAndroid Build Coastguard Worker }
142*0d6140beSAndroid Build Coastguard Worker free(arg);
143*0d6140beSAndroid Build Coastguard Worker
144*0d6140beSAndroid Build Coastguard Worker arg = extract_programmer_param_str(cfg, "type");
145*0d6140beSAndroid Build Coastguard Worker if (arg && !strcasecmp(arg, "serbang")) {
146*0d6140beSAndroid Build Coastguard Worker *type = TYPE_SERBANG;
147*0d6140beSAndroid Build Coastguard Worker } else if (arg && !strcasecmp(arg, "si_prog")) {
148*0d6140beSAndroid Build Coastguard Worker *type = TYPE_SI_PROG;
149*0d6140beSAndroid Build Coastguard Worker } else if (arg && !strcasecmp( arg, "ajawe")) {
150*0d6140beSAndroid Build Coastguard Worker *type = TYPE_AJAWE;
151*0d6140beSAndroid Build Coastguard Worker } else if (arg && !strlen(arg)) {
152*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Missing argument for programmer type.\n");
153*0d6140beSAndroid Build Coastguard Worker ret = 1;
154*0d6140beSAndroid Build Coastguard Worker } else if (arg) {
155*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: Invalid programmer type specified.\n");
156*0d6140beSAndroid Build Coastguard Worker ret = 1;
157*0d6140beSAndroid Build Coastguard Worker }
158*0d6140beSAndroid Build Coastguard Worker free(arg);
159*0d6140beSAndroid Build Coastguard Worker
160*0d6140beSAndroid Build Coastguard Worker return ret;
161*0d6140beSAndroid Build Coastguard Worker }
162*0d6140beSAndroid Build Coastguard Worker
pony_spi_init(const struct programmer_cfg * cfg)163*0d6140beSAndroid Build Coastguard Worker static int pony_spi_init(const struct programmer_cfg *cfg)
164*0d6140beSAndroid Build Coastguard Worker {
165*0d6140beSAndroid Build Coastguard Worker int i, data_out;
166*0d6140beSAndroid Build Coastguard Worker enum pony_type type;
167*0d6140beSAndroid Build Coastguard Worker const char *name;
168*0d6140beSAndroid Build Coastguard Worker bool have_device;
169*0d6140beSAndroid Build Coastguard Worker bool have_prog = false;
170*0d6140beSAndroid Build Coastguard Worker
171*0d6140beSAndroid Build Coastguard Worker if (get_params(cfg, &type, &have_device)) {
172*0d6140beSAndroid Build Coastguard Worker serialport_shutdown(NULL);
173*0d6140beSAndroid Build Coastguard Worker return 1;
174*0d6140beSAndroid Build Coastguard Worker }
175*0d6140beSAndroid Build Coastguard Worker if (!have_device) {
176*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: No valid device specified.\n"
177*0d6140beSAndroid Build Coastguard Worker "Use flashrom -p pony_spi:dev=/dev/device[,type=name]\n");
178*0d6140beSAndroid Build Coastguard Worker serialport_shutdown(NULL);
179*0d6140beSAndroid Build Coastguard Worker return 1;
180*0d6140beSAndroid Build Coastguard Worker }
181*0d6140beSAndroid Build Coastguard Worker
182*0d6140beSAndroid Build Coastguard Worker struct pony_spi_data *data = calloc(1, sizeof(*data));
183*0d6140beSAndroid Build Coastguard Worker if (!data) {
184*0d6140beSAndroid Build Coastguard Worker msg_perr("Unable to allocate space for SPI master data\n");
185*0d6140beSAndroid Build Coastguard Worker serialport_shutdown(NULL);
186*0d6140beSAndroid Build Coastguard Worker return 1;
187*0d6140beSAndroid Build Coastguard Worker }
188*0d6140beSAndroid Build Coastguard Worker data->negate_cs = true;
189*0d6140beSAndroid Build Coastguard Worker data->negate_sck = false;
190*0d6140beSAndroid Build Coastguard Worker data->negate_mosi = false;
191*0d6140beSAndroid Build Coastguard Worker data->negate_miso = false;
192*0d6140beSAndroid Build Coastguard Worker
193*0d6140beSAndroid Build Coastguard Worker if (register_shutdown(pony_spi_shutdown, data) != 0) {
194*0d6140beSAndroid Build Coastguard Worker free(data);
195*0d6140beSAndroid Build Coastguard Worker serialport_shutdown(NULL);
196*0d6140beSAndroid Build Coastguard Worker return 1;
197*0d6140beSAndroid Build Coastguard Worker }
198*0d6140beSAndroid Build Coastguard Worker
199*0d6140beSAndroid Build Coastguard Worker /*
200*0d6140beSAndroid Build Coastguard Worker * Configure the serial port pins, depending on the used programmer.
201*0d6140beSAndroid Build Coastguard Worker */
202*0d6140beSAndroid Build Coastguard Worker switch (type) {
203*0d6140beSAndroid Build Coastguard Worker case TYPE_AJAWE:
204*0d6140beSAndroid Build Coastguard Worker data->negate_cs = true;
205*0d6140beSAndroid Build Coastguard Worker data->negate_sck = true;
206*0d6140beSAndroid Build Coastguard Worker data->negate_mosi = true;
207*0d6140beSAndroid Build Coastguard Worker data->negate_miso = true;
208*0d6140beSAndroid Build Coastguard Worker name = "AJAWe";
209*0d6140beSAndroid Build Coastguard Worker break;
210*0d6140beSAndroid Build Coastguard Worker case TYPE_SERBANG:
211*0d6140beSAndroid Build Coastguard Worker data->negate_cs = false;
212*0d6140beSAndroid Build Coastguard Worker data->negate_sck = false;
213*0d6140beSAndroid Build Coastguard Worker data->negate_mosi = false;
214*0d6140beSAndroid Build Coastguard Worker data->negate_miso = true;
215*0d6140beSAndroid Build Coastguard Worker name = "serbang";
216*0d6140beSAndroid Build Coastguard Worker break;
217*0d6140beSAndroid Build Coastguard Worker default:
218*0d6140beSAndroid Build Coastguard Worker case TYPE_SI_PROG:
219*0d6140beSAndroid Build Coastguard Worker data->negate_cs = true;
220*0d6140beSAndroid Build Coastguard Worker data->negate_sck = false;
221*0d6140beSAndroid Build Coastguard Worker data->negate_mosi = false;
222*0d6140beSAndroid Build Coastguard Worker data->negate_miso = false;
223*0d6140beSAndroid Build Coastguard Worker name = "SI-Prog";
224*0d6140beSAndroid Build Coastguard Worker break;
225*0d6140beSAndroid Build Coastguard Worker }
226*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Using %s programmer pinout.\n", name);
227*0d6140beSAndroid Build Coastguard Worker
228*0d6140beSAndroid Build Coastguard Worker /*
229*0d6140beSAndroid Build Coastguard Worker * Detect if there is a compatible hardware programmer connected.
230*0d6140beSAndroid Build Coastguard Worker */
231*0d6140beSAndroid Build Coastguard Worker pony_bitbang_set_cs(1, data);
232*0d6140beSAndroid Build Coastguard Worker pony_bitbang_set_sck(1, data);
233*0d6140beSAndroid Build Coastguard Worker pony_bitbang_set_mosi(1, data);
234*0d6140beSAndroid Build Coastguard Worker
235*0d6140beSAndroid Build Coastguard Worker switch (type) {
236*0d6140beSAndroid Build Coastguard Worker case TYPE_AJAWE:
237*0d6140beSAndroid Build Coastguard Worker have_prog = true;
238*0d6140beSAndroid Build Coastguard Worker break;
239*0d6140beSAndroid Build Coastguard Worker case TYPE_SI_PROG:
240*0d6140beSAndroid Build Coastguard Worker case TYPE_SERBANG:
241*0d6140beSAndroid Build Coastguard Worker default:
242*0d6140beSAndroid Build Coastguard Worker have_prog = true;
243*0d6140beSAndroid Build Coastguard Worker /* We toggle RTS/SCK a few times and see if DSR changes too. */
244*0d6140beSAndroid Build Coastguard Worker for (i = 1; i <= 10; i++) {
245*0d6140beSAndroid Build Coastguard Worker data_out = i & 1;
246*0d6140beSAndroid Build Coastguard Worker sp_set_pin(PIN_RTS, data_out);
247*0d6140beSAndroid Build Coastguard Worker default_delay(1000);
248*0d6140beSAndroid Build Coastguard Worker
249*0d6140beSAndroid Build Coastguard Worker /* If DSR does not change, we are not connected to what we think */
250*0d6140beSAndroid Build Coastguard Worker if (data_out != sp_get_pin(PIN_DSR)) {
251*0d6140beSAndroid Build Coastguard Worker have_prog = false;
252*0d6140beSAndroid Build Coastguard Worker break;
253*0d6140beSAndroid Build Coastguard Worker }
254*0d6140beSAndroid Build Coastguard Worker }
255*0d6140beSAndroid Build Coastguard Worker break;
256*0d6140beSAndroid Build Coastguard Worker }
257*0d6140beSAndroid Build Coastguard Worker
258*0d6140beSAndroid Build Coastguard Worker if (!have_prog) {
259*0d6140beSAndroid Build Coastguard Worker msg_perr("No programmer compatible with %s detected.\n", name);
260*0d6140beSAndroid Build Coastguard Worker return 1;
261*0d6140beSAndroid Build Coastguard Worker }
262*0d6140beSAndroid Build Coastguard Worker
263*0d6140beSAndroid Build Coastguard Worker if (register_spi_bitbang_master(&bitbang_spi_master_pony, data))
264*0d6140beSAndroid Build Coastguard Worker return 1;
265*0d6140beSAndroid Build Coastguard Worker
266*0d6140beSAndroid Build Coastguard Worker return 0;
267*0d6140beSAndroid Build Coastguard Worker }
268*0d6140beSAndroid Build Coastguard Worker
269*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_pony_spi = {
270*0d6140beSAndroid Build Coastguard Worker .name = "pony_spi",
271*0d6140beSAndroid Build Coastguard Worker .type = OTHER,
272*0d6140beSAndroid Build Coastguard Worker /* FIXME */
273*0d6140beSAndroid Build Coastguard Worker .devs.note = "Programmers compatible with SI-Prog, serbang or AJAWe\n",
274*0d6140beSAndroid Build Coastguard Worker .init = pony_spi_init,
275*0d6140beSAndroid Build Coastguard Worker };
276