1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42#include <linux/module.h>
43#include <linux/delay.h>
44#include "hermes.h"
45#include "hermes_dld.h"
46
47#define PFX "hermes_dld: "
48
49
50#define PDI_END 0x00000000
51#define BLOCK_END 0xFFFFFFFF
52#define TEXT_END 0x1A
53
54
55
56
57
58
59
60
61
62
63
64struct dblock {
65 __le32 addr;
66 __le16 len;
67 char data[0];
68} __packed;
69
70
71
72
73
74
75struct pdr {
76 __le32 id;
77 __le32 addr;
78 __le32 len;
79 char next[0];
80} __packed;
81
82
83
84
85
86
87struct pdi {
88 __le16 len;
89 __le16 id;
90 char data[0];
91} __packed;
92
93
94
95static inline u32
96dblock_addr(const struct dblock *blk)
97{
98 return le32_to_cpu(blk->addr);
99}
100
101static inline u32
102dblock_len(const struct dblock *blk)
103{
104 return le16_to_cpu(blk->len);
105}
106
107
108
109static inline u32
110pdr_id(const struct pdr *pdr)
111{
112 return le32_to_cpu(pdr->id);
113}
114
115static inline u32
116pdr_addr(const struct pdr *pdr)
117{
118 return le32_to_cpu(pdr->addr);
119}
120
121static inline u32
122pdr_len(const struct pdr *pdr)
123{
124 return le32_to_cpu(pdr->len);
125}
126
127
128
129static inline u32
130pdi_id(const struct pdi *pdi)
131{
132 return le16_to_cpu(pdi->id);
133}
134
135
136static inline u32
137pdi_len(const struct pdi *pdi)
138{
139 return 2 * (le16_to_cpu(pdi->len) - 1);
140}
141
142
143
144
145
146
147
148static const struct pdr *
149hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
150{
151 const struct pdr *pdr = first_pdr;
152
153 end -= sizeof(struct pdr);
154
155 while (((void *) pdr <= end) &&
156 (pdr_id(pdr) != PDI_END)) {
157
158
159
160
161
162 if (pdr_len(pdr) < 2)
163 return NULL;
164
165
166 if (pdr_id(pdr) == record_id)
167 return pdr;
168
169 pdr = (struct pdr *) pdr->next;
170 }
171 return NULL;
172}
173
174
175static const struct pdi *
176hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
177{
178 const struct pdi *pdi = first_pdi;
179
180 end -= sizeof(struct pdi);
181
182 while (((void *) pdi <= end) &&
183 (pdi_id(pdi) != PDI_END)) {
184
185
186 if (pdi_id(pdi) == record_id)
187 return pdi;
188
189 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
190 }
191 return NULL;
192}
193
194
195static int
196hermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr,
197 const struct pdi *pdi, const void *pdr_end)
198{
199 const struct pdr *pdr;
200
201
202 pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
203
204
205 if (!pdr)
206 return 0;
207
208
209 if (pdi_len(pdi) != pdr_len(pdr))
210 return -EINVAL;
211
212
213 hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
214
215 return 0;
216}
217
218
219
220
221
222
223int hermes_apply_pda(struct hermes *hw,
224 const char *first_pdr,
225 const void *pdr_end,
226 const __le16 *pda,
227 const void *pda_end)
228{
229 int ret;
230 const struct pdi *pdi;
231 const struct pdr *pdr;
232
233 pdr = (const struct pdr *) first_pdr;
234 pda_end -= sizeof(struct pdi);
235
236
237 pdi = (const struct pdi *) (pda + 2);
238 while (((void *) pdi <= pda_end) &&
239 (pdi_id(pdi) != PDI_END)) {
240 ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
241 if (ret)
242 return ret;
243
244
245 pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
246 }
247 return 0;
248}
249
250
251
252
253size_t
254hermes_blocks_length(const char *first_block, const void *end)
255{
256 const struct dblock *blk = (const struct dblock *) first_block;
257 int total_len = 0;
258 int len;
259
260 end -= sizeof(*blk);
261
262
263
264 while (((void *) blk <= end) &&
265 (dblock_addr(blk) != BLOCK_END)) {
266 len = dblock_len(blk);
267 total_len += sizeof(*blk) + len;
268 blk = (struct dblock *) &blk->data[len];
269 }
270
271 return total_len;
272}
273
274
275
276
277int hermes_program(struct hermes *hw, const char *first_block, const void *end)
278{
279 const struct dblock *blk;
280 u32 blkaddr;
281 u32 blklen;
282 int err = 0;
283
284 blk = (const struct dblock *) first_block;
285
286 if ((void *) blk > (end - sizeof(*blk)))
287 return -EIO;
288
289 blkaddr = dblock_addr(blk);
290 blklen = dblock_len(blk);
291
292 while ((blkaddr != BLOCK_END) &&
293 (((void *) blk + blklen) <= end)) {
294 pr_debug(PFX "Programming block of length %d "
295 "to address 0x%08x\n", blklen, blkaddr);
296
297 err = hw->ops->program(hw, blk->data, blkaddr, blklen);
298 if (err)
299 break;
300
301 blk = (const struct dblock *) &blk->data[blklen];
302
303 if ((void *) blk > (end - sizeof(*blk)))
304 return -EIO;
305
306 blkaddr = dblock_addr(blk);
307 blklen = dblock_len(blk);
308 }
309 return err;
310}
311
312
313
314
315#define DEFINE_DEFAULT_PDR(pid, length, data) \
316static const struct { \
317 __le16 len; \
318 __le16 id; \
319 u8 val[length]; \
320} __packed default_pdr_data_##pid = { \
321 cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
322 sizeof(__le16)) - 1), \
323 cpu_to_le16(pid), \
324 data \
325}
326
327#define DEFAULT_PDR(pid) default_pdr_data_##pid
328
329
330DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
331
332
333DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
334
335
336DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
337
338
339DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
340
341
342DEFINE_DEFAULT_PDR(0x0160, 28,
343 "\x00\x00\x00\x00\x00\x00\x00\x00"
344 "\x00\x00\x00\x00\x00\x00\x00\x00"
345 "\x00\x00\x00\x00\x00\x00\x00\x00"
346 "\x00\x00\x00\x00");
347
348
349DEFINE_DEFAULT_PDR(0x0161, 256,
350 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
351 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
352 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
353 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
354 "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
355 "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
356 "\x3B\x01\x3A\01\x3A\x01\x39\x01"
357 "\x39\x01\x38\01\x38\x01\x37\x01"
358 "\x37\x01\x36\01\x36\x01\x35\x01"
359 "\x35\x01\x34\01\x34\x01\x33\x01"
360 "\x33\x01\x32\x01\x32\x01\x31\x01"
361 "\x31\x01\x30\x01\x30\x01\x7B\x01"
362 "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
363 "\x79\x01\x78\x01\x78\x01\x77\x01"
364 "\x77\x01\x76\x01\x76\x01\x75\x01"
365 "\x75\x01\x74\x01\x74\x01\x73\x01"
366 "\x73\x01\x72\x01\x72\x01\x71\x01"
367 "\x71\x01\x70\x01\x70\x01\x68\x01"
368 "\x68\x01\x67\x01\x67\x01\x66\x01"
369 "\x66\x01\x65\x01\x65\x01\x57\x01"
370 "\x57\x01\x56\x01\x56\x01\x55\x01"
371 "\x55\x01\x54\x01\x54\x01\x53\x01"
372 "\x53\x01\x52\x01\x52\x01\x51\x01"
373 "\x51\x01\x50\x01\x50\x01\x48\x01"
374 "\x48\x01\x47\x01\x47\x01\x46\x01"
375 "\x46\x01\x45\x01\x45\x01\x44\x01"
376 "\x44\x01\x43\x01\x43\x01\x42\x01"
377 "\x42\x01\x41\x01\x41\x01\x40\x01"
378 "\x40\x01\x40\x01\x40\x01\x40\x01"
379 "\x40\x01\x40\x01\x40\x01\x40\x01"
380 "\x40\x01\x40\x01\x40\x01\x40\x01"
381 "\x40\x01\x40\x01\x40\x01\x40\x01");
382
383
384
385
386
387
388
389
390int hermes_apply_pda_with_defaults(struct hermes *hw,
391 const char *first_pdr,
392 const void *pdr_end,
393 const __le16 *pda,
394 const void *pda_end)
395{
396 const struct pdr *pdr = (const struct pdr *) first_pdr;
397 const struct pdi *first_pdi = (const struct pdi *) &pda[2];
398 const struct pdi *pdi;
399 const struct pdi *default_pdi = NULL;
400 const struct pdi *outdoor_pdi;
401 int record_id;
402
403 pdr_end -= sizeof(struct pdr);
404
405 while (((void *) pdr <= pdr_end) &&
406 (pdr_id(pdr) != PDI_END)) {
407
408
409
410
411
412
413 if (pdr_len(pdr) < 2)
414 break;
415 record_id = pdr_id(pdr);
416
417 pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
418 if (pdi)
419 pr_debug(PFX "Found record 0x%04x at %p\n",
420 record_id, pdi);
421
422 switch (record_id) {
423 case 0x110:
424 case 0x120:
425 outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
426 pda_end);
427 default_pdi = NULL;
428 if (outdoor_pdi) {
429 pdi = outdoor_pdi;
430 pr_debug(PFX
431 "Using outdoor record 0x%04x at %p\n",
432 record_id + 1, pdi);
433 }
434 break;
435 case 0x5:
436 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
437 break;
438 case 0x108:
439 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
440 break;
441 case 0x109:
442 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
443 break;
444 case 0x150:
445 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
446 break;
447 case 0x160:
448 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
449 break;
450 case 0x161:
451 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
452 break;
453 default:
454 default_pdi = NULL;
455 break;
456 }
457 if (!pdi && default_pdi) {
458
459 pdi = default_pdi;
460 pr_debug(PFX "Using default record 0x%04x at %p\n",
461 record_id, pdi);
462 }
463
464 if (pdi) {
465
466 if ((pdi_len(pdi) == pdr_len(pdr)) &&
467 ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
468
469 hw->ops->program(hw, pdi->data, pdr_addr(pdr),
470 pdi_len(pdi));
471 }
472 }
473
474 pdr++;
475 }
476 return 0;
477}
478