blob: ed9d326c5eac56e7bec61e76402d3df762a10e49 [file] [log] [blame]
Edward O'Callaghan611253c2019-09-09 00:22:07 +10001/*
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 <stdlib.h>
40#include <strings.h>
41#include <string.h>
42
43#include "flash.h"
44#include "programmer.h"
45
46enum pony_type {
47 TYPE_SI_PROG,
48 TYPE_SERBANG,
49 TYPE_AJAWE
50};
51
52/* Pins for master->slave direction */
53static int pony_negate_cs = 1;
54static int pony_negate_sck = 0;
55static int pony_negate_mosi = 0;
56/* Pins for slave->master direction */
57static int pony_negate_miso = 0;
58
59static void pony_bitbang_set_cs(int val)
60{
61 if (pony_negate_cs)
62 val ^= 1;
63
64 sp_set_pin(PIN_TXD, val);
65}
66
67static void pony_bitbang_set_sck(int val)
68{
69 if (pony_negate_sck)
70 val ^= 1;
71
72 sp_set_pin(PIN_RTS, val);
73}
74
75static void pony_bitbang_set_mosi(int val)
76{
77 if (pony_negate_mosi)
78 val ^= 1;
79
80 sp_set_pin(PIN_DTR, val);
81}
82
83static int pony_bitbang_get_miso(void)
84{
85 int tmp = sp_get_pin(PIN_CTS);
86
87 if (pony_negate_miso)
88 tmp ^= 1;
89
90 return tmp;
91}
92
93static const struct bitbang_spi_master bitbang_spi_master_pony = {
94 .set_cs = pony_bitbang_set_cs,
95 .set_sck = pony_bitbang_set_sck,
96 .set_mosi = pony_bitbang_set_mosi,
97 .get_miso = pony_bitbang_get_miso,
98 .half_period = 0,
99};
100
101static int pony_spi_shutdown(void *data)
102{
103 /* Shut down serial port communication */
104 int ret = serialport_shutdown(NULL);
105 if (ret)
106 msg_pdbg("Pony SPI shutdown failed.\n");
107 else
108 msg_pdbg("Pony SPI shutdown completed.\n");
109
110 return ret;
111}
112
113int pony_spi_init(void)
114{
115 int i, data_out;
116 char *arg = NULL;
117 enum pony_type type = TYPE_SI_PROG;
Edward O'Callaghan442ea502020-10-03 00:14:45 +1000118 const char *name;
Edward O'Callaghan611253c2019-09-09 00:22:07 +1000119 int have_device = 0;
120 int have_prog = 0;
121
122 /* The parameter is in format "dev=/dev/device,type=serbang" */
123 arg = extract_programmer_param("dev");
124 if (arg && strlen(arg)) {
125 sp_fd = sp_openserport(arg, 9600);
126 if (sp_fd == SER_INV_FD) {
127 free(arg);
128 return 1;
129 }
130 if (register_shutdown(pony_spi_shutdown, NULL) != 0) {
131 free(arg);
132 serialport_shutdown(NULL);
133 return 1;
134 }
135 have_device++;
136 }
137 free(arg);
138
139 if (!have_device) {
140 msg_perr("Error: No valid device specified.\n"
141 "Use flashrom -p pony_spi:dev=/dev/device[,type=name]\n");
142 return 1;
143 }
144
145 arg = extract_programmer_param("type");
146 if (arg && !strcasecmp(arg, "serbang")) {
147 type = TYPE_SERBANG;
148 } else if (arg && !strcasecmp(arg, "si_prog")) {
149 type = TYPE_SI_PROG;
150 } else if (arg && !strcasecmp( arg, "ajawe")) {
151 type = TYPE_AJAWE;
152 } else if (arg && !strlen(arg)) {
153 msg_perr("Error: Missing argument for programmer type.\n");
154 free(arg);
155 return 1;
156 } else if (arg){
157 msg_perr("Error: Invalid programmer type specified.\n");
158 free(arg);
159 return 1;
160 }
161 free(arg);
162
163 /*
164 * Configure the serial port pins, depending on the used programmer.
165 */
166 switch (type) {
167 case TYPE_AJAWE:
168 pony_negate_cs = 1;
169 pony_negate_sck = 1;
170 pony_negate_mosi = 1;
171 pony_negate_miso = 1;
172 name = "AJAWe";
173 break;
174 case TYPE_SERBANG:
175 pony_negate_cs = 0;
176 pony_negate_sck = 0;
177 pony_negate_mosi = 0;
178 pony_negate_miso = 1;
179 name = "serbang";
180 break;
181 default:
182 case TYPE_SI_PROG:
183 pony_negate_cs = 1;
184 pony_negate_sck = 0;
185 pony_negate_mosi = 0;
186 pony_negate_miso = 0;
187 name = "SI-Prog";
188 break;
189 }
190 msg_pdbg("Using %s programmer pinout.\n", name);
191
192 /*
193 * Detect if there is a compatible hardware programmer connected.
194 */
195 pony_bitbang_set_cs(1);
196 pony_bitbang_set_sck(1);
197 pony_bitbang_set_mosi(1);
198
199 switch (type) {
200 case TYPE_AJAWE:
201 have_prog = 1;
202 break;
203 case TYPE_SI_PROG:
204 case TYPE_SERBANG:
205 default:
206 have_prog = 1;
207 /* We toggle RTS/SCK a few times and see if DSR changes too. */
208 for (i = 1; i <= 10; i++) {
209 data_out = i & 1;
210 sp_set_pin(PIN_RTS, data_out);
211 programmer_delay(1000);
212
213 /* If DSR does not change, we are not connected to what we think */
214 if (data_out != sp_get_pin(PIN_DSR)) {
215 have_prog = 0;
216 break;
217 }
218 }
219 break;
220 }
221
222 if (!have_prog) {
223 msg_perr("No programmer compatible with %s detected.\n", name);
224 return 1;
225 }
226
227 if (register_spi_bitbang_master(&bitbang_spi_master_pony)) {
228 return 1;
229 }
230 return 0;
231}