aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/hermes_dld.c285
-rw-r--r--drivers/net/wireless/hermes_dld.h5
2 files changed, 290 insertions, 0 deletions
diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c
index 22ae79dae41e..d8c626e61a3a 100644
--- a/drivers/net/wireless/hermes_dld.c
+++ b/drivers/net/wireless/hermes_dld.c
@@ -70,6 +70,12 @@ MODULE_LICENSE("Dual MPL/GPL");
70#define HERMES_AUX_PW1 0xDC23 70#define HERMES_AUX_PW1 0xDC23
71#define HERMES_AUX_PW2 0xBA45 71#define HERMES_AUX_PW2 0xBA45
72 72
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)
78
73/* End markers used in dblocks */ 79/* End markers used in dblocks */
74#define PDI_END 0x00000000 /* End of PDA */ 80#define PDI_END 0x00000000 /* End of PDA */
75#define BLOCK_END 0xFFFFFFFF /* Last image block */ 81#define BLOCK_END 0xFFFFFFFF /* Last image block */
@@ -247,6 +253,23 @@ hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
247 return NULL; 253 return NULL;
248} 254}
249 255
256/* Scan production data items for a particular entry */
257static struct pdi *
258hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
259{
260 struct pdi *pdi = first_pdi;
261
262 while (pdi_id(pdi) != PDI_END) {
263
264 /* If the record ID matches, we are done */
265 if (pdi_id(pdi) == record_id)
266 return pdi;
267
268 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
269 }
270 return NULL;
271}
272
250/* Process one Plug Data Item - find corresponding PDR and plug it */ 273/* Process one Plug Data Item - find corresponding PDR and plug it */
251static int 274static int
252hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) 275hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi)
@@ -290,6 +313,15 @@ int hermes_read_pda(hermes_t *hw,
290 ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); 313 ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
291 if (ret) 314 if (ret)
292 return ret; 315 return ret;
316 } else {
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;
324 data = pda + 2;
293 } 325 }
294 326
295 /* Open auxiliary port */ 327 /* Open auxiliary port */
@@ -370,6 +402,94 @@ EXPORT_SYMBOL(hermes_blocks_length);
370 402
371/*** Hermes programming ***/ 403/*** Hermes programming ***/
372 404
405/* About to start programming data (Hermes I)
406 * offset is the entry point
407 *
408 * Spectrum_cs' Symbol fw does not require this
409 * wl_lkm Agere fw does
410 * Don't know about intersil
411 */
412int hermesi_program_init(hermes_t *hw, u32 offset)
413{
414 int err;
415
416 /* Disable interrupts?*/
417 /*hw->inten = 0x0;*/
418 /*hermes_write_regn(hw, INTEN, 0);*/
419 /*hermes_set_irqmask(hw, 0);*/
420
421 /* Acknowledge any outstanding command */
422 hermes_write_regn(hw, EVACK, 0xFFFF);
423
424 /* Using doicmd_wait rather than docmd_wait */
425 err = hermes_doicmd_wait(hw,
426 0x0100 | HERMES_CMD_INIT,
427 0, 0, 0, NULL);
428 if (err)
429 return err;
430
431 err = hermes_doicmd_wait(hw,
432 0x0000 | HERMES_CMD_INIT,
433 0, 0, 0, NULL);
434 if (err)
435 return err;
436
437 err = hermes_aux_control(hw, 1);
438 printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
439
440 if (err)
441 return err;
442
443 printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
444 err = hermes_doicmd_wait(hw,
445 HERMES_PROGRAM_ENABLE_VOLATILE,
446 offset & 0xFFFFu,
447 offset >> 16,
448 0,
449 NULL);
450 printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
451 err);
452
453 return err;
454}
455EXPORT_SYMBOL(hermesi_program_init);
456
457/* Done programming data (Hermes I)
458 *
459 * Spectrum_cs' Symbol fw does not require this
460 * wl_lkm Agere fw does
461 * Don't know about intersil
462 */
463int hermesi_program_end(hermes_t *hw)
464{
465 struct hermes_response resp;
466 int rc = 0;
467 int err;
468
469 rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
470
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);
474
475 if ((rc == 0) &&
476 ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
477 rc = -EIO;
478
479 err = hermes_aux_control(hw, 0);
480 printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
481
482 /* Acknowledge any outstanding command */
483 hermes_write_regn(hw, EVACK, 0xFFFF);
484
485 /* Reinitialise, ignoring return */
486 (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
487 0, 0, 0, NULL);
488
489 return rc ? rc : err;
490}
491EXPORT_SYMBOL(hermesi_program_end);
492
373/* Program the data blocks */ 493/* Program the data blocks */
374int hermes_program(hermes_t *hw, const char *first_block, const char *end) 494int hermes_program(hermes_t *hw, const char *first_block, const char *end)
375{ 495{
@@ -443,3 +563,168 @@ static void __exit exit_hermes_dld(void)
443 563
444module_init(init_hermes_dld); 564module_init(init_hermes_dld);
445module_exit(exit_hermes_dld); 565module_exit(exit_hermes_dld);
566
567/*** Default plugging data for Hermes I ***/
568/* Values from wl_lkm_718/hcf/dhf.c */
569
570#define DEFINE_DEFAULT_PDR(pid, length, data) \
571static const struct { \
572 __le16 len; \
573 __le16 id; \
574 u8 val[length]; \
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), \
579 data \
580}
581
582#define DEFAULT_PDR(pid) default_pdr_data_##pid
583
584/* HWIF Compatiblity */
585DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
586
587/* PPPPSign */
588DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
589
590/* PPPPProf */
591DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
592
593/* Antenna diversity */
594DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
595
596/* Modem VCO band Set-up */
597DEFINE_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"
601 "\x00\x00\x00\x00");
602
603/* Modem Rx Gain Table Values */
604DEFINE_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");
637
638/* Write PDA according to certain rules.
639 *
640 * For every production data record, look for a previous setting in
641 * the pda, and use that.
642 *
643 * For certain records, use defaults if they are not found in pda.
644 */
645int hermes_apply_pda_with_defaults(hermes_t *hw,
646 const char *first_pdr,
647 const __le16 *pda)
648{
649 const struct pdr *pdr = (const struct pdr *) first_pdr;
650 struct pdi *first_pdi = (struct pdi *) &pda[2];
651 struct pdi *pdi;
652 struct pdi *default_pdi = NULL;
653 struct pdi *outdoor_pdi;
654 void *end = (void *)first_pdr + MAX_PDA_SIZE;
655 int record_id;
656
657 while (((void *)pdr < end) &&
658 (pdr_id(pdr) != PDI_END)) {
659 /*
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.
664 */
665 if (pdr_len(pdr) < 2)
666 break;
667 record_id = pdr_id(pdr);
668
669 pdi = hermes_find_pdi(first_pdi, record_id);
670 if (pdi)
671 printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
672 record_id, pdi);
673
674 switch (record_id) {
675 case 0x110: /* Modem REFDAC values */
676 case 0x120: /* Modem VGDAC values */
677 outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1);
678 default_pdi = NULL;
679 if (outdoor_pdi) {
680 pdi = outdoor_pdi;
681 printk(KERN_DEBUG PFX
682 "Using outdoor record 0x%04x at %p\n",
683 record_id + 1, pdi);
684 }
685 break;
686 case 0x5: /* HWIF Compatiblity */
687 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
688 break;
689 case 0x108: /* PPPPSign */
690 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
691 break;
692 case 0x109: /* PPPPProf */
693 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
694 break;
695 case 0x150: /* Antenna diversity */
696 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
697 break;
698 case 0x160: /* Modem VCO band Set-up */
699 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
700 break;
701 case 0x161: /* Modem Rx Gain Table Values */
702 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
703 break;
704 default:
705 default_pdi = NULL;
706 break;
707 }
708 if (!pdi && default_pdi) {
709 /* Use default */
710 pdi = default_pdi;
711 printk(KERN_DEBUG PFX
712 "Using default record 0x%04x at %p\n",
713 record_id, pdi);
714 }
715
716 if (pdi) {
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));
723 }
724 }
725
726 pdr++;
727 }
728 return 0;
729}
730EXPORT_SYMBOL(hermes_apply_pda_with_defaults);
diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h
index af75c030b11b..6fcb26277999 100644
--- a/drivers/net/wireless/hermes_dld.h
+++ b/drivers/net/wireless/hermes_dld.h
@@ -27,6 +27,8 @@
27 27
28#include "hermes.h" 28#include "hermes.h"
29 29
30int hermesi_program_init(hermes_t *hw, u32 offset);
31int hermesi_program_end(hermes_t *hw);
30int hermes_program(hermes_t *hw, const char *first_block, const char *end); 32int hermes_program(hermes_t *hw, const char *first_block, const char *end);
31 33
32int hermes_read_pda(hermes_t *hw, 34int hermes_read_pda(hermes_t *hw,
@@ -37,6 +39,9 @@ int hermes_read_pda(hermes_t *hw,
37int hermes_apply_pda(hermes_t *hw, 39int hermes_apply_pda(hermes_t *hw,
38 const char *first_pdr, 40 const char *first_pdr,
39 const __le16 *pda); 41 const __le16 *pda);
42int hermes_apply_pda_with_defaults(hermes_t *hw,
43 const char *first_pdr,
44 const __le16 *pda);
40 45
41size_t hermes_blocks_length(const char *first_block); 46size_t hermes_blocks_length(const char *first_block);
42 47