[OpenWrt-Devel] [PATCH 3/6] bcm53xx: update sprom from nvram to handle rev 11

Ian Kent raven at themaw.net
Mon Mar 9 23:30:23 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..742ab65
--- /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..a70d5de
--- /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