Add support for DDR3.

OK garbled@
This commit is contained in:
pgoyette 2008-09-28 12:59:54 +00:00
parent 10d92b0ee8
commit d3676b5978
2 changed files with 165 additions and 29 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: spdmem.c,v 1.10 2008/09/27 16:37:40 pgoyette Exp $ */
/* $NetBSD: spdmem.c,v 1.11 2008/09/28 12:59:54 pgoyette Exp $ */
/*
* Copyright (c) 2007 Nicolas Joly
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.10 2008/09/27 16:37:40 pgoyette Exp $");
__KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.11 2008/09/28 12:59:54 pgoyette Exp $");
#include <sys/param.h>
#include <sys/device.h>
@ -69,7 +69,8 @@ static const char* spdmem_basic_types[] = {
"DDR SDRAM",
"DDR2 SDRAM",
"DDR2 SDRAM FB",
"DDR2 SDRAM FB Probe"
"DDR2 SDRAM FB Probe",
"DDR3 SDRAM"
};
static const char* spdmem_superset_types[] = {
@ -174,8 +175,8 @@ spdmem_match(device_t parent, cfdata_t match, void *aux)
return 1;
}
/* For FBDIMM and newer, verify the CRC */
else {
/* For DDR3 and FBDIMM, verify the CRC */
else if (spd_type <= SPDMEM_MEMTYPE_DDR3SDRAM) {
spd_len = spdmem_read(&sc, 0);
if (spd_len && SPDMEM_SPDCRC_116)
spd_crc_cover = 116;
@ -208,6 +209,9 @@ spdmem_match(device_t parent, cfdata_t match, void *aux)
}
return 1;
}
/* For unrecognized memory types, don't match at all */
return 0;
}
static void
@ -236,7 +240,7 @@ spdmem_attach(device_t parent, device_t self, void *aux)
aprint_error_dev(self, "couldn't establish power handler\n");
/*
* FBDIMM (and probably all newer) has a different
* FBDIMM and DDR3 (and probably all newer) have a different
* encoding of the SPD EEPROM used/total sizes
*/
s->sm_len = spdmem_read(sc, 0);
@ -366,6 +370,8 @@ spdmem_attach(device_t parent, device_t self, void *aux)
s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM ||
s->sm_type == SPDMEM_MEMTYPE_DDR2SDRAM))
aprint_normal(", %s", spdmem_parity_types[s->sm_config]);
else if (s->sm_type == SPDMEM_MEMTYPE_DDR3SDRAM)
aprint_normal(", %sECC", s->sm_ddr3.ddr3_hasECC?"":"no ");
/* Extract module size info */
dimm_size = 0;
@ -385,10 +391,26 @@ spdmem_attach(device_t parent, device_t self, void *aux)
dimm_size = s->sm_ddr2.ddr2_rows + s->sm_ddr2.ddr2_cols - 17;
num_banks = s->sm_ddr2.ddr2_ranks + 1;
per_chip = s->sm_ddr2.ddr2_banks_per_chip;
} else if (s->sm_type == SPDMEM_MEMTYPE_DDR3SDRAM) {
/*
* DDR3 size specification is quite different from DDR2
*
* Module capacity is defined as
* Chip_Capacity_in_bits / 8bits-per-byte
* * external_bus_width
* / internal_bus_width
* We further divide by 2**20 to get our answer in MB
*/
dimm_size =
(s->sm_ddr3.ddr3_chipsize + 28 - 20) - 3 +
(s->sm_ddr3.ddr3_datawidth + 3) -
(s->sm_ddr3.ddr3_chipwidth + 2);
num_banks = s->sm_ddr3.ddr3_physbanks;
per_chip = 1;
} else if (s->sm_type == SPDMEM_MEMTYPE_FBDIMM ||
s->sm_type == SPDMEM_MEMTYPE_FBDIMM_PROBE) {
/*
* FB-DIMM is quite different from DDR2
* FB-DIMM is very much like DDR3
*/
dimm_size =
s->sm_fbd.fbdimm_rows + 12 +
@ -450,6 +472,17 @@ spdmem_attach(device_t parent, device_t self, void *aux)
if (s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM)
tAA /= 2;
}
else if (s->sm_type == SPDMEM_MEMTYPE_DDR3SDRAM) {
cycle_time = (1000 * s->sm_ddr3.ddr3_mtb_dividend +
(s->sm_ddr3.ddr3_mtb_divisor / 2)) /
s->sm_ddr3.ddr3_mtb_divisor;
cycle_time *= s->sm_ddr3.ddr3_tCKmin;
tAA = s->sm_ddr3.ddr3_tAAmin / s->sm_ddr3.ddr3_tCKmin;
tRCD = s->sm_ddr3.ddr3_tRCDmin / s->sm_ddr3.ddr3_tCKmin;
tRP = s->sm_ddr3.ddr3_tRPmin / s->sm_ddr3.ddr3_tCKmin;
tRAS = (s->sm_ddr3.ddr3_tRAS_msb * 256 +
s->sm_ddr3.ddr3_tRAS_lsb) / s->sm_ddr3.ddr3_tCKmin;
}
else if (s->sm_type == SPDMEM_MEMTYPE_FBDIMM ||
s->sm_type == SPDMEM_MEMTYPE_FBDIMM_PROBE) {
cycle_time = (1000 * s->sm_fbd.fbdimm_mtb_dividend +
@ -474,6 +507,11 @@ spdmem_attach(device_t parent, device_t self, void *aux)
d_clk *= 2;
bits = 1 << (s->sm_fbd.fbdimm_dev_width + 2);
ddr_type_string = "PC2";
} else if (s->sm_type == SPDMEM_MEMTYPE_DDR3SDRAM) {
/* DDR3 uses a dual-pumped clock */
d_clk *= 2;
bits = 1 << (s->sm_ddr3.ddr3_datawidth + 3);
ddr_type_string = "PC3";
} else if (s->sm_type == SPDMEM_MEMTYPE_DDR2SDRAM) {
/* DDR2 uses a dual-pumped clock */
d_clk *= 2;
@ -494,12 +532,21 @@ spdmem_attach(device_t parent, device_t self, void *aux)
bits -= 8;
ddr_type_string = "PC";
}
d_clk /= cycle_time;
p_clk = d_clk * bits / 8;
if ((p_clk % 100) >= 50)
p_clk += 50;
p_clk -= p_clk % 100;
aprint_normal(", %dMHz, %s-%d", d_clk, ddr_type_string, p_clk);
/*
* Calculate p_clk first, since for DDR3 we need maximum
* significance. DDR3 rating is not rounded to a multiple
* of 100. This results in cycle_time of 1.5ns displayed
* as PC3-10666.
*/
p_clk = (d_clk * bits) / 8 / cycle_time;
d_clk = ((d_clk + cycle_time / 2) ) / cycle_time;
if ( s->sm_type != SPDMEM_MEMTYPE_DDR3SDRAM) {
if ((p_clk % 100) >= 50)
p_clk += 50;
p_clk -= p_clk % 100;
}
aprint_normal(", %dMHz (%s-%d)\n",
d_clk, ddr_type_string, p_clk);
if (node != NULL)
sysctl_createv(NULL, 0, NULL, NULL,
CTLFLAG_IMMEDIATE,
@ -509,7 +556,6 @@ spdmem_attach(device_t parent, device_t self, void *aux)
CTL_HW, node->sysctl_num, CTL_CREATE,
CTL_EOL);
}
aprint_normal("\n");
aprint_verbose_dev(self, "");
switch (s->sm_type) {
@ -553,25 +599,36 @@ spdmem_attach(device_t parent, device_t self, void *aux)
cycle_time / 1000, (cycle_time % 1000 + 5) /10 );
aprint_verbose_dev(self, latency, tAA, tRCD, tRP, tRAS);
break;
case SPDMEM_MEMTYPE_DDR3SDRAM:
aprint_verbose(
"%d rows, %d cols, %d internal banks, %d physical banks, "
"%d.%03dns cycle time\n",
s->sm_ddr3.ddr3_rows + 9, s->sm_ddr3.ddr3_cols + 12,
8 << s->sm_ddr3.ddr3_logbanks, s->sm_ddr3.ddr3_physbanks,
cycle_time/1000, cycle_time % 1000);
aprint_verbose_dev(self, latency, tAA, tRCD, tRP, tRAS);
break;
default:
break;
}
if (s->sm_voltage < __arraycount(spdmem_voltage_types))
voltage = spdmem_voltage_types[s->sm_voltage];
else
voltage = "unknown";
if (s->sm_type < SPDMEM_MEMTYPE_DDR3SDRAM) {
if (s->sm_voltage < __arraycount(spdmem_voltage_types))
voltage = spdmem_voltage_types[s->sm_voltage];
else
voltage = "unknown";
if (s->sm_refresh < __arraycount(spdmem_refresh_types))
refresh = spdmem_refresh_types[s->sm_refresh];
else
refresh = "unknown";
if (s->sm_refresh < __arraycount(spdmem_refresh_types))
refresh = spdmem_refresh_types[s->sm_refresh];
else
refresh = "unknown";
aprint_verbose_dev(self, "voltage %s, refresh time %s",
voltage, refresh);
if (s->sm_selfrefresh)
aprint_verbose(" (self-refreshing)");
aprint_verbose("\n");
aprint_verbose_dev(self, "voltage %s, refresh time %s",
voltage, refresh);
if (s->sm_selfrefresh)
aprint_verbose(" (self-refreshing)");
aprint_verbose("\n");
}
}
static uint8_t

View File

@ -1,4 +1,4 @@
/* $NetBSD: spdmemvar.h,v 1.4 2008/09/27 06:58:09 pgoyette Exp $ */
/* $NetBSD: spdmemvar.h,v 1.5 2008/09/28 12:59:54 pgoyette Exp $ */
/*
* Copyright (c) 2007 Paul Goyette
@ -387,8 +387,85 @@ struct spdmem_rambus { /* Direct Rambus DRAM */
);
} __packed;
/*
* No JEDEC standard for DDR3 memory has yet been made publicly available.
* This information is compiled from information posted at www.simmtester.com
* and www.digit-life.com
*/
struct spdmem_ddr3 { /* Dual Data Rate 3 SDRAM */
uint8_t ddr3_mod_type;
SPD_BITFIELD( \
/* chipsize is offset by 28: 0 = 256M, 1 = 512M, ... */ \
uint8_t ddr3_chipsize:5, \
/* logbanks is offset by 1 */ \
uint8_t ddr3_logbanks:3, , \
);
/* cols is offset by 9, rows offset by 12 */
SPD_BITFIELD( \
uint8_t ddr3_cols:3, \
uint8_t ddr3_rows:5, , \
);
uint8_t ddr3_unused2;
/* chipwidth in bits offset by 2: 0 = X4, 1 = X8, 2 = X16 */
/* physbanks is offset by 1 */
SPD_BITFIELD( \
uint8_t ddr3_chipwidth:3, \
uint8_t ddr3_physbanks:5, , \
);
/* datawidth in bits offset by 3: 1 = 16b, 2 = 32b, 3 = 64b */
SPD_BITFIELD( \
uint8_t ddr3_datawidth:7, \
uint8_t ddr3_hasECC:1, , \
);
uint8_t ddr3_ftb; /* 0x52 = 2.5ps, 0x55 = 5.0ps */
uint8_t ddr3_mtb_dividend; /* 0x0108 = 0.1250ns */
uint8_t ddr3_mtb_divisor; /* 0x010f = 0.0625ns */
uint8_t ddr3_tCKmin; /* in terms of mtb */
uint8_t ddr3_unused3;
uint16_t ddr3_CAS_sup;
uint8_t ddr3_tAAmin; /* in terms of mtb */
uint8_t ddr3_tWRmin;
uint8_t ddr3_tRCDmin;
uint8_t ddr3_tRRDmin;
uint8_t ddr3_tRPmin;
SPD_BITFIELD( \
uint8_t ddr3_tRAS_msb:4, \
uint8_t ddr3_tRC_msb:4, , \
);
uint8_t ddr3_tRAS_lsb;
uint8_t ddr3_tRC_lsb;
uint8_t ddr3_tRFCmin_lsb;
uint8_t ddr3_tRFCmin_msb;
uint8_t ddr3_tWTRmin;
uint8_t ddr3_tRTPmin;
SPD_BITFIELD( \
uint8_t ddr3_tFAW_msb:4, , , \
);
uint8_t ddr3_tFAW_lsb;
uint8_t ddr3_output_drvrs;
SPD_BITFIELD( \
uint8_t ddr3_ext_temp_range:1, \
uint8_t ddr3_unused6:1, \
uint8_t ddr3_asr_refresh:1, \
uint8_t ddr3_unused7:5 \
);
uint8_t ddr3_unused4[28];
uint8_t ddr3_mod_height;
uint8_t ddr3_mod_thickness;
uint8_t ddr3_ref_card;
uint8_t ddr3_mapping;
uint8_t ddr3_unused5[53];
uint8_t ddr3_mfgID_lsb;
uint8_t ddr3_mfgID_msb;
uint8_t ddr3_mfgloc;
uint8_t ddr3_mfg_year;
uint8_t ddr3_mfg_week;
uint8_t ddr3_serial[4];
uint16_t ddr3_crc;
} __packed;
struct spdmem {
uint8_t sm_len;
uint8_t sm_len;
uint8_t sm_size;
uint8_t sm_type;
union {
@ -399,6 +476,7 @@ struct spdmem {
struct spdmem_sdram u1_sdr;
struct spdmem_rambus u1_rdr;
struct spdmem_rom u1_rom;
struct spdmem_ddr3 u1_ddr3;
} sm_u1;
uint8_t sm_extension[128];
} __packed;
@ -408,6 +486,7 @@ struct spdmem {
#define sm_ddr2 sm_u1.u1_ddr2
#define sm_rdr sm_u1.u1_rdr
#define sm_rom sm_u1.u1_rom
#define sm_ddr3 sm_u1.u1_ddr3
#define sm_sdr sm_u1.u1_sdr
/* some fields are in the same place for all memory types */