[OpenWrt-Devel] [PATCH 3/6] bcm53xx - update sprom from nvram to handle rev 11
Ian Kent
raven at themaw.net
Mon Mar 9 05:09:01 EDT 2015
Add new sprom revision 11 variables to the nvram -> sprom reader.
Signed-off-by: Ian Kent <raven at themaw.net>
---
.../111-bcm53xx-add-sprom-rev-11-vars.patch | 426 ++++++++++++++++++++
.../111-bcm53xx-add-sprom-rev-11-vars.patch | 432 ++++++++++++++++++++
2 files changed, 858 insertions(+)
create mode 100644 target/linux/bcm53xx/patches-3.14/111-bcm53xx-add-sprom-rev-11-vars.patch
create mode 100644 target/linux/bcm53xx/patches-3.18/111-bcm53xx-add-sprom-rev-11-vars.patch
diff --git a/target/linux/bcm53xx/patches-3.14/111-bcm53xx-add-sprom-rev-11-vars.patch b/target/linux/bcm53xx/patches-3.14/111-bcm53xx-add-sprom-rev-11-vars.patch
new file mode 100644
index 0000000..463c8b9
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/111-bcm53xx-add-sprom-rev-11-vars.patch
@@ -0,0 +1,426 @@
+bcm53xx - add sprom rev 11 vars
+
+From: Ian Kent <raven at themaw.net>
+
+Up date bcm47xx-sprom.c to read new sprom revision 11 variables.
+
+Signed-off-by: Ian Kent <raven at themaw.net>
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -165,7 +165,7 @@ static int bcma_sprom_valid(struct bcma_
+ return err;
+
+ revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
+- if (revision != 8 && revision != 9 && revision != 10) {
++ if (revision < 8 || revision > 11) {
+ pr_err("Unsupported SPROM revision: %d\n", revision);
+ return -ENOENT;
+ }
+--- a/drivers/misc/bcm47xx-sprom.c
++++ b/drivers/misc/bcm47xx-sprom.c
+@@ -187,6 +187,30 @@ static void nvram_read_alpha2(const stru
+ memcpy(val, buf, 2);
+ }
+
++static void nvram_read_string(const struct bcm47xx_sprom_fill *fill,
++ const char *name, char *val, unsigned int len)
++{
++ char buf[121];
++ int err;
++
++ *val = '\0';
++
++ if (len > 120)
++ return;
++
++ memset(buf, 0, 121);
++ err = get_nvram_var(fill, NULL, name, buf, sizeof(buf) - 1);
++ if (err < 0)
++ return;
++ if (buf[0] == '0')
++ return;
++ if (buf[120] != '\0') {
++ pr_warn("string is too long %s\n", buf);
++ return;
++ }
++ strcpy(val, buf);
++}
++
+ static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
+ const struct bcm47xx_sprom_fill *fill)
+ {
+@@ -439,6 +463,63 @@ static void bcm47xx_sprom_fill_r9(struct
+ nvram_read_u8(fill, NULL, "sar5g", &sprom->sar5g, 0);
+ }
+
++static void bcm47xx_sprom_fill_r11(struct ssb_sprom *sprom,
++ const struct bcm47xx_sprom_fill *fill)
++{
++ nvram_read_u8(fill, NULL, "agbg0", &sprom->agbg0, 0);
++ nvram_read_u8(fill, NULL, "agbg1", &sprom->agbg1, 0);
++ nvram_read_u8(fill, NULL, "agbg2", &sprom->agbg2, 0);
++ nvram_read_u8(fill, NULL, "aga0", &sprom->aga0, 0);
++ nvram_read_u8(fill, NULL, "aga1", &sprom->aga1, 0);
++ nvram_read_u8(fill, NULL, "aga2", &sprom->aga2, 0);
++ nvram_read_u8(fill, NULL, "tssiposslope2g", &sprom->tssiposslope2g, 0);
++ nvram_read_u8(fill, NULL, "epagain2g", &sprom->epagain2g, 0);
++ nvram_read_u8(fill, NULL, "pdgain2g", &sprom->pdgain2g, 0);
++ nvram_read_u8(fill, NULL, "tworangetssi2g", &sprom->tworangetssi2g, 0);
++ nvram_read_u8(fill, NULL, "papdcap2g", &sprom->papdcap2g, 0);
++ nvram_read_u8(fill, NULL, "femctrl", &sprom->femctrl, 0);
++ nvram_read_u8(fill, NULL, "tssiposslope5g", &sprom->tssiposslope5g, 0);
++ nvram_read_u8(fill, NULL, "epagain5g", &sprom->epagain5g, 0);
++ nvram_read_u8(fill, NULL, "pdgain5g", &sprom->pdgain5g, 0);
++ nvram_read_u8(fill, NULL, "tworangetssi5g", &sprom->tworangetssi5g, 0);
++ nvram_read_u8(fill, NULL, "papdcap5g", &sprom->papdcap5g, 0);
++ nvram_read_u8(fill, NULL, "gainctrlsph", &sprom->gainctrlsph, 0);
++ nvram_read_u16(fill, NULL, "pdoffset40ma0", &sprom->pdoffset40ma0, 0);
++ nvram_read_u16(fill, NULL, "pdoffset40ma1", &sprom->pdoffset40ma1, 0);
++ nvram_read_u16(fill, NULL, "pdoffset40ma2", &sprom->pdoffset40ma2, 0);
++ nvram_read_u16(fill, NULL, "pdoffset80ma0", &sprom->pdoffset80ma0, 0);
++ nvram_read_u16(fill, NULL, "pdoffset80ma1", &sprom->pdoffset80ma1, 0);
++ nvram_read_u16(fill, NULL, "pdoffset80ma2", &sprom->pdoffset80ma2, 0);
++ nvram_read_u16(fill, NULL, "dot11agofdmhrbw202gpo", &sprom->dot11agofdmhrbw202gpo, 0);
++ nvram_read_u16(fill, NULL, "ofdmlrbw202gpo", &sprom->ofdmlrbw202gpo, 0);
++ nvram_read_u16(fill, NULL, "mcsbw805glpo", &sprom->mcsbw805glpo, 0);
++ nvram_read_u16(fill, NULL, "mcsbw1605glpo", &sprom->mcsbw1605glpo, 0);
++ nvram_read_u16(fill, NULL, "mcsbw805ghpo", &sprom->mcsbw805ghpo, 0);
++ nvram_read_u16(fill, NULL, "mcsbw1605ghpo", &sprom->mcsbw1605ghpo, 0);
++ nvram_read_u16(fill, NULL, "mcslr5glpo", &sprom->ofdmlrbw202gpo, 0);
++ nvram_read_u16(fill, NULL, "mcslr5gmpo", &sprom->mcslr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "mcslr5ghpo", &sprom->mcslr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in40hrrpo", &sprom->sb20in40hrrpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160hr5glpo", &sprom->sb20in80and160hr5glpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80hr5glpo", &sprom->sb40and80hr5glpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160hr5gmpo", &sprom->sb20in80and160hr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80hr5gmpo", &sprom->sb40and80hr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160hr5ghpo", &sprom->sb20in80and160hr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80hr5ghpo", &sprom->sb40and80hr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in40lrpo", &sprom->sb20in40lrpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160lr5glpo", &sprom->sb20in80and160lr5glpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80lr5glpo", &sprom->sb40and80lr5glpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in40lrpo", &sprom->sb20in40lrpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160lr5gmpo", &sprom->sb20in80and160lr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80lr5gmpo", &sprom->sb40and80lr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160lr5ghpo", &sprom->sb20in80and160lr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80lr5ghpo", &sprom->sb40and80lr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "dot11agduphrpo", &sprom->dot11agduphrpo, 0);
++ nvram_read_u16(fill, NULL, "dot11agduplrpo", &sprom->dot11agduplrpo, 0);
++ nvram_read_u16(fill, NULL, "rxgainerr2g", &sprom->rxgainerr2g, 0);
++ nvram_read_u16(fill, NULL, "rxgainerr5g", &sprom->rxgainerr5g, 0);
++}
++
+ static void bcm47xx_sprom_fill_path_r4589(struct ssb_sprom *sprom,
+ const struct bcm47xx_sprom_fill *fill)
+ {
+@@ -487,6 +568,172 @@ static void bcm47xx_sprom_fill_path_r45(
+ }
+ }
+
++static void bcm47xx_sprom_fill_path_r11(struct ssb_sprom *sprom,
++ const struct bcm47xx_sprom_fill *fill)
++{
++ char postfix[2];
++ unsigned int entry_count;
++ char tmp[40], val[100];
++ int i, j;
++
++ for (i = 0; i < ARRAY_SIZE(sprom->core_rxgains_info); i++) {
++ struct ssb_sprom_core_pwr_info *pwr_info;
++ struct ssb_sprom_core_rxgains_info *gains_info;
++
++ gains_info = &sprom->core_rxgains_info[i];
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gmelnagaina);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gmelnagaina");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gmelnagaina[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gmtrisoa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gmtrisoa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gmtrisoa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gmtrelnabypa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gmtrelnabypa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gmtrelnabypa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5ghelnagaina);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5ghelnagaina");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5ghelnagaina[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5ghtrisoa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5ghtrisoa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5ghtrisoa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5ghtrelnabypa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5ghtrelnabypa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5ghtrelnabypa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains2gelnagaina);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains2gelnagaina");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains2gelnagaina[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains2gtrisoa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains2gtrisoa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains2gtrisoa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains2gtrelnabypa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains2gtrelnabypa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains2gtrelnabypa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gelnagaina);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gelnagaina");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gelnagaina[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gtrisoa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gtrisoa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gtrisoa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gtrelnabypa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gtrelnabypa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gtrelnabypa[j], 0);
++ }
++
++ pwr_info = &sprom->core_pwr_info[i];
++
++ entry_count = ARRAY_SIZE(pwr_info->pa2ga);
++ for (j = 0; j < entry_count; j++) {
++ char *str = &val[0];
++ char *tok;
++ int k;
++
++ snprintf(tmp, sizeof(tmp), "%i:%s%i", i, "pa2ga", j);
++ nvram_read_string(fill, tmp, val, 99);
++
++ if (!*val)
++ continue;
++
++ k = 0;
++ while ((tok = strsep(&str, ","))) {
++ unsigned long res;
++ int err;
++
++ err = kstrtoul(tok, 0, &res);
++ if (err)
++ continue;
++ pwr_info->pa5ga[j][k] = (u16) res;
++ if (++k > 11)
++ break;
++ }
++ }
++
++ entry_count = ARRAY_SIZE(pwr_info->pa5ga);
++ for (j = 0; j < entry_count; j++) {
++ char *str = &val[0];
++ char *tok;
++ int k;
++
++ snprintf(tmp, sizeof(tmp), "%i:%s%i", i, "pa5ga", j);
++ nvram_read_string(fill, tmp, val, 99);
++
++ if (!*val)
++ continue;
++
++ k = 0;
++ while ((tok = strsep(&str, ","))) {
++ unsigned long res;
++ int err;
++
++ err = kstrtoul(tok, 0, &res);
++ if (err)
++ continue;
++ pwr_info->pa5ga[j][k] = (u16) res;
++ if (++k > 11)
++ break;
++ }
++ }
++ }
++}
++
+ static bool bcm47xx_is_valid_mac(u8 *mac)
+ {
+ return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c);
+@@ -568,6 +815,9 @@ static void bcm47xx_sprom_fill_board_dat
+ &sprom->boardflags_hi);
+ nvram_read_u32_2(fill, "boardflags2", &sprom->boardflags2_lo,
+ &sprom->boardflags2_hi);
++ if (sprom->revision > 10)
++ nvram_read_u32_2(fill, "boardflags3", &sprom->boardflags3_lo,
++ &sprom->boardflags3_hi);
+ }
+
+ static void bcm47xx_sprom_fill(struct ssb_sprom *sprom,
+@@ -625,6 +875,18 @@ static void bcm47xx_sprom_fill(struct ss
+ bcm47xx_sprom_fill_r9(sprom, fill);
+ bcm47xx_sprom_fill_path_r4589(sprom, fill);
+ break;
++
++ case 11:
++ bcm47xx_sprom_fill_r1234589(sprom, fill);
++ bcm47xx_sprom_fill_r4589(sprom, fill);
++ bcm47xx_sprom_fill_r89(sprom, fill);
++ bcm47xx_sprom_fill_r9(sprom, fill);
++ bcm47xx_sprom_fill_r11(sprom, fill);
++ /* For maxp2ga and maxp5ga only */
++ bcm47xx_sprom_fill_path_r4589(sprom, fill);
++ bcm47xx_sprom_fill_path_r11(sprom, fill);
++ break;
++
+ default:
+ pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
+ sprom->revision);
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -13,6 +13,8 @@
+
+ #include <linux/ssb/ssb_regs.h>
+
++#define RXGAINS_PATH_COUNT 3
++#define RXGAINS_ENTRY_COUNT 3
+
+ struct pcmcia_device;
+ struct ssb_bus;
+@@ -22,6 +24,24 @@ struct ssb_sprom_core_pwr_info {
+ u8 itssi_2g, itssi_5g;
+ u8 maxpwr_2g, maxpwr_5gl, maxpwr_5g, maxpwr_5gh;
+ u16 pa_2g[4], pa_5gl[4], pa_5g[4], pa_5gh[4];
++ /* rev 11 */
++ u16 pa2ga[3][12], pa5ga[3][12];
++};
++
++/* rev 11 rxnoise */
++struct ssb_sprom_core_rxgains_info {
++ u8 rxgains5gmelnagaina[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gmtrisoa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gmtrelnabypa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5ghelnagaina[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5ghtrisoa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5ghtrelnabypa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains2gelnagaina[RXGAINS_ENTRY_COUNT];
++ u8 rxgains2gtrisoa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains2gtrelnabypa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gelnagaina[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gtrisoa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gtrelnabypa[RXGAINS_ENTRY_COUNT];
+ };
+
+ struct ssb_sprom {
+@@ -93,6 +113,9 @@ struct ssb_sprom {
+ u16 boardflags2_lo; /* Board flags (bits 32-47) */
+ u16 boardflags2_hi; /* Board flags (bits 48-63) */
+ /* TODO store board flags in a single u64 */
++ /* spromrev 11 */
++ u16 boardflags3_lo; /* Board flags (bits 64-79) */
++ u16 boardflags3_hi; /* Board flags (bits 80-95) */
+
+ struct ssb_sprom_core_pwr_info core_pwr_info[4];
+
+@@ -185,6 +208,62 @@ struct ssb_sprom {
+ u16 legofdm40duppo;
+ u8 sar2g;
+ u8 sar5g;
++
++ /* spromrev 11 */
++ u8 agbg0;
++ u8 agbg1;
++ u8 agbg2;
++ u8 aga0;
++ u8 aga1;
++ u8 aga2;
++ u8 tssiposslope2g;
++ u8 epagain2g;
++ u8 pdgain2g;
++ u8 tworangetssi2g;
++ u8 papdcap2g;
++ u8 femctrl;
++ u8 tssiposslope5g;
++ u8 epagain5g;
++ u8 pdgain5g;
++ u8 tworangetssi5g;
++ u8 papdcap5g;
++ u8 gainctrlsph;
++ u16 pdoffset40ma0;
++ u16 pdoffset40ma1;
++ u16 pdoffset40ma2;
++ u16 pdoffset80ma0;
++ u16 pdoffset80ma1;
++ u16 pdoffset80ma2;
++ u16 dot11agofdmhrbw202gpo;
++ u16 ofdmlrbw202gpo;
++ u16 mcsbw805glpo;
++ u16 mcsbw1605glpo;
++ u16 mcsbw805ghpo;
++ u16 mcsbw1605ghpo;
++ u16 mcslr5glpo;
++ u16 mcslr5gmpo;
++ u16 mcslr5ghpo;
++ u16 sb20in40hrrpo;
++ u16 sb20in80and160hr5glpo;
++ u16 sb40and80hr5glpo;
++ u16 sb20in80and160hr5gmpo;
++ u16 sb40and80hr5gmpo;
++ u16 sb20in80and160hr5ghpo;
++ u16 sb40and80hr5ghpo;
++ u16 sb20in40lrpo;
++ u16 sb20in80and160lr5glpo;
++ u16 sb40and80lr5glpo;
++ u16 sb20in80and160lr5gmpo;
++ u16 sb40and80lr5gmpo;
++ u16 sb20in80and160lr5ghpo;
++ u16 sb40and80lr5ghpo;
++ u16 dot11agduphrpo;
++ u16 dot11agduplrpo;
++ u16 rxgainerr2g;
++ u16 rxgainerr5g;
++
++ struct ssb_sprom_core_rxgains_info
++ core_rxgains_info[RXGAINS_PATH_COUNT];
+ };
+
+ /* Information about the PCB the circuitry is soldered on. */
diff --git a/target/linux/bcm53xx/patches-3.18/111-bcm53xx-add-sprom-rev-11-vars.patch b/target/linux/bcm53xx/patches-3.18/111-bcm53xx-add-sprom-rev-11-vars.patch
new file mode 100644
index 0000000..78590b5
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.18/111-bcm53xx-add-sprom-rev-11-vars.patch
@@ -0,0 +1,432 @@
+bcm53xx - add sprom rev 11 vars
+
+From: Ian Kent <raven at themaw.net>
+
+Up date bcm47xx-sprom.c to read new sprom revision 11 variables.
+
+Signed-off-by: Ian Kent <raven at themaw.net>
+---
+ drivers/bcma/sprom.c | 2 +
+ drivers/misc/bcm47xx-sprom.c | 72 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/ssb/ssb.h | 56 +++++++++++++++++++++++++++++++++
+ 3 files changed, 129 insertions(+), 1 deletion(-)
+
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -165,7 +165,7 @@ static int bcma_sprom_valid(struct bcma_
+ return err;
+
+ revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
+- if (revision != 8 && revision != 9 && revision != 10) {
++ if (revision < 8 || revision > 11) {
+ pr_err("Unsupported SPROM revision: %d\n", revision);
+ return -ENOENT;
+ }
+--- a/drivers/misc/bcm47xx-sprom.c
++++ b/drivers/misc/bcm47xx-sprom.c
+@@ -187,6 +187,30 @@ static void nvram_read_alpha2(const stru
+ memcpy(val, buf, 2);
+ }
+
++static void nvram_read_string(const struct bcm47xx_sprom_fill *fill,
++ const char *name, char *val, unsigned int len)
++{
++ char buf[121];
++ int err;
++
++ *val = '\0';
++
++ if (len > 120)
++ return;
++
++ memset(buf, 0, 121);
++ err = get_nvram_var(fill, NULL, name, buf, sizeof(buf) - 1);
++ if (err < 0)
++ return;
++ if (buf[0] == '0')
++ return;
++ if (buf[120] != '\0') {
++ pr_warn("string is too long %s\n", buf);
++ return;
++ }
++ strcpy(val, buf);
++}
++
+ static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
+ const struct bcm47xx_sprom_fill *fill)
+ {
+@@ -439,6 +463,63 @@ static void bcm47xx_sprom_fill_r9(struct
+ nvram_read_u8(fill, NULL, "sar5g", &sprom->sar5g, 0);
+ }
+
++static void bcm47xx_sprom_fill_r11(struct ssb_sprom *sprom,
++ const struct bcm47xx_sprom_fill *fill)
++{
++ nvram_read_u8(fill, NULL, "agbg0", &sprom->agbg0, 0);
++ nvram_read_u8(fill, NULL, "agbg1", &sprom->agbg1, 0);
++ nvram_read_u8(fill, NULL, "agbg2", &sprom->agbg2, 0);
++ nvram_read_u8(fill, NULL, "aga0", &sprom->aga0, 0);
++ nvram_read_u8(fill, NULL, "aga1", &sprom->aga1, 0);
++ nvram_read_u8(fill, NULL, "aga2", &sprom->aga2, 0);
++ nvram_read_u8(fill, NULL, "tssiposslope2g", &sprom->tssiposslope2g, 0);
++ nvram_read_u8(fill, NULL, "epagain2g", &sprom->epagain2g, 0);
++ nvram_read_u8(fill, NULL, "pdgain2g", &sprom->pdgain2g, 0);
++ nvram_read_u8(fill, NULL, "tworangetssi2g", &sprom->tworangetssi2g, 0);
++ nvram_read_u8(fill, NULL, "papdcap2g", &sprom->papdcap2g, 0);
++ nvram_read_u8(fill, NULL, "femctrl", &sprom->femctrl, 0);
++ nvram_read_u8(fill, NULL, "tssiposslope5g", &sprom->tssiposslope5g, 0);
++ nvram_read_u8(fill, NULL, "epagain5g", &sprom->epagain5g, 0);
++ nvram_read_u8(fill, NULL, "pdgain5g", &sprom->pdgain5g, 0);
++ nvram_read_u8(fill, NULL, "tworangetssi5g", &sprom->tworangetssi5g, 0);
++ nvram_read_u8(fill, NULL, "papdcap5g", &sprom->papdcap5g, 0);
++ nvram_read_u8(fill, NULL, "gainctrlsph", &sprom->gainctrlsph, 0);
++ nvram_read_u16(fill, NULL, "pdoffset40ma0", &sprom->pdoffset40ma0, 0);
++ nvram_read_u16(fill, NULL, "pdoffset40ma1", &sprom->pdoffset40ma1, 0);
++ nvram_read_u16(fill, NULL, "pdoffset40ma2", &sprom->pdoffset40ma2, 0);
++ nvram_read_u16(fill, NULL, "pdoffset80ma0", &sprom->pdoffset80ma0, 0);
++ nvram_read_u16(fill, NULL, "pdoffset80ma1", &sprom->pdoffset80ma1, 0);
++ nvram_read_u16(fill, NULL, "pdoffset80ma2", &sprom->pdoffset80ma2, 0);
++ nvram_read_u16(fill, NULL, "dot11agofdmhrbw202gpo", &sprom->dot11agofdmhrbw202gpo, 0);
++ nvram_read_u16(fill, NULL, "ofdmlrbw202gpo", &sprom->ofdmlrbw202gpo, 0);
++ nvram_read_u16(fill, NULL, "mcsbw805glpo", &sprom->mcsbw805glpo, 0);
++ nvram_read_u16(fill, NULL, "mcsbw1605glpo", &sprom->mcsbw1605glpo, 0);
++ nvram_read_u16(fill, NULL, "mcsbw805ghpo", &sprom->mcsbw805ghpo, 0);
++ nvram_read_u16(fill, NULL, "mcsbw1605ghpo", &sprom->mcsbw1605ghpo, 0);
++ nvram_read_u16(fill, NULL, "mcslr5glpo", &sprom->ofdmlrbw202gpo, 0);
++ nvram_read_u16(fill, NULL, "mcslr5gmpo", &sprom->mcslr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "mcslr5ghpo", &sprom->mcslr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in40hrrpo", &sprom->sb20in40hrrpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160hr5glpo", &sprom->sb20in80and160hr5glpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80hr5glpo", &sprom->sb40and80hr5glpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160hr5gmpo", &sprom->sb20in80and160hr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80hr5gmpo", &sprom->sb40and80hr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160hr5ghpo", &sprom->sb20in80and160hr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80hr5ghpo", &sprom->sb40and80hr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in40lrpo", &sprom->sb20in40lrpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160lr5glpo", &sprom->sb20in80and160lr5glpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80lr5glpo", &sprom->sb40and80lr5glpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in40lrpo", &sprom->sb20in40lrpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160lr5gmpo", &sprom->sb20in80and160lr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80lr5gmpo", &sprom->sb40and80lr5gmpo, 0);
++ nvram_read_u16(fill, NULL, "sb20in80and160lr5ghpo", &sprom->sb20in80and160lr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "sb40and80lr5ghpo", &sprom->sb40and80lr5ghpo, 0);
++ nvram_read_u16(fill, NULL, "dot11agduphrpo", &sprom->dot11agduphrpo, 0);
++ nvram_read_u16(fill, NULL, "dot11agduplrpo", &sprom->dot11agduplrpo, 0);
++ nvram_read_u16(fill, NULL, "rxgainerr2g", &sprom->rxgainerr2g, 0);
++ nvram_read_u16(fill, NULL, "rxgainerr5g", &sprom->rxgainerr5g, 0);
++}
++
+ static void bcm47xx_sprom_fill_path_r4589(struct ssb_sprom *sprom,
+ const struct bcm47xx_sprom_fill *fill)
+ {
+@@ -487,6 +568,172 @@ static void bcm47xx_sprom_fill_path_r45(
+ }
+ }
+
++static void bcm47xx_sprom_fill_path_r11(struct ssb_sprom *sprom,
++ const struct bcm47xx_sprom_fill *fill)
++{
++ char postfix[2];
++ unsigned int entry_count;
++ char tmp[40], val[100];
++ int i, j;
++
++ for (i = 0; i < ARRAY_SIZE(sprom->core_rxgains_info); i++) {
++ struct ssb_sprom_core_pwr_info *pwr_info;
++ struct ssb_sprom_core_rxgains_info *gains_info;
++
++ gains_info = &sprom->core_rxgains_info[i];
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gmelnagaina);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gmelnagaina");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gmelnagaina[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gmtrisoa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gmtrisoa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gmtrisoa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gmtrelnabypa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gmtrelnabypa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gmtrelnabypa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5ghelnagaina);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5ghelnagaina");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5ghelnagaina[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5ghtrisoa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5ghtrisoa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5ghtrisoa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5ghtrelnabypa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5ghtrelnabypa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5ghtrelnabypa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains2gelnagaina);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains2gelnagaina");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains2gelnagaina[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains2gtrisoa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains2gtrisoa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains2gtrisoa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains2gtrelnabypa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains2gtrelnabypa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains2gtrelnabypa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gelnagaina);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gelnagaina");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gelnagaina[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gtrisoa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gtrisoa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gtrisoa[j], 0);
++ }
++
++ entry_count = ARRAY_SIZE(gains_info->rxgains5gtrelnabypa);
++ for (j = 0; j < entry_count; j++) {
++ snprintf(postfix, sizeof(postfix), "%i", j);
++ snprintf(tmp, sizeof(tmp), "%i:%s", i, "rxgains5gtrelnabypa");
++ nvram_read_u8(fill, postfix, tmp,
++ &gains_info->rxgains5gtrelnabypa[j], 0);
++ }
++
++ pwr_info = &sprom->core_pwr_info[i];
++
++ entry_count = ARRAY_SIZE(pwr_info->pa2ga);
++ for (j = 0; j < entry_count; j++) {
++ char *str = &val[0];
++ char *tok;
++ int k;
++
++ snprintf(tmp, sizeof(tmp), "%i:%s%i", i, "pa2ga", j);
++ nvram_read_string(fill, tmp, val, 99);
++
++ if (!*val)
++ continue;
++
++ k = 0;
++ while ((tok = strsep(&str, ","))) {
++ unsigned long res;
++ int err;
++
++ err = kstrtoul(tok, 0, &res);
++ if (err)
++ continue;
++ pwr_info->pa5ga[j][k] = (u16) res;
++ if (++k > 11)
++ break;
++ }
++ }
++
++ entry_count = ARRAY_SIZE(pwr_info->pa5ga);
++ for (j = 0; j < entry_count; j++) {
++ char *str = &val[0];
++ char *tok;
++ int k;
++
++ snprintf(tmp, sizeof(tmp), "%i:%s%i", i, "pa5ga", j);
++ nvram_read_string(fill, tmp, val, 99);
++
++ if (!*val)
++ continue;
++
++ k = 0;
++ while ((tok = strsep(&str, ","))) {
++ unsigned long res;
++ int err;
++
++ err = kstrtoul(tok, 0, &res);
++ if (err)
++ continue;
++ pwr_info->pa5ga[j][k] = (u16) res;
++ if (++k > 11)
++ break;
++ }
++ }
++ }
++}
++
+ static bool bcm47xx_is_valid_mac(u8 *mac)
+ {
+ return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c);
+@@ -568,6 +815,9 @@ static void bcm47xx_sprom_fill_board_dat
+ &sprom->boardflags_hi);
+ nvram_read_u32_2(fill, "boardflags2", &sprom->boardflags2_lo,
+ &sprom->boardflags2_hi);
++ if (sprom->revision > 10)
++ nvram_read_u32_2(fill, "boardflags3", &sprom->boardflags3_lo,
++ &sprom->boardflags3_hi);
+ }
+
+ static void bcm47xx_sprom_fill(struct ssb_sprom *sprom,
+@@ -625,6 +875,18 @@ static void bcm47xx_sprom_fill(struct ss
+ bcm47xx_sprom_fill_r9(sprom, fill);
+ bcm47xx_sprom_fill_path_r4589(sprom, fill);
+ break;
++
++ case 11:
++ bcm47xx_sprom_fill_r1234589(sprom, fill);
++ bcm47xx_sprom_fill_r4589(sprom, fill);
++ bcm47xx_sprom_fill_r89(sprom, fill);
++ bcm47xx_sprom_fill_r9(sprom, fill);
++ bcm47xx_sprom_fill_r11(sprom, fill);
++ /* For maxp2ga and maxp5ga only */
++ bcm47xx_sprom_fill_path_r4589(sprom, fill);
++ bcm47xx_sprom_fill_path_r11(sprom, fill);
++ break;
++
+ default:
+ pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
+ sprom->revision);
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -13,6 +13,8 @@
+
+ #include <linux/ssb/ssb_regs.h>
+
++#define RXGAINS_PATH_COUNT 3
++#define RXGAINS_ENTRY_COUNT 3
+
+ struct pcmcia_device;
+ struct ssb_bus;
+@@ -22,6 +24,24 @@ struct ssb_sprom_core_pwr_info {
+ u8 itssi_2g, itssi_5g;
+ u8 maxpwr_2g, maxpwr_5gl, maxpwr_5g, maxpwr_5gh;
+ u16 pa_2g[4], pa_5gl[4], pa_5g[4], pa_5gh[4];
++ /* rev 11 */
++ u16 pa2ga[3][12], pa5ga[3][12];
++};
++
++/* rev 11 rxnoise */
++struct ssb_sprom_core_rxgains_info {
++ u8 rxgains5gmelnagaina[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gmtrisoa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gmtrelnabypa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5ghelnagaina[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5ghtrisoa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5ghtrelnabypa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains2gelnagaina[RXGAINS_ENTRY_COUNT];
++ u8 rxgains2gtrisoa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains2gtrelnabypa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gelnagaina[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gtrisoa[RXGAINS_ENTRY_COUNT];
++ u8 rxgains5gtrelnabypa[RXGAINS_ENTRY_COUNT];
+ };
+
+ struct ssb_sprom {
+@@ -93,6 +113,9 @@ struct ssb_sprom {
+ u16 boardflags2_lo; /* Board flags (bits 32-47) */
+ u16 boardflags2_hi; /* Board flags (bits 48-63) */
+ /* TODO store board flags in a single u64 */
++ /* spromrev 11 */
++ u16 boardflags3_lo; /* Board flags (bits 64-79) */
++ u16 boardflags3_hi; /* Board flags (bits 80-95) */
+
+ struct ssb_sprom_core_pwr_info core_pwr_info[4];
+
+@@ -185,6 +208,62 @@ struct ssb_sprom {
+ u16 legofdm40duppo;
+ u8 sar2g;
+ u8 sar5g;
++
++ /* spromrev 11 */
++ u8 agbg0;
++ u8 agbg1;
++ u8 agbg2;
++ u8 aga0;
++ u8 aga1;
++ u8 aga2;
++ u8 tssiposslope2g;
++ u8 epagain2g;
++ u8 pdgain2g;
++ u8 tworangetssi2g;
++ u8 papdcap2g;
++ u8 femctrl;
++ u8 tssiposslope5g;
++ u8 epagain5g;
++ u8 pdgain5g;
++ u8 tworangetssi5g;
++ u8 papdcap5g;
++ u8 gainctrlsph;
++ u16 pdoffset40ma0;
++ u16 pdoffset40ma1;
++ u16 pdoffset40ma2;
++ u16 pdoffset80ma0;
++ u16 pdoffset80ma1;
++ u16 pdoffset80ma2;
++ u16 dot11agofdmhrbw202gpo;
++ u16 ofdmlrbw202gpo;
++ u16 mcsbw805glpo;
++ u16 mcsbw1605glpo;
++ u16 mcsbw805ghpo;
++ u16 mcsbw1605ghpo;
++ u16 mcslr5glpo;
++ u16 mcslr5gmpo;
++ u16 mcslr5ghpo;
++ u16 sb20in40hrrpo;
++ u16 sb20in80and160hr5glpo;
++ u16 sb40and80hr5glpo;
++ u16 sb20in80and160hr5gmpo;
++ u16 sb40and80hr5gmpo;
++ u16 sb20in80and160hr5ghpo;
++ u16 sb40and80hr5ghpo;
++ u16 sb20in40lrpo;
++ u16 sb20in80and160lr5glpo;
++ u16 sb40and80lr5glpo;
++ u16 sb20in80and160lr5gmpo;
++ u16 sb40and80lr5gmpo;
++ u16 sb20in80and160lr5ghpo;
++ u16 sb40and80lr5ghpo;
++ u16 dot11agduphrpo;
++ u16 dot11agduplrpo;
++ u16 rxgainerr2g;
++ u16 rxgainerr5g;
++
++ struct ssb_sprom_core_rxgains_info
++ core_rxgains_info[RXGAINS_PATH_COUNT];
+ };
+
+ /* Information about the PCB the circuitry is soldered on. */
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list