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