0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <linux/module.h>
0043 #include <linux/delay.h>
0044 #include "hermes.h"
0045 #include "hermes_dld.h"
0046
0047 #define PFX "hermes_dld: "
0048
0049
0050 #define PDI_END 0x00000000
0051 #define BLOCK_END 0xFFFFFFFF
0052 #define TEXT_END 0x1A
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 struct dblock {
0065 __le32 addr;
0066 __le16 len;
0067 char data[];
0068 } __packed;
0069
0070
0071
0072
0073
0074
0075 struct pdr {
0076 __le32 id;
0077 __le32 addr;
0078 __le32 len;
0079 char next[];
0080 } __packed;
0081
0082
0083
0084
0085
0086
0087 struct pdi {
0088 __le16 len;
0089 __le16 id;
0090 char data[];
0091 } __packed;
0092
0093
0094
0095 static inline u32
0096 dblock_addr(const struct dblock *blk)
0097 {
0098 return le32_to_cpu(blk->addr);
0099 }
0100
0101 static inline u32
0102 dblock_len(const struct dblock *blk)
0103 {
0104 return le16_to_cpu(blk->len);
0105 }
0106
0107
0108
0109 static inline u32
0110 pdr_id(const struct pdr *pdr)
0111 {
0112 return le32_to_cpu(pdr->id);
0113 }
0114
0115 static inline u32
0116 pdr_addr(const struct pdr *pdr)
0117 {
0118 return le32_to_cpu(pdr->addr);
0119 }
0120
0121 static inline u32
0122 pdr_len(const struct pdr *pdr)
0123 {
0124 return le32_to_cpu(pdr->len);
0125 }
0126
0127
0128
0129 static inline u32
0130 pdi_id(const struct pdi *pdi)
0131 {
0132 return le16_to_cpu(pdi->id);
0133 }
0134
0135
0136 static inline u32
0137 pdi_len(const struct pdi *pdi)
0138 {
0139 return 2 * (le16_to_cpu(pdi->len) - 1);
0140 }
0141
0142
0143
0144
0145
0146
0147
0148 static const struct pdr *
0149 hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
0150 {
0151 const struct pdr *pdr = first_pdr;
0152
0153 end -= sizeof(struct pdr);
0154
0155 while (((void *) pdr <= end) &&
0156 (pdr_id(pdr) != PDI_END)) {
0157
0158
0159
0160
0161
0162 if (pdr_len(pdr) < 2)
0163 return NULL;
0164
0165
0166 if (pdr_id(pdr) == record_id)
0167 return pdr;
0168
0169 pdr = (struct pdr *) pdr->next;
0170 }
0171 return NULL;
0172 }
0173
0174
0175 static const struct pdi *
0176 hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
0177 {
0178 const struct pdi *pdi = first_pdi;
0179
0180 end -= sizeof(struct pdi);
0181
0182 while (((void *) pdi <= end) &&
0183 (pdi_id(pdi) != PDI_END)) {
0184
0185
0186 if (pdi_id(pdi) == record_id)
0187 return pdi;
0188
0189 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
0190 }
0191 return NULL;
0192 }
0193
0194
0195 static int
0196 hermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr,
0197 const struct pdi *pdi, const void *pdr_end)
0198 {
0199 const struct pdr *pdr;
0200
0201
0202 pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
0203
0204
0205 if (!pdr)
0206 return 0;
0207
0208
0209 if (pdi_len(pdi) != pdr_len(pdr))
0210 return -EINVAL;
0211
0212
0213 hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
0214
0215 return 0;
0216 }
0217
0218
0219
0220
0221
0222
0223 int hermes_apply_pda(struct hermes *hw,
0224 const char *first_pdr,
0225 const void *pdr_end,
0226 const __le16 *pda,
0227 const void *pda_end)
0228 {
0229 int ret;
0230 const struct pdi *pdi;
0231 const struct pdr *pdr;
0232
0233 pdr = (const struct pdr *) first_pdr;
0234 pda_end -= sizeof(struct pdi);
0235
0236
0237 pdi = (const struct pdi *) (pda + 2);
0238 while (((void *) pdi <= pda_end) &&
0239 (pdi_id(pdi) != PDI_END)) {
0240 ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
0241 if (ret)
0242 return ret;
0243
0244
0245 pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
0246 }
0247 return 0;
0248 }
0249
0250
0251
0252
0253 size_t
0254 hermes_blocks_length(const char *first_block, const void *end)
0255 {
0256 const struct dblock *blk = (const struct dblock *) first_block;
0257 int total_len = 0;
0258 int len;
0259
0260 end -= sizeof(*blk);
0261
0262
0263
0264 while (((void *) blk <= end) &&
0265 (dblock_addr(blk) != BLOCK_END)) {
0266 len = dblock_len(blk);
0267 total_len += sizeof(*blk) + len;
0268 blk = (struct dblock *) &blk->data[len];
0269 }
0270
0271 return total_len;
0272 }
0273
0274
0275
0276
0277 int hermes_program(struct hermes *hw, const char *first_block, const void *end)
0278 {
0279 const struct dblock *blk;
0280 u32 blkaddr;
0281 u32 blklen;
0282 int err = 0;
0283
0284 blk = (const struct dblock *) first_block;
0285
0286 if ((void *) blk > (end - sizeof(*blk)))
0287 return -EIO;
0288
0289 blkaddr = dblock_addr(blk);
0290 blklen = dblock_len(blk);
0291
0292 while ((blkaddr != BLOCK_END) &&
0293 (((void *) blk + blklen) <= end)) {
0294 pr_debug(PFX "Programming block of length %d "
0295 "to address 0x%08x\n", blklen, blkaddr);
0296
0297 err = hw->ops->program(hw, blk->data, blkaddr, blklen);
0298 if (err)
0299 break;
0300
0301 blk = (const struct dblock *) &blk->data[blklen];
0302
0303 if ((void *) blk > (end - sizeof(*blk)))
0304 return -EIO;
0305
0306 blkaddr = dblock_addr(blk);
0307 blklen = dblock_len(blk);
0308 }
0309 return err;
0310 }
0311
0312
0313
0314
0315 #define DEFINE_DEFAULT_PDR(pid, length, data) \
0316 static const struct { \
0317 __le16 len; \
0318 __le16 id; \
0319 u8 val[length]; \
0320 } __packed default_pdr_data_##pid = { \
0321 cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
0322 sizeof(__le16)) - 1), \
0323 cpu_to_le16(pid), \
0324 data \
0325 }
0326
0327 #define DEFAULT_PDR(pid) default_pdr_data_##pid
0328
0329
0330 DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
0331
0332
0333 DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
0334
0335
0336 DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
0337
0338
0339 DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
0340
0341
0342 DEFINE_DEFAULT_PDR(0x0160, 28,
0343 "\x00\x00\x00\x00\x00\x00\x00\x00"
0344 "\x00\x00\x00\x00\x00\x00\x00\x00"
0345 "\x00\x00\x00\x00\x00\x00\x00\x00"
0346 "\x00\x00\x00\x00");
0347
0348
0349 DEFINE_DEFAULT_PDR(0x0161, 256,
0350 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
0351 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
0352 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
0353 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
0354 "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
0355 "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
0356 "\x3B\x01\x3A\01\x3A\x01\x39\x01"
0357 "\x39\x01\x38\01\x38\x01\x37\x01"
0358 "\x37\x01\x36\01\x36\x01\x35\x01"
0359 "\x35\x01\x34\01\x34\x01\x33\x01"
0360 "\x33\x01\x32\x01\x32\x01\x31\x01"
0361 "\x31\x01\x30\x01\x30\x01\x7B\x01"
0362 "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
0363 "\x79\x01\x78\x01\x78\x01\x77\x01"
0364 "\x77\x01\x76\x01\x76\x01\x75\x01"
0365 "\x75\x01\x74\x01\x74\x01\x73\x01"
0366 "\x73\x01\x72\x01\x72\x01\x71\x01"
0367 "\x71\x01\x70\x01\x70\x01\x68\x01"
0368 "\x68\x01\x67\x01\x67\x01\x66\x01"
0369 "\x66\x01\x65\x01\x65\x01\x57\x01"
0370 "\x57\x01\x56\x01\x56\x01\x55\x01"
0371 "\x55\x01\x54\x01\x54\x01\x53\x01"
0372 "\x53\x01\x52\x01\x52\x01\x51\x01"
0373 "\x51\x01\x50\x01\x50\x01\x48\x01"
0374 "\x48\x01\x47\x01\x47\x01\x46\x01"
0375 "\x46\x01\x45\x01\x45\x01\x44\x01"
0376 "\x44\x01\x43\x01\x43\x01\x42\x01"
0377 "\x42\x01\x41\x01\x41\x01\x40\x01"
0378 "\x40\x01\x40\x01\x40\x01\x40\x01"
0379 "\x40\x01\x40\x01\x40\x01\x40\x01"
0380 "\x40\x01\x40\x01\x40\x01\x40\x01"
0381 "\x40\x01\x40\x01\x40\x01\x40\x01");
0382
0383
0384
0385
0386
0387
0388
0389
0390 int hermes_apply_pda_with_defaults(struct hermes *hw,
0391 const char *first_pdr,
0392 const void *pdr_end,
0393 const __le16 *pda,
0394 const void *pda_end)
0395 {
0396 const struct pdr *pdr = (const struct pdr *) first_pdr;
0397 const struct pdi *first_pdi = (const struct pdi *) &pda[2];
0398 const struct pdi *pdi;
0399 const struct pdi *default_pdi = NULL;
0400 const struct pdi *outdoor_pdi;
0401 int record_id;
0402
0403 pdr_end -= sizeof(struct pdr);
0404
0405 while (((void *) pdr <= pdr_end) &&
0406 (pdr_id(pdr) != PDI_END)) {
0407
0408
0409
0410
0411
0412
0413 if (pdr_len(pdr) < 2)
0414 break;
0415 record_id = pdr_id(pdr);
0416
0417 pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
0418 if (pdi)
0419 pr_debug(PFX "Found record 0x%04x at %p\n",
0420 record_id, pdi);
0421
0422 switch (record_id) {
0423 case 0x110:
0424 case 0x120:
0425 outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
0426 pda_end);
0427 default_pdi = NULL;
0428 if (outdoor_pdi) {
0429 pdi = outdoor_pdi;
0430 pr_debug(PFX
0431 "Using outdoor record 0x%04x at %p\n",
0432 record_id + 1, pdi);
0433 }
0434 break;
0435 case 0x5:
0436 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
0437 break;
0438 case 0x108:
0439 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
0440 break;
0441 case 0x109:
0442 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
0443 break;
0444 case 0x150:
0445 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
0446 break;
0447 case 0x160:
0448 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
0449 break;
0450 case 0x161:
0451 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
0452 break;
0453 default:
0454 default_pdi = NULL;
0455 break;
0456 }
0457 if (!pdi && default_pdi) {
0458
0459 pdi = default_pdi;
0460 pr_debug(PFX "Using default record 0x%04x at %p\n",
0461 record_id, pdi);
0462 }
0463
0464 if (pdi) {
0465
0466 if ((pdi_len(pdi) == pdr_len(pdr)) &&
0467 ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
0468
0469 hw->ops->program(hw, pdi->data, pdr_addr(pdr),
0470 pdi_len(pdi));
0471 }
0472 }
0473
0474 pdr++;
0475 }
0476 return 0;
0477 }