18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> 38c2ecf20Sopenharmony_ci * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> 48c2ecf20Sopenharmony_ci * Copyright (C) 2006 Michael Buesch <m@bues.ch> 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org> 68c2ecf20Sopenharmony_ci * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 98c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License as published by the 108c2ecf20Sopenharmony_ci * Free Software Foundation; either version 2 of the License, or (at your 118c2ecf20Sopenharmony_ci * option) any later version. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 148c2ecf20Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 158c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 168c2ecf20Sopenharmony_ci * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 178c2ecf20Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 188c2ecf20Sopenharmony_ci * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 198c2ecf20Sopenharmony_ci * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 208c2ecf20Sopenharmony_ci * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 218c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 228c2ecf20Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License along 258c2ecf20Sopenharmony_ci * with this program; if not, write to the Free Software Foundation, Inc., 268c2ecf20Sopenharmony_ci * 675 Mass Ave, Cambridge, MA 02139, USA. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/bcm47xx_nvram.h> 308c2ecf20Sopenharmony_ci#include <linux/bcm47xx_sprom.h> 318c2ecf20Sopenharmony_ci#include <linux/bcma/bcma.h> 328c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 338c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 348c2ecf20Sopenharmony_ci#include <linux/ssb/ssb.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void create_key(const char *prefix, const char *postfix, 378c2ecf20Sopenharmony_ci const char *name, char *buf, int len) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci if (prefix && postfix) 408c2ecf20Sopenharmony_ci snprintf(buf, len, "%s%s%s", prefix, name, postfix); 418c2ecf20Sopenharmony_ci else if (prefix) 428c2ecf20Sopenharmony_ci snprintf(buf, len, "%s%s", prefix, name); 438c2ecf20Sopenharmony_ci else if (postfix) 448c2ecf20Sopenharmony_ci snprintf(buf, len, "%s%s", name, postfix); 458c2ecf20Sopenharmony_ci else 468c2ecf20Sopenharmony_ci snprintf(buf, len, "%s", name); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int get_nvram_var(const char *prefix, const char *postfix, 508c2ecf20Sopenharmony_ci const char *name, char *buf, int len, bool fallback) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci char key[40]; 538c2ecf20Sopenharmony_ci int err; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci create_key(prefix, postfix, name, key, sizeof(key)); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci err = bcm47xx_nvram_getenv(key, buf, len); 588c2ecf20Sopenharmony_ci if (fallback && err == -ENOENT && prefix) { 598c2ecf20Sopenharmony_ci create_key(NULL, postfix, name, key, sizeof(key)); 608c2ecf20Sopenharmony_ci err = bcm47xx_nvram_getenv(key, buf, len); 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci return err; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define NVRAM_READ_VAL(type) \ 668c2ecf20Sopenharmony_cistatic void nvram_read_ ## type(const char *prefix, \ 678c2ecf20Sopenharmony_ci const char *postfix, const char *name, \ 688c2ecf20Sopenharmony_ci type *val, type allset, bool fallback) \ 698c2ecf20Sopenharmony_ci{ \ 708c2ecf20Sopenharmony_ci char buf[100]; \ 718c2ecf20Sopenharmony_ci int err; \ 728c2ecf20Sopenharmony_ci type var; \ 738c2ecf20Sopenharmony_ci \ 748c2ecf20Sopenharmony_ci err = get_nvram_var(prefix, postfix, name, buf, sizeof(buf), \ 758c2ecf20Sopenharmony_ci fallback); \ 768c2ecf20Sopenharmony_ci if (err < 0) \ 778c2ecf20Sopenharmony_ci return; \ 788c2ecf20Sopenharmony_ci err = kstrto ## type(strim(buf), 0, &var); \ 798c2ecf20Sopenharmony_ci if (err) { \ 808c2ecf20Sopenharmony_ci pr_warn("can not parse nvram name %s%s%s with value %s got %i\n", \ 818c2ecf20Sopenharmony_ci prefix, name, postfix, buf, err); \ 828c2ecf20Sopenharmony_ci return; \ 838c2ecf20Sopenharmony_ci } \ 848c2ecf20Sopenharmony_ci if (allset && var == allset) \ 858c2ecf20Sopenharmony_ci return; \ 868c2ecf20Sopenharmony_ci *val = var; \ 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciNVRAM_READ_VAL(u8) 908c2ecf20Sopenharmony_ciNVRAM_READ_VAL(s8) 918c2ecf20Sopenharmony_ciNVRAM_READ_VAL(u16) 928c2ecf20Sopenharmony_ciNVRAM_READ_VAL(u32) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#undef NVRAM_READ_VAL 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void nvram_read_u32_2(const char *prefix, const char *name, 978c2ecf20Sopenharmony_ci u16 *val_lo, u16 *val_hi, bool fallback) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci char buf[100]; 1008c2ecf20Sopenharmony_ci int err; 1018c2ecf20Sopenharmony_ci u32 val; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); 1048c2ecf20Sopenharmony_ci if (err < 0) 1058c2ecf20Sopenharmony_ci return; 1068c2ecf20Sopenharmony_ci err = kstrtou32(strim(buf), 0, &val); 1078c2ecf20Sopenharmony_ci if (err) { 1088c2ecf20Sopenharmony_ci pr_warn("can not parse nvram name %s%s with value %s got %i\n", 1098c2ecf20Sopenharmony_ci prefix, name, buf, err); 1108c2ecf20Sopenharmony_ci return; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci *val_lo = (val & 0x0000FFFFU); 1138c2ecf20Sopenharmony_ci *val_hi = (val & 0xFFFF0000U) >> 16; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void nvram_read_leddc(const char *prefix, const char *name, 1178c2ecf20Sopenharmony_ci u8 *leddc_on_time, u8 *leddc_off_time, 1188c2ecf20Sopenharmony_ci bool fallback) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci char buf[100]; 1218c2ecf20Sopenharmony_ci int err; 1228c2ecf20Sopenharmony_ci u32 val; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); 1258c2ecf20Sopenharmony_ci if (err < 0) 1268c2ecf20Sopenharmony_ci return; 1278c2ecf20Sopenharmony_ci err = kstrtou32(strim(buf), 0, &val); 1288c2ecf20Sopenharmony_ci if (err) { 1298c2ecf20Sopenharmony_ci pr_warn("can not parse nvram name %s%s with value %s got %i\n", 1308c2ecf20Sopenharmony_ci prefix, name, buf, err); 1318c2ecf20Sopenharmony_ci return; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (val == 0xffff || val == 0xffffffff) 1358c2ecf20Sopenharmony_ci return; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci *leddc_on_time = val & 0xff; 1388c2ecf20Sopenharmony_ci *leddc_off_time = (val >> 16) & 0xff; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void nvram_read_macaddr(const char *prefix, const char *name, 1428c2ecf20Sopenharmony_ci u8 val[6], bool fallback) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci char buf[100]; 1458c2ecf20Sopenharmony_ci int err; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); 1488c2ecf20Sopenharmony_ci if (err < 0) 1498c2ecf20Sopenharmony_ci return; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci strreplace(buf, '-', ':'); 1528c2ecf20Sopenharmony_ci if (!mac_pton(buf, val)) 1538c2ecf20Sopenharmony_ci pr_warn("Can not parse mac address: %s\n", buf); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void nvram_read_alpha2(const char *prefix, const char *name, 1578c2ecf20Sopenharmony_ci char val[2], bool fallback) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci char buf[10]; 1608c2ecf20Sopenharmony_ci int err; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); 1638c2ecf20Sopenharmony_ci if (err < 0) 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci if (buf[0] == '0') 1668c2ecf20Sopenharmony_ci return; 1678c2ecf20Sopenharmony_ci if (strlen(buf) > 2) { 1688c2ecf20Sopenharmony_ci pr_warn("alpha2 is too long %s\n", buf); 1698c2ecf20Sopenharmony_ci return; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci memcpy(val, buf, 2); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* This is one-function-only macro, it uses local "sprom" variable! */ 1758c2ecf20Sopenharmony_ci#define ENTRY(_revmask, _type, _prefix, _name, _val, _allset, _fallback) \ 1768c2ecf20Sopenharmony_ci if (_revmask & BIT(sprom->revision)) \ 1778c2ecf20Sopenharmony_ci nvram_read_ ## _type(_prefix, NULL, _name, &sprom->_val, \ 1788c2ecf20Sopenharmony_ci _allset, _fallback) 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * Special version of filling function that can be safely called for any SPROM 1818c2ecf20Sopenharmony_ci * revision. For every NVRAM to SPROM mapping it contains bitmask of revisions 1828c2ecf20Sopenharmony_ci * for which the mapping is valid. 1838c2ecf20Sopenharmony_ci * It obviously requires some hexadecimal/bitmasks knowledge, but allows 1848c2ecf20Sopenharmony_ci * writing cleaner code (easy revisions handling). 1858c2ecf20Sopenharmony_ci * Note that while SPROM revision 0 was never used, we still keep BIT(0) 1868c2ecf20Sopenharmony_ci * reserved for it, just to keep numbering sane. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_cistatic void bcm47xx_sprom_fill_auto(struct ssb_sprom *sprom, 1898c2ecf20Sopenharmony_ci const char *prefix, bool fallback) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci const char *pre = prefix; 1928c2ecf20Sopenharmony_ci bool fb = fallback; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* Broadcom extracts it for rev 8+ but it was found on 2 and 4 too */ 1958c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u16, pre, "devid", dev_id, 0, fallback); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u16, pre, "boardrev", board_rev, 0, true); 1988c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u32, pre, "boardflags", boardflags, 0, fb); 1998c2ecf20Sopenharmony_ci ENTRY(0xfffffff0, u32, pre, "boardflags2", boardflags2, 0, fb); 2008c2ecf20Sopenharmony_ci ENTRY(0xfffff800, u32, pre, "boardflags3", boardflags3, 0, fb); 2018c2ecf20Sopenharmony_ci ENTRY(0x00000002, u16, pre, "boardflags", boardflags_lo, 0, fb); 2028c2ecf20Sopenharmony_ci ENTRY(0xfffffffc, u16, pre, "boardtype", board_type, 0, true); 2038c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u16, pre, "boardnum", board_num, 0, fb); 2048c2ecf20Sopenharmony_ci ENTRY(0x00000002, u8, pre, "cc", country_code, 0, fb); 2058c2ecf20Sopenharmony_ci ENTRY(0xfffffff8, u8, pre, "regrev", regrev, 0, fb); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "ledbh0", gpio0, 0xff, fb); 2088c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "ledbh1", gpio1, 0xff, fb); 2098c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "ledbh2", gpio2, 0xff, fb); 2108c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "ledbh3", gpio3, 0xff, fb); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa0b0", pa0b0, 0, fb); 2138c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa0b1", pa0b1, 0, fb); 2148c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa0b2", pa0b2, 0, fb); 2158c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u8, pre, "pa0itssit", itssi_bg, 0, fb); 2168c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u8, pre, "pa0maxpwr", maxpwr_bg, 0, fb); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u8, pre, "opo", opo, 0, fb); 2198c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "aa2g", ant_available_bg, 0, fb); 2208c2ecf20Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "aa5g", ant_available_a, 0, fb); 2218c2ecf20Sopenharmony_ci ENTRY(0x000007fe, s8, pre, "ag0", antenna_gain.a0, 0, fb); 2228c2ecf20Sopenharmony_ci ENTRY(0x000007fe, s8, pre, "ag1", antenna_gain.a1, 0, fb); 2238c2ecf20Sopenharmony_ci ENTRY(0x000007f0, s8, pre, "ag2", antenna_gain.a2, 0, fb); 2248c2ecf20Sopenharmony_ci ENTRY(0x000007f0, s8, pre, "ag3", antenna_gain.a3, 0, fb); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa1b0", pa1b0, 0, fb); 2278c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa1b1", pa1b1, 0, fb); 2288c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa1b2", pa1b2, 0, fb); 2298c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1lob0", pa1lob0, 0, fb); 2308c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1lob1", pa1lob1, 0, fb); 2318c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1lob2", pa1lob2, 0, fb); 2328c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1hib0", pa1hib0, 0, fb); 2338c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1hib1", pa1hib1, 0, fb); 2348c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1hib2", pa1hib2, 0, fb); 2358c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u8, pre, "pa1itssit", itssi_a, 0, fb); 2368c2ecf20Sopenharmony_ci ENTRY(0x0000070e, u8, pre, "pa1maxpwr", maxpwr_a, 0, fb); 2378c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u8, pre, "pa1lomaxpwr", maxpwr_al, 0, fb); 2388c2ecf20Sopenharmony_ci ENTRY(0x0000070c, u8, pre, "pa1himaxpwr", maxpwr_ah, 0, fb); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "bxa2g", bxa2g, 0, fb); 2418c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssisav2g", rssisav2g, 0, fb); 2428c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssismc2g", rssismc2g, 0, fb); 2438c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssismf2g", rssismf2g, 0, fb); 2448c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "bxa5g", bxa5g, 0, fb); 2458c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssisav5g", rssisav5g, 0, fb); 2468c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssismc5g", rssismc5g, 0, fb); 2478c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssismf5g", rssismf5g, 0, fb); 2488c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "tri2g", tri2g, 0, fb); 2498c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "tri5g", tri5g, 0, fb); 2508c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "tri5gl", tri5gl, 0, fb); 2518c2ecf20Sopenharmony_ci ENTRY(0x00000708, u8, pre, "tri5gh", tri5gh, 0, fb); 2528c2ecf20Sopenharmony_ci ENTRY(0x00000708, s8, pre, "rxpo2g", rxpo2g, 0, fb); 2538c2ecf20Sopenharmony_ci ENTRY(0x00000708, s8, pre, "rxpo5g", rxpo5g, 0, fb); 2548c2ecf20Sopenharmony_ci ENTRY(0xfffffff0, u8, pre, "txchain", txchain, 0xf, fb); 2558c2ecf20Sopenharmony_ci ENTRY(0xfffffff0, u8, pre, "rxchain", rxchain, 0xf, fb); 2568c2ecf20Sopenharmony_ci ENTRY(0xfffffff0, u8, pre, "antswitch", antswitch, 0xff, fb); 2578c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "tssipos2g", fem.ghz2.tssipos, 0, fb); 2588c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "extpagain2g", fem.ghz2.extpa_gain, 0, fb); 2598c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "pdetrange2g", fem.ghz2.pdet_range, 0, fb); 2608c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "triso2g", fem.ghz2.tr_iso, 0, fb); 2618c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "antswctl2g", fem.ghz2.antswlut, 0, fb); 2628c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "tssipos5g", fem.ghz5.tssipos, 0, fb); 2638c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "extpagain5g", fem.ghz5.extpa_gain, 0, fb); 2648c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "pdetrange5g", fem.ghz5.pdet_range, 0, fb); 2658c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "triso5g", fem.ghz5.tr_iso, 0, fb); 2668c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "antswctl5g", fem.ghz5.antswlut, 0, fb); 2678c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid2ga0", txpid2g[0], 0, fb); 2688c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid2ga1", txpid2g[1], 0, fb); 2698c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid2ga2", txpid2g[2], 0, fb); 2708c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid2ga3", txpid2g[3], 0, fb); 2718c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5ga0", txpid5g[0], 0, fb); 2728c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5ga1", txpid5g[1], 0, fb); 2738c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5ga2", txpid5g[2], 0, fb); 2748c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5ga3", txpid5g[3], 0, fb); 2758c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gla0", txpid5gl[0], 0, fb); 2768c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gla1", txpid5gl[1], 0, fb); 2778c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gla2", txpid5gl[2], 0, fb); 2788c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gla3", txpid5gl[3], 0, fb); 2798c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gha0", txpid5gh[0], 0, fb); 2808c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gha1", txpid5gh[1], 0, fb); 2818c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gha2", txpid5gh[2], 0, fb); 2828c2ecf20Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gha3", txpid5gh[3], 0, fb); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempthresh", tempthresh, 0, fb); 2858c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempoffset", tempoffset, 0, fb); 2868c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u16, pre, "rawtempsense", rawtempsense, 0, fb); 2878c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "measpower", measpower, 0, fb); 2888c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempsense_slope", tempsense_slope, 0, fb); 2898c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempcorrx", tempcorrx, 0, fb); 2908c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempsense_option", tempsense_option, 0, fb); 2918c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "freqoffset_corr", freqoffset_corr, 0, fb); 2928c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "iqcal_swp_dis", iqcal_swp_dis, 0, fb); 2938c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "hw_iqcal_en", hw_iqcal_en, 0, fb); 2948c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "elna2g", elna2g, 0, fb); 2958c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "elna5g", elna5g, 0, fb); 2968c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "phycal_tempdelta", phycal_tempdelta, 0, fb); 2978c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "temps_period", temps_period, 0, fb); 2988c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "temps_hysteresis", temps_hysteresis, 0, fb); 2998c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "measpower1", measpower1, 0, fb); 3008c2ecf20Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "measpower2", measpower2, 0, fb); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "cck2gpo", cck2gpo, 0, fb); 3038c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u32, pre, "ofdm2gpo", ofdm2gpo, 0, fb); 3048c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u32, pre, "ofdm5gpo", ofdm5gpo, 0, fb); 3058c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u32, pre, "ofdm5glpo", ofdm5glpo, 0, fb); 3068c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u32, pre, "ofdm5ghpo", ofdm5ghpo, 0, fb); 3078c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo0", mcs2gpo[0], 0, fb); 3088c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo1", mcs2gpo[1], 0, fb); 3098c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo2", mcs2gpo[2], 0, fb); 3108c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo3", mcs2gpo[3], 0, fb); 3118c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo4", mcs2gpo[4], 0, fb); 3128c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo5", mcs2gpo[5], 0, fb); 3138c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo6", mcs2gpo[6], 0, fb); 3148c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo7", mcs2gpo[7], 0, fb); 3158c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo0", mcs5gpo[0], 0, fb); 3168c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo1", mcs5gpo[1], 0, fb); 3178c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo2", mcs5gpo[2], 0, fb); 3188c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo3", mcs5gpo[3], 0, fb); 3198c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo4", mcs5gpo[4], 0, fb); 3208c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo5", mcs5gpo[5], 0, fb); 3218c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo6", mcs5gpo[6], 0, fb); 3228c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo7", mcs5gpo[7], 0, fb); 3238c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo0", mcs5glpo[0], 0, fb); 3248c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo1", mcs5glpo[1], 0, fb); 3258c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo2", mcs5glpo[2], 0, fb); 3268c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo3", mcs5glpo[3], 0, fb); 3278c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo4", mcs5glpo[4], 0, fb); 3288c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo5", mcs5glpo[5], 0, fb); 3298c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo6", mcs5glpo[6], 0, fb); 3308c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo7", mcs5glpo[7], 0, fb); 3318c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo0", mcs5ghpo[0], 0, fb); 3328c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo1", mcs5ghpo[1], 0, fb); 3338c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo2", mcs5ghpo[2], 0, fb); 3348c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo3", mcs5ghpo[3], 0, fb); 3358c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo4", mcs5ghpo[4], 0, fb); 3368c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo5", mcs5ghpo[5], 0, fb); 3378c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo6", mcs5ghpo[6], 0, fb); 3388c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo7", mcs5ghpo[7], 0, fb); 3398c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "cddpo", cddpo, 0, fb); 3408c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "stbcpo", stbcpo, 0, fb); 3418c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "bw40po", bw40po, 0, fb); 3428c2ecf20Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "bwduppo", bwduppo, 0, fb); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u16, pre, "cckbw202gpo", cckbw202gpo, 0, fb); 3458c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u16, pre, "cckbw20ul2gpo", cckbw20ul2gpo, 0, fb); 3468c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw202gpo", legofdmbw202gpo, 0, fb); 3478c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw20ul2gpo", legofdmbw20ul2gpo, 0, fb); 3488c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw205glpo", legofdmbw205glpo, 0, fb); 3498c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw20ul5glpo", legofdmbw20ul5glpo, 0, fb); 3508c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw205gmpo", legofdmbw205gmpo, 0, fb); 3518c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw20ul5gmpo", legofdmbw20ul5gmpo, 0, fb); 3528c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw205ghpo", legofdmbw205ghpo, 0, fb); 3538c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw20ul5ghpo", legofdmbw20ul5ghpo, 0, fb); 3548c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw202gpo", mcsbw202gpo, 0, fb); 3558c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "mcsbw20ul2gpo", mcsbw20ul2gpo, 0, fb); 3568c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw402gpo", mcsbw402gpo, 0, fb); 3578c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw205glpo", mcsbw205glpo, 0, fb); 3588c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "mcsbw20ul5glpo", mcsbw20ul5glpo, 0, fb); 3598c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw405glpo", mcsbw405glpo, 0, fb); 3608c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw205gmpo", mcsbw205gmpo, 0, fb); 3618c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "mcsbw20ul5gmpo", mcsbw20ul5gmpo, 0, fb); 3628c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw405gmpo", mcsbw405gmpo, 0, fb); 3638c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw205ghpo", mcsbw205ghpo, 0, fb); 3648c2ecf20Sopenharmony_ci ENTRY(0x00000600, u32, pre, "mcsbw20ul5ghpo", mcsbw20ul5ghpo, 0, fb); 3658c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw405ghpo", mcsbw405ghpo, 0, fb); 3668c2ecf20Sopenharmony_ci ENTRY(0x00000600, u16, pre, "mcs32po", mcs32po, 0, fb); 3678c2ecf20Sopenharmony_ci ENTRY(0x00000600, u16, pre, "legofdm40duppo", legofdm40duppo, 0, fb); 3688c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "pcieingress_war", pcieingress_war, 0, fb); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* TODO: rev 11 support */ 3718c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr2ga0", rxgainerr2ga[0], 0, fb); 3728c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr2ga1", rxgainerr2ga[1], 0, fb); 3738c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr2ga2", rxgainerr2ga[2], 0, fb); 3748c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gla0", rxgainerr5gla[0], 0, fb); 3758c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gla1", rxgainerr5gla[1], 0, fb); 3768c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gla2", rxgainerr5gla[2], 0, fb); 3778c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gma0", rxgainerr5gma[0], 0, fb); 3788c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gma1", rxgainerr5gma[1], 0, fb); 3798c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gma2", rxgainerr5gma[2], 0, fb); 3808c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gha0", rxgainerr5gha[0], 0, fb); 3818c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gha1", rxgainerr5gha[1], 0, fb); 3828c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gha2", rxgainerr5gha[2], 0, fb); 3838c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gua0", rxgainerr5gua[0], 0, fb); 3848c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gua1", rxgainerr5gua[1], 0, fb); 3858c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gua2", rxgainerr5gua[2], 0, fb); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u8, pre, "sar2g", sar2g, 0, fb); 3888c2ecf20Sopenharmony_ci ENTRY(0xfffffe00, u8, pre, "sar5g", sar5g, 0, fb); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* TODO: rev 11 support */ 3918c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl2ga0", noiselvl2ga[0], 0, fb); 3928c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl2ga1", noiselvl2ga[1], 0, fb); 3938c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl2ga2", noiselvl2ga[2], 0, fb); 3948c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gla0", noiselvl5gla[0], 0, fb); 3958c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gla1", noiselvl5gla[1], 0, fb); 3968c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gla2", noiselvl5gla[2], 0, fb); 3978c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gma0", noiselvl5gma[0], 0, fb); 3988c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gma1", noiselvl5gma[1], 0, fb); 3998c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gma2", noiselvl5gma[2], 0, fb); 4008c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gha0", noiselvl5gha[0], 0, fb); 4018c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gha1", noiselvl5gha[1], 0, fb); 4028c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gha2", noiselvl5gha[2], 0, fb); 4038c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gua0", noiselvl5gua[0], 0, fb); 4048c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gua1", noiselvl5gua[1], 0, fb); 4058c2ecf20Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gua2", noiselvl5gua[2], 0, fb); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci#undef ENTRY /* It's specififc, uses local variable, don't use it (again). */ 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom, 4108c2ecf20Sopenharmony_ci const char *prefix, bool fallback) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci char postfix[2]; 4138c2ecf20Sopenharmony_ci int i; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) { 4168c2ecf20Sopenharmony_ci struct ssb_sprom_core_pwr_info *pwr_info; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci pwr_info = &sprom->core_pwr_info[i]; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci snprintf(postfix, sizeof(postfix), "%i", i); 4218c2ecf20Sopenharmony_ci nvram_read_u8(prefix, postfix, "maxp2ga", 4228c2ecf20Sopenharmony_ci &pwr_info->maxpwr_2g, 0, fallback); 4238c2ecf20Sopenharmony_ci nvram_read_u8(prefix, postfix, "itt2ga", 4248c2ecf20Sopenharmony_ci &pwr_info->itssi_2g, 0, fallback); 4258c2ecf20Sopenharmony_ci nvram_read_u8(prefix, postfix, "itt5ga", 4268c2ecf20Sopenharmony_ci &pwr_info->itssi_5g, 0, fallback); 4278c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa2gw0a", 4288c2ecf20Sopenharmony_ci &pwr_info->pa_2g[0], 0, fallback); 4298c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa2gw1a", 4308c2ecf20Sopenharmony_ci &pwr_info->pa_2g[1], 0, fallback); 4318c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa2gw2a", 4328c2ecf20Sopenharmony_ci &pwr_info->pa_2g[2], 0, fallback); 4338c2ecf20Sopenharmony_ci nvram_read_u8(prefix, postfix, "maxp5ga", 4348c2ecf20Sopenharmony_ci &pwr_info->maxpwr_5g, 0, fallback); 4358c2ecf20Sopenharmony_ci nvram_read_u8(prefix, postfix, "maxp5gha", 4368c2ecf20Sopenharmony_ci &pwr_info->maxpwr_5gh, 0, fallback); 4378c2ecf20Sopenharmony_ci nvram_read_u8(prefix, postfix, "maxp5gla", 4388c2ecf20Sopenharmony_ci &pwr_info->maxpwr_5gl, 0, fallback); 4398c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5gw0a", 4408c2ecf20Sopenharmony_ci &pwr_info->pa_5g[0], 0, fallback); 4418c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5gw1a", 4428c2ecf20Sopenharmony_ci &pwr_info->pa_5g[1], 0, fallback); 4438c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5gw2a", 4448c2ecf20Sopenharmony_ci &pwr_info->pa_5g[2], 0, fallback); 4458c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5glw0a", 4468c2ecf20Sopenharmony_ci &pwr_info->pa_5gl[0], 0, fallback); 4478c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5glw1a", 4488c2ecf20Sopenharmony_ci &pwr_info->pa_5gl[1], 0, fallback); 4498c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5glw2a", 4508c2ecf20Sopenharmony_ci &pwr_info->pa_5gl[2], 0, fallback); 4518c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5ghw0a", 4528c2ecf20Sopenharmony_ci &pwr_info->pa_5gh[0], 0, fallback); 4538c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5ghw1a", 4548c2ecf20Sopenharmony_ci &pwr_info->pa_5gh[1], 0, fallback); 4558c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5ghw2a", 4568c2ecf20Sopenharmony_ci &pwr_info->pa_5gh[2], 0, fallback); 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom, 4618c2ecf20Sopenharmony_ci const char *prefix, bool fallback) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci char postfix[2]; 4648c2ecf20Sopenharmony_ci int i; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) { 4678c2ecf20Sopenharmony_ci struct ssb_sprom_core_pwr_info *pwr_info; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci pwr_info = &sprom->core_pwr_info[i]; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci snprintf(postfix, sizeof(postfix), "%i", i); 4728c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa2gw3a", 4738c2ecf20Sopenharmony_ci &pwr_info->pa_2g[3], 0, fallback); 4748c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5gw3a", 4758c2ecf20Sopenharmony_ci &pwr_info->pa_5g[3], 0, fallback); 4768c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5glw3a", 4778c2ecf20Sopenharmony_ci &pwr_info->pa_5gl[3], 0, fallback); 4788c2ecf20Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5ghw3a", 4798c2ecf20Sopenharmony_ci &pwr_info->pa_5gh[3], 0, fallback); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic bool bcm47xx_is_valid_mac(u8 *mac) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int bcm47xx_increase_mac_addr(u8 *mac, u8 num) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci u8 *oui = mac + ETH_ALEN/2 - 1; 4918c2ecf20Sopenharmony_ci u8 *p = mac + ETH_ALEN - 1; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci do { 4948c2ecf20Sopenharmony_ci (*p) += num; 4958c2ecf20Sopenharmony_ci if (*p > num) 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci p--; 4988c2ecf20Sopenharmony_ci num = 1; 4998c2ecf20Sopenharmony_ci } while (p != oui); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (p == oui) { 5028c2ecf20Sopenharmony_ci pr_err("unable to fetch mac address\n"); 5038c2ecf20Sopenharmony_ci return -ENOENT; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic int mac_addr_used = 2; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, 5118c2ecf20Sopenharmony_ci const char *prefix, bool fallback) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci bool fb = fallback; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci nvram_read_macaddr(prefix, "et0macaddr", sprom->et0mac, fallback); 5168c2ecf20Sopenharmony_ci nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0, 5178c2ecf20Sopenharmony_ci fallback); 5188c2ecf20Sopenharmony_ci nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0, 5198c2ecf20Sopenharmony_ci fallback); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci nvram_read_macaddr(prefix, "et1macaddr", sprom->et1mac, fallback); 5228c2ecf20Sopenharmony_ci nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0, 5238c2ecf20Sopenharmony_ci fallback); 5248c2ecf20Sopenharmony_ci nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0, 5258c2ecf20Sopenharmony_ci fallback); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci nvram_read_macaddr(prefix, "et2macaddr", sprom->et2mac, fb); 5288c2ecf20Sopenharmony_ci nvram_read_u8(prefix, NULL, "et2mdcport", &sprom->et2mdcport, 0, fb); 5298c2ecf20Sopenharmony_ci nvram_read_u8(prefix, NULL, "et2phyaddr", &sprom->et2phyaddr, 0, fb); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci nvram_read_macaddr(prefix, "macaddr", sprom->il0mac, fallback); 5328c2ecf20Sopenharmony_ci nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* The address prefix 00:90:4C is used by Broadcom in their initial 5358c2ecf20Sopenharmony_ci * configuration. When a mac address with the prefix 00:90:4C is used 5368c2ecf20Sopenharmony_ci * all devices from the same series are sharing the same mac address. 5378c2ecf20Sopenharmony_ci * To prevent mac address collisions we replace them with a mac address 5388c2ecf20Sopenharmony_ci * based on the base address. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_ci if (!bcm47xx_is_valid_mac(sprom->il0mac)) { 5418c2ecf20Sopenharmony_ci u8 mac[6]; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci nvram_read_macaddr(NULL, "et0macaddr", mac, false); 5448c2ecf20Sopenharmony_ci if (bcm47xx_is_valid_mac(mac)) { 5458c2ecf20Sopenharmony_ci int err = bcm47xx_increase_mac_addr(mac, mac_addr_used); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (!err) { 5488c2ecf20Sopenharmony_ci ether_addr_copy(sprom->il0mac, mac); 5498c2ecf20Sopenharmony_ci mac_addr_used++; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix, 5568c2ecf20Sopenharmony_ci bool fallback) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo, 5598c2ecf20Sopenharmony_ci &sprom->boardflags_hi, fallback); 5608c2ecf20Sopenharmony_ci nvram_read_u32_2(prefix, "boardflags2", &sprom->boardflags2_lo, 5618c2ecf20Sopenharmony_ci &sprom->boardflags2_hi, fallback); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_civoid bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix, 5658c2ecf20Sopenharmony_ci bool fallback) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci bcm47xx_fill_sprom_ethernet(sprom, prefix, fallback); 5688c2ecf20Sopenharmony_ci bcm47xx_fill_board_data(sprom, prefix, fallback); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0, fallback); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* Entries requiring custom functions */ 5738c2ecf20Sopenharmony_ci nvram_read_alpha2(prefix, "ccode", sprom->alpha2, fallback); 5748c2ecf20Sopenharmony_ci if (sprom->revision >= 3) 5758c2ecf20Sopenharmony_ci nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time, 5768c2ecf20Sopenharmony_ci &sprom->leddc_off_time, fallback); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci switch (sprom->revision) { 5798c2ecf20Sopenharmony_ci case 4: 5808c2ecf20Sopenharmony_ci case 5: 5818c2ecf20Sopenharmony_ci bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback); 5828c2ecf20Sopenharmony_ci bcm47xx_fill_sprom_path_r45(sprom, prefix, fallback); 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci case 8: 5858c2ecf20Sopenharmony_ci case 9: 5868c2ecf20Sopenharmony_ci bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback); 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci bcm47xx_sprom_fill_auto(sprom, prefix, fallback); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_SSB) && IS_ENABLED(CONFIG_SSB_SPROM) 5948c2ecf20Sopenharmony_cistatic int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci char prefix[10]; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci switch (bus->bustype) { 5998c2ecf20Sopenharmony_ci case SSB_BUSTYPE_SSB: 6008c2ecf20Sopenharmony_ci bcm47xx_fill_sprom(out, NULL, false); 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci case SSB_BUSTYPE_PCI: 6038c2ecf20Sopenharmony_ci memset(out, 0, sizeof(struct ssb_sprom)); 6048c2ecf20Sopenharmony_ci snprintf(prefix, sizeof(prefix), "pci/%u/%u/", 6058c2ecf20Sopenharmony_ci bus->host_pci->bus->number + 1, 6068c2ecf20Sopenharmony_ci PCI_SLOT(bus->host_pci->devfn)); 6078c2ecf20Sopenharmony_ci bcm47xx_fill_sprom(out, prefix, false); 6088c2ecf20Sopenharmony_ci return 0; 6098c2ecf20Sopenharmony_ci default: 6108c2ecf20Sopenharmony_ci pr_warn("Unable to fill SPROM for given bustype.\n"); 6118c2ecf20Sopenharmony_ci return -EINVAL; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci#endif 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_BCMA) 6178c2ecf20Sopenharmony_ci/* 6188c2ecf20Sopenharmony_ci * Having many NVRAM entries for PCI devices led to repeating prefixes like 6198c2ecf20Sopenharmony_ci * pci/1/1/ all the time and wasting flash space. So at some point Broadcom 6208c2ecf20Sopenharmony_ci * decided to introduce prefixes like 0: 1: 2: etc. 6218c2ecf20Sopenharmony_ci * If we find e.g. devpath0=pci/2/1 or devpath0=pci/2/1/ we should use 0: 6228c2ecf20Sopenharmony_ci * instead of pci/2/1/. 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_cistatic void bcm47xx_sprom_apply_prefix_alias(char *prefix, size_t prefix_size) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci size_t prefix_len = strlen(prefix); 6278c2ecf20Sopenharmony_ci size_t short_len = prefix_len - 1; 6288c2ecf20Sopenharmony_ci char nvram_var[10]; 6298c2ecf20Sopenharmony_ci char buf[20]; 6308c2ecf20Sopenharmony_ci int i; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* Passed prefix has to end with a slash */ 6338c2ecf20Sopenharmony_ci if (prefix_len <= 0 || prefix[prefix_len - 1] != '/') 6348c2ecf20Sopenharmony_ci return; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 6378c2ecf20Sopenharmony_ci if (snprintf(nvram_var, sizeof(nvram_var), "devpath%d", i) <= 0) 6388c2ecf20Sopenharmony_ci continue; 6398c2ecf20Sopenharmony_ci if (bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf)) < 0) 6408c2ecf20Sopenharmony_ci continue; 6418c2ecf20Sopenharmony_ci if (!strcmp(buf, prefix) || 6428c2ecf20Sopenharmony_ci (short_len && strlen(buf) == short_len && !strncmp(buf, prefix, short_len))) { 6438c2ecf20Sopenharmony_ci snprintf(prefix, prefix_size, "%d:", i); 6448c2ecf20Sopenharmony_ci return; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct bcma_boardinfo *binfo = &bus->boardinfo; 6528c2ecf20Sopenharmony_ci struct bcma_device *core; 6538c2ecf20Sopenharmony_ci char buf[10]; 6548c2ecf20Sopenharmony_ci char *prefix; 6558c2ecf20Sopenharmony_ci bool fallback = false; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci switch (bus->hosttype) { 6588c2ecf20Sopenharmony_ci case BCMA_HOSTTYPE_PCI: 6598c2ecf20Sopenharmony_ci memset(out, 0, sizeof(struct ssb_sprom)); 6608c2ecf20Sopenharmony_ci /* On BCM47XX all PCI buses share the same domain */ 6618c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_BCM47XX)) 6628c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "pci/%u/%u/", 6638c2ecf20Sopenharmony_ci bus->host_pci->bus->number + 1, 6648c2ecf20Sopenharmony_ci PCI_SLOT(bus->host_pci->devfn)); 6658c2ecf20Sopenharmony_ci else 6668c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "pci/%u/%u/", 6678c2ecf20Sopenharmony_ci pci_domain_nr(bus->host_pci->bus) + 1, 6688c2ecf20Sopenharmony_ci bus->host_pci->bus->number); 6698c2ecf20Sopenharmony_ci bcm47xx_sprom_apply_prefix_alias(buf, sizeof(buf)); 6708c2ecf20Sopenharmony_ci prefix = buf; 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci case BCMA_HOSTTYPE_SOC: 6738c2ecf20Sopenharmony_ci memset(out, 0, sizeof(struct ssb_sprom)); 6748c2ecf20Sopenharmony_ci core = bcma_find_core(bus, BCMA_CORE_80211); 6758c2ecf20Sopenharmony_ci if (core) { 6768c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "sb/%u/", 6778c2ecf20Sopenharmony_ci core->core_index); 6788c2ecf20Sopenharmony_ci prefix = buf; 6798c2ecf20Sopenharmony_ci fallback = true; 6808c2ecf20Sopenharmony_ci } else { 6818c2ecf20Sopenharmony_ci prefix = NULL; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci break; 6848c2ecf20Sopenharmony_ci default: 6858c2ecf20Sopenharmony_ci pr_warn("Unable to fill SPROM for given bustype.\n"); 6868c2ecf20Sopenharmony_ci return -EINVAL; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci nvram_read_u16(prefix, NULL, "boardvendor", &binfo->vendor, 0, true); 6908c2ecf20Sopenharmony_ci if (!binfo->vendor) 6918c2ecf20Sopenharmony_ci binfo->vendor = SSB_BOARDVENDOR_BCM; 6928c2ecf20Sopenharmony_ci nvram_read_u16(prefix, NULL, "boardtype", &binfo->type, 0, true); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci bcm47xx_fill_sprom(out, prefix, fallback); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return 0; 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci#endif 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic unsigned int bcm47xx_sprom_registered; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci/* 7038c2ecf20Sopenharmony_ci * On bcm47xx we need to register SPROM fallback handler very early, so we can't 7048c2ecf20Sopenharmony_ci * use anything like platform device / driver for this. 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ciint bcm47xx_sprom_register_fallbacks(void) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci if (bcm47xx_sprom_registered) 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_SSB) && IS_ENABLED(CONFIG_SSB_SPROM) 7128c2ecf20Sopenharmony_ci if (ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb)) 7138c2ecf20Sopenharmony_ci pr_warn("Failed to register ssb SPROM handler\n"); 7148c2ecf20Sopenharmony_ci#endif 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_BCMA) 7178c2ecf20Sopenharmony_ci if (bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma)) 7188c2ecf20Sopenharmony_ci pr_warn("Failed to register bcma SPROM handler\n"); 7198c2ecf20Sopenharmony_ci#endif 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci bcm47xx_sprom_registered = 1; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return 0; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cifs_initcall(bcm47xx_sprom_register_fallbacks); 727