xref: /aosp_15_r20/external/flashrom/pony_spi.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
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