blob: 52b01c9f189fb207334472cd42b654dd82d7f7b4 [file] [log] [blame]
Stefan Reinauerdb126f42019-11-18 18:25:45 -08001/*
2 * Copyright 2012 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 Reinauerdb126f42019-11-18 18:25:45 -080012 */
13
14#include <unistd.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <stdint.h>
21#ifdef __APPLE__
22#include <libkern/OSByteOrder.h>
23#define bswap_16(x) OSSwapInt16(x)
24#define bswap_32(x) OSSwapInt32(x)
25#include <architecture/byte_order.h>
26 #if BYTE_ORDER == LITTLE_ENDIAN
27 #define le32toh(x) (x)
28 #define le16toh(x) (x)
29 #define htobe16(x) bswap_16(x)
30 #else
31 #define le32toh(x) bswap_32(x)
32 #define le16toh(x) bswap_16(x)
33 #define htobe16(x) (x)
34 #endif
35#else
36#include <endian.h>
37#endif
38
39#include "em100.h"
40
41#define DEDIPROG_CFG_PRO_MAX_ENTRIES 212
42
43#define DEDIPROG_CFG_PRO_SIZE 176
44#define DEDIPROG_CFG_PRO_SIZE_SFDP 256
45#define DEDIPROG_CFG_PRO_SIZE_SRST 144
46
47#define DEDIPROG_CFG_MAGIC 0x67666344 /* 'Dcfg' */
48#define DEDIPROG_SFDP_MAGIC 0x50444653 /* 'SFDP' */
49#define DEDIPROG_SRST_MAGIC 0x54535253 /* 'SRST' */
50#define DEDIPROG_PROT_MAGIC 0x544f5250 /* 'PROT' */
51
52#define INIT_SEQUENCE_REIGSTER_OFFSET_0 0x2300
53#define INIT_SEQUENCE_REIGSTER_OFFSET_1 0x1100
54
55/* Init sequence and file format:
56 *
57 * All v1.1 dediprog configuration files are 176 bytes and all values are
58 * encoded as little endian format.
59
60 * At offset init_offset the init sequence consists of init entries that are
61 * sent to endpoint 1. There are 2 sets of entries separated by a 32-bit
62 * terminator of 0xffffffff. Each entry consists of a value and register offset.
63 * The first set of entries have a base register address of 0x2300 while the
64 * the second set of entries have a base register address of 0x1100. Each entry
65 * is sent to the device as <register> <value>, however the data is sent in
66 * big endian format. Additionally, each entry is sent as a 16-byte transfer
67 * with the remaining bytes all 0's.
68 *
69 * Configuration files that are >= 436 bytes contain SFDP data, separated by
70 * the magic value 'SFDP' while those that are 584 bytes contain SRST data
71 * separated by the magic value 'SRST' and containing 0 or 3 entries followed
72 * by PROT data in the rest of the buffer. Unfortunately there does not seem
73 * to be any change in the version fields and these are still reported as 1.1.
74 */
75
76
77struct dediprog_cfg_hdr {
78 uint32_t magic;
79 uint16_t ver_min;
80 uint16_t ver_maj;
81 uint32_t init_offset;
82 uint32_t chip_size;
83 uint32_t vendor_name_offset;
84 uint32_t chip_name_offset;
85 uint32_t unknown_offset[2];
86} __attribute__((packed));
87
88struct dediprog_cfg_pro {
89 struct dediprog_cfg_hdr hdr;
90 uint8_t payload[DEDIPROG_CFG_PRO_SIZE-sizeof(struct dediprog_cfg_hdr)];
91} __attribute__((packed));
92
93
94struct dediprog_cfg_init_entry {
95 uint16_t value;
96 uint16_t reg;
97} __attribute__((packed));
98
99unsigned char cfg_buffer[DEDIPROG_CFG_PRO_SIZE];
100
101static int parse_and_output_config(struct dediprog_cfg_pro *cfg, chipdesc *chip)
102{
103 struct dediprog_cfg_init_entry *entry, *end;
104 struct dediprog_cfg_hdr *hdr;
105 const char *vendor, *chip_name;
106 uint16_t reg_offset;
107 int entries = 0;
108
109 hdr = &cfg->hdr;
110
111 /* The magic number is actually string, but it can be converted to
112 * a host ordered 32-bit number. */
113 hdr->magic= le32toh(hdr->magic);
114
115 if (hdr->magic != DEDIPROG_CFG_MAGIC) {
116 fprintf(stderr, "Invalid magic number: 0x%x\n", hdr->magic);
117 return -1;
118 }
119
120 /* Convert all header values from little endian to host byte order. */
121 hdr->ver_min = le16toh(hdr->ver_min);
122 hdr->ver_maj = le16toh(hdr->ver_maj);
123 hdr->init_offset = le32toh(hdr->init_offset);
124 hdr->chip_size = le32toh(hdr->chip_size);
125 hdr->vendor_name_offset = le32toh(hdr->vendor_name_offset);
126 hdr->chip_name_offset = le32toh(hdr->chip_name_offset);
127
128 if (hdr->ver_maj != 1 && hdr->ver_min != 1) {
129 fprintf(stderr, "Invalid version number: %d.%d\n", hdr->ver_maj,
130 hdr->ver_min);
131 return -1;
132 }
133
134 /* Adjust the offsets to be into the payload of the config file. */
135 hdr->init_offset -= sizeof(*hdr);
136 hdr->vendor_name_offset -= sizeof(*hdr);
137 hdr->chip_name_offset -= sizeof(*hdr);
138
139 vendor = (void *)&cfg->payload[hdr->vendor_name_offset];
140 chip_name = (void *)&cfg->payload[hdr->chip_name_offset];
141
142 /* Since configs.tar is resident, we don't have to malloc */
143 chip->vendor = (const char *)vendor;
144 chip->name = (const char *)chip_name;
145 chip->size = hdr->chip_size;
146
147#ifdef DEBUG
148 printf("%s %s (%d kB)\n",
149 vendor, chip_name, hdr->chip_size/1024);
150#endif
151
152 entry = (void *)&cfg->payload[hdr->init_offset];
153 end = (void *)&cfg[1]; /* 1 past the last entry */
154
155 reg_offset = INIT_SEQUENCE_REIGSTER_OFFSET_0;
156
157 for (; entry != end; entry++) {
158 uint8_t *reg, *value;
159
160 /* Convert from little endian to host format. */
161 entry->value = le16toh(entry->value);
162 entry->reg = le16toh(entry->reg);
163
164 if (entry->value == 0xffff && entry->reg == 0xffff) {
165 reg_offset = INIT_SEQUENCE_REIGSTER_OFFSET_1;
166 continue;
167 }
168
169 entry->reg += reg_offset;
170
171 /* Convert from host to big endian format. */
172 entry->value = htobe16(entry->value);
173 entry->reg = htobe16(entry->reg);
174
175 value = (void *)&entry->value;
176 reg = (void *)&entry->reg;
177
178 chip->init[entries][0] = reg[0];
179 chip->init[entries][1] = reg[1];
180 chip->init[entries][2] = value[0];
181 chip->init[entries][3] = value[1];
182 ++entries;
183 }
184
185 return entries;
186}
187
Stefan Reinauer79533882019-11-22 00:57:29 -0800188static int parse_and_output_sfdp(chipdesc *chip, void **ptr, size_t *length, int entries)
Stefan Reinauerdb126f42019-11-18 18:25:45 -0800189{
190 int i, len = 0;
191 unsigned char *sfdp_buffer = (unsigned char *)*ptr;
192
193 if (*length < DEDIPROG_CFG_PRO_SIZE_SFDP) {
194 fprintf(stderr, "Error reading SFDP\n");
195 return -1;
196 }
197
198 chip->init[entries][0] = 0x23;
199 chip->init[entries][1] = 0xc9;
200 chip->init[entries][2] = 0x00;
201 chip->init[entries][3] = 0x01;
202
203 len++;
204
205 for (i = 0; i < DEDIPROG_CFG_PRO_SIZE_SFDP; i+=2) {
206 chip->init[entries+len][0] = 0x23;
207 chip->init[entries+len][1] = 0xc1;
208 chip->init[entries+len][2] = sfdp_buffer[i+1];
209 chip->init[entries+len][3] = sfdp_buffer[i];
210 len++;
211 }
212
213 *ptr += DEDIPROG_CFG_PRO_SIZE_SFDP;
214 *length -= DEDIPROG_CFG_PRO_SIZE_SFDP;
215
216 return len;
217}
218
Stefan Reinauer79533882019-11-22 00:57:29 -0800219static int parse_and_output_srst(chipdesc *chip, void **ptr, size_t *length, int entries)
Stefan Reinauerdb126f42019-11-18 18:25:45 -0800220{
221 int i, len = 0;
222 uint32_t magic;
223 unsigned char *srst_buffer = (unsigned char *)*ptr;
224
225 if (*length < DEDIPROG_CFG_PRO_SIZE_SRST) {
226 fprintf(stderr, "Error reading SRST\n");
227 return -1;
228 }
229
230 /* SRST has 0 or 3 entries before PROT */
231 memcpy(&magic, &srst_buffer[0], sizeof(magic));
232
233 if (magic != DEDIPROG_PROT_MAGIC) {
234 int j;
235
236 for (j = 0; j < 3; j++) {
237 chip->init[entries+len][0] = 0x23;
238 chip->init[entries+len][1] = srst_buffer[j*4+2];
239 chip->init[entries+len][2] = srst_buffer[j*4+1];
240 chip->init[entries+len][3] = srst_buffer[j*4];
241 len++;
242 }
243
244 /* Start after SFDP data and PROT magic */
245 i = 16;
246 } else {
247 /* Start after PROT magic */
248 i = 4;
249 }
250
251 chip->init[entries+len][0] = 0x23;
252 chip->init[entries+len][1] = 0xc4;
253 chip->init[entries+len][2] = 0x00;
254 chip->init[entries+len][3] = 0x01;
255 len++;
256
257 for (; i < DEDIPROG_CFG_PRO_SIZE_SRST; i+=2) {
258 chip->init[entries+len][0] = 0x23;
259 chip->init[entries+len][1] = 0xc5;
260 chip->init[entries+len][2] = srst_buffer[i+1];
261 chip->init[entries+len][3] = srst_buffer[i];
262 len++;
263 }
264
265 *ptr += DEDIPROG_CFG_PRO_SIZE_SRST;
266 *length -= DEDIPROG_CFG_PRO_SIZE_SRST;
267
268 return len;
269}
270
271int parse_dcfg(chipdesc *chip, TFILE *dcfg)
272{
273 struct dediprog_cfg_pro *cfg;
274 int init_len = 0;
275 uint32_t magic;
276
277 void *ptr = (void *)dcfg->address;
Stefan Reinauer79533882019-11-22 00:57:29 -0800278 size_t length = dcfg->length;
Stefan Reinauerdb126f42019-11-18 18:25:45 -0800279
280 if (length < sizeof(cfg_buffer)) {
281 /* Not a config file */
282 return 1;
283 }
284 cfg = (struct dediprog_cfg_pro *)ptr;
285
286 init_len = parse_and_output_config(cfg, chip);
287 if (init_len < 0) {
288 fprintf(stderr, "Error parsing Dcfg\n");
289 return 1;
290 }
291
292 ptr += DEDIPROG_CFG_PRO_SIZE;
293 length -= DEDIPROG_CFG_PRO_SIZE;
294
295 /* Handle any extra data */
296 while (length) {
297 int ret = 0;
298
299 magic = *(uint32_t *)ptr;
300 ptr+=sizeof(uint32_t);
301 length-=sizeof(uint32_t);
302
303 switch (magic) {
304 case DEDIPROG_SFDP_MAGIC:
305 ret = parse_and_output_sfdp(chip, &ptr, &length, init_len);
306 break;
307 case DEDIPROG_SRST_MAGIC:
308 ret = parse_and_output_srst(chip, &ptr, &length, init_len);
309 break;
310 default:
311 fprintf(stderr, "Unknown magic: 0x%08x\n", magic);
312 break;
313 }
314
315 if (ret < 0) {
316 fprintf(stderr, "FAILED.\n");
317 return 1;
318 }
319 init_len += ret;
320 }
321
322 chip->init_len = init_len;
323
324 return 0;
325}