blob: a09021d0e30e0e5b48668538e6de6ebef20f076d [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"
Nico Huberd16a9112024-01-07 00:11:44 +010045#include "bitbang_spi.h"
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000046
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000047enum pony_type {
48 TYPE_SI_PROG,
49 TYPE_SERBANG,
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000050 TYPE_AJAWE
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000051};
52
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000053/* Pins for master->slave direction */
54static int pony_negate_cs = 1;
55static int pony_negate_sck = 0;
56static int pony_negate_mosi = 0;
57/* Pins for slave->master direction */
58static int pony_negate_miso = 0;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000059
Anastasia Klimchuk0e788182021-05-26 09:54:08 +100060static void pony_bitbang_set_cs(int val, void *spi_data)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000061{
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000062 if (pony_negate_cs)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000063 val ^= 1;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000064
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000065 sp_set_pin(PIN_TXD, val);
66}
67
Anastasia Klimchuk0e788182021-05-26 09:54:08 +100068static void pony_bitbang_set_sck(int val, void *spi_data)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000069{
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000070 if (pony_negate_sck)
71 val ^= 1;
72
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000073 sp_set_pin(PIN_RTS, val);
74}
75
Anastasia Klimchuk0e788182021-05-26 09:54:08 +100076static void pony_bitbang_set_mosi(int val, void *spi_data)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000077{
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000078 if (pony_negate_mosi)
79 val ^= 1;
80
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000081 sp_set_pin(PIN_DTR, val);
82}
83
Anastasia Klimchuk0e788182021-05-26 09:54:08 +100084static int pony_bitbang_get_miso(void *spi_data)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000085{
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000086 int tmp = sp_get_pin(PIN_CTS);
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000087
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000088 if (pony_negate_miso)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000089 tmp ^= 1;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +000090
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +000091 return tmp;
92}
93
94static const struct bitbang_spi_master bitbang_spi_master_pony = {
Thomas Heijligen43040f22022-06-23 14:38:35 +020095 .set_cs = pony_bitbang_set_cs,
96 .set_sck = pony_bitbang_set_sck,
97 .set_mosi = pony_bitbang_set_mosi,
98 .get_miso = pony_bitbang_get_miso,
99 .half_period = 0,
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000100};
101
Carl-Daniel Hailfinger8b6690c2016-03-13 16:24:09 +0000102static int pony_spi_shutdown(void *data)
103{
104 /* Shut down serial port communication */
105 int ret = serialport_shutdown(NULL);
106 if (ret)
107 msg_pdbg("Pony SPI shutdown failed.\n");
108 else
109 msg_pdbg("Pony SPI shutdown completed.\n");
110
111 return ret;
112}
113
Nico Hubere3a26882023-01-11 21:45:51 +0100114static int pony_spi_init(struct flashprog_programmer *const prog)
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000115{
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000116 int i, data_out;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000117 char *arg = NULL;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000118 enum pony_type type = TYPE_SI_PROG;
Jacob Garber4a84ec22019-07-25 19:12:31 -0600119 const char *name;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000120 int have_device = 0;
121 int have_prog = 0;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000122
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000123 /* The parameter is in format "dev=/dev/device,type=serbang" */
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000124 arg = extract_programmer_param("dev");
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000125 if (arg && strlen(arg)) {
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000126 sp_fd = sp_openserport(arg, 9600);
Stefan Tauneracfc4c62012-11-30 16:46:45 +0000127 if (sp_fd == SER_INV_FD) {
Niklas Söderlund2a95e872012-07-30 19:42:33 +0000128 free(arg);
129 return 1;
130 }
Carl-Daniel Hailfinger8b6690c2016-03-13 16:24:09 +0000131 if (register_shutdown(pony_spi_shutdown, NULL) != 0) {
132 free(arg);
133 serialport_shutdown(NULL);
134 return 1;
135 }
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000136 have_device++;
137 }
138 free(arg);
139
140 if (!have_device) {
141 msg_perr("Error: No valid device specified.\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200142 "Use flashprog -p pony_spi:dev=/dev/device[,type=name]\n");
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000143 return 1;
144 }
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000145
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000146 arg = extract_programmer_param("type");
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000147 if (arg && !strcasecmp(arg, "serbang")) {
148 type = TYPE_SERBANG;
149 } else if (arg && !strcasecmp(arg, "si_prog")) {
150 type = TYPE_SI_PROG;
151 } else if (arg && !strcasecmp( arg, "ajawe")) {
152 type = TYPE_AJAWE;
153 } else if (arg && !strlen(arg)) {
154 msg_perr("Error: Missing argument for programmer type.\n");
155 free(arg);
Stefan Reinauerbbdde552014-04-26 16:11:30 +0000156 return 1;
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000157 } else if (arg){
158 msg_perr("Error: Invalid programmer type specified.\n");
159 free(arg);
160 return 1;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000161 }
162 free(arg);
163
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000164 /*
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000165 * Configure the serial port pins, depending on the used programmer.
166 */
167 switch (type) {
168 case TYPE_AJAWE:
169 pony_negate_cs = 1;
170 pony_negate_sck = 1;
171 pony_negate_mosi = 1;
172 pony_negate_miso = 1;
173 name = "AJAWe";
174 break;
175 case TYPE_SERBANG:
176 pony_negate_cs = 0;
177 pony_negate_sck = 0;
178 pony_negate_mosi = 0;
179 pony_negate_miso = 1;
180 name = "serbang";
181 break;
182 default:
183 case TYPE_SI_PROG:
184 pony_negate_cs = 1;
185 pony_negate_sck = 0;
186 pony_negate_mosi = 0;
187 pony_negate_miso = 0;
188 name = "SI-Prog";
189 break;
190 }
191 msg_pdbg("Using %s programmer pinout.\n", name);
192
193 /*
194 * Detect if there is a compatible hardware programmer connected.
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000195 */
Anastasia Klimchuk0e788182021-05-26 09:54:08 +1000196 pony_bitbang_set_cs(1, NULL);
197 pony_bitbang_set_sck(1, NULL);
198 pony_bitbang_set_mosi(1, NULL);
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000199
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000200 switch (type) {
201 case TYPE_AJAWE:
202 have_prog = 1;
203 break;
204 case TYPE_SI_PROG:
205 case TYPE_SERBANG:
206 default:
207 have_prog = 1;
208 /* We toggle RTS/SCK a few times and see if DSR changes too. */
209 for (i = 1; i <= 10; i++) {
210 data_out = i & 1;
211 sp_set_pin(PIN_RTS, data_out);
212 programmer_delay(1000);
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000213
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000214 /* If DSR does not change, we are not connected to what we think */
215 if (data_out != sp_get_pin(PIN_DSR)) {
216 have_prog = 0;
217 break;
218 }
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000219 }
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000220 break;
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000221 }
222
223 if (!have_prog) {
Virgil-Adrian Teacadabca202012-09-01 21:32:04 +0000224 msg_perr("No programmer compatible with %s detected.\n", name);
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000225 return 1;
226 }
227
Anastasia Klimchuka447c122021-05-31 11:20:01 +1000228 if (register_spi_bitbang_master(&bitbang_spi_master_pony, NULL)) {
Virgil-Adrian Teacada7c5452012-04-30 23:11:06 +0000229 return 1;
230 }
231 return 0;
232}
Thomas Heijligencc853d82021-05-04 15:32:17 +0200233
234const struct programmer_entry programmer_pony_spi = {
235 .name = "pony_spi",
236 .type = OTHER,
237 /* FIXME */
238 .devs.note = "Programmers compatible with SI-Prog, serbang or AJAWe\n",
239 .init = pony_spi_init,
Thomas Heijligencc853d82021-05-04 15:32:17 +0200240};