blob: 6005bd4c213c94908b7353a28ba2c92be407800b [file] [log] [blame]
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +00001/*
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.
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000014 */
15
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000016/* 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
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000037 */
38
39#include <stdlib.h>
Carl-Daniel Hailfinger1c6d2ff2012-08-27 00:44:42 +000040#include <strings.h>
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000041#include <string.h>
42
43#include "flash.h"
44#include "programmer.h"
45
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000046enum pony_type {
47 TYPE_SI_PROG,
48 TYPE_SERBANG,
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000049 TYPE_AJAWE
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000050};
51
Anastasia Klimchukf7b06742021-05-27 09:46:23 +100052struct pony_spi_data {
53 /* Pins for master->slave direction */
54 int negate_cs;
55 int negate_sck;
56 int negate_mosi;
57 /* Pins for slave->master direction */
58 int negate_miso;
59};
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000060
Anastasia Klimchuk5f5eaeb2021-05-26 09:54:08 +100061static void pony_bitbang_set_cs(int val, void *spi_data)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000062{
Anastasia Klimchukf7b06742021-05-27 09:46:23 +100063 struct pony_spi_data *data = spi_data;
64
65 if (data->negate_cs)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000066 val ^= 1;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000067
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000068 sp_set_pin(PIN_TXD, val);
69}
70
Anastasia Klimchuk5f5eaeb2021-05-26 09:54:08 +100071static void pony_bitbang_set_sck(int val, void *spi_data)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000072{
Anastasia Klimchukf7b06742021-05-27 09:46:23 +100073 struct pony_spi_data *data = spi_data;
74
75 if (data->negate_sck)
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000076 val ^= 1;
77
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000078 sp_set_pin(PIN_RTS, val);
79}
80
Anastasia Klimchuk5f5eaeb2021-05-26 09:54:08 +100081static void pony_bitbang_set_mosi(int val, void *spi_data)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000082{
Anastasia Klimchukf7b06742021-05-27 09:46:23 +100083 struct pony_spi_data *data = spi_data;
84
85 if (data->negate_mosi)
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000086 val ^= 1;
87
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000088 sp_set_pin(PIN_DTR, val);
89}
90
Anastasia Klimchuk5f5eaeb2021-05-26 09:54:08 +100091static int pony_bitbang_get_miso(void *spi_data)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000092{
Anastasia Klimchukf7b06742021-05-27 09:46:23 +100093 struct pony_spi_data *data = spi_data;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000094 int tmp = sp_get_pin(PIN_CTS);
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000095
Anastasia Klimchukf7b06742021-05-27 09:46:23 +100096 if (data->negate_miso)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000097 tmp ^= 1;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000098
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000099 return tmp;
100}
101
102static const struct bitbang_spi_master bitbang_spi_master_pony = {
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000103 .set_cs = pony_bitbang_set_cs,
104 .set_sck = pony_bitbang_set_sck,
105 .set_mosi = pony_bitbang_set_mosi,
106 .get_miso = pony_bitbang_get_miso,
107 .half_period = 0,
108};
109
Carl-Daniel Hailfinger8b6690c2016-03-13 16:24:09 +0000110static int pony_spi_shutdown(void *data)
111{
112 /* Shut down serial port communication */
113 int ret = serialport_shutdown(NULL);
114 if (ret)
115 msg_pdbg("Pony SPI shutdown failed.\n");
116 else
117 msg_pdbg("Pony SPI shutdown completed.\n");
118
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000119 free(data);
Carl-Daniel Hailfinger8b6690c2016-03-13 16:24:09 +0000120 return ret;
121}
122
Thomas Heijligen4f5169d2021-05-04 15:32:17 +0200123static int pony_spi_init(void)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000124{
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000125 int i, data_out;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000126 char *arg = NULL;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000127 enum pony_type type = TYPE_SI_PROG;
Jacob Garber4a84ec22019-07-25 19:12:31 -0600128 const char *name;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000129 int have_device = 0;
130 int have_prog = 0;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000131
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000132 struct pony_spi_data *data = calloc(1, sizeof(*data));
133 if (!data) {
134 msg_perr("Unable to allocate space for SPI master data\n");
135 return 1;
136 }
137 data->negate_cs = 1;
138 data->negate_sck = 0;
139 data->negate_mosi = 0;
140 data->negate_miso = 0;
141
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000142 /* The parameter is in format "dev=/dev/device,type=serbang" */
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000143 arg = extract_programmer_param("dev");
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000144 if (arg && strlen(arg)) {
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000145 sp_fd = sp_openserport(arg, 9600);
Stefan Tauneracfc4c62012-11-30 16:46:45 +0000146 if (sp_fd == SER_INV_FD) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000147 free(arg);
148 return 1;
149 }
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000150 if (register_shutdown(pony_spi_shutdown, data) != 0) {
Carl-Daniel Hailfinger8b6690c2016-03-13 16:24:09 +0000151 free(arg);
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000152 free(data);
Carl-Daniel Hailfinger8b6690c2016-03-13 16:24:09 +0000153 serialport_shutdown(NULL);
154 return 1;
155 }
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000156 have_device++;
157 }
158 free(arg);
159
160 if (!have_device) {
161 msg_perr("Error: No valid device specified.\n"
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000162 "Use flashrom -p pony_spi:dev=/dev/device[,type=name]\n");
163 return 1;
164 }
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000165
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000166 arg = extract_programmer_param("type");
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000167 if (arg && !strcasecmp(arg, "serbang")) {
168 type = TYPE_SERBANG;
169 } else if (arg && !strcasecmp(arg, "si_prog")) {
170 type = TYPE_SI_PROG;
171 } else if (arg && !strcasecmp( arg, "ajawe")) {
172 type = TYPE_AJAWE;
173 } else if (arg && !strlen(arg)) {
174 msg_perr("Error: Missing argument for programmer type.\n");
175 free(arg);
Stefan Reinauerbbdde552014-04-26 16:11:30 +0000176 return 1;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000177 } else if (arg){
178 msg_perr("Error: Invalid programmer type specified.\n");
179 free(arg);
180 return 1;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000181 }
182 free(arg);
183
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000184 /*
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000185 * Configure the serial port pins, depending on the used programmer.
186 */
187 switch (type) {
188 case TYPE_AJAWE:
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000189 data->negate_cs = 1;
190 data->negate_sck = 1;
191 data->negate_mosi = 1;
192 data->negate_miso = 1;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000193 name = "AJAWe";
194 break;
195 case TYPE_SERBANG:
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000196 data->negate_cs = 0;
197 data->negate_sck = 0;
198 data->negate_mosi = 0;
199 data->negate_miso = 1;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000200 name = "serbang";
201 break;
202 default:
203 case TYPE_SI_PROG:
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000204 data->negate_cs = 1;
205 data->negate_sck = 0;
206 data->negate_mosi = 0;
207 data->negate_miso = 0;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000208 name = "SI-Prog";
209 break;
210 }
211 msg_pdbg("Using %s programmer pinout.\n", name);
212
213 /*
214 * Detect if there is a compatible hardware programmer connected.
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000215 */
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000216 pony_bitbang_set_cs(1, data);
217 pony_bitbang_set_sck(1, data);
218 pony_bitbang_set_mosi(1, data);
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000219
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000220 switch (type) {
221 case TYPE_AJAWE:
222 have_prog = 1;
223 break;
224 case TYPE_SI_PROG:
225 case TYPE_SERBANG:
226 default:
227 have_prog = 1;
228 /* We toggle RTS/SCK a few times and see if DSR changes too. */
229 for (i = 1; i <= 10; i++) {
230 data_out = i & 1;
231 sp_set_pin(PIN_RTS, data_out);
232 programmer_delay(1000);
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000233
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000234 /* If DSR does not change, we are not connected to what we think */
235 if (data_out != sp_get_pin(PIN_DSR)) {
236 have_prog = 0;
237 break;
238 }
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000239 }
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000240 break;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000241 }
242
243 if (!have_prog) {
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000244 msg_perr("No programmer compatible with %s detected.\n", name);
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000245 return 1;
246 }
247
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000248 if (register_spi_bitbang_master(&bitbang_spi_master_pony, data))
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000249 return 1;
Anastasia Klimchukf7b06742021-05-27 09:46:23 +1000250
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000251 return 0;
252}
Thomas Heijligen4f5169d2021-05-04 15:32:17 +0200253
254const struct programmer_entry programmer_pony_spi = {
255 .name = "pony_spi",
256 .type = OTHER,
257 /* FIXME */
258 .devs.note = "Programmers compatible with SI-Prog, serbang or AJAWe\n",
259 .init = pony_spi_init,
260 .map_flash_region = fallback_map,
261 .unmap_flash_region = fallback_unmap,
262 .delay = internal_delay,
263};