blob: 5260ceb5cfecae7e98244196e51041daced6c006 [file] [log] [blame]
David Kilroyf482eb72008-08-21 23:27:51 +01001/*
David Kilroyf90d8d42009-02-04 23:05:57 +00002 * Hermes download helper.
David Kilroyf482eb72008-08-21 23:27:51 +01003 *
David Kilroyf90d8d42009-02-04 23:05:57 +00004 * This helper:
David Kilroyf482eb72008-08-21 23:27:51 +01005 * - is capable of writing to the volatile area of the hermes device
6 * - is currently not capable of writing to non-volatile areas
7 * - provide helpers to identify and update plugin data
8 * - is not capable of interpreting a fw image directly. That is up to
9 * the main card driver.
10 * - deals with Hermes I devices. It can probably be modified to deal
11 * with Hermes II devices
12 *
13 * Copyright (C) 2007, David Kilroy
14 *
15 * Plug data code slightly modified from spectrum_cs driver
16 * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
17 * Portions based on information in wl_lkm_718 Agere driver
18 * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
19 *
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License
23 * at http://www.mozilla.org/MPL/
24 *
25 * Software distributed under the License is distributed on an "AS IS"
26 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
27 * the License for the specific language governing rights and
28 * limitations under the License.
29 *
30 * Alternatively, the contents of this file may be used under the
31 * terms of the GNU General Public License version 2 (the "GPL"), in
32 * which case the provisions of the GPL are applicable instead of the
33 * above. If you wish to allow the use of your version of this file
34 * only under the terms of the GPL and not to allow others to use your
35 * version of this file under the MPL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and
37 * other provisions required by the GPL. If you do not delete the
38 * provisions above, a recipient may use your version of this file
39 * under either the MPL or the GPL.
40 */
41
42#include <linux/module.h>
43#include <linux/delay.h>
44#include "hermes.h"
45#include "hermes_dld.h"
46
David Kilroyf482eb72008-08-21 23:27:51 +010047#define PFX "hermes_dld: "
48
49/*
50 * AUX port access. To unlock the AUX port write the access keys to the
51 * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
52 * register. Then read it and make sure it's HERMES_AUX_ENABLED.
53 */
54#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
55#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
56#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
David Kilroye2334182008-08-21 23:27:52 +010057#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
David Kilroyf482eb72008-08-21 23:27:51 +010058
59#define HERMES_AUX_PW0 0xFE01
60#define HERMES_AUX_PW1 0xDC23
61#define HERMES_AUX_PW2 0xBA45
62
David Kilroy8f5ae732008-08-21 23:27:53 +010063/* HERMES_CMD_DOWNLD */
64#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
65#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
66#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
67#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
68
David Kilroye2334182008-08-21 23:27:52 +010069/* End markers used in dblocks */
David Kilroyf482eb72008-08-21 23:27:51 +010070#define PDI_END 0x00000000 /* End of PDA */
71#define BLOCK_END 0xFFFFFFFF /* Last image block */
David Kilroye2334182008-08-21 23:27:52 +010072#define TEXT_END 0x1A /* End of text header */
73
74/*
75 * PDA == Production Data Area
76 *
77 * In principle, the max. size of the PDA is is 4096 words. Currently,
78 * however, only about 500 bytes of this area are used.
79 *
80 * Some USB implementations can't handle sizes in excess of 1016. Note
81 * that PDA is not actually used in those USB environments, but may be
82 * retrieved by common code.
83 */
84#define MAX_PDA_SIZE 1000
85
86/* Limit the amout we try to download in a single shot.
87 * Size is in bytes.
88 */
89#define MAX_DL_SIZE 1024
90#define LIMIT_PROGRAM_SIZE 0
David Kilroyf482eb72008-08-21 23:27:51 +010091
92/*
93 * The following structures have little-endian fields denoted by
94 * the leading underscore. Don't access them directly - use inline
95 * functions defined below.
96 */
97
98/*
99 * The binary image to be downloaded consists of series of data blocks.
100 * Each block has the following structure.
101 */
102struct dblock {
103 __le32 addr; /* adapter address where to write the block */
104 __le16 len; /* length of the data only, in bytes */
105 char data[0]; /* data to be written */
106} __attribute__ ((packed));
107
108/*
109 * Plug Data References are located in in the image after the last data
110 * block. They refer to areas in the adapter memory where the plug data
111 * items with matching ID should be written.
112 */
113struct pdr {
114 __le32 id; /* record ID */
115 __le32 addr; /* adapter address where to write the data */
116 __le32 len; /* expected length of the data, in bytes */
117 char next[0]; /* next PDR starts here */
118} __attribute__ ((packed));
119
120/*
121 * Plug Data Items are located in the EEPROM read from the adapter by
122 * primary firmware. They refer to the device-specific data that should
123 * be plugged into the secondary firmware.
124 */
125struct pdi {
126 __le16 len; /* length of ID and data, in words */
127 __le16 id; /* record ID */
128 char data[0]; /* plug data */
129} __attribute__ ((packed));
130
David Kilroye2334182008-08-21 23:27:52 +0100131/*** FW data block access functions ***/
132
David Kilroyf482eb72008-08-21 23:27:51 +0100133static inline u32
134dblock_addr(const struct dblock *blk)
135{
136 return le32_to_cpu(blk->addr);
137}
138
139static inline u32
140dblock_len(const struct dblock *blk)
141{
142 return le16_to_cpu(blk->len);
143}
144
David Kilroye2334182008-08-21 23:27:52 +0100145/*** PDR Access functions ***/
146
David Kilroyf482eb72008-08-21 23:27:51 +0100147static inline u32
148pdr_id(const struct pdr *pdr)
149{
150 return le32_to_cpu(pdr->id);
151}
152
153static inline u32
154pdr_addr(const struct pdr *pdr)
155{
156 return le32_to_cpu(pdr->addr);
157}
158
159static inline u32
160pdr_len(const struct pdr *pdr)
161{
162 return le32_to_cpu(pdr->len);
163}
164
David Kilroye2334182008-08-21 23:27:52 +0100165/*** PDI Access functions ***/
166
David Kilroyf482eb72008-08-21 23:27:51 +0100167static inline u32
168pdi_id(const struct pdi *pdi)
169{
170 return le16_to_cpu(pdi->id);
171}
172
173/* Return length of the data only, in bytes */
174static inline u32
175pdi_len(const struct pdi *pdi)
176{
177 return 2 * (le16_to_cpu(pdi->len) - 1);
178}
179
David Kilroye2334182008-08-21 23:27:52 +0100180/*** Hermes AUX control ***/
181
David Kilroyf482eb72008-08-21 23:27:51 +0100182static inline void
David Kilroye2334182008-08-21 23:27:52 +0100183hermes_aux_setaddr(hermes_t *hw, u32 addr)
David Kilroyf482eb72008-08-21 23:27:51 +0100184{
185 hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
186 hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
187}
188
David Kilroye2334182008-08-21 23:27:52 +0100189static inline int
190hermes_aux_control(hermes_t *hw, int enabled)
David Kilroyf482eb72008-08-21 23:27:51 +0100191{
David Kilroye2334182008-08-21 23:27:52 +0100192 int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
193 int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
David Kilroyf482eb72008-08-21 23:27:51 +0100194 int i;
195
196 /* Already open? */
David Kilroye2334182008-08-21 23:27:52 +0100197 if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
David Kilroyf482eb72008-08-21 23:27:51 +0100198 return 0;
199
200 hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
201 hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
202 hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
David Kilroye2334182008-08-21 23:27:52 +0100203 hermes_write_reg(hw, HERMES_CONTROL, action);
David Kilroyf482eb72008-08-21 23:27:51 +0100204
205 for (i = 0; i < 20; i++) {
206 udelay(10);
207 if (hermes_read_reg(hw, HERMES_CONTROL) ==
David Kilroye2334182008-08-21 23:27:52 +0100208 desired_state)
David Kilroyf482eb72008-08-21 23:27:51 +0100209 return 0;
210 }
211
212 return -EBUSY;
213}
214
David Kilroye2334182008-08-21 23:27:52 +0100215/*** Plug Data Functions ***/
216
David Kilroyf482eb72008-08-21 23:27:51 +0100217/*
218 * Scan PDR for the record with the specified RECORD_ID.
219 * If it's not found, return NULL.
220 */
221static struct pdr *
David Kilroye2334182008-08-21 23:27:52 +0100222hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
David Kilroyf482eb72008-08-21 23:27:51 +0100223{
224 struct pdr *pdr = first_pdr;
David Kilroye2334182008-08-21 23:27:52 +0100225 void *end = (void *)first_pdr + MAX_PDA_SIZE;
David Kilroyf482eb72008-08-21 23:27:51 +0100226
David Kilroye2334182008-08-21 23:27:52 +0100227 while (((void *)pdr < end) &&
228 (pdr_id(pdr) != PDI_END)) {
David Kilroyf482eb72008-08-21 23:27:51 +0100229 /*
230 * PDR area is currently not terminated by PDI_END.
231 * It's followed by CRC records, which have the type
232 * field where PDR has length. The type can be 0 or 1.
233 */
234 if (pdr_len(pdr) < 2)
235 return NULL;
236
237 /* If the record ID matches, we are done */
238 if (pdr_id(pdr) == record_id)
239 return pdr;
240
241 pdr = (struct pdr *) pdr->next;
242 }
243 return NULL;
244}
245
David Kilroy8f5ae732008-08-21 23:27:53 +0100246/* Scan production data items for a particular entry */
247static struct pdi *
248hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
249{
250 struct pdi *pdi = first_pdi;
251
252 while (pdi_id(pdi) != PDI_END) {
253
254 /* If the record ID matches, we are done */
255 if (pdi_id(pdi) == record_id)
256 return pdi;
257
258 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
259 }
260 return NULL;
261}
262
David Kilroyf482eb72008-08-21 23:27:51 +0100263/* Process one Plug Data Item - find corresponding PDR and plug it */
264static int
David Kilroye2334182008-08-21 23:27:52 +0100265hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi)
David Kilroyf482eb72008-08-21 23:27:51 +0100266{
267 struct pdr *pdr;
268
David Kilroye2334182008-08-21 23:27:52 +0100269 /* Find the PDR corresponding to this PDI */
270 pdr = hermes_find_pdr(first_pdr, pdi_id(pdi));
David Kilroyf482eb72008-08-21 23:27:51 +0100271
272 /* No match is found, safe to ignore */
273 if (!pdr)
274 return 0;
275
276 /* Lengths of the data in PDI and PDR must match */
277 if (pdi_len(pdi) != pdr_len(pdr))
278 return -EINVAL;
279
280 /* do the actual plugging */
David Kilroye2334182008-08-21 23:27:52 +0100281 hermes_aux_setaddr(hw, pdr_addr(pdr));
David Kilroyf482eb72008-08-21 23:27:51 +0100282 hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
283
284 return 0;
285}
286
287/* Read PDA from the adapter */
David Kilroye2334182008-08-21 23:27:52 +0100288int hermes_read_pda(hermes_t *hw,
289 __le16 *pda,
290 u32 pda_addr,
291 u16 pda_len,
292 int use_eeprom) /* can we get this into hw? */
David Kilroyf482eb72008-08-21 23:27:51 +0100293{
294 int ret;
David Kilroye2334182008-08-21 23:27:52 +0100295 u16 pda_size;
296 u16 data_len = pda_len;
297 __le16 *data = pda;
David Kilroyf482eb72008-08-21 23:27:51 +0100298
David Kilroye2334182008-08-21 23:27:52 +0100299 if (use_eeprom) {
300 /* PDA of spectrum symbol is in eeprom */
301
302 /* Issue command to read EEPROM */
303 ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
304 if (ret)
305 return ret;
David Kilroy8f5ae732008-08-21 23:27:53 +0100306 } else {
307 /* wl_lkm does not include PDA size in the PDA area.
308 * We will pad the information into pda, so other routines
309 * don't have to be modified */
310 pda[0] = cpu_to_le16(pda_len - 2);
311 /* Includes CFG_PROD_DATA but not itself */
312 pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
313 data_len = pda_len - 4;
314 data = pda + 2;
David Kilroye2334182008-08-21 23:27:52 +0100315 }
David Kilroyf482eb72008-08-21 23:27:51 +0100316
317 /* Open auxiliary port */
David Kilroye2334182008-08-21 23:27:52 +0100318 ret = hermes_aux_control(hw, 1);
319 printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
David Kilroyf482eb72008-08-21 23:27:51 +0100320 if (ret)
321 return ret;
322
323 /* read PDA from EEPROM */
David Kilroye2334182008-08-21 23:27:52 +0100324 hermes_aux_setaddr(hw, pda_addr);
325 hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
326
327 /* Close aux port */
328 ret = hermes_aux_control(hw, 0);
329 printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
David Kilroyf482eb72008-08-21 23:27:51 +0100330
331 /* Check PDA length */
332 pda_size = le16_to_cpu(pda[0]);
David Kilroye2334182008-08-21 23:27:52 +0100333 printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
334 pda_size, pda_len);
David Kilroyf482eb72008-08-21 23:27:51 +0100335 if (pda_size > pda_len)
336 return -EINVAL;
337
338 return 0;
339}
David Kilroyf482eb72008-08-21 23:27:51 +0100340
David Kilroye2334182008-08-21 23:27:52 +0100341/* Parse PDA and write the records into the adapter
342 *
343 * Attempt to write every records that is in the specified pda
344 * which also has a valid production data record for the firmware.
345 */
346int hermes_apply_pda(hermes_t *hw,
347 const char *first_pdr,
348 const __le16 *pda)
David Kilroyf482eb72008-08-21 23:27:51 +0100349{
350 int ret;
David Kilroye2334182008-08-21 23:27:52 +0100351 const struct pdi *pdi;
352 struct pdr *pdr;
David Kilroyf482eb72008-08-21 23:27:51 +0100353
David Kilroye2334182008-08-21 23:27:52 +0100354 pdr = (struct pdr *) first_pdr;
David Kilroyf482eb72008-08-21 23:27:51 +0100355
356 /* Go through every PDI and plug them into the adapter */
David Kilroye2334182008-08-21 23:27:52 +0100357 pdi = (const struct pdi *) (pda + 2);
David Kilroyf482eb72008-08-21 23:27:51 +0100358 while (pdi_id(pdi) != PDI_END) {
David Kilroye2334182008-08-21 23:27:52 +0100359 ret = hermes_plug_pdi(hw, pdr, pdi);
David Kilroyf482eb72008-08-21 23:27:51 +0100360 if (ret)
361 return ret;
362
363 /* Increment to the next PDI */
David Kilroye2334182008-08-21 23:27:52 +0100364 pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
David Kilroyf482eb72008-08-21 23:27:51 +0100365 }
366 return 0;
367}
David Kilroyf482eb72008-08-21 23:27:51 +0100368
David Kilroye2334182008-08-21 23:27:52 +0100369/* Identify the total number of bytes in all blocks
370 * including the header data.
371 */
372size_t
373hermes_blocks_length(const char *first_block)
374{
375 const struct dblock *blk = (const struct dblock *) first_block;
376 int total_len = 0;
377 int len;
378
379 /* Skip all blocks to locate Plug Data References
380 * (Spectrum CS) */
381 while (dblock_addr(blk) != BLOCK_END) {
382 len = dblock_len(blk);
383 total_len += sizeof(*blk) + len;
384 blk = (struct dblock *) &blk->data[len];
385 }
386
387 return total_len;
388}
David Kilroye2334182008-08-21 23:27:52 +0100389
390/*** Hermes programming ***/
391
David Kilroy8f5ae732008-08-21 23:27:53 +0100392/* About to start programming data (Hermes I)
393 * offset is the entry point
394 *
395 * Spectrum_cs' Symbol fw does not require this
396 * wl_lkm Agere fw does
397 * Don't know about intersil
398 */
399int hermesi_program_init(hermes_t *hw, u32 offset)
400{
401 int err;
402
403 /* Disable interrupts?*/
404 /*hw->inten = 0x0;*/
405 /*hermes_write_regn(hw, INTEN, 0);*/
406 /*hermes_set_irqmask(hw, 0);*/
407
408 /* Acknowledge any outstanding command */
409 hermes_write_regn(hw, EVACK, 0xFFFF);
410
411 /* Using doicmd_wait rather than docmd_wait */
412 err = hermes_doicmd_wait(hw,
413 0x0100 | HERMES_CMD_INIT,
414 0, 0, 0, NULL);
415 if (err)
416 return err;
417
418 err = hermes_doicmd_wait(hw,
419 0x0000 | HERMES_CMD_INIT,
420 0, 0, 0, NULL);
421 if (err)
422 return err;
423
424 err = hermes_aux_control(hw, 1);
425 printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
426
427 if (err)
428 return err;
429
430 printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
431 err = hermes_doicmd_wait(hw,
432 HERMES_PROGRAM_ENABLE_VOLATILE,
433 offset & 0xFFFFu,
434 offset >> 16,
435 0,
436 NULL);
437 printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
438 err);
439
440 return err;
441}
David Kilroy8f5ae732008-08-21 23:27:53 +0100442
443/* Done programming data (Hermes I)
444 *
445 * Spectrum_cs' Symbol fw does not require this
446 * wl_lkm Agere fw does
447 * Don't know about intersil
448 */
449int hermesi_program_end(hermes_t *hw)
450{
451 struct hermes_response resp;
452 int rc = 0;
453 int err;
454
455 rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
456
457 printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
458 "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
459 rc, resp.resp0, resp.resp1, resp.resp2);
460
461 if ((rc == 0) &&
462 ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
463 rc = -EIO;
464
465 err = hermes_aux_control(hw, 0);
466 printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
467
468 /* Acknowledge any outstanding command */
469 hermes_write_regn(hw, EVACK, 0xFFFF);
470
471 /* Reinitialise, ignoring return */
472 (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
473 0, 0, 0, NULL);
474
475 return rc ? rc : err;
476}
David Kilroy8f5ae732008-08-21 23:27:53 +0100477
David Kilroye2334182008-08-21 23:27:52 +0100478/* Program the data blocks */
479int hermes_program(hermes_t *hw, const char *first_block, const char *end)
David Kilroyf482eb72008-08-21 23:27:51 +0100480{
481 const struct dblock *blk;
482 u32 blkaddr;
483 u32 blklen;
David Kilroye2334182008-08-21 23:27:52 +0100484#if LIMIT_PROGRAM_SIZE
485 u32 addr;
486 u32 len;
487#endif
David Kilroyf482eb72008-08-21 23:27:51 +0100488
David Kilroye2334182008-08-21 23:27:52 +0100489 blk = (const struct dblock *) first_block;
490
491 if ((const char *) blk > (end - sizeof(*blk)))
492 return -EIO;
493
David Kilroyf482eb72008-08-21 23:27:51 +0100494 blkaddr = dblock_addr(blk);
495 blklen = dblock_len(blk);
496
David Kilroye2334182008-08-21 23:27:52 +0100497 while ((blkaddr != BLOCK_END) &&
498 (((const char *) blk + blklen) <= end)) {
499 printk(KERN_DEBUG PFX
500 "Programming block of length %d to address 0x%08x\n",
501 blklen, blkaddr);
502
503#if !LIMIT_PROGRAM_SIZE
504 /* wl_lkm driver splits this into writes of 2000 bytes */
505 hermes_aux_setaddr(hw, blkaddr);
David Kilroyf482eb72008-08-21 23:27:51 +0100506 hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
507 blklen);
David Kilroye2334182008-08-21 23:27:52 +0100508#else
509 len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
510 addr = blkaddr;
David Kilroyf482eb72008-08-21 23:27:51 +0100511
David Kilroye2334182008-08-21 23:27:52 +0100512 while (addr < (blkaddr + blklen)) {
513 printk(KERN_DEBUG PFX
514 "Programming subblock of length %d "
515 "to address 0x%08x. Data @ %p\n",
516 len, addr, &blk->data[addr - blkaddr]);
517
518 hermes_aux_setaddr(hw, addr);
519 hermes_write_bytes(hw, HERMES_AUXDATA,
520 &blk->data[addr - blkaddr],
521 len);
522
523 addr += len;
524 len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
525 (blkaddr + blklen - addr) : MAX_DL_SIZE;
526 }
527#endif
528 blk = (const struct dblock *) &blk->data[blklen];
529
530 if ((const char *) blk > (end - sizeof(*blk)))
531 return -EIO;
532
David Kilroyf482eb72008-08-21 23:27:51 +0100533 blkaddr = dblock_addr(blk);
534 blklen = dblock_len(blk);
535 }
536 return 0;
537}
David Kilroy8f5ae732008-08-21 23:27:53 +0100538
539/*** Default plugging data for Hermes I ***/
540/* Values from wl_lkm_718/hcf/dhf.c */
541
542#define DEFINE_DEFAULT_PDR(pid, length, data) \
543static const struct { \
544 __le16 len; \
545 __le16 id; \
546 u8 val[length]; \
547} __attribute__ ((packed)) default_pdr_data_##pid = { \
Harvey Harrisonc1b4aa32009-01-29 13:26:44 -0800548 cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
David Kilroy8f5ae732008-08-21 23:27:53 +0100549 sizeof(__le16)) - 1), \
Harvey Harrisonc1b4aa32009-01-29 13:26:44 -0800550 cpu_to_le16(pid), \
David Kilroy8f5ae732008-08-21 23:27:53 +0100551 data \
552}
553
554#define DEFAULT_PDR(pid) default_pdr_data_##pid
555
556/* HWIF Compatiblity */
557DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
558
559/* PPPPSign */
560DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
561
562/* PPPPProf */
563DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
564
565/* Antenna diversity */
566DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
567
568/* Modem VCO band Set-up */
569DEFINE_DEFAULT_PDR(0x0160, 28,
570 "\x00\x00\x00\x00\x00\x00\x00\x00"
571 "\x00\x00\x00\x00\x00\x00\x00\x00"
572 "\x00\x00\x00\x00\x00\x00\x00\x00"
573 "\x00\x00\x00\x00");
574
575/* Modem Rx Gain Table Values */
576DEFINE_DEFAULT_PDR(0x0161, 256,
577 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
578 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
579 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
580 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
581 "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
582 "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
583 "\x3B\x01\x3A\01\x3A\x01\x39\x01"
584 "\x39\x01\x38\01\x38\x01\x37\x01"
585 "\x37\x01\x36\01\x36\x01\x35\x01"
586 "\x35\x01\x34\01\x34\x01\x33\x01"
587 "\x33\x01\x32\x01\x32\x01\x31\x01"
588 "\x31\x01\x30\x01\x30\x01\x7B\x01"
589 "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
590 "\x79\x01\x78\x01\x78\x01\x77\x01"
591 "\x77\x01\x76\x01\x76\x01\x75\x01"
592 "\x75\x01\x74\x01\x74\x01\x73\x01"
593 "\x73\x01\x72\x01\x72\x01\x71\x01"
594 "\x71\x01\x70\x01\x70\x01\x68\x01"
595 "\x68\x01\x67\x01\x67\x01\x66\x01"
596 "\x66\x01\x65\x01\x65\x01\x57\x01"
597 "\x57\x01\x56\x01\x56\x01\x55\x01"
598 "\x55\x01\x54\x01\x54\x01\x53\x01"
599 "\x53\x01\x52\x01\x52\x01\x51\x01"
600 "\x51\x01\x50\x01\x50\x01\x48\x01"
601 "\x48\x01\x47\x01\x47\x01\x46\x01"
602 "\x46\x01\x45\x01\x45\x01\x44\x01"
603 "\x44\x01\x43\x01\x43\x01\x42\x01"
604 "\x42\x01\x41\x01\x41\x01\x40\x01"
605 "\x40\x01\x40\x01\x40\x01\x40\x01"
606 "\x40\x01\x40\x01\x40\x01\x40\x01"
607 "\x40\x01\x40\x01\x40\x01\x40\x01"
608 "\x40\x01\x40\x01\x40\x01\x40\x01");
609
610/* Write PDA according to certain rules.
611 *
612 * For every production data record, look for a previous setting in
613 * the pda, and use that.
614 *
615 * For certain records, use defaults if they are not found in pda.
616 */
617int hermes_apply_pda_with_defaults(hermes_t *hw,
618 const char *first_pdr,
619 const __le16 *pda)
620{
621 const struct pdr *pdr = (const struct pdr *) first_pdr;
622 struct pdi *first_pdi = (struct pdi *) &pda[2];
623 struct pdi *pdi;
624 struct pdi *default_pdi = NULL;
625 struct pdi *outdoor_pdi;
626 void *end = (void *)first_pdr + MAX_PDA_SIZE;
627 int record_id;
628
629 while (((void *)pdr < end) &&
630 (pdr_id(pdr) != PDI_END)) {
631 /*
632 * For spectrum_cs firmwares,
633 * PDR area is currently not terminated by PDI_END.
634 * It's followed by CRC records, which have the type
635 * field where PDR has length. The type can be 0 or 1.
636 */
637 if (pdr_len(pdr) < 2)
638 break;
639 record_id = pdr_id(pdr);
640
641 pdi = hermes_find_pdi(first_pdi, record_id);
642 if (pdi)
643 printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
644 record_id, pdi);
645
646 switch (record_id) {
647 case 0x110: /* Modem REFDAC values */
648 case 0x120: /* Modem VGDAC values */
649 outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1);
650 default_pdi = NULL;
651 if (outdoor_pdi) {
652 pdi = outdoor_pdi;
653 printk(KERN_DEBUG PFX
654 "Using outdoor record 0x%04x at %p\n",
655 record_id + 1, pdi);
656 }
657 break;
658 case 0x5: /* HWIF Compatiblity */
659 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
660 break;
661 case 0x108: /* PPPPSign */
662 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
663 break;
664 case 0x109: /* PPPPProf */
665 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
666 break;
667 case 0x150: /* Antenna diversity */
668 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
669 break;
670 case 0x160: /* Modem VCO band Set-up */
671 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
672 break;
673 case 0x161: /* Modem Rx Gain Table Values */
674 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
675 break;
676 default:
677 default_pdi = NULL;
678 break;
679 }
680 if (!pdi && default_pdi) {
681 /* Use default */
682 pdi = default_pdi;
683 printk(KERN_DEBUG PFX
684 "Using default record 0x%04x at %p\n",
685 record_id, pdi);
686 }
687
688 if (pdi) {
689 /* Lengths of the data in PDI and PDR must match */
690 if (pdi_len(pdi) == pdr_len(pdr)) {
691 /* do the actual plugging */
692 hermes_aux_setaddr(hw, pdr_addr(pdr));
693 hermes_write_bytes(hw, HERMES_AUXDATA,
694 pdi->data, pdi_len(pdi));
695 }
696 }
697
698 pdr++;
699 }
700 return 0;
701}