summaryrefslogtreecommitdiff
path: root/sys/dev/i2c/spdmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/i2c/spdmem.c')
-rw-r--r--sys/dev/i2c/spdmem.c415
1 files changed, 248 insertions, 167 deletions
diff --git a/sys/dev/i2c/spdmem.c b/sys/dev/i2c/spdmem.c
index e8dbaff55bd..d4aad4aca47 100644
--- a/sys/dev/i2c/spdmem.c
+++ b/sys/dev/i2c/spdmem.c
@@ -1,7 +1,23 @@
-/* $OpenBSD: spdmem.c,v 1.19 2007/10/20 02:39:56 deraadt Exp $ */
+/* $OpenBSD: spdmem.c,v 1.20 2007/10/20 08:33:37 jsg Exp $ */
/* $NetBSD: spdmem.c,v 1.3 2007/09/20 23:09:59 xtraeme Exp $ */
/*
+ * Copyright (c) 2007 Jonathan Gray <jsg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
* Copyright (c) 2007 Nicolas Joly
* Copyright (c) 2007 Paul Goyette
* Copyright (c) 2007 Tobias Nygren
@@ -167,6 +183,9 @@ int spdmem_match(struct device *, void *, void *);
void spdmem_attach(struct device *, struct device *, void *);
uint8_t spdmem_read(struct spdmem_softc *, uint8_t);
void spdmem_hexdump(struct spdmem_softc *, int, int);
+void spdmem_sdram_decode(struct spdmem_softc *, struct spdmem *);
+void spdmem_ddr_decode(struct spdmem_softc *, struct spdmem *);
+void spdmem_ddr2_decode(struct spdmem_softc *, struct spdmem *);
struct cfattach spdmem_ca = {
sizeof(struct spdmem_softc), spdmem_match, spdmem_attach
@@ -222,87 +241,111 @@ spdmem_match(struct device *parent, void *match, void *aux)
}
void
-spdmem_attach(struct device *parent, struct device *self, void *aux)
+spdmem_sdram_decode(struct spdmem_softc *sc, struct spdmem *s)
{
- struct spdmem_softc *sc = (struct spdmem_softc *)self;
- struct i2c_attach_args *ia = aux;
- struct spdmem *s = &(sc->sc_spd_data);
const char *type;
- const char *ddr_type_string = NULL;
int dimm_size, cycle_time, d_clk, p_clk, bits;
- int i;
- uint8_t config, rows, cols, cl;
+ int num_banks, per_chip;
+ uint8_t config, rows, cols;
- sc->sc_tag = ia->ia_tag;
- sc->sc_addr = ia->ia_addr;
+ type = spdmem_basic_types[s->sm_type];
- printf(":");
+ if (s->sm_data[SPDMEM_SDR_SUPERSET] == SPDMEM_SUPERSET_SDR_PEM)
+ type = spdmem_superset_types[SPDMEM_SUPERSET_SDR_PEM];
+ if (s->sm_data[SPDMEM_SDR_SUPERSET] == SPDMEM_SUPERSET_ESDRAM)
+ type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM];
- /* All SPD have at least 64 bytes of data including checksum */
- for (i = 0; i < 64; i++) {
- ((uint8_t *)s)[i] = spdmem_read(sc, i);
- }
+ dimm_size = 0;
-#if 0
- for (i = 0; i < 64; i += 16) {
- int j;
- printf("\n%s: 0x%02x:", self->dv_xname, i);
- for (j = 0; j < 16; j++)
- printf(" %02x", ((uint8_t *)s)[i + j]);
- }
- printf("\n%s", self->dv_xname);
-#endif
+ num_banks = s->sm_data[SPDMEM_SDR_BANKS];
+ per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP];
+ rows = s->sm_data[SPDMEM_SDR_ROWS] & 0x0f;
+ cols = s->sm_data[SPDMEM_SDR_COLS] & 0x0f;
+ dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip;
- /*
- * Decode and print SPD contents
- */
- if (IS_RAMBUS_TYPE)
- type = "Rambus";
- else {
- if (s->sm_type <= 10)
- type = spdmem_basic_types[s->sm_type];
+ if (dimm_size > 0) {
+ if (dimm_size < 1024)
+ printf(" %dMB", dimm_size);
else
- type = "unknown";
-
- if (s->sm_type == SPDMEM_MEMTYPE_EDO &&
- s->sm_data[SPDMEM_FPM_SUPERSET] == SPDMEM_SUPERSET_EDO_PEM)
- type = spdmem_superset_types[SPDMEM_SUPERSET_EDO_PEM];
- if (s->sm_type == SPDMEM_MEMTYPE_SDRAM &&
- s->sm_data[SPDMEM_SDR_SUPERSET] == SPDMEM_SUPERSET_SDR_PEM)
- type = spdmem_superset_types[SPDMEM_SUPERSET_SDR_PEM];
- if (s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM &&
- s->sm_data[SPDMEM_DDR_SUPERSET] ==
- SPDMEM_SUPERSET_DDR_ESDRAM)
- type =
- spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM];
- if (s->sm_type == SPDMEM_MEMTYPE_SDRAM &&
- s->sm_data[SPDMEM_SDR_SUPERSET] == SPDMEM_SUPERSET_ESDRAM) {
- type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM];
+ printf(" %dGB", dimm_size / 1024);
+ }
+
+ printf(" %s", type);
+ strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN);
+
+ if (s->sm_data[SPDMEM_DDR_MOD_ATTRIB] & SPDMEM_DDR_ATTRIB_REG)
+ printf(" registered");
+
+ if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
+ printf(" %s",
+ spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
+
+ /* cycle_time is expressed in units of 0.01 ns */
+ cycle_time = (s->sm_data[SPDMEM_DDR_CYCLE] >> 4) * 100 +
+ (s->sm_data[SPDMEM_DDR_CYCLE] & 0x0f) * 10;
+
+ if (cycle_time != 0) {
+ /*
+ * cycle time is scaled by a factor of 100 to avoid using
+ * floating point. Calculate memory speed as the number
+ * of cycles per microsecond.
+ */
+ d_clk = 100 * 1000;
+ config = s->sm_data[SPDMEM_FPM_CONFIG];
+ bits = s->sm_data[SPDMEM_DDR_DATAWIDTH] |
+ (s->sm_data[SPDMEM_DDR_DATAWIDTH + 1] << 8);
+ if (config == 1 || config == 2)
+ bits -= 8;
+
+ p_clk = 66;
+ if (s->sm_len >= 128) {
+ switch (spdmem_read(sc, SPDMEM_SDR_FREQUENCY)) {
+ case SPDMEM_SDR_FREQ_100:
+ case SPDMEM_SDR_FREQ_133:
+ /* We need to check ns to decide here */
+ if (s->sm_data[SPDMEM_SDR_CYCLE] < 0x80)
+ p_clk = 133;
+ else
+ p_clk = 100;
+ break;
+ case SPDMEM_SDR_FREQ_66:
+ default:
+ p_clk = 66;
+ break;
+ }
}
+ printf(" PC%d", p_clk);
}
+ /* Print CAS latency */
+ if (s->sm_len < 128)
+ return;
+ if (spdmem_read(sc, SPDMEM_SDR_CAS) & SPDMEM_SDR_CAS2)
+ printf("CL2");
+ else if (spdmem_read(sc, SPDMEM_SDR_CAS) & SPDMEM_SDR_CAS3)
+ printf("CL3");
+}
+
+void
+spdmem_ddr_decode(struct spdmem_softc *sc, struct spdmem *s)
+{
+ const char *type;
+ int dimm_size, cycle_time, d_clk, p_clk, bits;
+ int i, num_banks, per_chip;
+ uint8_t config, rows, cols, cl;
+
+ type = spdmem_basic_types[s->sm_type];
+
+ if (s->sm_data[SPDMEM_DDR_SUPERSET] == SPDMEM_SUPERSET_DDR_ESDRAM)
+ type = spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM];
+
dimm_size = 0;
- if (IS_RAMBUS_TYPE) {
- rows = s->sm_data[SPDMEM_RDR_ROWS_COLS] & 0x0f;
- cols = s->sm_data[SPDMEM_RDR_ROWS_COLS] >> 4;
- dimm_size = (1 << (rows + cols - 13));
- } else if (s->sm_type == SPDMEM_MEMTYPE_SDRAM ||
- s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM) {
- int num_banks, per_chip;
-
- num_banks = s->sm_data[SPDMEM_SDR_BANKS];
- per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP];
- rows = s->sm_data[SPDMEM_SDR_ROWS] & 0x0f;
- cols = s->sm_data[SPDMEM_SDR_COLS] & 0x0f;
- dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip;
- } else if (s->sm_type == SPDMEM_MEMTYPE_DDR2SDRAM) {
- int num_ranks, density;
-
- num_ranks = (s->sm_data[SPDMEM_DDR2_RANKS] & 0x7) + 1;
- density = (s->sm_data[SPDMEM_DDR2_RANK_DENSITY] & 0xf0) |
- ((s->sm_data[SPDMEM_DDR2_RANK_DENSITY] & 0x0f) << 8);
- dimm_size = num_ranks * density * 4;
- }
+
+ num_banks = s->sm_data[SPDMEM_SDR_BANKS];
+ per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP];
+ rows = s->sm_data[SPDMEM_SDR_ROWS] & 0x0f;
+ cols = s->sm_data[SPDMEM_SDR_COLS] & 0x0f;
+ dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip;
if (dimm_size > 0) {
if (dimm_size < 1024)
@@ -314,135 +357,173 @@ spdmem_attach(struct device *parent, struct device *self, void *aux)
printf(" %s", type);
strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN);
- if (((s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM ||
- s->sm_type == SPDMEM_MEMTYPE_SDRAM) &&
- (s->sm_data[SPDMEM_DDR_MOD_ATTRIB] & SPDMEM_DDR_ATTRIB_REG)) ||
- ((s->sm_type == SPDMEM_MEMTYPE_DDR2SDRAM) &&
- (s->sm_data[SPDMEM_DDR2_DIMMTYPE] & SPDMEM_DDR2_TYPE_REGMASK)))
+ if (s->sm_data[SPDMEM_DDR_MOD_ATTRIB] & SPDMEM_DDR_ATTRIB_REG)
printf(" registered");
- if ((s->sm_type == SPDMEM_MEMTYPE_SDRAM ||
- s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM ||
- s->sm_type == SPDMEM_MEMTYPE_DDR2SDRAM ) &&
- s->sm_data[SPDMEM_FPM_CONFIG] < 8)
+ if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
printf(" %s",
spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
/* cycle_time is expressed in units of 0.01 ns */
- cycle_time = 0;
- if (s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM ||
- s->sm_type == SPDMEM_MEMTYPE_SDRAM)
- cycle_time = (s->sm_data[SPDMEM_DDR_CYCLE] >> 4) * 100 +
- (s->sm_data[SPDMEM_DDR_CYCLE] & 0x0f) * 10;
- else if (s->sm_type == SPDMEM_MEMTYPE_DDR2SDRAM) {
- cycle_time = (s->sm_data[SPDMEM_DDR2_CYCLE] >> 4) * 100 +
- ddr2_cycle_tenths[(s->sm_data[SPDMEM_DDR2_CYCLE] & 0x0f)];
- }
+ cycle_time = (s->sm_data[SPDMEM_DDR_CYCLE] >> 4) * 100 +
+ (s->sm_data[SPDMEM_DDR_CYCLE] & 0x0f) * 10;
if (cycle_time != 0) {
/*
* cycle time is scaled by a factor of 100 to avoid using
* floating point. Calculate memory speed as the number
* of cycles per microsecond.
+ * DDR2 uses dual-pumped clock
*/
- d_clk = 100 * 1000;
+ d_clk = 100 * 1000 * 2;
config = s->sm_data[SPDMEM_FPM_CONFIG];
- switch (s->sm_type) {
- case SPDMEM_MEMTYPE_DDR2SDRAM:
- /* DDR2 uses quad-pumped clock */
- d_clk *= 4;
- bits = s->sm_data[SPDMEM_DDR2_DATAWIDTH];
- if ((config & 0x03) != 0)
- bits -= 8;
- ddr_type_string = "PC2-";
+ bits = s->sm_data[SPDMEM_DDR_DATAWIDTH] |
+ (s->sm_data[SPDMEM_DDR_DATAWIDTH + 1] << 8);
+ if (config == 1 || config == 2)
+ bits -= 8;
+
+ d_clk /= cycle_time;
+ p_clk = d_clk * bits / 8;
+ if ((p_clk % 100) >= 50)
+ p_clk += 50;
+ p_clk -= p_clk % 100;
+ printf(" PC%d", p_clk);
+ }
+
+ /* Print CAS latency */
+ for (i = 6; i >= 0; i--) {
+ if (s->sm_data[SPDMEM_DDR_CAS] & (1 << i)) {
+ cl = ((i * 10) / 2) + 10;
+ printf("CL%d.%d", cl / 10, cl % 10);
break;
- case SPDMEM_MEMTYPE_DDRSDRAM:
- /* DDR uses dual-pumped clock */
- d_clk *= 2;
- /* FALLTHROUGH */
- default: /* SPDMEM_MEMTYPE_SDRAM */
- bits = s->sm_data[SPDMEM_DDR_DATAWIDTH] |
- (s->sm_data[SPDMEM_DDR_DATAWIDTH + 1] << 8);
- if (config == 1 || config == 2)
- bits -= 8;
- ddr_type_string = "PC";
}
+ }
+}
- if (s->sm_type == SPDMEM_MEMTYPE_SDRAM) {
- p_clk = 66;
- if (s->sm_len >= 128) {
- switch (spdmem_read(sc, SPDMEM_SDR_FREQUENCY)) {
- case SPDMEM_SDR_FREQ_100:
- case SPDMEM_SDR_FREQ_133:
- /* We need to check ns to decide here */
- if (s->sm_data[SPDMEM_SDR_CYCLE] < 0x80)
- p_clk = 133;
- else
- p_clk = 100;
- break;
- case SPDMEM_SDR_FREQ_66:
- default:
- p_clk = 66;
- break;
- }
- }
- } else {
- d_clk /= cycle_time;
- if (s->sm_type == SPDMEM_MEMTYPE_DDR2SDRAM)
- d_clk = (d_clk + 1) / 2;
- p_clk = d_clk * bits / 8;
- if (s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM &&
- (p_clk % 100) >= 50)
- p_clk += 50;
- p_clk -= p_clk % 100;
- }
- printf(" %s%d", ddr_type_string, p_clk);
+void
+spdmem_ddr2_decode(struct spdmem_softc *sc, struct spdmem *s)
+{
+ const char *type;
+ int dimm_size, cycle_time, d_clk, p_clk, bits;
+ int i, num_ranks, density;
+ uint8_t config;
+
+ type = spdmem_basic_types[s->sm_type];
+
+ dimm_size = 0;
+
+ num_ranks = (s->sm_data[SPDMEM_DDR2_RANKS] & 0x7) + 1;
+ density = (s->sm_data[SPDMEM_DDR2_RANK_DENSITY] & 0xf0) |
+ ((s->sm_data[SPDMEM_DDR2_RANK_DENSITY] & 0x0f) << 8);
+ dimm_size = num_ranks * density * 4;
+
+ if (dimm_size > 0) {
+ if (dimm_size < 1024)
+ printf(" %dMB", dimm_size);
+ else
+ printf(" %dGB", dimm_size / 1024);
+ }
+
+ printf(" %s", type);
+ strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN);
+
+ if (s->sm_data[SPDMEM_DDR2_DIMMTYPE] & SPDMEM_DDR2_TYPE_REGMASK)
+ printf(" registered");
+
+ if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
+ printf(" %s",
+ spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
+
+ /* cycle_time is expressed in units of 0.01 ns */
+ cycle_time = (s->sm_data[SPDMEM_DDR2_CYCLE] >> 4) * 100 +
+ ddr2_cycle_tenths[(s->sm_data[SPDMEM_DDR2_CYCLE] & 0x0f)];
+
+ if (cycle_time != 0) {
+ /*
+ * cycle time is scaled by a factor of 100 to avoid using
+ * floating point. Calculate memory speed as the number
+ * of cycles per microsecond.
+ * DDR2 uses quad-pumped clock
+ */
+ d_clk = 100 * 1000 * 4;
+ config = s->sm_data[SPDMEM_FPM_CONFIG];
+ bits = s->sm_data[SPDMEM_DDR2_DATAWIDTH];
+ if ((config & 0x03) != 0)
+ bits -= 8;
+ d_clk /= cycle_time;
+ d_clk = (d_clk + 1) / 2;
+ p_clk = d_clk * bits / 8;
+ p_clk -= p_clk % 100;
+ printf(" PC2-%d", p_clk);
}
/* Print CAS latency */
- switch (s->sm_type) {
- case SPDMEM_MEMTYPE_SDRAM:
- if (s->sm_len < 128)
+ for (i = 5; i >= 2; i--) {
+ if (s->sm_data[SPDMEM_DDR_CAS] & (i << i)) {
+ printf("CL%d", i);
break;
- if (spdmem_read(sc, SPDMEM_SDR_CAS) & SPDMEM_SDR_CAS2)
- printf("CL2");
- else if (spdmem_read(sc, SPDMEM_SDR_CAS) & SPDMEM_SDR_CAS3)
- printf("CL3");
- break;
- case SPDMEM_MEMTYPE_DDRSDRAM:
- for (i = 6; i >= 0; i--) {
- if (s->sm_data[SPDMEM_DDR_CAS] & (1 << i)) {
- cl = ((i * 10) / 2) + 10;
- printf("CL%d.%d", cl / 10, cl % 10);
- break;
- }
}
+ }
+
+ switch (s->sm_data[SPDMEM_DDR2_DIMMTYPE]) {
+ case SPDMEM_DDR2_SODIMM:
+ printf(" SO-DIMM");
break;
- case SPDMEM_MEMTYPE_DDR2SDRAM:
- for (i = 5; i >= 2; i--) {
- if (s->sm_data[SPDMEM_DDR_CAS] & (i << i)) {
- printf("CL%d", i);
- break;
- }
- }
+ case SPDMEM_DDR2_MICRO_DIMM:
+ printf(" Micro-DIMM");
+ break;
+ case SPDMEM_DDR2_MINI_RDIMM:
+ case SPDMEM_DDR2_MINI_UDIMM:
+ printf(" Mini-DIMM");
break;
}
+}
+
+void
+spdmem_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct spdmem_softc *sc = (struct spdmem_softc *)self;
+ struct i2c_attach_args *ia = aux;
+ struct spdmem *s = &(sc->sc_spd_data);
+ int i;
+
+ sc->sc_tag = ia->ia_tag;
+ sc->sc_addr = ia->ia_addr;
+
+ printf(":");
+
+ /* All SPD have at least 64 bytes of data including checksum */
+ for (i = 0; i < 64; i++) {
+ ((uint8_t *)s)[i] = spdmem_read(sc, i);
+ }
- if (s->sm_type == SPDMEM_MEMTYPE_DDR2SDRAM) {
- switch (s->sm_data[SPDMEM_DDR2_DIMMTYPE]) {
- case SPDMEM_DDR2_SODIMM:
- printf(" SO-DIMM");
+ /*
+ * Decode and print SPD contents
+ */
+ if (s->sm_len < 4)
+ printf(" no decode method for Rambus memory");
+ else {
+ switch(s->sm_type) {
+ case SPDMEM_MEMTYPE_EDO:
+ case SPDMEM_MEMTYPE_SDRAM:
+ spdmem_sdram_decode(sc, s);
break;
- case SPDMEM_DDR2_MICRO_DIMM:
- printf(" Micro-DIMM");
+ case SPDMEM_MEMTYPE_DDRSDRAM:
+ spdmem_ddr_decode(sc, s);
+ break;
+ case SPDMEM_MEMTYPE_DDR2SDRAM:
+ spdmem_ddr2_decode(sc, s);
break;
- case SPDMEM_DDR2_MINI_RDIMM:
- case SPDMEM_DDR2_MINI_UDIMM:
- printf(" Mini-DIMM");
+ default:
+ if (s->sm_type <= 10)
+ printf(" no decode method for %s memory",
+ spdmem_basic_types[s->sm_type]);
+ else
+ printf(" unknown memory type %d", s->sm_type);
break;
}
}
-
+
printf("\n");
}