blob: 7f5da23064a82e8385c91624a86f226da54fe317 [file] [log] [blame]
Paul Fox05dfbe62009-06-16 21:08:06 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
5 * Copyright (C) 2009 Carl-Daniel Hailfinger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
Carl-Daniel Hailfinger3426ef62009-08-19 13:27:58 +000021#if FT2232_SPI_SUPPORT == 1
22
Paul Fox05dfbe62009-06-16 21:08:06 +000023#include <stdio.h>
24#include <stdint.h>
25#include <string.h>
26#include <stdlib.h>
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +000027#include <ctype.h>
Paul Fox05dfbe62009-06-16 21:08:06 +000028#include "flash.h"
29#include "spi.h"
Paul Fox05dfbe62009-06-16 21:08:06 +000030#include <ftdi.h>
31
32/* the 'H' chips can run internally at either 12Mhz or 60Mhz.
33 * the non-H chips can only run at 12Mhz. */
34#define CLOCK_5X 1
35
36/* in either case, the divisor is a simple integer clock divider.
37 * if CLOCK_5X is set, this divisor divides 30Mhz, else it
38 * divides 6Mhz */
39#define DIVIDE_BY 3 // e.g. '3' will give either 10Mhz or 2Mhz spi clock
40
41
42static struct ftdi_context ftdic_context;
43
44int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size)
45{
46 int r;
47 r = ftdi_write_data(ftdic, (unsigned char *) buf, size);
48 if (r < 0) {
49 fprintf(stderr, "ftdi_write_data: %d, %s\n", r,
50 ftdi_get_error_string(ftdic));
51 return 1;
52 }
53 return 0;
54}
55
56int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size)
57{
58 int r;
59 r = ftdi_read_data(ftdic, (unsigned char *) buf, size);
60 if (r < 0) {
61 fprintf(stderr, "ftdi_read_data: %d, %s\n", r,
62 ftdi_get_error_string(ftdic));
63 return 1;
64 }
65 return 0;
66}
67
68int ft2232_spi_init(void)
69{
70 int f;
71 struct ftdi_context *ftdic = &ftdic_context;
72 unsigned char buf[512];
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +000073 char *portpos = NULL;
74 int ft2232_type = FTDI_FT4232H;
75 enum ftdi_interface ft2232_interface = INTERFACE_B;
Paul Fox05dfbe62009-06-16 21:08:06 +000076
77 if (ftdi_init(ftdic) < 0) {
78 fprintf(stderr, "ftdi_init failed\n");
79 return EXIT_FAILURE;
80 }
81
Carl-Daniel Hailfingeref58a9c2009-08-12 13:32:56 +000082 if (programmer_param && !strlen(programmer_param)) {
83 free(programmer_param);
84 programmer_param = NULL;
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +000085 }
Carl-Daniel Hailfingeref58a9c2009-08-12 13:32:56 +000086 if (programmer_param) {
87 if (strstr(programmer_param, "2232"))
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +000088 ft2232_type = FTDI_FT2232H;
Carl-Daniel Hailfingeref58a9c2009-08-12 13:32:56 +000089 if (strstr(programmer_param, "4232"))
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +000090 ft2232_type = FTDI_FT4232H;
Carl-Daniel Hailfingeref58a9c2009-08-12 13:32:56 +000091 portpos = strstr(programmer_param, "port=");
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +000092 if (portpos) {
93 portpos += 5;
94 switch (toupper(*portpos)) {
95 case 'A':
96 ft2232_interface = INTERFACE_A;
97 break;
98 case 'B':
99 ft2232_interface = INTERFACE_B;
100 break;
101 default:
102 fprintf(stderr, "Invalid interface specified, "
103 "using default.\n");
104 }
105 }
Carl-Daniel Hailfingeref58a9c2009-08-12 13:32:56 +0000106 free(programmer_param);
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +0000107 }
108 printf_debug("Using device type %s ",
109 (ft2232_type == FTDI_FT2232H) ? "2232H" : "4232H");
110 printf_debug("interface %s\n",
111 (ft2232_interface == INTERFACE_A) ? "A" : "B");
112
113 f = ftdi_usb_open(ftdic, 0x0403, ft2232_type);
Paul Fox05dfbe62009-06-16 21:08:06 +0000114
115 if (f < 0 && f != -5) {
116 fprintf(stderr, "Unable to open ftdi device: %d (%s)\n", f,
117 ftdi_get_error_string(ftdic));
118 exit(-1);
119 }
120
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +0000121 if (ftdi_set_interface(ftdic, ft2232_interface) < 0) {
122 fprintf(stderr, "Unable to select interface: %s\n",
Paul Fox05dfbe62009-06-16 21:08:06 +0000123 ftdic->error_str);
124 }
125
126 if (ftdi_usb_reset(ftdic) < 0) {
127 fprintf(stderr, "Unable to reset ftdi device\n");
128 }
129
130 if (ftdi_set_latency_timer(ftdic, 2) < 0) {
131 fprintf(stderr, "Unable to set latency timer\n");
132 }
133
134 if (ftdi_write_data_set_chunksize(ftdic, 512)) {
135 fprintf(stderr, "Unable to set chunk size\n");
136 }
137
138 if (ftdi_set_bitmode(ftdic, 0x00, 2) < 0) {
139 fprintf(stderr, "Unable to set bitmode\n");
140 }
141
142#if CLOCK_5X
143 printf_debug("Disable divide-by-5 front stage\n");
144 buf[0] = 0x8a; /* disable divide-by-5 */
145 if (send_buf(ftdic, buf, 1))
146 return -1;
147#define MPSSE_CLK 60.0
148
149#else
150
151#define MPSSE_CLK 12.0
152
153#endif
154 printf_debug("Set clock divisor\n");
155 buf[0] = 0x86; /* command "set divisor" */
156 /* valueL/valueH are (desired_divisor - 1) */
157 buf[1] = (DIVIDE_BY-1) & 0xff;
158 buf[2] = ((DIVIDE_BY-1) >> 8) & 0xff;
159 if (send_buf(ftdic, buf, 3))
160 return -1;
161
162 printf("SPI clock is %fMHz\n",
163 (double)(MPSSE_CLK / (((DIVIDE_BY-1) + 1) * 2)));
164
165 /* Disconnect TDI/DO to TDO/DI for Loopback */
166 printf_debug("No loopback of tdi/do tdo/di\n");
167 buf[0] = 0x85;
168 if (send_buf(ftdic, buf, 1))
169 return -1;
170
171 printf_debug("Set data bits\n");
172 /* Set data bits low-byte command:
173 * value: 0x08 CS=high, DI=low, DO=low, SK=low
174 * dir: 0x0b CS=output, DI=input, DO=output, SK=output
175 */
176#define CS_BIT 0x08
Paul Fox05dfbe62009-06-16 21:08:06 +0000177 buf[0] = SET_BITS_LOW;
Stefan Reinauerab044b22009-09-16 08:26:59 +0000178 buf[1] = CS_BIT;
Paul Fox05dfbe62009-06-16 21:08:06 +0000179 buf[2] = 0x0b;
180 if (send_buf(ftdic, buf, 3))
181 return -1;
182
183 printf_debug("\nft2232 chosen\n");
184
185 buses_supported = CHIP_BUSTYPE_SPI;
186 spi_controller = SPI_CONTROLLER_FT2232;
187
188 return 0;
189}
190
Carl-Daniel Hailfingerd0478292009-07-10 21:08:55 +0000191int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt,
Paul Fox05dfbe62009-06-16 21:08:06 +0000192 const unsigned char *writearr, unsigned char *readarr)
193{
194 struct ftdi_context *ftdic = &ftdic_context;
195 static unsigned char *buf = NULL;
Paul Fox05dfbe62009-06-16 21:08:06 +0000196 int i, ret = 0;
197
Carl-Daniel Hailfinger142e30f2009-07-14 10:26:56 +0000198 if (writecnt > 65536 || readcnt > 65536)
199 return SPI_INVALID_LENGTH;
200
Paul Fox05dfbe62009-06-16 21:08:06 +0000201 buf = realloc(buf, writecnt + readcnt + 100);
202 if (!buf) {
203 fprintf(stderr, "Out of memory!\n");
204 exit(1);
205 }
206
207 i = 0;
208
209 /* minimize USB transfers by packing as many commands
210 * as possible together. if we're not expecting to
211 * read, we can assert CS, write, and deassert CS all
212 * in one shot. if reading, we do three separate
Stefan Reinauerab044b22009-09-16 08:26:59 +0000213 * operations.
214 */
Paul Fox05dfbe62009-06-16 21:08:06 +0000215 printf_debug("Assert CS#\n");
216 buf[i++] = SET_BITS_LOW;
Stefan Reinauerab044b22009-09-16 08:26:59 +0000217 buf[i++] = 0 & ~CS_BIT; /* assertive */
Paul Fox05dfbe62009-06-16 21:08:06 +0000218 buf[i++] = 0x0b;
219
220 if (writecnt) {
221 buf[i++] = 0x11;
222 buf[i++] = (writecnt - 1) & 0xff;
223 buf[i++] = ((writecnt - 1) >> 8) & 0xff;
224 memcpy(buf+i, writearr, writecnt);
225 i += writecnt;
226 }
227
228 /* optionally terminate this batch of commands with a
229 * read command, then do the fetch of the results.
230 */
231 if (readcnt) {
232 buf[i++] = 0x20;
233 buf[i++] = (readcnt - 1) & 0xff;
234 buf[i++] = ((readcnt - 1) >> 8) & 0xff;
235 ret = send_buf(ftdic, buf, i);
236 i = 0;
Stefan Reinauerab044b22009-09-16 08:26:59 +0000237 if (ret == 0) {
238 /* FIXME: This is unreliable. There's no guarantee that we read
239 * the response directly after sending the read command.
240 * We may be scheduled out etc.
241 */
242 ret = get_buf(ftdic, readarr, readcnt);
243 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000244
245 }
246
Paul Fox05dfbe62009-06-16 21:08:06 +0000247 printf_debug("De-assert CS#\n");
248 buf[i++] = SET_BITS_LOW;
Stefan Reinauerab044b22009-09-16 08:26:59 +0000249 buf[i++] = CS_BIT;
Paul Fox05dfbe62009-06-16 21:08:06 +0000250 buf[i++] = 0x0b;
251 if (send_buf(ftdic, buf, i))
252 return -1;
253
254 return ret;
255}
256
257int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
258{
259 /* Maximum read length is 64k bytes. */
260 return spi_read_chunked(flash, buf, start, len, 64 * 1024);
261}
262
263int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf)
264{
265 int total_size = 1024 * flash->total_size;
266 int i;
267
Carl-Daniel Hailfinger116081a2009-08-10 02:29:21 +0000268 spi_disable_blockprotect();
269 /* Erase first */
270 printf("Erasing flash before programming... ");
Carl-Daniel Hailfingerf38431a2009-09-05 02:30:58 +0000271 if (erase_flash(flash)) {
Carl-Daniel Hailfinger116081a2009-08-10 02:29:21 +0000272 fprintf(stderr, "ERASE FAILED!\n");
273 return -1;
274 }
275 printf("done.\n");
Paul Fox05dfbe62009-06-16 21:08:06 +0000276 printf_debug("total_size is %d\n", total_size);
277 for (i = 0; i < total_size; i += 256) {
278 int l, r;
279 if (i + 256 <= total_size)
280 l = 256;
281 else
282 l = total_size - i;
283
Paul Fox05dfbe62009-06-16 21:08:06 +0000284 if ((r = spi_nbyte_program(i, &buf[i], l))) {
Uwe Hermann04aa59a2009-09-02 22:09:00 +0000285 fprintf(stderr, "%s: write fail %d\n", __func__, r);
Paul Fox05dfbe62009-06-16 21:08:06 +0000286 return 1;
287 }
288
289 while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
290 /* loop */;
291 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000292
293 return 0;
294}
295
Paul Fox05dfbe62009-06-16 21:08:06 +0000296#endif