blob: 73b38e9dee27e8b12af3d83bd572048b7d0a472b [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.
Stefan Reinauerc566d202015-08-25 09:52:42 -070012 */
13
14#include <stdio.h>
15#include <string.h>
16#include "em100.h"
17
18/* SPI Trace related operations */
19
20/**
21 * reset_spi_trace: clear SPI trace buffer
22 * @param em100: em100 device structure
23 *
24 * out(16 bytes): 0xbd 0 .. 0
25 */
26int reset_spi_trace(struct em100 *em100)
27{
28 unsigned char cmd[16];
29 memset(cmd, 0, 16);
30 cmd[0] = 0xbd; /* reset SPI trace buffer*/
31 if (!send_cmd(em100->dev, cmd)) {
32 return 0;
33 }
34 return 1;
35}
36
37/**
38 * read_spi_trace: fetch SPI trace data
39 * @param em100: em100 device structure
40 * globals: curpos, counter, cmdid
41 *
42 * out(16 bytes): bc 00 00 00 08 00 00 00 00 15 00 00 00 00 00 00
43 * in(8x8192 bytes): 2 bytes (BE) number of records (0..0x3ff),
44 * then records of 8 bytes each
45 */
46static unsigned int counter = 0;
47static unsigned char curpos = 0;
48static unsigned char cmdid = 0xff; // timestamp, so never a valid command id
49
Martin Roth330de302015-09-17 16:33:07 -060050#define REPORT_BUFFER_LENGTH 8192
51#define REPORT_BUFFER_COUNT 8
52
Stefan Reinauerabd3e322019-12-04 18:29:24 -080053static int read_report_buffer(struct em100 *em100,
Martin Roth330de302015-09-17 16:33:07 -060054 unsigned char reportdata[REPORT_BUFFER_COUNT][REPORT_BUFFER_LENGTH])
Stefan Reinauerc566d202015-08-25 09:52:42 -070055{
Martin Roth330de302015-09-17 16:33:07 -060056 unsigned char cmd[16] = {0};
57 int len;
58 unsigned int report;
59
Stefan Reinauerc566d202015-08-25 09:52:42 -070060 cmd[0] = 0xbc; /* read SPI trace buffer*/
61
Stefan Reinauerabd3e322019-12-04 18:29:24 -080062 /*
Martin Roth330de302015-09-17 16:33:07 -060063 * Trace length, unit is 4k according to specs
64 *
65 * cmd1..cmd4 are probably u32BE on how many
66 * reports (8192 bytes each) to fetch
67 */
Stefan Reinauerc566d202015-08-25 09:52:42 -070068 cmd[1] = 0x00;
69 cmd[2] = 0x00;
70 cmd[3] = 0x00;
Martin Roth330de302015-09-17 16:33:07 -060071 cmd[4] = REPORT_BUFFER_COUNT;
Stefan Reinauerc566d202015-08-25 09:52:42 -070072 /* Timeout in ms */
73 cmd[5] = 0x00;
74 cmd[6] = 0x00;
75 cmd[7] = 0x00;
76 cmd[8] = 0x00;
77 /* Trace Config
78 * [1:0] 00 start/stop spi trace according to emulation status
79 * 01 start when TraceConfig[2] == 1
80 * 10 start when trig signal goes high
81 * 11 RFU
82 * [2] When TraceConfig[1:0] == 01 this bit starts the trace
83 * [7:3] RFU
84 */
85 cmd[9] = 0x15;
86
87 if (!send_cmd(em100->dev, cmd)) {
88 printf("sending trace command failed\n");
89 return 0;
90 }
Stefan Reinauerd7f959b2015-09-03 16:03:40 -070091
Martin Roth330de302015-09-17 16:33:07 -060092 for (report = 0; report < REPORT_BUFFER_COUNT; report++) {
Martin Rothb54d6ba2015-09-29 14:49:37 -060093 len = get_response(em100->dev, &reportdata[report][0],
94 REPORT_BUFFER_LENGTH);
Martin Roth330de302015-09-17 16:33:07 -060095 if (len != REPORT_BUFFER_LENGTH) {
96 printf("error, report length = %d instead of %d.\n\n",
97 len, REPORT_BUFFER_LENGTH);
Stefan Reinauerc566d202015-08-25 09:52:42 -070098 return 0;
99 }
Martin Roth330de302015-09-17 16:33:07 -0600100 }
101
102 return 1;
103}
104
Martin Rothe8a72dd2015-09-17 17:14:48 -0600105struct spi_cmd_values {
Stefan Reinauer79533882019-11-22 00:57:29 -0800106 const char *cmd_name;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600107 uint8_t cmd;
108 uint8_t uses_address;
109 uint8_t pad_bytes;
110};
111
112struct spi_cmd_values spi_command_list[] = {
113 /* name cmd, addr, pad */
114 {"write status register", 0x01, 0, 0},
115 {"page program", 0x02, 1, 0},
116 {"read", 0x03, 1, 0},
117 {"write disable", 0x04, 0, 0},
118 {"read status register", 0x05, 0, 0},
119 {"write enable", 0x06, 0, 0},
120 {"fast read", 0x0b, 1, 1},
121 {"EM100 specific", 0x11, 0, 0},
122 {"fast dual read", 0x3b, 1, 2},
123 {"chip erase", 0x60, 0, 0},
124 {"read JEDEC ID", 0x9f, 0, 0},
125 {"chip erase", 0xc7, 0, 0},
126 {"sector erase", 0xd8, 1, 0},
Alexander Amelkin6e2d9392020-06-26 17:26:55 +0300127 {"enter 4-byte address mode", 0xb7, 0, 0},
128 {"exit 4-byte address mode", 0xe9, 0, 0},
129 {"enter quad i/o mode", 0x35, 0, 0},
130 {"exit quad i/o mode", 0xf5, 0, 0},
Stefan Reinauerdfb107d2020-12-10 19:22:40 -0800131 {"read SFDP Table", 0x5a, 1, 0},
Martin Rothe8a72dd2015-09-17 17:14:48 -0600132
133 {"unknown command", 0xff, 0, 0}
134};
135
Stefan Reinauerabd3e322019-12-04 18:29:24 -0800136static struct spi_cmd_values * get_command_vals(uint8_t command)
137{
Martin Rothe8a72dd2015-09-17 17:14:48 -0600138 /* cache last command so a search isn't needed every time */
139 static struct spi_cmd_values *spi_cmd = &spi_command_list[3]; /* init to read */
140 int i;
141
142 if (spi_cmd->cmd != command) {
143 for (i = 0; spi_command_list[i].cmd != 0xff; i++) {
144 if (spi_command_list[i].cmd == command)
145 break;
146 }
147 spi_cmd = &spi_command_list[i];
148 }
149
150 return spi_cmd;
151}
152
153#define MAX_TRACE_BLOCKLENGTH 6
Martin Roth712262a2015-09-18 14:01:18 -0600154int read_spi_trace(struct em100 *em100, int display_terminal,
155 unsigned long addr_offset)
Martin Roth330de302015-09-17 16:33:07 -0600156{
Martin Rothb54d6ba2015-09-29 14:49:37 -0600157 unsigned char reportdata[REPORT_BUFFER_COUNT][REPORT_BUFFER_LENGTH] =
158 {{0}};
Martin Roth330de302015-09-17 16:33:07 -0600159 unsigned char *data;
160 unsigned int count, i, report;
161 static int outbytes = 0;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600162 static int additional_pad_bytes = 0;
163 static unsigned int address = 0;
164 static unsigned long long timestamp = 0;
165 static unsigned long long start_timestamp = 0;
166 static struct spi_cmd_values *spi_cmd_vals = &spi_command_list[3];
Martin Roth330de302015-09-17 16:33:07 -0600167
168 if (!read_report_buffer(em100, reportdata))
169 return 0;
170
171 for (report = 0; report < REPORT_BUFFER_COUNT; report++) {
172 data = &reportdata[report][0];
Stefan Reinauerc566d202015-08-25 09:52:42 -0700173 count = (data[0] << 8) | data[1];
Stefan Reinauer2372d7a2015-10-10 10:46:45 +0000174 if (count > 1022) {
175 printf("Warning: EM100pro sends too much data.\n");
176 count = 1022;
177 }
Stefan Reinauerc566d202015-08-25 09:52:42 -0700178 for (i = 0; i < count; i++) {
Martin Rothe8a72dd2015-09-17 17:14:48 -0600179 unsigned int j = additional_pad_bytes;
180 additional_pad_bytes = 0;
Stefan Reinauerc566d202015-08-25 09:52:42 -0700181 unsigned char cmd = data[2 + i*8];
Stefan Reinauerdfb107d2020-12-10 19:22:40 -0800182
183 if (cmd == 0x00) {
184 /* packet without valid data */
185 continue;
186 }
Stefan Reinauerc566d202015-08-25 09:52:42 -0700187 if (cmd == 0xff) {
188 /* timestamp */
Stefan Reinauerc566d202015-08-25 09:52:42 -0700189 timestamp = data[2 + i*8 + 2];
190 timestamp = (timestamp << 8) | data[2 + i*8 + 3];
191 timestamp = (timestamp << 8) | data[2 + i*8 + 4];
192 timestamp = (timestamp << 8) | data[2 + i*8 + 5];
193 timestamp = (timestamp << 8) | data[2 + i*8 + 6];
194 timestamp = (timestamp << 8) | data[2 + i*8 + 7];
Martin Rothdfdff3e2015-09-18 09:42:03 -0600195 if (display_terminal)
196 read_spi_terminal(em100, 1);
Stefan Reinauerc566d202015-08-25 09:52:42 -0700197 continue;
198 }
Martin Rothe8a72dd2015-09-17 17:14:48 -0600199
Stefan Reinauerc566d202015-08-25 09:52:42 -0700200 /* from here, it must be data */
201 if (cmd != cmdid) {
Martin Rothe8a72dd2015-09-17 17:14:48 -0600202 unsigned char spi_command = data[i * 8 + 4];
203 spi_cmd_vals = get_command_vals(spi_command);
204
Stefan Reinauerc566d202015-08-25 09:52:42 -0700205 /* new command */
206 cmdid = cmd;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600207 if (counter == 0)
208 start_timestamp = timestamp;
209
Stefan Reinauerdfb107d2020-12-10 19:22:40 -0800210 /* Special commands */
211 switch (spi_command) {
212 case 0xb7:
213 address_mode = 4;
214 break;
215 case 0xe9:
216 address_mode = 3;
217 break;
218 }
219
Martin Rothe8a72dd2015-09-17 17:14:48 -0600220 /* set up address if used by this command*/
221 if (!spi_cmd_vals->uses_address) {
222 j = 1; /* skip command byte */
223 } else {
Stefan Reinauerdfb107d2020-12-10 19:22:40 -0800224 if (address_mode == 3)
225 address = (data[i * 8 + 5] << 16) + (data[i * 8 + 6] << 8) + data[i * 8 + 7];
226 else
227 address = (data[i * 8 + 5] << 24) + (data[i * 8 + 6] << 16) + (data[i * 8 + 7] << 8) + data[i * 8 + 8];
Martin Rothe8a72dd2015-09-17 17:14:48 -0600228
229 /* skip command, address bytes, and padding */
Stefan Reinauerdfb107d2020-12-10 19:22:40 -0800230 j = 1 + address_mode + spi_cmd_vals->pad_bytes;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600231 if (j > MAX_TRACE_BLOCKLENGTH) {
Martin Rothb54d6ba2015-09-29 14:49:37 -0600232 additional_pad_bytes = j -
233 MAX_TRACE_BLOCKLENGTH;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600234 j = MAX_TRACE_BLOCKLENGTH;
235 }
236 }
237 printf("\nTime: %06lld.%08lld",
Martin Rothb54d6ba2015-09-29 14:49:37 -0600238 (timestamp - start_timestamp) /
239 100000000,
240 (timestamp - start_timestamp) %
241 100000000);
242 printf(" command # %-6d : 0x%02x - %s",
243 ++counter, spi_command,
244 spi_cmd_vals->cmd_name);
Stefan Reinauerc566d202015-08-25 09:52:42 -0700245 curpos = 0;
Stefan Reinauerd7f959b2015-09-03 16:03:40 -0700246 outbytes = 0;
Stefan Reinauerc566d202015-08-25 09:52:42 -0700247 }
Martin Rothe8a72dd2015-09-17 17:14:48 -0600248
Stefan Reinauerc566d202015-08-25 09:52:42 -0700249 /* this exploits 8bit wrap around in curpos */
250 unsigned char blocklen = (data[2 + i*8 + 1] - curpos);
251 blocklen /= 8;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600252
253 for (; j < blocklen; j++) {
254 if (outbytes == 0) {
255 if (spi_cmd_vals->uses_address) {
Martin Roth712262a2015-09-18 14:01:18 -0600256 printf("\n%08lx : ",
257 addr_offset +
258 address);
Martin Rothe8a72dd2015-09-17 17:14:48 -0600259 } else {
260 printf("\n : ");
261 }
262 }
263 printf("%02x ", data[i * 8 + 4 + j]);
Stefan Reinauerd7f959b2015-09-03 16:03:40 -0700264 outbytes++;
265 if (outbytes == 16) {
Martin Rothe8a72dd2015-09-17 17:14:48 -0600266 outbytes = 0;
267 if (spi_cmd_vals->uses_address)
268 address += 16;
Stefan Reinauerd7f959b2015-09-03 16:03:40 -0700269 }
Stefan Reinauerc566d202015-08-25 09:52:42 -0700270 }
Martin Rothb54d6ba2015-09-29 14:49:37 -0600271 // this is because the em100 counts funny
272 curpos = data[2 + i*8 + 1] + 0x10;
Martin Rothe8a72dd2015-09-17 17:14:48 -0600273 fflush(stdout);
Stefan Reinauerc566d202015-08-25 09:52:42 -0700274 }
275 }
276 return 1;
277}
Martin Rothdfdff3e2015-09-18 09:42:03 -0600278
279#define UFIFO_SIZE 512
280#define UFIFO_TIMEOUT 0x00
281
282/*
283 * Polls the uFIFO buffer to see if there's any data. The HT registers don't
284 * seem to ever be updated to reflect that there's data present, and the
285 * Dediprog software doesn't use them either.
Martin Rothc69319c2015-09-29 14:09:40 -0600286 *
Martin Rothdfdff3e2015-09-18 09:42:03 -0600287 * Multiple messages can be in a single uFIFO transfer, so loop through
288 * the data looking for the signature.
289 */
Stefan Reinauerabd3e322019-12-04 18:29:24 -0800290int read_spi_terminal(struct em100 *em100, int show_counter)
291{
Martin Rothdfdff3e2015-09-18 09:42:03 -0600292 unsigned char data[UFIFO_SIZE] = { 0 };
293 static unsigned int msg_counter = 1; /* Number of messages */
Martin Rothc69319c2015-09-29 14:09:40 -0600294 uint16_t data_length;
Martin Rothdfdff3e2015-09-18 09:42:03 -0600295 unsigned char *data_start;
296 unsigned int j, k;
297 struct em100_msg *msg = NULL;
298
299 if (!read_ufifo(em100, UFIFO_SIZE, UFIFO_TIMEOUT, &data[0]))
300 return 0;
301
302 /* the first two bytes are the amount of valid data */
Martin Rothc69319c2015-09-29 14:09:40 -0600303 data_length = (data[0] << 8) + data[1];
304 if (data_length == 0)
Martin Rothdfdff3e2015-09-18 09:42:03 -0600305 return 1;
306
307 /* actual data starts after the length */
308 data_start = &data[sizeof(uint16_t)];
309
310 /* examine data; stop when we run out of message or buffer */
Martin Rothc69319c2015-09-29 14:09:40 -0600311 for (j = 0; j < data_length &&
Martin Rothdfdff3e2015-09-18 09:42:03 -0600312 j < UFIFO_SIZE - sizeof(struct em100_msg_header); j++) {
313
314 msg = (struct em100_msg *)(data_start + j);
315 if (msg->header.signature == EM100_MSG_SIGNATURE) {
316
317 if (show_counter)
318 printf("\nHT%06d: ", msg_counter);
319
320 /* print message byte according to format */
321 for (k = 0; k < msg->header.data_length; k++) {
Martin Rothc69319c2015-09-29 14:09:40 -0600322 if (&msg->data[k] >= data_start + data_length)
Martin Rothdfdff3e2015-09-18 09:42:03 -0600323 break;
324 if (&msg->data[k] >= &data[0] + UFIFO_SIZE)
325 break;
326
327 switch (msg->header.data_type) {
328 case ht_checkpoint_1byte:
329 case ht_checkpoint_2bytes:
330 case ht_checkpoint_4bytes:
331 case ht_hexadecimal_data:
332 case ht_timestamp_data:
333 printf("%02x ", msg->data[k]);
334 break;
335 case ht_ascii_data:
336 printf("%c", msg->data[k]);
337 break;
338 case ht_lookup_table:
339 /* TODO - support lookup table */
340 printf("Lookup unsupported: %02x%02x",
341 msg->data[k], msg->data[k + 1]);
342 k++;
343 break;
344 }
345 }
346
347 /* advance to the end of the message */
Martin Rothb54d6ba2015-09-29 14:49:37 -0600348 j += msg->header.data_length +
349 sizeof(struct em100_msg_header) - 1;
Martin Rothdfdff3e2015-09-18 09:42:03 -0600350 msg_counter++;
351 fflush(stdout);
352 }
353 }
354
355 return 1;
356}
357
358int init_spi_terminal (struct em100 *em100)
359{
360 int retval = 0x01;
361 uint16_t val;
362
363 retval &= write_ht_register(em100, ufifo_data_fmt_reg, 0);
364 retval &= write_ht_register(em100, status_reg, START_SPI_EMULATION);
365
366 /* set em100 to recognize spi command 0x11 */
367 retval &= write_fpga_register(em100, 0x82, EM100_SPECIFIC_CMD);
368 retval &= read_fpga_register(em100, 0x28, &val);
369
370 return retval;
371}