diff --git a/src/jaguar1/EepromManager.cpp b/src/jaguar1/EepromManager.cpp index f3dfca9..ae53c8a 100644 --- a/src/jaguar1/EepromManager.cpp +++ b/src/jaguar1/EepromManager.cpp @@ -392,12 +392,15 @@ static uint8_t classify_channel(uint8_t ch, uint8_t *group, uint8_t *cck_group) if (cck_group) *cck_group = static_cast(cck_gp); return 0; /* 2.4G */ } + /* 5G group boundaries — verbatim from upstream `rtw_get_ch_group` + * (core/rtw_rf.c). NB the gp3/gp4 split is at 98/100 (not 80/82) and the + * top group runs to 253: channels 82..98 belong to gp3, not gp4. */ int gp = -1; - if (15 <= ch && ch <= 42) gp = 0; + if (16 <= ch && ch <= 42) gp = 0; else if (44 <= ch && ch <= 48) gp = 1; else if (50 <= ch && ch <= 58) gp = 2; - else if (60 <= ch && ch <= 80) gp = 3; - else if (82 <= ch && ch <= 106) gp = 4; + else if (60 <= ch && ch <= 98) gp = 3; + else if (100 <= ch && ch <= 106) gp = 4; else if (108 <= ch && ch <= 114) gp = 5; else if (116 <= ch && ch <= 122) gp = 6; else if (124 <= ch && ch <= 130) gp = 7; @@ -406,7 +409,7 @@ static uint8_t classify_channel(uint8_t ch, uint8_t *group, uint8_t *cck_group) else if (149 <= ch && ch <= 155) gp = 10; else if (157 <= ch && ch <= 161) gp = 11; else if (165 <= ch && ch <= 171) gp = 12; - else if (173 <= ch && ch <= 177) gp = 13; + else if (173 <= ch && ch <= 253) gp = 13; if (gp < 0) return 0xFF; if (group) *group = static_cast(gp); return 1; /* 5G */ @@ -423,6 +426,54 @@ static const uint8_t kCenterCh5gAll[65] = { 165, 167, 169, 171, 173, 175, 177, }; +/* Vendor default PG TX-power maps — verbatim from upstream `hal_com_phycfg.c` + * (`pg_txpwr_def_info` + per-chip `rtl88{12,21}a_pg_txpwr_def_info`). Each map + * is the per-path byte stream that starts at PG offset `pg_txpwr_saddr` (0x10), + * laid out identically to the EFUSE PG block (2.4G 18 B + 5G 24 B per path). + * The kernel's `hal_load_pg_txpwr_info` uses these as fallback sources + * (PG_DATA -> IC_DEF -> DEF): a base cell whose EFUSE byte is invalid + * (> txgi_max = 63, e.g. an unprogrammed 0xFF) is filled from the IC map, then + * the generic map. 0xEE/0xFF bytes at base positions are themselves invalid and + * fall through to the next source. */ +static const uint8_t kPgTxpwrDefGeneric[168] = { + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x04, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x04, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x04, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x04, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE}; + +static const uint8_t kPgTxpwrDef8814a[168] = { + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0x00, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE}; + +static const uint8_t kPgTxpwrDef8812a[82] = { + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xFF, 0xFF, + 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x02, 0xEE, 0xFF, 0xFF, 0xEE, 0xFF, 0x00, 0xEE, 0xFF, 0xFF, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, 0xFF, 0xFF, 0xEE, 0xFF, + 0x00, 0xEE}; + +static const uint8_t kPgTxpwrDef8821a[39] = { + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; + void EepromManager::LoadTxPowerInfo() { /* EFUSE PG TX-power block layout — port of * `hal_load_pg_txpwr_info_path_{2,5}g` from upstream @@ -463,12 +514,41 @@ void EepromManager::LoadTxPowerInfo() { uint8_t bw40_base_2g[kMaxRfPath][6] = {}; uint8_t bw40_base_5g[kMaxRfPath][14] = {}; + /* Fallback sources for invalid (unprogrammed) base cells — port of the + * kernel's PG_DATA -> IC_DEF -> DEF chain in `hal_load_pg_txpwr_info`. Pick + * the IC default map by chip; the generic map is the final fallback. */ + const uint8_t *ic_def = nullptr; + size_t ic_def_len = 0; + switch (version_id.ICType) { + case CHIP_8814A: ic_def = kPgTxpwrDef8814a; ic_def_len = sizeof(kPgTxpwrDef8814a); break; + case CHIP_8812: ic_def = kPgTxpwrDef8812a; ic_def_len = sizeof(kPgTxpwrDef8812a); break; + case CHIP_8821: ic_def = kPgTxpwrDef8821a; ic_def_len = sizeof(kPgTxpwrDef8821a); break; + default: break; + } + /* Read a base byte with the vendor fallback chain. A base is invalid when it + * exceeds txgi_max (63) — the same test the kernel uses + * (IS_PG_TXPWR_BASE_INVALID). First valid of {EFUSE, IC-def, generic-def} + * wins; if all are invalid the (invalid) EFUSE byte is returned and gets + * clamped downstream, matching the kernel leaving the cell invalid. */ + auto def_at = [](const uint8_t *map, size_t len, uint16_t o) -> uint8_t { + return (o >= kPgSaddr && (size_t)(o - kPgSaddr) < len) ? map[o - kPgSaddr] + : 0xFF; + }; + auto read_base = [&](uint16_t o) -> uint8_t { + uint8_t v = efuse_eeprom_data[o]; + if (v <= 63) return v; + if (ic_def) { uint8_t d = def_at(ic_def, ic_def_len, o); if (d <= 63) return d; } + uint8_t d = def_at(kPgTxpwrDefGeneric, sizeof(kPgTxpwrDefGeneric), o); + if (d <= 63) return d; + return v; + }; + for (int path = 0; path < numTotalRfPath && path < kMaxRfPath; path++) { /* 2.4G section — 18 bytes per path. */ for (int g = 0; g < 6; g++) - cck_base_2g[path][g] = efuse_eeprom_data[off++]; + cck_base_2g[path][g] = read_base(off++); for (int g = 0; g < 5; g++) - bw40_base_2g[path][g] = efuse_eeprom_data[off++]; + bw40_base_2g[path][g] = read_base(off++); /* Ntx=1: 1 byte (MSB=BW20, LSB=OFDM) */ { uint8_t v = efuse_eeprom_data[off++]; @@ -487,7 +567,7 @@ void EepromManager::LoadTxPowerInfo() { /* 5G section — 24 bytes per path. */ for (int g = 0; g < 14; g++) - bw40_base_5g[path][g] = efuse_eeprom_data[off++]; + bw40_base_5g[path][g] = read_base(off++); /* Ntx=1: 1 byte (MSB=BW20, LSB=OFDM) */ { uint8_t v = efuse_eeprom_data[off++]; diff --git a/src/jaguar1/RadioManagementModule.cpp b/src/jaguar1/RadioManagementModule.cpp index ae52e90..77e4112 100644 --- a/src/jaguar1/RadioManagementModule.cpp +++ b/src/jaguar1/RadioManagementModule.cpp @@ -1351,9 +1351,9 @@ uint32_t RadioManagementModule::phy_get_tx_bb_swing_8812a(BandType Band, } else if (bbSwing_2G == 0) swing = 0x00; /* 0 dB */ else if (bbSwing_2G == -3) - swing = 0x05; /* -3 dB */ + swing = 0x55; /* -3 dB (all 4 paths; matches PHY_GetTxBBSwing_8814A) */ else if (bbSwing_2G == -6) - swing = 0x0A; /* -6 dB */ + swing = 0xAA; /* -6 dB (all 4 paths) */ else if (bbSwing_2G == -9) swing = 0xFF; /* -9 dB */ else @@ -1366,9 +1366,9 @@ uint32_t RadioManagementModule::phy_get_tx_bb_swing_8812a(BandType Band, } else if (bbSwing_5G == 0) swing = 0x00; /* 0 dB */ else if (bbSwing_5G == -3) - swing = 0x05; /* -3 dB */ + swing = 0x55; /* -3 dB (all 4 paths; matches PHY_GetTxBBSwing_8814A) */ else if (bbSwing_5G == -6) - swing = 0x0A; /* -6 dB */ + swing = 0xAA; /* -6 dB (all 4 paths) */ else if (bbSwing_5G == -9) swing = 0xFF; /* -9 dB */ else