diff options
Diffstat (limited to 'drivers/ssb/pci.c')
-rw-r--r-- | drivers/ssb/pci.c | 118 |
1 files changed, 84 insertions, 34 deletions
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 6e88d2b603b4..7ad48585c5e6 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c | |||
@@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) | |||
406 | out->antenna_gain.ghz5.a3 = gain; | 406 | out->antenna_gain.ghz5.a3 = gain; |
407 | } | 407 | } |
408 | 408 | ||
409 | /* Revs 4 5 and 8 have partially shared layout */ | ||
410 | static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in) | ||
411 | { | ||
412 | SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, | ||
413 | SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT); | ||
414 | SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, | ||
415 | SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT); | ||
416 | SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, | ||
417 | SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT); | ||
418 | SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, | ||
419 | SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT); | ||
420 | |||
421 | SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, | ||
422 | SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT); | ||
423 | SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, | ||
424 | SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT); | ||
425 | SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, | ||
426 | SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT); | ||
427 | SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, | ||
428 | SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT); | ||
429 | |||
430 | SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, | ||
431 | SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT); | ||
432 | SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, | ||
433 | SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT); | ||
434 | SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, | ||
435 | SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT); | ||
436 | SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, | ||
437 | SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT); | ||
438 | |||
439 | SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, | ||
440 | SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT); | ||
441 | SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, | ||
442 | SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT); | ||
443 | SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, | ||
444 | SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT); | ||
445 | SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, | ||
446 | SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT); | ||
447 | } | ||
448 | |||
409 | static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) | 449 | static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) |
410 | { | 450 | { |
411 | int i; | 451 | int i; |
@@ -428,10 +468,14 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) | |||
428 | SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); | 468 | SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); |
429 | SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); | 469 | SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); |
430 | SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); | 470 | SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); |
471 | SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); | ||
472 | SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); | ||
431 | } else { | 473 | } else { |
432 | SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0); | 474 | SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0); |
433 | SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); | 475 | SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); |
434 | SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); | 476 | SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); |
477 | SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); | ||
478 | SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0); | ||
435 | } | 479 | } |
436 | SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, | 480 | SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, |
437 | SSB_SPROM4_ANTAVAIL_A_SHIFT); | 481 | SSB_SPROM4_ANTAVAIL_A_SHIFT); |
@@ -471,6 +515,8 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) | |||
471 | memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24, | 515 | memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24, |
472 | sizeof(out->antenna_gain.ghz5)); | 516 | sizeof(out->antenna_gain.ghz5)); |
473 | 517 | ||
518 | sprom_extract_r458(out, in); | ||
519 | |||
474 | /* TODO - get remaining rev 4 stuff needed */ | 520 | /* TODO - get remaining rev 4 stuff needed */ |
475 | } | 521 | } |
476 | 522 | ||
@@ -561,6 +607,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) | |||
561 | memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24, | 607 | memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24, |
562 | sizeof(out->antenna_gain.ghz5)); | 608 | sizeof(out->antenna_gain.ghz5)); |
563 | 609 | ||
610 | sprom_extract_r458(out, in); | ||
611 | |||
564 | /* TODO - get remaining rev 8 stuff needed */ | 612 | /* TODO - get remaining rev 8 stuff needed */ |
565 | } | 613 | } |
566 | 614 | ||
@@ -573,37 +621,34 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, | |||
573 | ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision); | 621 | ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision); |
574 | memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */ | 622 | memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */ |
575 | memset(out->et1mac, 0xFF, 6); | 623 | memset(out->et1mac, 0xFF, 6); |
624 | |||
576 | if ((bus->chip_id & 0xFF00) == 0x4400) { | 625 | if ((bus->chip_id & 0xFF00) == 0x4400) { |
577 | /* Workaround: The BCM44XX chip has a stupid revision | 626 | /* Workaround: The BCM44XX chip has a stupid revision |
578 | * number stored in the SPROM. | 627 | * number stored in the SPROM. |
579 | * Always extract r1. */ | 628 | * Always extract r1. */ |
580 | out->revision = 1; | 629 | out->revision = 1; |
630 | ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision); | ||
631 | } | ||
632 | |||
633 | switch (out->revision) { | ||
634 | case 1: | ||
635 | case 2: | ||
636 | case 3: | ||
581 | sprom_extract_r123(out, in); | 637 | sprom_extract_r123(out, in); |
582 | } else if (bus->chip_id == 0x4321) { | 638 | break; |
583 | /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */ | 639 | case 4: |
584 | out->revision = 4; | 640 | case 5: |
585 | sprom_extract_r45(out, in); | 641 | sprom_extract_r45(out, in); |
586 | } else { | 642 | break; |
587 | switch (out->revision) { | 643 | case 8: |
588 | case 1: | 644 | sprom_extract_r8(out, in); |
589 | case 2: | 645 | break; |
590 | case 3: | 646 | default: |
591 | sprom_extract_r123(out, in); | 647 | ssb_printk(KERN_WARNING PFX "Unsupported SPROM" |
592 | break; | 648 | " revision %d detected. Will extract" |
593 | case 4: | 649 | " v1\n", out->revision); |
594 | case 5: | 650 | out->revision = 1; |
595 | sprom_extract_r45(out, in); | 651 | sprom_extract_r123(out, in); |
596 | break; | ||
597 | case 8: | ||
598 | sprom_extract_r8(out, in); | ||
599 | break; | ||
600 | default: | ||
601 | ssb_printk(KERN_WARNING PFX "Unsupported SPROM" | ||
602 | " revision %d detected. Will extract" | ||
603 | " v1\n", out->revision); | ||
604 | out->revision = 1; | ||
605 | sprom_extract_r123(out, in); | ||
606 | } | ||
607 | } | 652 | } |
608 | 653 | ||
609 | if (out->boardflags_lo == 0xFFFF) | 654 | if (out->boardflags_lo == 0xFFFF) |
@@ -617,15 +662,14 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, | |||
617 | static int ssb_pci_sprom_get(struct ssb_bus *bus, | 662 | static int ssb_pci_sprom_get(struct ssb_bus *bus, |
618 | struct ssb_sprom *sprom) | 663 | struct ssb_sprom *sprom) |
619 | { | 664 | { |
620 | const struct ssb_sprom *fallback; | 665 | int err; |
621 | int err = -ENOMEM; | ||
622 | u16 *buf; | 666 | u16 *buf; |
623 | 667 | ||
624 | if (!ssb_is_sprom_available(bus)) { | 668 | if (!ssb_is_sprom_available(bus)) { |
625 | ssb_printk(KERN_ERR PFX "No SPROM available!\n"); | 669 | ssb_printk(KERN_ERR PFX "No SPROM available!\n"); |
626 | return -ENODEV; | 670 | return -ENODEV; |
627 | } | 671 | } |
628 | if (bus->chipco.dev) { /* can be unavailible! */ | 672 | if (bus->chipco.dev) { /* can be unavailable! */ |
629 | /* | 673 | /* |
630 | * get SPROM offset: SSB_SPROM_BASE1 except for | 674 | * get SPROM offset: SSB_SPROM_BASE1 except for |
631 | * chipcommon rev >= 31 or chip ID is 0x4312 and | 675 | * chipcommon rev >= 31 or chip ID is 0x4312 and |
@@ -645,7 +689,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, | |||
645 | 689 | ||
646 | buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); | 690 | buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); |
647 | if (!buf) | 691 | if (!buf) |
648 | goto out; | 692 | return -ENOMEM; |
649 | bus->sprom_size = SSB_SPROMSIZE_WORDS_R123; | 693 | bus->sprom_size = SSB_SPROMSIZE_WORDS_R123; |
650 | sprom_do_read(bus, buf); | 694 | sprom_do_read(bus, buf); |
651 | err = sprom_check_crc(buf, bus->sprom_size); | 695 | err = sprom_check_crc(buf, bus->sprom_size); |
@@ -655,17 +699,24 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, | |||
655 | buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), | 699 | buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), |
656 | GFP_KERNEL); | 700 | GFP_KERNEL); |
657 | if (!buf) | 701 | if (!buf) |
658 | goto out; | 702 | return -ENOMEM; |
659 | bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; | 703 | bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; |
660 | sprom_do_read(bus, buf); | 704 | sprom_do_read(bus, buf); |
661 | err = sprom_check_crc(buf, bus->sprom_size); | 705 | err = sprom_check_crc(buf, bus->sprom_size); |
662 | if (err) { | 706 | if (err) { |
663 | /* All CRC attempts failed. | 707 | /* All CRC attempts failed. |
664 | * Maybe there is no SPROM on the device? | 708 | * Maybe there is no SPROM on the device? |
665 | * If we have a fallback, use that. */ | 709 | * Now we ask the arch code if there is some sprom |
666 | fallback = ssb_get_fallback_sprom(); | 710 | * available for this device in some other storage */ |
667 | if (fallback) { | 711 | err = ssb_fill_sprom_with_fallback(bus, sprom); |
668 | memcpy(sprom, fallback, sizeof(*sprom)); | 712 | if (err) { |
713 | ssb_printk(KERN_WARNING PFX "WARNING: Using" | ||
714 | " fallback SPROM failed (err %d)\n", | ||
715 | err); | ||
716 | } else { | ||
717 | ssb_dprintk(KERN_DEBUG PFX "Using SPROM" | ||
718 | " revision %d provided by" | ||
719 | " platform.\n", sprom->revision); | ||
669 | err = 0; | 720 | err = 0; |
670 | goto out_free; | 721 | goto out_free; |
671 | } | 722 | } |
@@ -677,7 +728,6 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, | |||
677 | 728 | ||
678 | out_free: | 729 | out_free: |
679 | kfree(buf); | 730 | kfree(buf); |
680 | out: | ||
681 | return err; | 731 | return err; |
682 | } | 732 | } |
683 | 733 | ||