blob: a595997bcf55f7a172b744bd1a885f566b9ce879 [file] [log] [blame]
Stefan Reinauerc566d202015-08-25 09:52:42 -07001/*
2 * Copyright 2012-2015 Google Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18#include <stdio.h>
19#include <string.h>
20#include "em100.h"
21
22/* SPI Trace related operations */
23
24/**
25 * reset_spi_trace: clear SPI trace buffer
26 * @param em100: em100 device structure
27 *
28 * out(16 bytes): 0xbd 0 .. 0
29 */
30int reset_spi_trace(struct em100 *em100)
31{
32 unsigned char cmd[16];
33 memset(cmd, 0, 16);
34 cmd[0] = 0xbd; /* reset SPI trace buffer*/
35 if (!send_cmd(em100->dev, cmd)) {
36 return 0;
37 }
38 return 1;
39}
40
41/**
42 * read_spi_trace: fetch SPI trace data
43 * @param em100: em100 device structure
44 * globals: curpos, counter, cmdid
45 *
46 * out(16 bytes): bc 00 00 00 08 00 00 00 00 15 00 00 00 00 00 00
47 * in(8x8192 bytes): 2 bytes (BE) number of records (0..0x3ff),
48 * then records of 8 bytes each
49 */
50static unsigned int counter = 0;
51static unsigned char curpos = 0;
52static unsigned char cmdid = 0xff; // timestamp, so never a valid command id
53
Martin Roth330de302015-09-17 16:33:07 -060054#define REPORT_BUFFER_LENGTH 8192
55#define REPORT_BUFFER_COUNT 8
56
57static int read_report_buffer(struct em100 *em100,
58 unsigned char reportdata[REPORT_BUFFER_COUNT][REPORT_BUFFER_LENGTH])
Stefan Reinauerc566d202015-08-25 09:52:42 -070059{
Martin Roth330de302015-09-17 16:33:07 -060060 unsigned char cmd[16] = {0};
61 int len;
62 unsigned int report;
63
Stefan Reinauerc566d202015-08-25 09:52:42 -070064 cmd[0] = 0xbc; /* read SPI trace buffer*/
65
Martin Roth330de302015-09-17 16:33:07 -060066 /*
67 * Trace length, unit is 4k according to specs
68 *
69 * cmd1..cmd4 are probably u32BE on how many
70 * reports (8192 bytes each) to fetch
71 */
Stefan Reinauerc566d202015-08-25 09:52:42 -070072 cmd[1] = 0x00;
73 cmd[2] = 0x00;
74 cmd[3] = 0x00;
Martin Roth330de302015-09-17 16:33:07 -060075 cmd[4] = REPORT_BUFFER_COUNT;
Stefan Reinauerc566d202015-08-25 09:52:42 -070076 /* Timeout in ms */
77 cmd[5] = 0x00;
78 cmd[6] = 0x00;
79 cmd[7] = 0x00;
80 cmd[8] = 0x00;
81 /* Trace Config
82 * [1:0] 00 start/stop spi trace according to emulation status
83 * 01 start when TraceConfig[2] == 1
84 * 10 start when trig signal goes high
85 * 11 RFU
86 * [2] When TraceConfig[1:0] == 01 this bit starts the trace
87 * [7:3] RFU
88 */
89 cmd[9] = 0x15;
90
91 if (!send_cmd(em100->dev, cmd)) {
92 printf("sending trace command failed\n");
93 return 0;
94 }
Stefan Reinauerd7f959b2015-09-03 16:03:40 -070095
Martin Roth330de302015-09-17 16:33:07 -060096 for (report = 0; report < REPORT_BUFFER_COUNT; report++) {
97 len = get_response(em100->dev, &reportdata[report][0], REPORT_BUFFER_LENGTH);
98 if (len != REPORT_BUFFER_LENGTH) {
99 printf("error, report length = %d instead of %d.\n\n",
100 len, REPORT_BUFFER_LENGTH);
Stefan Reinauerc566d202015-08-25 09:52:42 -0700101 return 0;
102 }
Martin Roth330de302015-09-17 16:33:07 -0600103 }
104
105 return 1;
106}
107
Martin Rothe8a72dd2015-09-17 17:14:48 -0600108struct spi_cmd_values {
109 char *cmd_name;
110 uint8_t cmd;
111 uint8_t uses_address;
112 uint8_t pad_bytes;
113};
114
115struct spi_cmd_values spi_command_list[] = {
116 /* name cmd, addr, pad */
117 {"write status register", 0x01, 0, 0},
118 {"page program", 0x02, 1, 0},
119 {"read", 0x03, 1, 0},
120 {"write disable", 0x04, 0, 0},
121 {"read status register", 0x05, 0, 0},
122 {"write enable", 0x06, 0, 0},
123 {"fast read", 0x0b, 1, 1},
124 {"EM100 specific", 0x11, 0, 0},
125 {"fast dual read", 0x3b, 1, 2},
126 {"chip erase", 0x60, 0, 0},
127 {"read JEDEC ID", 0x9f, 0, 0},
128 {"chip erase", 0xc7, 0, 0},
129 {"sector erase", 0xd8, 1, 0},
130
131 {"unknown command", 0xff, 0, 0}
132};
133
134static struct spi_cmd_values * get_command_vals(uint8_t command) {
135 /* cache last command so a search isn't needed every time */
136 static struct spi_cmd_values *spi_cmd = &spi_command_list[3]; /* init to read */
137 int i;
138
139 if (spi_cmd->cmd != command) {
140 for (i = 0; spi_command_list[i].cmd != 0xff; i++) {
141 if (spi_command_list[i].cmd == command)
142 break;
143 }
144 spi_cmd = &spi_command_list[i];
145 }
146
147 return spi_cmd;
148}
149
150#define MAX_TRACE_BLOCKLENGTH 6
Martin Roth712262a2015-09-18 14:01:18 -0600151int read_spi_trace(struct em100 *em100, int display_terminal,
152 unsigned long addr_offset)
Martin Roth330de302015-09-17 16:33:07 -0600153{
154 unsigned char reportdata[REPORT_BUFFER_COUNT][REPORT_BUFFER_LENGTH] = {{0}};
155 unsigned char *data;
156 unsigned int count, i, report;
157 static int outbytes = 0;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600158 static int additional_pad_bytes = 0;
159 static unsigned int address = 0;
160 static unsigned long long timestamp = 0;
161 static unsigned long long start_timestamp = 0;
162 static struct spi_cmd_values *spi_cmd_vals = &spi_command_list[3];
Martin Roth330de302015-09-17 16:33:07 -0600163
164 if (!read_report_buffer(em100, reportdata))
165 return 0;
166
167 for (report = 0; report < REPORT_BUFFER_COUNT; report++) {
168 data = &reportdata[report][0];
Stefan Reinauerc566d202015-08-25 09:52:42 -0700169 count = (data[0] << 8) | data[1];
170 for (i = 0; i < count; i++) {
Martin Rothe8a72dd2015-09-17 17:14:48 -0600171 unsigned int j = additional_pad_bytes;
172 additional_pad_bytes = 0;
Stefan Reinauerc566d202015-08-25 09:52:42 -0700173 unsigned char cmd = data[2 + i*8];
174 if (cmd == 0xff) {
175 /* timestamp */
Stefan Reinauerc566d202015-08-25 09:52:42 -0700176 timestamp = data[2 + i*8 + 2];
177 timestamp = (timestamp << 8) | data[2 + i*8 + 3];
178 timestamp = (timestamp << 8) | data[2 + i*8 + 4];
179 timestamp = (timestamp << 8) | data[2 + i*8 + 5];
180 timestamp = (timestamp << 8) | data[2 + i*8 + 6];
181 timestamp = (timestamp << 8) | data[2 + i*8 + 7];
Martin Rothdfdff3e2015-09-18 09:42:03 -0600182 if (display_terminal)
183 read_spi_terminal(em100, 1);
Stefan Reinauerc566d202015-08-25 09:52:42 -0700184 continue;
185 }
Martin Rothe8a72dd2015-09-17 17:14:48 -0600186
Stefan Reinauerc566d202015-08-25 09:52:42 -0700187 /* from here, it must be data */
188 if (cmd != cmdid) {
Martin Rothe8a72dd2015-09-17 17:14:48 -0600189 unsigned char spi_command = data[i * 8 + 4];
190 spi_cmd_vals = get_command_vals(spi_command);
191
Stefan Reinauerc566d202015-08-25 09:52:42 -0700192 /* new command */
193 cmdid = cmd;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600194 if (counter == 0)
195 start_timestamp = timestamp;
196
197 /* set up address if used by this command*/
198 if (!spi_cmd_vals->uses_address) {
199 j = 1; /* skip command byte */
200 } else {
201 address = (data[i * 8 + 5] << 16) +
202 (data[i * 8 + 6] << 8) +
203 data[i * 8 + 7];
204
205 /* skip command, address bytes, and padding */
206 j = 4 + spi_cmd_vals->pad_bytes;
207 if (j > MAX_TRACE_BLOCKLENGTH) {
208 additional_pad_bytes = j - MAX_TRACE_BLOCKLENGTH;
209 j = MAX_TRACE_BLOCKLENGTH;
210 }
211 }
212 printf("\nTime: %06lld.%08lld",
213 (timestamp - start_timestamp) / 100000000,
214 (timestamp - start_timestamp) % 100000000);
215 printf(" command # %-6d : 0x%02x - %s", ++counter,
216 spi_command,spi_cmd_vals->cmd_name);
Stefan Reinauerc566d202015-08-25 09:52:42 -0700217 curpos = 0;
Stefan Reinauerd7f959b2015-09-03 16:03:40 -0700218 outbytes = 0;
Stefan Reinauerc566d202015-08-25 09:52:42 -0700219 }
Martin Rothe8a72dd2015-09-17 17:14:48 -0600220
Stefan Reinauerc566d202015-08-25 09:52:42 -0700221 /* this exploits 8bit wrap around in curpos */
222 unsigned char blocklen = (data[2 + i*8 + 1] - curpos);
223 blocklen /= 8;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600224
225 for (; j < blocklen; j++) {
226 if (outbytes == 0) {
227 if (spi_cmd_vals->uses_address) {
Martin Roth712262a2015-09-18 14:01:18 -0600228 printf("\n%08lx : ",
229 addr_offset +
230 address);
Martin Rothe8a72dd2015-09-17 17:14:48 -0600231 } else {
232 printf("\n : ");
233 }
234 }
235 printf("%02x ", data[i * 8 + 4 + j]);
Stefan Reinauerd7f959b2015-09-03 16:03:40 -0700236 outbytes++;
237 if (outbytes == 16) {
Martin Rothe8a72dd2015-09-17 17:14:48 -0600238 outbytes = 0;
239 if (spi_cmd_vals->uses_address)
240 address += 16;
Stefan Reinauerd7f959b2015-09-03 16:03:40 -0700241 }
Stefan Reinauerc566d202015-08-25 09:52:42 -0700242 }
243 curpos = data[2 + i*8 + 1] + 0x10; // this is because the em100 counts funny
Martin Rothe8a72dd2015-09-17 17:14:48 -0600244 fflush(stdout);
Stefan Reinauerc566d202015-08-25 09:52:42 -0700245 }
246 }
247 return 1;
248}
Martin Rothdfdff3e2015-09-18 09:42:03 -0600249
250#define UFIFO_SIZE 512
251#define UFIFO_TIMEOUT 0x00
252
253/*
254 * Polls the uFIFO buffer to see if there's any data. The HT registers don't
255 * seem to ever be updated to reflect that there's data present, and the
256 * Dediprog software doesn't use them either.
Martin Rothc69319c2015-09-29 14:09:40 -0600257 *
Martin Rothdfdff3e2015-09-18 09:42:03 -0600258 * Multiple messages can be in a single uFIFO transfer, so loop through
259 * the data looking for the signature.
260 */
261int read_spi_terminal(struct em100 *em100, int show_counter) {
262 unsigned char data[UFIFO_SIZE] = { 0 };
263 static unsigned int msg_counter = 1; /* Number of messages */
Martin Rothc69319c2015-09-29 14:09:40 -0600264 uint16_t data_length;
Martin Rothdfdff3e2015-09-18 09:42:03 -0600265 unsigned char *data_start;
266 unsigned int j, k;
267 struct em100_msg *msg = NULL;
268
269 if (!read_ufifo(em100, UFIFO_SIZE, UFIFO_TIMEOUT, &data[0]))
270 return 0;
271
272 /* the first two bytes are the amount of valid data */
Martin Rothc69319c2015-09-29 14:09:40 -0600273 data_length = (data[0] << 8) + data[1];
274 if (data_length == 0)
Martin Rothdfdff3e2015-09-18 09:42:03 -0600275 return 1;
276
277 /* actual data starts after the length */
278 data_start = &data[sizeof(uint16_t)];
279
280 /* examine data; stop when we run out of message or buffer */
Martin Rothc69319c2015-09-29 14:09:40 -0600281 for (j = 0; j < data_length &&
Martin Rothdfdff3e2015-09-18 09:42:03 -0600282 j < UFIFO_SIZE - sizeof(struct em100_msg_header); j++) {
283
284 msg = (struct em100_msg *)(data_start + j);
285 if (msg->header.signature == EM100_MSG_SIGNATURE) {
286
287 if (show_counter)
288 printf("\nHT%06d: ", msg_counter);
289
290 /* print message byte according to format */
291 for (k = 0; k < msg->header.data_length; k++) {
Martin Rothc69319c2015-09-29 14:09:40 -0600292 if (&msg->data[k] >= data_start + data_length)
Martin Rothdfdff3e2015-09-18 09:42:03 -0600293 break;
294 if (&msg->data[k] >= &data[0] + UFIFO_SIZE)
295 break;
296
297 switch (msg->header.data_type) {
298 case ht_checkpoint_1byte:
299 case ht_checkpoint_2bytes:
300 case ht_checkpoint_4bytes:
301 case ht_hexadecimal_data:
302 case ht_timestamp_data:
303 printf("%02x ", msg->data[k]);
304 break;
305 case ht_ascii_data:
306 printf("%c", msg->data[k]);
307 break;
308 case ht_lookup_table:
309 /* TODO - support lookup table */
310 printf("Lookup unsupported: %02x%02x",
311 msg->data[k], msg->data[k + 1]);
312 k++;
313 break;
314 }
315 }
316
317 /* advance to the end of the message */
Martin Rothc69319c2015-09-29 14:09:40 -0600318 j += msg->header.data_length + sizeof(struct em100_msg_header) - 1;
Martin Rothdfdff3e2015-09-18 09:42:03 -0600319 msg_counter++;
320 fflush(stdout);
321 }
322 }
323
324 return 1;
325}
326
327int init_spi_terminal (struct em100 *em100)
328{
329 int retval = 0x01;
330 uint16_t val;
331
332 retval &= write_ht_register(em100, ufifo_data_fmt_reg, 0);
333 retval &= write_ht_register(em100, status_reg, START_SPI_EMULATION);
334
335 /* set em100 to recognize spi command 0x11 */
336 retval &= write_fpga_register(em100, 0x82, EM100_SPECIFIC_CMD);
337 retval &= read_fpga_register(em100, 0x28, &val);
338
339 return retval;
340}