summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2009-02-22 13:45:12 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2009-02-22 13:45:12 +0000
commite4f662acc28db277dac316ba4a822253bd4c10f9 (patch)
tree6adc902fa740a786322178941b61d8babaf14647
parent09f74cff4bdb5a17114c6c300bff4f51a97cd8f0 (diff)
Untested FB-DIMM decoding adapted from changes made to NetBSD
by Paul Goyette. ok deraadt@
-rw-r--r--sys/dev/i2c/spdmem.c73
1 files changed, 72 insertions, 1 deletions
diff --git a/sys/dev/i2c/spdmem.c b/sys/dev/i2c/spdmem.c
index 7cf2de4d78a..41eca85e4fb 100644
--- a/sys/dev/i2c/spdmem.c
+++ b/sys/dev/i2c/spdmem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: spdmem.c,v 1.30 2009/02/19 23:21:09 jsg Exp $ */
+/* $OpenBSD: spdmem.c,v 1.31 2009/02/22 13:45:11 jsg Exp $ */
/* $NetBSD: spdmem.c,v 1.3 2007/09/20 23:09:59 xtraeme Exp $ */
/*
@@ -185,6 +185,22 @@
#define SPDMEM_DDR2_MINI_RDIMM (1 << 4)
#define SPDMEM_DDR2_MINI_UDIMM (1 << 5)
+/* DDR2 FB-DIMM SDRAM */
+#define SPDMEM_FBDIMM_ADDR 0x01
+#define SPDMEM_FBDIMM_RANKS 0x04
+#define SPDMEM_FBDIMM_MTB_DIVIDEND 0x06
+#define SPDMEM_FBDIMM_MTB_DIVISOR 0x07
+#define SPDMEM_FBDIMM_PROTO 0x4e
+
+#define SPDMEM_FBDIMM_RANKS_WIDTH 0x07
+#define SPDMEM_FBDIMM_ADDR_BANKS 0x02
+#define SPDMEM_FBDIMM_ADDR_COL 0x0c
+#define SPDMEM_FBDIMM_ADDR_COL_SHIFT 2
+#define SPDMEM_FBDIMM_ADDR_ROW 0xe0
+#define SPDMEM_FBDIMM_ADDR_ROW_SHIFT 5
+#define SPDMEM_FBDIMM_PROTO_ECC (1 << 1)
+
+
/* Dual Data Rate 3 SDRAM */
#define SPDMEM_DDR3_MODTYPE 0x00
#define SPDMEM_DDR3_DENSITY 0x01
@@ -234,6 +250,7 @@ void spdmem_sdram_decode(struct spdmem_softc *, struct spdmem *);
void spdmem_rdr_decode(struct spdmem_softc *, struct spdmem *);
void spdmem_ddr_decode(struct spdmem_softc *, struct spdmem *);
void spdmem_ddr2_decode(struct spdmem_softc *, struct spdmem *);
+void spdmem_fbdimm_decode(struct spdmem_softc *, struct spdmem *);
void spdmem_ddr3_decode(struct spdmem_softc *, struct spdmem *);
struct cfattach spdmem_ca = {
@@ -616,6 +633,56 @@ spdmem_ddr2_decode(struct spdmem_softc *sc, struct spdmem *s)
}
void
+spdmem_fbdimm_decode(struct spdmem_softc *sc, struct spdmem *s)
+{
+ int dimm_size, num_banks, cycle_time, d_clk, p_clk, bits;
+ uint8_t rows, cols, banks, dividend, divisor;
+ /*
+ * FB-DIMM is very much like DDR3
+ */
+
+ banks = s->sm_data[SPDMEM_FBDIMM_ADDR] & SPDMEM_FBDIMM_ADDR_BANKS;
+ cols = (s->sm_data[SPDMEM_FBDIMM_ADDR] & SPDMEM_FBDIMM_ADDR_COL) >>
+ SPDMEM_FBDIMM_ADDR_COL_SHIFT;
+ rows = (s->sm_data[SPDMEM_FBDIMM_ADDR] & SPDMEM_FBDIMM_ADDR_ROW) >>
+ SPDMEM_FBDIMM_ADDR_ROW_SHIFT;
+ dimm_size = rows + 12 + cols + 9 - 20 - 3;
+ num_banks = 1 << (banks + 2);
+
+ if (dimm_size < 1024)
+ printf(" %dMB", dimm_size);
+ else
+ printf(" %dGB", dimm_size / 1024);
+
+ if (s->sm_data[SPDMEM_FBDIMM_PROTO] & SPDMEM_FBDIMM_PROTO_ECC)
+ printf(" ECC");
+
+ dividend = s->sm_data[SPDMEM_FBDIMM_MTB_DIVIDEND];
+ divisor = s->sm_data[SPDMEM_FBDIMM_MTB_DIVISOR];
+
+ cycle_time = (1000 * dividend + (divisor / 2)) / divisor;
+
+ if (cycle_time != 0) {
+ /*
+ * cycle time is scaled by a factor of 1000 to avoid using
+ * floating point. Calculate memory speed as the number
+ * of cycles per microsecond.
+ */
+ d_clk = 1000 * 1000;
+
+ /* DDR2 FB-DIMM uses a dual-pumped clock */
+ d_clk *= 2;
+ bits = 1 << ((s->sm_data[SPDMEM_FBDIMM_RANKS] &
+ SPDMEM_FBDIMM_RANKS_WIDTH) + 2);
+
+ p_clk = (d_clk * bits) / 8 / cycle_time;
+ d_clk = ((d_clk + cycle_time / 2) ) / cycle_time;
+ p_clk -= p_clk % 100;
+ printf(" PC2-%d", p_clk);
+ }
+}
+
+void
spdmem_ddr3_decode(struct spdmem_softc *sc, struct spdmem *s)
{
const char *type;
@@ -726,6 +793,10 @@ spdmem_attach(struct device *parent, struct device *self, void *aux)
case SPDMEM_MEMTYPE_DDR2SDRAM:
spdmem_ddr2_decode(sc, s);
break;
+ case SPDMEM_MEMTYPE_FBDIMM:
+ case SPDMEM_MEMTYPE_FBDIMM_PROBE:
+ spdmem_fbdimm_decode(sc, s);
+ break;
case SPDMEM_MEMTYPE_DDR3SDRAM:
spdmem_ddr3_decode(sc, s);
break;