Add new sprom revision 11 variables to the nvram -> sprom reader.

Signed-off-by: Ian Kent <ra...@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 <ra...@themaw.net>
+
+Up date bcm47xx-sprom.c to read new sprom revision 11 variables.
+
+Signed-off-by: Ian Kent <ra...@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 <ra...@themaw.net>
+
+Up date bcm47xx-sprom.c to read new sprom revision 11 variables.
+
+Signed-off-by: Ian Kent <ra...@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@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to