| | 202 | #define AR5K_RESET_CTL 0x4000 /* Register Address */ |
|---|
| | 203 | #define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */ |
|---|
| | 204 | #define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset -5210 only */ |
|---|
| | 205 | #define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset (5211/5212) */ |
|---|
| | 206 | #define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) -5210 only */ |
|---|
| | 207 | #define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset -5210 only */ |
|---|
| | 208 | #define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ |
|---|
| | 209 | #define AR5K_RESET_CTL_CHIP (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA | \ |
|---|
| | 210 | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY) |
|---|
| | 211 | |
|---|
| | 212 | /* |
|---|
| | 213 | * Sleep control register |
|---|
| | 214 | */ |
|---|
| | 215 | #define AR5K_SLEEP_CTL 0x4004 /*Register Address*/ |
|---|
| | 216 | #define AR5K_SLEEP_CTL_SLDUR 0x0000ffff /*Sleep duration mask*/ |
|---|
| | 217 | #define AR5K_SLEEP_CTL_SLDUR_S 0 |
|---|
| | 218 | #define AR5K_SLEEP_CTL_SLE 0x00030000 /*Sleep enable mask*/ |
|---|
| | 219 | #define AR5K_SLEEP_CTL_SLE_S 16 |
|---|
| | 220 | #define AR5K_SLEEP_CTL_SLE_WAKE 0x00000000 /*Force chip awake*/ |
|---|
| | 221 | #define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /*Force chip sleep*/ |
|---|
| | 222 | #define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 |
|---|
| | 223 | #define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /*non 5210*/ |
|---|
| | 224 | |
|---|
| | 415 | * Write to EEPROM |
|---|
| | 416 | */ |
|---|
| | 417 | int |
|---|
| | 418 | ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data, |
|---|
| | 419 | u_int8_t mac_version) |
|---|
| | 420 | { |
|---|
| | 421 | u_int32_t status, timeout; |
|---|
| | 422 | |
|---|
| | 423 | /* |
|---|
| | 424 | * Initialize EEPROM access |
|---|
| | 425 | */ |
|---|
| | 426 | |
|---|
| | 427 | if (mac_version == AR5K_SREV_VER_AR5210) { |
|---|
| | 428 | |
|---|
| | 429 | AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE); |
|---|
| | 430 | |
|---|
| | 431 | /* data to write */ |
|---|
| | 432 | (void)AR5K_REG_WRITE(AR5K_EEPROM_BASE + (4 * offset), data); |
|---|
| | 433 | |
|---|
| | 434 | } else { |
|---|
| | 435 | /* != 5210 */ |
|---|
| | 436 | /* reset eeprom access */ |
|---|
| | 437 | AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_RESET); |
|---|
| | 438 | usleep(5); |
|---|
| | 439 | |
|---|
| | 440 | AR5K_REG_WRITE(AR5K_EEPROM_DATA, data); |
|---|
| | 441 | |
|---|
| | 442 | /* set offset in EEPROM to write to */ |
|---|
| | 443 | AR5K_REG_WRITE(AR5K_EEPROM_BASE, offset); |
|---|
| | 444 | usleep(5); |
|---|
| | 445 | |
|---|
| | 446 | /* issue write command */ |
|---|
| | 447 | AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_WRITE); |
|---|
| | 448 | } |
|---|
| | 449 | |
|---|
| | 450 | for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { |
|---|
| | 451 | status = AR5K_REG_READ(AR5K_EEPROM_STATUS); |
|---|
| | 452 | if (status & AR5K_EEPROM_STAT_WRDONE) { |
|---|
| | 453 | if (status & AR5K_EEPROM_STAT_WRERR) { |
|---|
| | 454 | err("eeprom write access to 0x%04x failed", offset); |
|---|
| | 455 | return 1; |
|---|
| | 456 | } |
|---|
| | 457 | return 0; |
|---|
| | 458 | } |
|---|
| | 459 | usleep(15); |
|---|
| | 460 | } |
|---|
| | 461 | |
|---|
| | 462 | return 1; |
|---|
| | 463 | } |
|---|
| | 464 | |
|---|
| | 465 | |
|---|
| | 466 | /* |
|---|
| | 522 | /* returns -1 on unknown name */ |
|---|
| | 523 | int eeprom_name2addr(const char *name) |
|---|
| | 524 | { |
|---|
| | 525 | int i; |
|---|
| | 526 | if (!name || !name[0]) |
|---|
| | 527 | return -1; |
|---|
| | 528 | for(i=0; i < eeprom_addr_len; i++) |
|---|
| | 529 | if (!strcmp(name, eeprom_addr[i].name)) |
|---|
| | 530 | return eeprom_addr[i].addr; |
|---|
| | 531 | return -1; |
|---|
| | 532 | } /* eeprom_name2addr */ |
|---|
| | 533 | |
|---|
| | 534 | /* returns "<unknown>" on unknown address */ |
|---|
| | 535 | const char *eeprom_addr2name(int addr) |
|---|
| | 536 | { |
|---|
| | 537 | int i; |
|---|
| | 538 | for(i=0; i < eeprom_addr_len; i++) |
|---|
| | 539 | if (eeprom_addr[i].addr == addr) |
|---|
| | 540 | return eeprom_addr[i].name; |
|---|
| | 541 | return "<unknown>"; |
|---|
| | 542 | } /* eeprom_addr2name */ |
|---|
| | 543 | |
|---|
| | 544 | |
|---|
| | 545 | static int |
|---|
| | 546 | do_write_pairs(int anr, int argc, char **argv, unsigned char *mem, int mac_version) |
|---|
| | 547 | { |
|---|
| | 548 | #define MAX_NR_WRITES 16 |
|---|
| | 549 | struct { |
|---|
| | 550 | int addr; |
|---|
| | 551 | unsigned int val; |
|---|
| | 552 | } wr_ops[MAX_NR_WRITES]; |
|---|
| | 553 | int wr_ops_len = 0; |
|---|
| | 554 | int i; |
|---|
| | 555 | char *end; |
|---|
| | 556 | int errors = 0; /* count errors during write/verify */ |
|---|
| | 557 | |
|---|
| | 558 | if (anr >= argc) { |
|---|
| | 559 | err("missing values to write."); |
|---|
| | 560 | usage(argv[0]); |
|---|
| | 561 | return 1; |
|---|
| | 562 | } |
|---|
| | 563 | |
|---|
| | 564 | if ((argc-anr) % 2) { |
|---|
| | 565 | err("write spec. needs an even number of arguments."); |
|---|
| | 566 | usage(argv[0]); |
|---|
| | 567 | return 2; |
|---|
| | 568 | } |
|---|
| | 569 | |
|---|
| | 570 | if ((argc-anr)/2 > MAX_NR_WRITES) { |
|---|
| | 571 | err("too many values to write (max. %d)", MAX_NR_WRITES); |
|---|
| | 572 | return 3; |
|---|
| | 573 | } |
|---|
| | 574 | |
|---|
| | 575 | /* get the (addr,val) pairs we have to write */ |
|---|
| | 576 | i=0; |
|---|
| | 577 | while (anr < (argc-1)) { |
|---|
| | 578 | wr_ops[i].addr = strtoul(argv[anr], &end, 0); |
|---|
| | 579 | if (end == argv[anr]) { |
|---|
| | 580 | /* maybe a symbolic name for the address ? */ |
|---|
| | 581 | if ((wr_ops[i].addr = eeprom_name2addr(argv[anr])) == -1) { |
|---|
| | 582 | err("pair %d: bad address %s", i, argv[anr]); |
|---|
| | 583 | return 4; |
|---|
| | 584 | } |
|---|
| | 585 | } |
|---|
| | 586 | |
|---|
| | 587 | if (wr_ops[i].addr >= AR5K_EEPROM_INFO_BASE) { |
|---|
| | 588 | err("offset 0x%04x in CRC protected area is not supported", |
|---|
| | 589 | wr_ops[i].addr); |
|---|
| | 590 | return 5; |
|---|
| | 591 | } |
|---|
| | 592 | |
|---|
| | 593 | anr++; |
|---|
| | 594 | wr_ops[i].val = strtoul(argv[anr], &end, 0); |
|---|
| | 595 | if (end == argv[anr]) { |
|---|
| | 596 | err("pair %d: bad val %s", i, argv[anr]); |
|---|
| | 597 | return 5; |
|---|
| | 598 | } |
|---|
| | 599 | |
|---|
| | 600 | if (wr_ops[i].val > 0xffff) { |
|---|
| | 601 | err("pair %d: value %u too large", i, wr_ops[i].val); |
|---|
| | 602 | return 6; |
|---|
| | 603 | } |
|---|
| | 604 | anr++; |
|---|
| | 605 | i++; |
|---|
| | 606 | } /* while (anr < (argc-1)) */ |
|---|
| | 607 | |
|---|
| | 608 | if (!(wr_ops_len=i)) { |
|---|
| | 609 | err("no (addr,val) pairs given"); |
|---|
| | 610 | return 7; |
|---|
| | 611 | } |
|---|
| | 612 | |
|---|
| | 613 | if (verbose || !force_write) { |
|---|
| | 614 | for(i=0; i < wr_ops_len; i++) |
|---|
| | 615 | printf("%20s (0x%04x) := 0x%04x\n", |
|---|
| | 616 | eeprom_addr2name(wr_ops[i].addr), wr_ops[i].addr, wr_ops[i].val); |
|---|
| | 617 | } |
|---|
| | 618 | |
|---|
| | 619 | if (!force_write) { |
|---|
| | 620 | int c; |
|---|
| | 621 | printf( |
|---|
| | 622 | "WARNING: The write function may easy brick your device or\n" |
|---|
| | 623 | "violate state regulation on frequency usage.\n" |
|---|
| | 624 | "Proceed on your own risk!\n" |
|---|
| | 625 | "Shall I write the above value(s)? (y/n)\n"); |
|---|
| | 626 | c=getchar(); |
|---|
| | 627 | if (c != 'y' && c != 'Y') { |
|---|
| | 628 | printf("user abort\n"); |
|---|
| | 629 | return 0; |
|---|
| | 630 | } |
|---|
| | 631 | } |
|---|
| | 632 | |
|---|
| | 633 | for(i=0; i < wr_ops_len; i++) { |
|---|
| | 634 | u_int16_t oldval,u; |
|---|
| | 635 | |
|---|
| | 636 | if (ath5k_hw_eeprom_read(mem, wr_ops[i].addr, &oldval, mac_version)) { |
|---|
| | 637 | err("failed to read old value from offset 0x%04x ", wr_ops[i].addr); |
|---|
| | 638 | errors++; |
|---|
| | 639 | } |
|---|
| | 640 | |
|---|
| | 641 | if (oldval == wr_ops[i].val) { |
|---|
| | 642 | dbg("pair %d: skipped, value already there", i); |
|---|
| | 643 | continue; |
|---|
| | 644 | } |
|---|
| | 645 | |
|---|
| | 646 | dbg("writing *0x%04x := 0x%04x", wr_ops[i].addr, wr_ops[i].val); |
|---|
| | 647 | if (ath5k_hw_eeprom_write(mem, wr_ops[i].addr, wr_ops[i].val, mac_version)) { |
|---|
| | 648 | err("failed to write 0x%04x to offset 0x%04x", |
|---|
| | 649 | wr_ops[i].val, wr_ops[i].addr); |
|---|
| | 650 | errors++; |
|---|
| | 651 | } else { |
|---|
| | 652 | if (ath5k_hw_eeprom_read(mem, wr_ops[i].addr, &u, mac_version)) { |
|---|
| | 653 | err("failed to read offset 0x%04x for verification", wr_ops[i].addr); |
|---|
| | 654 | errors++; |
|---|
| | 655 | } else { |
|---|
| | 656 | if (u != wr_ops[i].val) { |
|---|
| | 657 | err("offset 0x%04x: wrote 0x%04x but read 0x%04x", |
|---|
| | 658 | wr_ops[i].addr, wr_ops[i].val, u); |
|---|
| | 659 | errors++; |
|---|
| | 660 | } |
|---|
| | 661 | } |
|---|
| | 662 | } |
|---|
| | 663 | } |
|---|
| | 664 | |
|---|
| | 665 | return errors ? 11 : 0; |
|---|
| | 666 | } /* do_write_pairs */ |
|---|
| | 667 | |
|---|
| | 668 | static void |
|---|
| | 669 | usage(const char *n) |
|---|
| | 670 | { |
|---|
| | 671 | int i; |
|---|
| | 672 | |
|---|
| | 673 | fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] <base_address> " |
|---|
| | 674 | "[<name1> <val1> [<name2> <val2> ...]]\n\n", n); |
|---|
| | 675 | fprintf(stderr, |
|---|
| | 676 | "-w write values into EEPROM\n" |
|---|
| | 677 | "-g N:M set GPIO N to level M (only used with -w)\n" |
|---|
| | 678 | "-v verbose output\n" |
|---|
| | 679 | "-f force; suppress question before writing\n" |
|---|
| | 680 | "<base_address> device base address (see lspci output)\n\n"); |
|---|
| | 681 | |
|---|
| | 682 | fprintf(stderr, |
|---|
| | 683 | "- read info:\n" |
|---|
| | 684 | " %s <base_address>\n\n" |
|---|
| | 685 | "- set regdomain to N:\n" |
|---|
| | 686 | " %s -w <base_address> regdomain N\n\n" |
|---|
| | 687 | "- set a PCI id field to value N:\n" |
|---|
| | 688 | " %s -w <base_address> <field> N\n" |
|---|
| | 689 | " where <field> is on of:\n ", n,n,n); |
|---|
| | 690 | for(i=0; i < eeprom_addr_len; i++) |
|---|
| | 691 | fprintf(stderr, " %s", eeprom_addr[i].name); |
|---|
| | 692 | fprintf(stderr,"\n\n"); |
|---|
| | 693 | fprintf(stderr, |
|---|
| | 694 | "You may need to set a GPIO to a certain value in order to enable\n" |
|---|
| | 695 | "writing to the EEPROM with newer chipsets, e.g. set GPIO 4 to low:\n" |
|---|
| | 696 | " %s -g 4:0 -w <base_address> regdomain N\n", n); |
|---|
| | 697 | fprintf(stderr, |
|---|
| | 698 | "\nDISCLAIMER: The authors are not responsible for any damages caused by\n" |
|---|
| | 699 | "this program. Writing improper values may damage the card or cause\n" |
|---|
| | 700 | "unlawful radio transmissions!\n\n"); |
|---|
| | 701 | } |
|---|
| | 702 | |
|---|
| | 977 | |
|---|
| | 978 | /* print current GPIO settings */ |
|---|
| | 979 | printf("GPIO registers: CR %08lx DO %08lx DI %08lx\n", |
|---|
| | 980 | AR5K_REG_READ(AR5K_GPIOCR), AR5K_REG_READ(AR5K_GPIODO), |
|---|
| | 981 | AR5K_REG_READ(AR5K_GPIODI)); |
|---|
| | 982 | |
|---|
| | 983 | if (do_write) { |
|---|
| | 984 | unsigned long int rcr=AR5K_REG_READ(AR5K_GPIOCR), |
|---|
| | 985 | rdo=AR5K_REG_READ(AR5K_GPIODO); |
|---|
| | 986 | unsigned long int old_cr=rcr, old_do= rdo; |
|---|
| | 987 | int rc; |
|---|
| | 988 | |
|---|
| | 989 | if (mac_version >= AR5K_SREV_VER_AR5213 && !nr_gpio_set) { |
|---|
| | 990 | dbg("new MAC %x (>= AR5213) set gpio4 to low", mac_version); |
|---|
| | 991 | gpio_set[4].valid=1; |
|---|
| | 992 | gpio_set[4].value=0; |
|---|
| | 993 | } |
|---|
| | 994 | |
|---|
| | 995 | /* set gpios */ |
|---|
| | 996 | dbg("old GPIO CR %08lx DO %08lx DI %08lx", |
|---|
| | 997 | rcr, rdo, AR5K_REG_READ(AR5K_GPIODI)); |
|---|
| | 998 | |
|---|
| | 999 | for(i=0; i < sizeof(gpio_set)/sizeof(gpio_set[0]); i++) { |
|---|
| | 1000 | if (gpio_set[i].valid) { |
|---|
| | 1001 | rcr |= AR5K_GPIOCR_OUT(i); /* we use mode 3 */ |
|---|
| | 1002 | rcr &= ~AR5K_GPIOCR_INT_SEL(i); |
|---|
| | 1003 | rdo &= ~(1<<i); |
|---|
| | 1004 | rdo |= (gpio_set[i].value<<i); |
|---|
| | 1005 | } |
|---|
| | 1006 | } |
|---|
| | 1007 | |
|---|
| | 1008 | if (rcr != old_cr) { |
|---|
| | 1009 | dbg("GPIO CR %lx -> %lx", old_cr, rcr); |
|---|
| | 1010 | AR5K_REG_WRITE(AR5K_GPIOCR, rcr); |
|---|
| | 1011 | } |
|---|
| | 1012 | usleep(5); |
|---|
| | 1013 | |
|---|
| | 1014 | if (rdo != old_do) { |
|---|
| | 1015 | dbg("GPIO CR %lx -> %lx", old_do, rdo); |
|---|
| | 1016 | AR5K_REG_WRITE(AR5K_GPIODO, rdo); |
|---|
| | 1017 | } |
|---|
| | 1018 | |
|---|
| | 1019 | /*dump current values again if we have written anything */ |
|---|
| | 1020 | if (rcr != old_cr || rdo != old_do) |
|---|
| | 1021 | dbg("new GPIO CR %08lx DO %08lx DI %08lx", |
|---|
| | 1022 | AR5K_REG_READ(AR5K_GPIOCR), |
|---|
| | 1023 | AR5K_REG_READ(AR5K_GPIODO), |
|---|
| | 1024 | AR5K_REG_READ(AR5K_GPIODI)); |
|---|
| | 1025 | |
|---|
| | 1026 | /* let argv[anr] be the first write parameter */ |
|---|
| | 1027 | anr++; |
|---|
| | 1028 | |
|---|
| | 1029 | rc=do_write_pairs(anr, argc, argv, mem, mac_version); |
|---|
| | 1030 | |
|---|
| | 1031 | /* restore old GPIO settings */ |
|---|
| | 1032 | if (rcr != old_cr) { |
|---|
| | 1033 | dbg("restoring GPIO CR %lx -> %lx", rcr, old_cr); |
|---|
| | 1034 | AR5K_REG_WRITE(AR5K_GPIOCR, old_cr); |
|---|
| | 1035 | } |
|---|
| | 1036 | usleep(5); |
|---|
| | 1037 | |
|---|
| | 1038 | if (rdo != old_do) { |
|---|
| | 1039 | dbg("restoring GPIO CR %lx -> %lx", rdo, old_do); |
|---|
| | 1040 | AR5K_REG_WRITE(AR5K_GPIODO, old_do); |
|---|
| | 1041 | } |
|---|
| | 1042 | |
|---|
| | 1043 | return rc; |
|---|
| | 1044 | } |
|---|