162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> 362306a36Sopenharmony_ci * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> 462306a36Sopenharmony_ci * Copyright (C) 2006 Michael Buesch <m@bues.ch> 562306a36Sopenharmony_ci * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org> 662306a36Sopenharmony_ci * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 962306a36Sopenharmony_ci * under the terms of the GNU General Public License as published by the 1062306a36Sopenharmony_ci * Free Software Foundation; either version 2 of the License, or (at your 1162306a36Sopenharmony_ci * option) any later version. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 1462306a36Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1562306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 1662306a36Sopenharmony_ci * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1762306a36Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1862306a36Sopenharmony_ci * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 1962306a36Sopenharmony_ci * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 2062306a36Sopenharmony_ci * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2162306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2262306a36Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License along 2562306a36Sopenharmony_ci * with this program; if not, write to the Free Software Foundation, Inc., 2662306a36Sopenharmony_ci * 675 Mass Ave, Cambridge, MA 02139, USA. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/bcm47xx_nvram.h> 3062306a36Sopenharmony_ci#include <linux/bcm47xx_sprom.h> 3162306a36Sopenharmony_ci#include <linux/bcma/bcma.h> 3262306a36Sopenharmony_ci#include <linux/etherdevice.h> 3362306a36Sopenharmony_ci#include <linux/if_ether.h> 3462306a36Sopenharmony_ci#include <linux/ssb/ssb.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void create_key(const char *prefix, const char *postfix, 3762306a36Sopenharmony_ci const char *name, char *buf, int len) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci if (prefix && postfix) 4062306a36Sopenharmony_ci snprintf(buf, len, "%s%s%s", prefix, name, postfix); 4162306a36Sopenharmony_ci else if (prefix) 4262306a36Sopenharmony_ci snprintf(buf, len, "%s%s", prefix, name); 4362306a36Sopenharmony_ci else if (postfix) 4462306a36Sopenharmony_ci snprintf(buf, len, "%s%s", name, postfix); 4562306a36Sopenharmony_ci else 4662306a36Sopenharmony_ci snprintf(buf, len, "%s", name); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int get_nvram_var(const char *prefix, const char *postfix, 5062306a36Sopenharmony_ci const char *name, char *buf, int len, bool fallback) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci char key[40]; 5362306a36Sopenharmony_ci int err; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci create_key(prefix, postfix, name, key, sizeof(key)); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci err = bcm47xx_nvram_getenv(key, buf, len); 5862306a36Sopenharmony_ci if (fallback && err == -ENOENT && prefix) { 5962306a36Sopenharmony_ci create_key(NULL, postfix, name, key, sizeof(key)); 6062306a36Sopenharmony_ci err = bcm47xx_nvram_getenv(key, buf, len); 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci return err; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define NVRAM_READ_VAL(type) \ 6662306a36Sopenharmony_cistatic void nvram_read_ ## type(const char *prefix, \ 6762306a36Sopenharmony_ci const char *postfix, const char *name, \ 6862306a36Sopenharmony_ci type *val, type allset, bool fallback) \ 6962306a36Sopenharmony_ci{ \ 7062306a36Sopenharmony_ci char buf[100]; \ 7162306a36Sopenharmony_ci int err; \ 7262306a36Sopenharmony_ci type var; \ 7362306a36Sopenharmony_ci \ 7462306a36Sopenharmony_ci err = get_nvram_var(prefix, postfix, name, buf, sizeof(buf), \ 7562306a36Sopenharmony_ci fallback); \ 7662306a36Sopenharmony_ci if (err < 0) \ 7762306a36Sopenharmony_ci return; \ 7862306a36Sopenharmony_ci err = kstrto ## type(strim(buf), 0, &var); \ 7962306a36Sopenharmony_ci if (err) { \ 8062306a36Sopenharmony_ci pr_warn("can not parse nvram name %s%s%s with value %s got %i\n", \ 8162306a36Sopenharmony_ci prefix, name, postfix, buf, err); \ 8262306a36Sopenharmony_ci return; \ 8362306a36Sopenharmony_ci } \ 8462306a36Sopenharmony_ci if (allset && var == allset) \ 8562306a36Sopenharmony_ci return; \ 8662306a36Sopenharmony_ci *val = var; \ 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ciNVRAM_READ_VAL(u8) 9062306a36Sopenharmony_ciNVRAM_READ_VAL(s8) 9162306a36Sopenharmony_ciNVRAM_READ_VAL(u16) 9262306a36Sopenharmony_ciNVRAM_READ_VAL(u32) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#undef NVRAM_READ_VAL 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void nvram_read_u32_2(const char *prefix, const char *name, 9762306a36Sopenharmony_ci u16 *val_lo, u16 *val_hi, bool fallback) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci char buf[100]; 10062306a36Sopenharmony_ci int err; 10162306a36Sopenharmony_ci u32 val; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); 10462306a36Sopenharmony_ci if (err < 0) 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci err = kstrtou32(strim(buf), 0, &val); 10762306a36Sopenharmony_ci if (err) { 10862306a36Sopenharmony_ci pr_warn("can not parse nvram name %s%s with value %s got %i\n", 10962306a36Sopenharmony_ci prefix, name, buf, err); 11062306a36Sopenharmony_ci return; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci *val_lo = (val & 0x0000FFFFU); 11362306a36Sopenharmony_ci *val_hi = (val & 0xFFFF0000U) >> 16; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void nvram_read_leddc(const char *prefix, const char *name, 11762306a36Sopenharmony_ci u8 *leddc_on_time, u8 *leddc_off_time, 11862306a36Sopenharmony_ci bool fallback) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci char buf[100]; 12162306a36Sopenharmony_ci int err; 12262306a36Sopenharmony_ci u32 val; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); 12562306a36Sopenharmony_ci if (err < 0) 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci err = kstrtou32(strim(buf), 0, &val); 12862306a36Sopenharmony_ci if (err) { 12962306a36Sopenharmony_ci pr_warn("can not parse nvram name %s%s with value %s got %i\n", 13062306a36Sopenharmony_ci prefix, name, buf, err); 13162306a36Sopenharmony_ci return; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (val == 0xffff || val == 0xffffffff) 13562306a36Sopenharmony_ci return; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci *leddc_on_time = val & 0xff; 13862306a36Sopenharmony_ci *leddc_off_time = (val >> 16) & 0xff; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void nvram_read_macaddr(const char *prefix, const char *name, 14262306a36Sopenharmony_ci u8 val[6], bool fallback) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci char buf[100]; 14562306a36Sopenharmony_ci int err; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); 14862306a36Sopenharmony_ci if (err < 0) 14962306a36Sopenharmony_ci return; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci strreplace(buf, '-', ':'); 15262306a36Sopenharmony_ci if (!mac_pton(buf, val)) 15362306a36Sopenharmony_ci pr_warn("Can not parse mac address: %s\n", buf); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void nvram_read_alpha2(const char *prefix, const char *name, 15762306a36Sopenharmony_ci char val[2], bool fallback) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci char buf[10]; 16062306a36Sopenharmony_ci int err; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); 16362306a36Sopenharmony_ci if (err < 0) 16462306a36Sopenharmony_ci return; 16562306a36Sopenharmony_ci if (buf[0] == '0') 16662306a36Sopenharmony_ci return; 16762306a36Sopenharmony_ci if (strlen(buf) > 2) { 16862306a36Sopenharmony_ci pr_warn("alpha2 is too long %s\n", buf); 16962306a36Sopenharmony_ci return; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci memcpy(val, buf, 2); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* This is one-function-only macro, it uses local "sprom" variable! */ 17562306a36Sopenharmony_ci#define ENTRY(_revmask, _type, _prefix, _name, _val, _allset, _fallback) \ 17662306a36Sopenharmony_ci if (_revmask & BIT(sprom->revision)) \ 17762306a36Sopenharmony_ci nvram_read_ ## _type(_prefix, NULL, _name, &sprom->_val, \ 17862306a36Sopenharmony_ci _allset, _fallback) 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * Special version of filling function that can be safely called for any SPROM 18162306a36Sopenharmony_ci * revision. For every NVRAM to SPROM mapping it contains bitmask of revisions 18262306a36Sopenharmony_ci * for which the mapping is valid. 18362306a36Sopenharmony_ci * It obviously requires some hexadecimal/bitmasks knowledge, but allows 18462306a36Sopenharmony_ci * writing cleaner code (easy revisions handling). 18562306a36Sopenharmony_ci * Note that while SPROM revision 0 was never used, we still keep BIT(0) 18662306a36Sopenharmony_ci * reserved for it, just to keep numbering sane. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_cistatic void bcm47xx_sprom_fill_auto(struct ssb_sprom *sprom, 18962306a36Sopenharmony_ci const char *prefix, bool fallback) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci const char *pre = prefix; 19262306a36Sopenharmony_ci bool fb = fallback; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Broadcom extracts it for rev 8+ but it was found on 2 and 4 too */ 19562306a36Sopenharmony_ci ENTRY(0xfffffffe, u16, pre, "devid", dev_id, 0, fallback); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ENTRY(0xfffffffe, u16, pre, "boardrev", board_rev, 0, true); 19862306a36Sopenharmony_ci ENTRY(0xfffffffe, u32, pre, "boardflags", boardflags, 0, fb); 19962306a36Sopenharmony_ci ENTRY(0xfffffff0, u32, pre, "boardflags2", boardflags2, 0, fb); 20062306a36Sopenharmony_ci ENTRY(0xfffff800, u32, pre, "boardflags3", boardflags3, 0, fb); 20162306a36Sopenharmony_ci ENTRY(0x00000002, u16, pre, "boardflags", boardflags_lo, 0, fb); 20262306a36Sopenharmony_ci ENTRY(0xfffffffc, u16, pre, "boardtype", board_type, 0, true); 20362306a36Sopenharmony_ci ENTRY(0xfffffffe, u16, pre, "boardnum", board_num, 0, fb); 20462306a36Sopenharmony_ci ENTRY(0x00000002, u8, pre, "cc", country_code, 0, fb); 20562306a36Sopenharmony_ci ENTRY(0xfffffff8, u8, pre, "regrev", regrev, 0, fb); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "ledbh0", gpio0, 0xff, fb); 20862306a36Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "ledbh1", gpio1, 0xff, fb); 20962306a36Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "ledbh2", gpio2, 0xff, fb); 21062306a36Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "ledbh3", gpio3, 0xff, fb); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa0b0", pa0b0, 0, fb); 21362306a36Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa0b1", pa0b1, 0, fb); 21462306a36Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa0b2", pa0b2, 0, fb); 21562306a36Sopenharmony_ci ENTRY(0x0000070e, u8, pre, "pa0itssit", itssi_bg, 0, fb); 21662306a36Sopenharmony_ci ENTRY(0x0000070e, u8, pre, "pa0maxpwr", maxpwr_bg, 0, fb); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci ENTRY(0x0000070c, u8, pre, "opo", opo, 0, fb); 21962306a36Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "aa2g", ant_available_bg, 0, fb); 22062306a36Sopenharmony_ci ENTRY(0xfffffffe, u8, pre, "aa5g", ant_available_a, 0, fb); 22162306a36Sopenharmony_ci ENTRY(0x000007fe, s8, pre, "ag0", antenna_gain.a0, 0, fb); 22262306a36Sopenharmony_ci ENTRY(0x000007fe, s8, pre, "ag1", antenna_gain.a1, 0, fb); 22362306a36Sopenharmony_ci ENTRY(0x000007f0, s8, pre, "ag2", antenna_gain.a2, 0, fb); 22462306a36Sopenharmony_ci ENTRY(0x000007f0, s8, pre, "ag3", antenna_gain.a3, 0, fb); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa1b0", pa1b0, 0, fb); 22762306a36Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa1b1", pa1b1, 0, fb); 22862306a36Sopenharmony_ci ENTRY(0x0000070e, u16, pre, "pa1b2", pa1b2, 0, fb); 22962306a36Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1lob0", pa1lob0, 0, fb); 23062306a36Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1lob1", pa1lob1, 0, fb); 23162306a36Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1lob2", pa1lob2, 0, fb); 23262306a36Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1hib0", pa1hib0, 0, fb); 23362306a36Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1hib1", pa1hib1, 0, fb); 23462306a36Sopenharmony_ci ENTRY(0x0000070c, u16, pre, "pa1hib2", pa1hib2, 0, fb); 23562306a36Sopenharmony_ci ENTRY(0x0000070e, u8, pre, "pa1itssit", itssi_a, 0, fb); 23662306a36Sopenharmony_ci ENTRY(0x0000070e, u8, pre, "pa1maxpwr", maxpwr_a, 0, fb); 23762306a36Sopenharmony_ci ENTRY(0x0000070c, u8, pre, "pa1lomaxpwr", maxpwr_al, 0, fb); 23862306a36Sopenharmony_ci ENTRY(0x0000070c, u8, pre, "pa1himaxpwr", maxpwr_ah, 0, fb); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "bxa2g", bxa2g, 0, fb); 24162306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssisav2g", rssisav2g, 0, fb); 24262306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssismc2g", rssismc2g, 0, fb); 24362306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssismf2g", rssismf2g, 0, fb); 24462306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "bxa5g", bxa5g, 0, fb); 24562306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssisav5g", rssisav5g, 0, fb); 24662306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssismc5g", rssismc5g, 0, fb); 24762306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "rssismf5g", rssismf5g, 0, fb); 24862306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "tri2g", tri2g, 0, fb); 24962306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "tri5g", tri5g, 0, fb); 25062306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "tri5gl", tri5gl, 0, fb); 25162306a36Sopenharmony_ci ENTRY(0x00000708, u8, pre, "tri5gh", tri5gh, 0, fb); 25262306a36Sopenharmony_ci ENTRY(0x00000708, s8, pre, "rxpo2g", rxpo2g, 0, fb); 25362306a36Sopenharmony_ci ENTRY(0x00000708, s8, pre, "rxpo5g", rxpo5g, 0, fb); 25462306a36Sopenharmony_ci ENTRY(0xfffffff0, u8, pre, "txchain", txchain, 0xf, fb); 25562306a36Sopenharmony_ci ENTRY(0xfffffff0, u8, pre, "rxchain", rxchain, 0xf, fb); 25662306a36Sopenharmony_ci ENTRY(0xfffffff0, u8, pre, "antswitch", antswitch, 0xff, fb); 25762306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "tssipos2g", fem.ghz2.tssipos, 0, fb); 25862306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "extpagain2g", fem.ghz2.extpa_gain, 0, fb); 25962306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "pdetrange2g", fem.ghz2.pdet_range, 0, fb); 26062306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "triso2g", fem.ghz2.tr_iso, 0, fb); 26162306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "antswctl2g", fem.ghz2.antswlut, 0, fb); 26262306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "tssipos5g", fem.ghz5.tssipos, 0, fb); 26362306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "extpagain5g", fem.ghz5.extpa_gain, 0, fb); 26462306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "pdetrange5g", fem.ghz5.pdet_range, 0, fb); 26562306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "triso5g", fem.ghz5.tr_iso, 0, fb); 26662306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "antswctl5g", fem.ghz5.antswlut, 0, fb); 26762306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid2ga0", txpid2g[0], 0, fb); 26862306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid2ga1", txpid2g[1], 0, fb); 26962306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid2ga2", txpid2g[2], 0, fb); 27062306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid2ga3", txpid2g[3], 0, fb); 27162306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5ga0", txpid5g[0], 0, fb); 27262306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5ga1", txpid5g[1], 0, fb); 27362306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5ga2", txpid5g[2], 0, fb); 27462306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5ga3", txpid5g[3], 0, fb); 27562306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gla0", txpid5gl[0], 0, fb); 27662306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gla1", txpid5gl[1], 0, fb); 27762306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gla2", txpid5gl[2], 0, fb); 27862306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gla3", txpid5gl[3], 0, fb); 27962306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gha0", txpid5gh[0], 0, fb); 28062306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gha1", txpid5gh[1], 0, fb); 28162306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gha2", txpid5gh[2], 0, fb); 28262306a36Sopenharmony_ci ENTRY(0x000000f0, u8, pre, "txpid5gha3", txpid5gh[3], 0, fb); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempthresh", tempthresh, 0, fb); 28562306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempoffset", tempoffset, 0, fb); 28662306a36Sopenharmony_ci ENTRY(0xffffff00, u16, pre, "rawtempsense", rawtempsense, 0, fb); 28762306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "measpower", measpower, 0, fb); 28862306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempsense_slope", tempsense_slope, 0, fb); 28962306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempcorrx", tempcorrx, 0, fb); 29062306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "tempsense_option", tempsense_option, 0, fb); 29162306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "freqoffset_corr", freqoffset_corr, 0, fb); 29262306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "iqcal_swp_dis", iqcal_swp_dis, 0, fb); 29362306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "hw_iqcal_en", hw_iqcal_en, 0, fb); 29462306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "elna2g", elna2g, 0, fb); 29562306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "elna5g", elna5g, 0, fb); 29662306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "phycal_tempdelta", phycal_tempdelta, 0, fb); 29762306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "temps_period", temps_period, 0, fb); 29862306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "temps_hysteresis", temps_hysteresis, 0, fb); 29962306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "measpower1", measpower1, 0, fb); 30062306a36Sopenharmony_ci ENTRY(0xffffff00, u8, pre, "measpower2", measpower2, 0, fb); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "cck2gpo", cck2gpo, 0, fb); 30362306a36Sopenharmony_ci ENTRY(0x000001f0, u32, pre, "ofdm2gpo", ofdm2gpo, 0, fb); 30462306a36Sopenharmony_ci ENTRY(0x000001f0, u32, pre, "ofdm5gpo", ofdm5gpo, 0, fb); 30562306a36Sopenharmony_ci ENTRY(0x000001f0, u32, pre, "ofdm5glpo", ofdm5glpo, 0, fb); 30662306a36Sopenharmony_ci ENTRY(0x000001f0, u32, pre, "ofdm5ghpo", ofdm5ghpo, 0, fb); 30762306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo0", mcs2gpo[0], 0, fb); 30862306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo1", mcs2gpo[1], 0, fb); 30962306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo2", mcs2gpo[2], 0, fb); 31062306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo3", mcs2gpo[3], 0, fb); 31162306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo4", mcs2gpo[4], 0, fb); 31262306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo5", mcs2gpo[5], 0, fb); 31362306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo6", mcs2gpo[6], 0, fb); 31462306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs2gpo7", mcs2gpo[7], 0, fb); 31562306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo0", mcs5gpo[0], 0, fb); 31662306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo1", mcs5gpo[1], 0, fb); 31762306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo2", mcs5gpo[2], 0, fb); 31862306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo3", mcs5gpo[3], 0, fb); 31962306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo4", mcs5gpo[4], 0, fb); 32062306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo5", mcs5gpo[5], 0, fb); 32162306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo6", mcs5gpo[6], 0, fb); 32262306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5gpo7", mcs5gpo[7], 0, fb); 32362306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo0", mcs5glpo[0], 0, fb); 32462306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo1", mcs5glpo[1], 0, fb); 32562306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo2", mcs5glpo[2], 0, fb); 32662306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo3", mcs5glpo[3], 0, fb); 32762306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo4", mcs5glpo[4], 0, fb); 32862306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo5", mcs5glpo[5], 0, fb); 32962306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo6", mcs5glpo[6], 0, fb); 33062306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5glpo7", mcs5glpo[7], 0, fb); 33162306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo0", mcs5ghpo[0], 0, fb); 33262306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo1", mcs5ghpo[1], 0, fb); 33362306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo2", mcs5ghpo[2], 0, fb); 33462306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo3", mcs5ghpo[3], 0, fb); 33562306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo4", mcs5ghpo[4], 0, fb); 33662306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo5", mcs5ghpo[5], 0, fb); 33762306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo6", mcs5ghpo[6], 0, fb); 33862306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "mcs5ghpo7", mcs5ghpo[7], 0, fb); 33962306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "cddpo", cddpo, 0, fb); 34062306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "stbcpo", stbcpo, 0, fb); 34162306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "bw40po", bw40po, 0, fb); 34262306a36Sopenharmony_ci ENTRY(0x000001f0, u16, pre, "bwduppo", bwduppo, 0, fb); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ENTRY(0xfffffe00, u16, pre, "cckbw202gpo", cckbw202gpo, 0, fb); 34562306a36Sopenharmony_ci ENTRY(0xfffffe00, u16, pre, "cckbw20ul2gpo", cckbw20ul2gpo, 0, fb); 34662306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw202gpo", legofdmbw202gpo, 0, fb); 34762306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw20ul2gpo", legofdmbw20ul2gpo, 0, fb); 34862306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw205glpo", legofdmbw205glpo, 0, fb); 34962306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw20ul5glpo", legofdmbw20ul5glpo, 0, fb); 35062306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw205gmpo", legofdmbw205gmpo, 0, fb); 35162306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw20ul5gmpo", legofdmbw20ul5gmpo, 0, fb); 35262306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw205ghpo", legofdmbw205ghpo, 0, fb); 35362306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "legofdmbw20ul5ghpo", legofdmbw20ul5ghpo, 0, fb); 35462306a36Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw202gpo", mcsbw202gpo, 0, fb); 35562306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "mcsbw20ul2gpo", mcsbw20ul2gpo, 0, fb); 35662306a36Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw402gpo", mcsbw402gpo, 0, fb); 35762306a36Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw205glpo", mcsbw205glpo, 0, fb); 35862306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "mcsbw20ul5glpo", mcsbw20ul5glpo, 0, fb); 35962306a36Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw405glpo", mcsbw405glpo, 0, fb); 36062306a36Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw205gmpo", mcsbw205gmpo, 0, fb); 36162306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "mcsbw20ul5gmpo", mcsbw20ul5gmpo, 0, fb); 36262306a36Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw405gmpo", mcsbw405gmpo, 0, fb); 36362306a36Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw205ghpo", mcsbw205ghpo, 0, fb); 36462306a36Sopenharmony_ci ENTRY(0x00000600, u32, pre, "mcsbw20ul5ghpo", mcsbw20ul5ghpo, 0, fb); 36562306a36Sopenharmony_ci ENTRY(0xfffffe00, u32, pre, "mcsbw405ghpo", mcsbw405ghpo, 0, fb); 36662306a36Sopenharmony_ci ENTRY(0x00000600, u16, pre, "mcs32po", mcs32po, 0, fb); 36762306a36Sopenharmony_ci ENTRY(0x00000600, u16, pre, "legofdm40duppo", legofdm40duppo, 0, fb); 36862306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "pcieingress_war", pcieingress_war, 0, fb); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* TODO: rev 11 support */ 37162306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr2ga0", rxgainerr2ga[0], 0, fb); 37262306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr2ga1", rxgainerr2ga[1], 0, fb); 37362306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr2ga2", rxgainerr2ga[2], 0, fb); 37462306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gla0", rxgainerr5gla[0], 0, fb); 37562306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gla1", rxgainerr5gla[1], 0, fb); 37662306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gla2", rxgainerr5gla[2], 0, fb); 37762306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gma0", rxgainerr5gma[0], 0, fb); 37862306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gma1", rxgainerr5gma[1], 0, fb); 37962306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gma2", rxgainerr5gma[2], 0, fb); 38062306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gha0", rxgainerr5gha[0], 0, fb); 38162306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gha1", rxgainerr5gha[1], 0, fb); 38262306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gha2", rxgainerr5gha[2], 0, fb); 38362306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gua0", rxgainerr5gua[0], 0, fb); 38462306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gua1", rxgainerr5gua[1], 0, fb); 38562306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "rxgainerr5gua2", rxgainerr5gua[2], 0, fb); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci ENTRY(0xfffffe00, u8, pre, "sar2g", sar2g, 0, fb); 38862306a36Sopenharmony_ci ENTRY(0xfffffe00, u8, pre, "sar5g", sar5g, 0, fb); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* TODO: rev 11 support */ 39162306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl2ga0", noiselvl2ga[0], 0, fb); 39262306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl2ga1", noiselvl2ga[1], 0, fb); 39362306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl2ga2", noiselvl2ga[2], 0, fb); 39462306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gla0", noiselvl5gla[0], 0, fb); 39562306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gla1", noiselvl5gla[1], 0, fb); 39662306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gla2", noiselvl5gla[2], 0, fb); 39762306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gma0", noiselvl5gma[0], 0, fb); 39862306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gma1", noiselvl5gma[1], 0, fb); 39962306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gma2", noiselvl5gma[2], 0, fb); 40062306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gha0", noiselvl5gha[0], 0, fb); 40162306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gha1", noiselvl5gha[1], 0, fb); 40262306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gha2", noiselvl5gha[2], 0, fb); 40362306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gua0", noiselvl5gua[0], 0, fb); 40462306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gua1", noiselvl5gua[1], 0, fb); 40562306a36Sopenharmony_ci ENTRY(0x00000700, u8, pre, "noiselvl5gua2", noiselvl5gua[2], 0, fb); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci#undef ENTRY /* It's specififc, uses local variable, don't use it (again). */ 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom, 41062306a36Sopenharmony_ci const char *prefix, bool fallback) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci char postfix[2]; 41362306a36Sopenharmony_ci int i; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) { 41662306a36Sopenharmony_ci struct ssb_sprom_core_pwr_info *pwr_info; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci pwr_info = &sprom->core_pwr_info[i]; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci snprintf(postfix, sizeof(postfix), "%i", i); 42162306a36Sopenharmony_ci nvram_read_u8(prefix, postfix, "maxp2ga", 42262306a36Sopenharmony_ci &pwr_info->maxpwr_2g, 0, fallback); 42362306a36Sopenharmony_ci nvram_read_u8(prefix, postfix, "itt2ga", 42462306a36Sopenharmony_ci &pwr_info->itssi_2g, 0, fallback); 42562306a36Sopenharmony_ci nvram_read_u8(prefix, postfix, "itt5ga", 42662306a36Sopenharmony_ci &pwr_info->itssi_5g, 0, fallback); 42762306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa2gw0a", 42862306a36Sopenharmony_ci &pwr_info->pa_2g[0], 0, fallback); 42962306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa2gw1a", 43062306a36Sopenharmony_ci &pwr_info->pa_2g[1], 0, fallback); 43162306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa2gw2a", 43262306a36Sopenharmony_ci &pwr_info->pa_2g[2], 0, fallback); 43362306a36Sopenharmony_ci nvram_read_u8(prefix, postfix, "maxp5ga", 43462306a36Sopenharmony_ci &pwr_info->maxpwr_5g, 0, fallback); 43562306a36Sopenharmony_ci nvram_read_u8(prefix, postfix, "maxp5gha", 43662306a36Sopenharmony_ci &pwr_info->maxpwr_5gh, 0, fallback); 43762306a36Sopenharmony_ci nvram_read_u8(prefix, postfix, "maxp5gla", 43862306a36Sopenharmony_ci &pwr_info->maxpwr_5gl, 0, fallback); 43962306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5gw0a", 44062306a36Sopenharmony_ci &pwr_info->pa_5g[0], 0, fallback); 44162306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5gw1a", 44262306a36Sopenharmony_ci &pwr_info->pa_5g[1], 0, fallback); 44362306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5gw2a", 44462306a36Sopenharmony_ci &pwr_info->pa_5g[2], 0, fallback); 44562306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5glw0a", 44662306a36Sopenharmony_ci &pwr_info->pa_5gl[0], 0, fallback); 44762306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5glw1a", 44862306a36Sopenharmony_ci &pwr_info->pa_5gl[1], 0, fallback); 44962306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5glw2a", 45062306a36Sopenharmony_ci &pwr_info->pa_5gl[2], 0, fallback); 45162306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5ghw0a", 45262306a36Sopenharmony_ci &pwr_info->pa_5gh[0], 0, fallback); 45362306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5ghw1a", 45462306a36Sopenharmony_ci &pwr_info->pa_5gh[1], 0, fallback); 45562306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5ghw2a", 45662306a36Sopenharmony_ci &pwr_info->pa_5gh[2], 0, fallback); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom, 46162306a36Sopenharmony_ci const char *prefix, bool fallback) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci char postfix[2]; 46462306a36Sopenharmony_ci int i; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) { 46762306a36Sopenharmony_ci struct ssb_sprom_core_pwr_info *pwr_info; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci pwr_info = &sprom->core_pwr_info[i]; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci snprintf(postfix, sizeof(postfix), "%i", i); 47262306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa2gw3a", 47362306a36Sopenharmony_ci &pwr_info->pa_2g[3], 0, fallback); 47462306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5gw3a", 47562306a36Sopenharmony_ci &pwr_info->pa_5g[3], 0, fallback); 47662306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5glw3a", 47762306a36Sopenharmony_ci &pwr_info->pa_5gl[3], 0, fallback); 47862306a36Sopenharmony_ci nvram_read_u16(prefix, postfix, "pa5ghw3a", 47962306a36Sopenharmony_ci &pwr_info->pa_5gh[3], 0, fallback); 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic bool bcm47xx_is_valid_mac(u8 *mac) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int bcm47xx_increase_mac_addr(u8 *mac, u8 num) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci u8 *oui = mac + ETH_ALEN/2 - 1; 49162306a36Sopenharmony_ci u8 *p = mac + ETH_ALEN - 1; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci do { 49462306a36Sopenharmony_ci (*p) += num; 49562306a36Sopenharmony_ci if (*p > num) 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci p--; 49862306a36Sopenharmony_ci num = 1; 49962306a36Sopenharmony_ci } while (p != oui); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (p == oui) { 50262306a36Sopenharmony_ci pr_err("unable to fetch mac address\n"); 50362306a36Sopenharmony_ci return -ENOENT; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int mac_addr_used = 2; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, 51162306a36Sopenharmony_ci const char *prefix, bool fallback) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci bool fb = fallback; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci nvram_read_macaddr(prefix, "et0macaddr", sprom->et0mac, fallback); 51662306a36Sopenharmony_ci nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0, 51762306a36Sopenharmony_ci fallback); 51862306a36Sopenharmony_ci nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0, 51962306a36Sopenharmony_ci fallback); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci nvram_read_macaddr(prefix, "et1macaddr", sprom->et1mac, fallback); 52262306a36Sopenharmony_ci nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0, 52362306a36Sopenharmony_ci fallback); 52462306a36Sopenharmony_ci nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0, 52562306a36Sopenharmony_ci fallback); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci nvram_read_macaddr(prefix, "et2macaddr", sprom->et2mac, fb); 52862306a36Sopenharmony_ci nvram_read_u8(prefix, NULL, "et2mdcport", &sprom->et2mdcport, 0, fb); 52962306a36Sopenharmony_ci nvram_read_u8(prefix, NULL, "et2phyaddr", &sprom->et2phyaddr, 0, fb); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci nvram_read_macaddr(prefix, "macaddr", sprom->il0mac, fallback); 53262306a36Sopenharmony_ci nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* The address prefix 00:90:4C is used by Broadcom in their initial 53562306a36Sopenharmony_ci * configuration. When a mac address with the prefix 00:90:4C is used 53662306a36Sopenharmony_ci * all devices from the same series are sharing the same mac address. 53762306a36Sopenharmony_ci * To prevent mac address collisions we replace them with a mac address 53862306a36Sopenharmony_ci * based on the base address. 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_ci if (!bcm47xx_is_valid_mac(sprom->il0mac)) { 54162306a36Sopenharmony_ci u8 mac[6]; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci nvram_read_macaddr(NULL, "et0macaddr", mac, false); 54462306a36Sopenharmony_ci if (bcm47xx_is_valid_mac(mac)) { 54562306a36Sopenharmony_ci int err = bcm47xx_increase_mac_addr(mac, mac_addr_used); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (!err) { 54862306a36Sopenharmony_ci ether_addr_copy(sprom->il0mac, mac); 54962306a36Sopenharmony_ci mac_addr_used++; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix, 55662306a36Sopenharmony_ci bool fallback) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo, 55962306a36Sopenharmony_ci &sprom->boardflags_hi, fallback); 56062306a36Sopenharmony_ci nvram_read_u32_2(prefix, "boardflags2", &sprom->boardflags2_lo, 56162306a36Sopenharmony_ci &sprom->boardflags2_hi, fallback); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_civoid bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix, 56562306a36Sopenharmony_ci bool fallback) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci bcm47xx_fill_sprom_ethernet(sprom, prefix, fallback); 56862306a36Sopenharmony_ci bcm47xx_fill_board_data(sprom, prefix, fallback); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0, fallback); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Entries requiring custom functions */ 57362306a36Sopenharmony_ci nvram_read_alpha2(prefix, "ccode", sprom->alpha2, fallback); 57462306a36Sopenharmony_ci if (sprom->revision >= 3) 57562306a36Sopenharmony_ci nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time, 57662306a36Sopenharmony_ci &sprom->leddc_off_time, fallback); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci switch (sprom->revision) { 57962306a36Sopenharmony_ci case 4: 58062306a36Sopenharmony_ci case 5: 58162306a36Sopenharmony_ci bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback); 58262306a36Sopenharmony_ci bcm47xx_fill_sprom_path_r45(sprom, prefix, fallback); 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci case 8: 58562306a36Sopenharmony_ci case 9: 58662306a36Sopenharmony_ci bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback); 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci bcm47xx_sprom_fill_auto(sprom, prefix, fallback); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_SSB) && IS_ENABLED(CONFIG_SSB_SPROM) 59462306a36Sopenharmony_cistatic int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci char prefix[10]; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci switch (bus->bustype) { 59962306a36Sopenharmony_ci case SSB_BUSTYPE_SSB: 60062306a36Sopenharmony_ci bcm47xx_fill_sprom(out, NULL, false); 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci case SSB_BUSTYPE_PCI: 60362306a36Sopenharmony_ci memset(out, 0, sizeof(struct ssb_sprom)); 60462306a36Sopenharmony_ci snprintf(prefix, sizeof(prefix), "pci/%u/%u/", 60562306a36Sopenharmony_ci bus->host_pci->bus->number + 1, 60662306a36Sopenharmony_ci PCI_SLOT(bus->host_pci->devfn)); 60762306a36Sopenharmony_ci bcm47xx_fill_sprom(out, prefix, false); 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci default: 61062306a36Sopenharmony_ci pr_warn("Unable to fill SPROM for given bustype.\n"); 61162306a36Sopenharmony_ci return -EINVAL; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci#endif 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_BCMA) 61762306a36Sopenharmony_ci/* 61862306a36Sopenharmony_ci * Having many NVRAM entries for PCI devices led to repeating prefixes like 61962306a36Sopenharmony_ci * pci/1/1/ all the time and wasting flash space. So at some point Broadcom 62062306a36Sopenharmony_ci * decided to introduce prefixes like 0: 1: 2: etc. 62162306a36Sopenharmony_ci * If we find e.g. devpath0=pci/2/1 or devpath0=pci/2/1/ we should use 0: 62262306a36Sopenharmony_ci * instead of pci/2/1/. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_cistatic void bcm47xx_sprom_apply_prefix_alias(char *prefix, size_t prefix_size) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci size_t prefix_len = strlen(prefix); 62762306a36Sopenharmony_ci size_t short_len = prefix_len - 1; 62862306a36Sopenharmony_ci char nvram_var[10]; 62962306a36Sopenharmony_ci char buf[20]; 63062306a36Sopenharmony_ci int i; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* Passed prefix has to end with a slash */ 63362306a36Sopenharmony_ci if (prefix_len <= 0 || prefix[prefix_len - 1] != '/') 63462306a36Sopenharmony_ci return; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 63762306a36Sopenharmony_ci if (snprintf(nvram_var, sizeof(nvram_var), "devpath%d", i) <= 0) 63862306a36Sopenharmony_ci continue; 63962306a36Sopenharmony_ci if (bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf)) < 0) 64062306a36Sopenharmony_ci continue; 64162306a36Sopenharmony_ci if (!strcmp(buf, prefix) || 64262306a36Sopenharmony_ci (short_len && strlen(buf) == short_len && !strncmp(buf, prefix, short_len))) { 64362306a36Sopenharmony_ci snprintf(prefix, prefix_size, "%d:", i); 64462306a36Sopenharmony_ci return; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct bcma_boardinfo *binfo = &bus->boardinfo; 65262306a36Sopenharmony_ci struct bcma_device *core; 65362306a36Sopenharmony_ci char buf[10]; 65462306a36Sopenharmony_ci char *prefix; 65562306a36Sopenharmony_ci bool fallback = false; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci switch (bus->hosttype) { 65862306a36Sopenharmony_ci case BCMA_HOSTTYPE_PCI: 65962306a36Sopenharmony_ci memset(out, 0, sizeof(struct ssb_sprom)); 66062306a36Sopenharmony_ci /* On BCM47XX all PCI buses share the same domain */ 66162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_BCM47XX)) 66262306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "pci/%u/%u/", 66362306a36Sopenharmony_ci bus->host_pci->bus->number + 1, 66462306a36Sopenharmony_ci PCI_SLOT(bus->host_pci->devfn)); 66562306a36Sopenharmony_ci else 66662306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "pci/%u/%u/", 66762306a36Sopenharmony_ci pci_domain_nr(bus->host_pci->bus) + 1, 66862306a36Sopenharmony_ci bus->host_pci->bus->number); 66962306a36Sopenharmony_ci bcm47xx_sprom_apply_prefix_alias(buf, sizeof(buf)); 67062306a36Sopenharmony_ci prefix = buf; 67162306a36Sopenharmony_ci break; 67262306a36Sopenharmony_ci case BCMA_HOSTTYPE_SOC: 67362306a36Sopenharmony_ci memset(out, 0, sizeof(struct ssb_sprom)); 67462306a36Sopenharmony_ci core = bcma_find_core(bus, BCMA_CORE_80211); 67562306a36Sopenharmony_ci if (core) { 67662306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "sb/%u/", 67762306a36Sopenharmony_ci core->core_index); 67862306a36Sopenharmony_ci prefix = buf; 67962306a36Sopenharmony_ci fallback = true; 68062306a36Sopenharmony_ci } else { 68162306a36Sopenharmony_ci prefix = NULL; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci default: 68562306a36Sopenharmony_ci pr_warn("Unable to fill SPROM for given bustype.\n"); 68662306a36Sopenharmony_ci return -EINVAL; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci nvram_read_u16(prefix, NULL, "boardvendor", &binfo->vendor, 0, true); 69062306a36Sopenharmony_ci if (!binfo->vendor) 69162306a36Sopenharmony_ci binfo->vendor = SSB_BOARDVENDOR_BCM; 69262306a36Sopenharmony_ci nvram_read_u16(prefix, NULL, "boardtype", &binfo->type, 0, true); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci bcm47xx_fill_sprom(out, prefix, fallback); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return 0; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci#endif 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic unsigned int bcm47xx_sprom_registered; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci/* 70362306a36Sopenharmony_ci * On bcm47xx we need to register SPROM fallback handler very early, so we can't 70462306a36Sopenharmony_ci * use anything like platform device / driver for this. 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ciint bcm47xx_sprom_register_fallbacks(void) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci if (bcm47xx_sprom_registered) 70962306a36Sopenharmony_ci return 0; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_SSB) && IS_ENABLED(CONFIG_SSB_SPROM) 71262306a36Sopenharmony_ci if (ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb)) 71362306a36Sopenharmony_ci pr_warn("Failed to register ssb SPROM handler\n"); 71462306a36Sopenharmony_ci#endif 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_BCMA) 71762306a36Sopenharmony_ci if (bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma)) 71862306a36Sopenharmony_ci pr_warn("Failed to register bcma SPROM handler\n"); 71962306a36Sopenharmony_ci#endif 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci bcm47xx_sprom_registered = 1; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cifs_initcall(bcm47xx_sprom_register_fallbacks); 727