2 * Hermes download helper driver.
4 * This could be entirely merged into hermes.c.
6 * I'm keeping it separate to minimise the amount of merging between
7 * kernel upgrades. It also means the memory overhead for drivers that
8 * don't need firmware download low.
11 * - is capable of writing to the volatile area of the hermes device
12 * - is currently not capable of writing to non-volatile areas
13 * - provide helpers to identify and update plugin data
14 * - is not capable of interpreting a fw image directly. That is up to
15 * the main card driver.
16 * - deals with Hermes I devices. It can probably be modified to deal
17 * with Hermes II devices
19 * Copyright (C) 2007, David Kilroy
21 * Plug data code slightly modified from spectrum_cs driver
22 * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
23 * Portions based on information in wl_lkm_718 Agere driver
24 * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
26 * The contents of this file are subject to the Mozilla Public License
27 * Version 1.1 (the "License"); you may not use this file except in
28 * compliance with the License. You may obtain a copy of the License
29 * at http://www.mozilla.org/MPL/
31 * Software distributed under the License is distributed on an "AS IS"
32 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
33 * the License for the specific language governing rights and
34 * limitations under the License.
36 * Alternatively, the contents of this file may be used under the
37 * terms of the GNU General Public License version 2 (the "GPL"), in
38 * which case the provisions of the GPL are applicable instead of the
39 * above. If you wish to allow the use of your version of this file
40 * only under the terms of the GPL and not to allow others to use your
41 * version of this file under the MPL, indicate your decision by
42 * deleting the provisions above and replace them with the notice and
43 * other provisions required by the GPL. If you do not delete the
44 * provisions above, a recipient may use your version of this file
45 * under either the MPL or the GPL.
48 #include <linux/module.h>
49 #include <linux/delay.h>
51 #include "hermes_dld.h"
53 MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset");
54 MODULE_AUTHOR("David Kilroy <kilroyd@gmail.com>");
55 MODULE_LICENSE("Dual MPL/GPL");
57 #define PFX "hermes_dld: "
60 * AUX port access. To unlock the AUX port write the access keys to the
61 * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
62 * register. Then read it and make sure it's HERMES_AUX_ENABLED.
64 #define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
65 #define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
66 #define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
67 #define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
69 #define HERMES_AUX_PW0 0xFE01
70 #define HERMES_AUX_PW1 0xDC23
71 #define HERMES_AUX_PW2 0xBA45
73 /* HERMES_CMD_DOWNLD */
74 #define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
75 #define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
76 #define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
77 #define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
79 /* End markers used in dblocks */
80 #define PDI_END 0x00000000 /* End of PDA */
81 #define BLOCK_END 0xFFFFFFFF /* Last image block */
82 #define TEXT_END 0x1A /* End of text header */
85 * PDA == Production Data Area
87 * In principle, the max. size of the PDA is is 4096 words. Currently,
88 * however, only about 500 bytes of this area are used.
90 * Some USB implementations can't handle sizes in excess of 1016. Note
91 * that PDA is not actually used in those USB environments, but may be
92 * retrieved by common code.
94 #define MAX_PDA_SIZE 1000
96 /* Limit the amout we try to download in a single shot.
99 #define MAX_DL_SIZE 1024
100 #define LIMIT_PROGRAM_SIZE 0
103 * The following structures have little-endian fields denoted by
104 * the leading underscore. Don't access them directly - use inline
105 * functions defined below.
109 * The binary image to be downloaded consists of series of data blocks.
110 * Each block has the following structure.
113 __le32 addr; /* adapter address where to write the block */
114 __le16 len; /* length of the data only, in bytes */
115 char data[0]; /* data to be written */
116 } __attribute__ ((packed));
119 * Plug Data References are located in in the image after the last data
120 * block. They refer to areas in the adapter memory where the plug data
121 * items with matching ID should be written.
124 __le32 id; /* record ID */
125 __le32 addr; /* adapter address where to write the data */
126 __le32 len; /* expected length of the data, in bytes */
127 char next[0]; /* next PDR starts here */
128 } __attribute__ ((packed));
131 * Plug Data Items are located in the EEPROM read from the adapter by
132 * primary firmware. They refer to the device-specific data that should
133 * be plugged into the secondary firmware.
136 __le16 len; /* length of ID and data, in words */
137 __le16 id; /* record ID */
138 char data[0]; /* plug data */
139 } __attribute__ ((packed));
141 /*** FW data block access functions ***/
144 dblock_addr(const struct dblock *blk)
146 return le32_to_cpu(blk->addr);
150 dblock_len(const struct dblock *blk)
152 return le16_to_cpu(blk->len);
155 /*** PDR Access functions ***/
158 pdr_id(const struct pdr *pdr)
160 return le32_to_cpu(pdr->id);
164 pdr_addr(const struct pdr *pdr)
166 return le32_to_cpu(pdr->addr);
170 pdr_len(const struct pdr *pdr)
172 return le32_to_cpu(pdr->len);
175 /*** PDI Access functions ***/
178 pdi_id(const struct pdi *pdi)
180 return le16_to_cpu(pdi->id);
183 /* Return length of the data only, in bytes */
185 pdi_len(const struct pdi *pdi)
187 return 2 * (le16_to_cpu(pdi->len) - 1);
190 /*** Hermes AUX control ***/
193 hermes_aux_setaddr(hermes_t *hw, u32 addr)
195 hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
196 hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
200 hermes_aux_control(hermes_t *hw, int enabled)
202 int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
203 int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
207 if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
210 hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
211 hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
212 hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
213 hermes_write_reg(hw, HERMES_CONTROL, action);
215 for (i = 0; i < 20; i++) {
217 if (hermes_read_reg(hw, HERMES_CONTROL) ==
225 /*** Plug Data Functions ***/
228 * Scan PDR for the record with the specified RECORD_ID.
229 * If it's not found, return NULL.
232 hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
234 struct pdr *pdr = first_pdr;
235 void *end = (void *)first_pdr + MAX_PDA_SIZE;
237 while (((void *)pdr < end) &&
238 (pdr_id(pdr) != PDI_END)) {
240 * PDR area is currently not terminated by PDI_END.
241 * It's followed by CRC records, which have the type
242 * field where PDR has length. The type can be 0 or 1.
244 if (pdr_len(pdr) < 2)
247 /* If the record ID matches, we are done */
248 if (pdr_id(pdr) == record_id)
251 pdr = (struct pdr *) pdr->next;
256 /* Scan production data items for a particular entry */
258 hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
260 struct pdi *pdi = first_pdi;
262 while (pdi_id(pdi) != PDI_END) {
264 /* If the record ID matches, we are done */
265 if (pdi_id(pdi) == record_id)
268 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
273 /* Process one Plug Data Item - find corresponding PDR and plug it */
275 hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi)
279 /* Find the PDR corresponding to this PDI */
280 pdr = hermes_find_pdr(first_pdr, pdi_id(pdi));
282 /* No match is found, safe to ignore */
286 /* Lengths of the data in PDI and PDR must match */
287 if (pdi_len(pdi) != pdr_len(pdr))
290 /* do the actual plugging */
291 hermes_aux_setaddr(hw, pdr_addr(pdr));
292 hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
297 /* Read PDA from the adapter */
298 int hermes_read_pda(hermes_t *hw,
302 int use_eeprom) /* can we get this into hw? */
306 u16 data_len = pda_len;
310 /* PDA of spectrum symbol is in eeprom */
312 /* Issue command to read EEPROM */
313 ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
317 /* wl_lkm does not include PDA size in the PDA area.
318 * We will pad the information into pda, so other routines
319 * don't have to be modified */
320 pda[0] = cpu_to_le16(pda_len - 2);
321 /* Includes CFG_PROD_DATA but not itself */
322 pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
323 data_len = pda_len - 4;
327 /* Open auxiliary port */
328 ret = hermes_aux_control(hw, 1);
329 printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
333 /* read PDA from EEPROM */
334 hermes_aux_setaddr(hw, pda_addr);
335 hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
338 ret = hermes_aux_control(hw, 0);
339 printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
341 /* Check PDA length */
342 pda_size = le16_to_cpu(pda[0]);
343 printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
345 if (pda_size > pda_len)
350 EXPORT_SYMBOL(hermes_read_pda);
352 /* Parse PDA and write the records into the adapter
354 * Attempt to write every records that is in the specified pda
355 * which also has a valid production data record for the firmware.
357 int hermes_apply_pda(hermes_t *hw,
358 const char *first_pdr,
362 const struct pdi *pdi;
365 pdr = (struct pdr *) first_pdr;
367 /* Go through every PDI and plug them into the adapter */
368 pdi = (const struct pdi *) (pda + 2);
369 while (pdi_id(pdi) != PDI_END) {
370 ret = hermes_plug_pdi(hw, pdr, pdi);
374 /* Increment to the next PDI */
375 pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
379 EXPORT_SYMBOL(hermes_apply_pda);
381 /* Identify the total number of bytes in all blocks
382 * including the header data.
385 hermes_blocks_length(const char *first_block)
387 const struct dblock *blk = (const struct dblock *) first_block;
391 /* Skip all blocks to locate Plug Data References
393 while (dblock_addr(blk) != BLOCK_END) {
394 len = dblock_len(blk);
395 total_len += sizeof(*blk) + len;
396 blk = (struct dblock *) &blk->data[len];
401 EXPORT_SYMBOL(hermes_blocks_length);
403 /*** Hermes programming ***/
405 /* About to start programming data (Hermes I)
406 * offset is the entry point
408 * Spectrum_cs' Symbol fw does not require this
409 * wl_lkm Agere fw does
410 * Don't know about intersil
412 int hermesi_program_init(hermes_t *hw, u32 offset)
416 /* Disable interrupts?*/
418 /*hermes_write_regn(hw, INTEN, 0);*/
419 /*hermes_set_irqmask(hw, 0);*/
421 /* Acknowledge any outstanding command */
422 hermes_write_regn(hw, EVACK, 0xFFFF);
424 /* Using doicmd_wait rather than docmd_wait */
425 err = hermes_doicmd_wait(hw,
426 0x0100 | HERMES_CMD_INIT,
431 err = hermes_doicmd_wait(hw,
432 0x0000 | HERMES_CMD_INIT,
437 err = hermes_aux_control(hw, 1);
438 printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
443 printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
444 err = hermes_doicmd_wait(hw,
445 HERMES_PROGRAM_ENABLE_VOLATILE,
450 printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
455 EXPORT_SYMBOL(hermesi_program_init);
457 /* Done programming data (Hermes I)
459 * Spectrum_cs' Symbol fw does not require this
460 * wl_lkm Agere fw does
461 * Don't know about intersil
463 int hermesi_program_end(hermes_t *hw)
465 struct hermes_response resp;
469 rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
471 printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
472 "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
473 rc, resp.resp0, resp.resp1, resp.resp2);
476 ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
479 err = hermes_aux_control(hw, 0);
480 printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
482 /* Acknowledge any outstanding command */
483 hermes_write_regn(hw, EVACK, 0xFFFF);
485 /* Reinitialise, ignoring return */
486 (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
489 return rc ? rc : err;
491 EXPORT_SYMBOL(hermesi_program_end);
493 /* Program the data blocks */
494 int hermes_program(hermes_t *hw, const char *first_block, const char *end)
496 const struct dblock *blk;
499 #if LIMIT_PROGRAM_SIZE
504 blk = (const struct dblock *) first_block;
506 if ((const char *) blk > (end - sizeof(*blk)))
509 blkaddr = dblock_addr(blk);
510 blklen = dblock_len(blk);
512 while ((blkaddr != BLOCK_END) &&
513 (((const char *) blk + blklen) <= end)) {
514 printk(KERN_DEBUG PFX
515 "Programming block of length %d to address 0x%08x\n",
518 #if !LIMIT_PROGRAM_SIZE
519 /* wl_lkm driver splits this into writes of 2000 bytes */
520 hermes_aux_setaddr(hw, blkaddr);
521 hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
524 len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
527 while (addr < (blkaddr + blklen)) {
528 printk(KERN_DEBUG PFX
529 "Programming subblock of length %d "
530 "to address 0x%08x. Data @ %p\n",
531 len, addr, &blk->data[addr - blkaddr]);
533 hermes_aux_setaddr(hw, addr);
534 hermes_write_bytes(hw, HERMES_AUXDATA,
535 &blk->data[addr - blkaddr],
539 len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
540 (blkaddr + blklen - addr) : MAX_DL_SIZE;
543 blk = (const struct dblock *) &blk->data[blklen];
545 if ((const char *) blk > (end - sizeof(*blk)))
548 blkaddr = dblock_addr(blk);
549 blklen = dblock_len(blk);
553 EXPORT_SYMBOL(hermes_program);
555 static int __init init_hermes_dld(void)
560 static void __exit exit_hermes_dld(void)
564 module_init(init_hermes_dld);
565 module_exit(exit_hermes_dld);
567 /*** Default plugging data for Hermes I ***/
568 /* Values from wl_lkm_718/hcf/dhf.c */
570 #define DEFINE_DEFAULT_PDR(pid, length, data) \
571 static const struct { \
575 } __attribute__ ((packed)) default_pdr_data_##pid = { \
576 __constant_cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
577 sizeof(__le16)) - 1), \
578 __constant_cpu_to_le16(pid), \
582 #define DEFAULT_PDR(pid) default_pdr_data_##pid
584 /* HWIF Compatiblity */
585 DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
588 DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
591 DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
593 /* Antenna diversity */
594 DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
596 /* Modem VCO band Set-up */
597 DEFINE_DEFAULT_PDR(0x0160, 28,
598 "\x00\x00\x00\x00\x00\x00\x00\x00"
599 "\x00\x00\x00\x00\x00\x00\x00\x00"
600 "\x00\x00\x00\x00\x00\x00\x00\x00"
603 /* Modem Rx Gain Table Values */
604 DEFINE_DEFAULT_PDR(0x0161, 256,
605 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
606 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
607 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
608 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
609 "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
610 "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
611 "\x3B\x01\x3A\01\x3A\x01\x39\x01"
612 "\x39\x01\x38\01\x38\x01\x37\x01"
613 "\x37\x01\x36\01\x36\x01\x35\x01"
614 "\x35\x01\x34\01\x34\x01\x33\x01"
615 "\x33\x01\x32\x01\x32\x01\x31\x01"
616 "\x31\x01\x30\x01\x30\x01\x7B\x01"
617 "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
618 "\x79\x01\x78\x01\x78\x01\x77\x01"
619 "\x77\x01\x76\x01\x76\x01\x75\x01"
620 "\x75\x01\x74\x01\x74\x01\x73\x01"
621 "\x73\x01\x72\x01\x72\x01\x71\x01"
622 "\x71\x01\x70\x01\x70\x01\x68\x01"
623 "\x68\x01\x67\x01\x67\x01\x66\x01"
624 "\x66\x01\x65\x01\x65\x01\x57\x01"
625 "\x57\x01\x56\x01\x56\x01\x55\x01"
626 "\x55\x01\x54\x01\x54\x01\x53\x01"
627 "\x53\x01\x52\x01\x52\x01\x51\x01"
628 "\x51\x01\x50\x01\x50\x01\x48\x01"
629 "\x48\x01\x47\x01\x47\x01\x46\x01"
630 "\x46\x01\x45\x01\x45\x01\x44\x01"
631 "\x44\x01\x43\x01\x43\x01\x42\x01"
632 "\x42\x01\x41\x01\x41\x01\x40\x01"
633 "\x40\x01\x40\x01\x40\x01\x40\x01"
634 "\x40\x01\x40\x01\x40\x01\x40\x01"
635 "\x40\x01\x40\x01\x40\x01\x40\x01"
636 "\x40\x01\x40\x01\x40\x01\x40\x01");
638 /* Write PDA according to certain rules.
640 * For every production data record, look for a previous setting in
641 * the pda, and use that.
643 * For certain records, use defaults if they are not found in pda.
645 int hermes_apply_pda_with_defaults(hermes_t *hw,
646 const char *first_pdr,
649 const struct pdr *pdr = (const struct pdr *) first_pdr;
650 struct pdi *first_pdi = (struct pdi *) &pda[2];
652 struct pdi *default_pdi = NULL;
653 struct pdi *outdoor_pdi;
654 void *end = (void *)first_pdr + MAX_PDA_SIZE;
657 while (((void *)pdr < end) &&
658 (pdr_id(pdr) != PDI_END)) {
660 * For spectrum_cs firmwares,
661 * PDR area is currently not terminated by PDI_END.
662 * It's followed by CRC records, which have the type
663 * field where PDR has length. The type can be 0 or 1.
665 if (pdr_len(pdr) < 2)
667 record_id = pdr_id(pdr);
669 pdi = hermes_find_pdi(first_pdi, record_id);
671 printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
675 case 0x110: /* Modem REFDAC values */
676 case 0x120: /* Modem VGDAC values */
677 outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1);
681 printk(KERN_DEBUG PFX
682 "Using outdoor record 0x%04x at %p\n",
686 case 0x5: /* HWIF Compatiblity */
687 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
689 case 0x108: /* PPPPSign */
690 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
692 case 0x109: /* PPPPProf */
693 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
695 case 0x150: /* Antenna diversity */
696 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
698 case 0x160: /* Modem VCO band Set-up */
699 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
701 case 0x161: /* Modem Rx Gain Table Values */
702 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
708 if (!pdi && default_pdi) {
711 printk(KERN_DEBUG PFX
712 "Using default record 0x%04x at %p\n",
717 /* Lengths of the data in PDI and PDR must match */
718 if (pdi_len(pdi) == pdr_len(pdr)) {
719 /* do the actual plugging */
720 hermes_aux_setaddr(hw, pdr_addr(pdr));
721 hermes_write_bytes(hw, HERMES_AUXDATA,
722 pdi->data, pdi_len(pdi));
730 EXPORT_SYMBOL(hermes_apply_pda_with_defaults);