Home | History | Annotate | Line # | Download | only in ic
spdmem.c revision 1.2
      1  1.2  pgoyette /* $NetBSD: spdmem.c,v 1.2 2010/06/29 04:42:30 pgoyette Exp $ */
      2  1.1  pgoyette 
      3  1.1  pgoyette /*
      4  1.1  pgoyette  * Copyright (c) 2007 Nicolas Joly
      5  1.1  pgoyette  * Copyright (c) 2007 Paul Goyette
      6  1.1  pgoyette  * Copyright (c) 2007 Tobias Nygren
      7  1.1  pgoyette  * All rights reserved.
      8  1.1  pgoyette  *
      9  1.1  pgoyette  * Redistribution and use in source and binary forms, with or without
     10  1.1  pgoyette  * modification, are permitted provided that the following conditions
     11  1.1  pgoyette  * are met:
     12  1.1  pgoyette  * 1. Redistributions of source code must retain the above copyright
     13  1.1  pgoyette  *    notice, this list of conditions and the following disclaimer.
     14  1.1  pgoyette  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1  pgoyette  *    notice, this list of conditions and the following disclaimer in the
     16  1.1  pgoyette  *    documentation and/or other materials provided with the distribution.
     17  1.1  pgoyette  * 3. The name of the author may not be used to endorse or promote products
     18  1.1  pgoyette  *    derived from this software without specific prior written permission.
     19  1.1  pgoyette  *
     20  1.1  pgoyette  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
     21  1.1  pgoyette  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  1.1  pgoyette  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  1.1  pgoyette  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  1.1  pgoyette  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  1.1  pgoyette  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  1.1  pgoyette  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  1.1  pgoyette  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  1.1  pgoyette  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  1.1  pgoyette  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  1.1  pgoyette  * POSSIBILITY OF SUCH DAMAGE.
     31  1.1  pgoyette  */
     32  1.1  pgoyette 
     33  1.1  pgoyette /*
     34  1.1  pgoyette  * Serial Presence Detect (SPD) memory identification
     35  1.1  pgoyette  */
     36  1.1  pgoyette 
     37  1.1  pgoyette #include <sys/cdefs.h>
     38  1.2  pgoyette __KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.2 2010/06/29 04:42:30 pgoyette Exp $");
     39  1.1  pgoyette 
     40  1.1  pgoyette #include <sys/param.h>
     41  1.1  pgoyette #include <sys/device.h>
     42  1.1  pgoyette #include <sys/endian.h>
     43  1.1  pgoyette #include <sys/sysctl.h>
     44  1.1  pgoyette #include <machine/bswap.h>
     45  1.1  pgoyette 
     46  1.1  pgoyette #include <dev/i2c/i2cvar.h>
     47  1.1  pgoyette #include <dev/ic/spdmemreg.h>
     48  1.1  pgoyette #include <dev/ic/spdmemvar.h>
     49  1.1  pgoyette 
     50  1.1  pgoyette SYSCTL_SETUP_PROTO(sysctl_spdmem_setup);
     51  1.1  pgoyette 
     52  1.1  pgoyette /* Routines for decoding spd data */
     53  1.1  pgoyette static void decode_edofpm(const struct sysctlnode *, device_t, struct spdmem *);
     54  1.1  pgoyette static void decode_rom(const struct sysctlnode *, device_t, struct spdmem *);
     55  1.1  pgoyette static void decode_sdram(const struct sysctlnode *, device_t, struct spdmem *,
     56  1.1  pgoyette 	int);
     57  1.1  pgoyette static void decode_ddr(const struct sysctlnode *, device_t, struct spdmem *);
     58  1.1  pgoyette static void decode_ddr2(const struct sysctlnode *, device_t, struct spdmem *);
     59  1.1  pgoyette static void decode_ddr3(const struct sysctlnode *, device_t, struct spdmem *);
     60  1.1  pgoyette static void decode_fbdimm(const struct sysctlnode *, device_t, struct spdmem *);
     61  1.1  pgoyette 
     62  1.1  pgoyette static void decode_size_speed(const struct sysctlnode *, int, int, int, int,
     63  1.1  pgoyette 			      bool, const char *, int);
     64  1.1  pgoyette static void decode_voltage_refresh(device_t, struct spdmem *);
     65  1.1  pgoyette 
     66  1.1  pgoyette #define IS_RAMBUS_TYPE (s->sm_len < 4)
     67  1.1  pgoyette 
     68  1.1  pgoyette static const char* spdmem_basic_types[] = {
     69  1.1  pgoyette 	"unknown",
     70  1.1  pgoyette 	"FPM",
     71  1.1  pgoyette 	"EDO",
     72  1.1  pgoyette 	"Pipelined Nibble",
     73  1.1  pgoyette 	"SDRAM",
     74  1.1  pgoyette 	"ROM",
     75  1.1  pgoyette 	"DDR SGRAM",
     76  1.1  pgoyette 	"DDR SDRAM",
     77  1.1  pgoyette 	"DDR2 SDRAM",
     78  1.1  pgoyette 	"DDR2 SDRAM FB",
     79  1.1  pgoyette 	"DDR2 SDRAM FB Probe",
     80  1.1  pgoyette 	"DDR3 SDRAM"
     81  1.1  pgoyette };
     82  1.1  pgoyette 
     83  1.1  pgoyette static const char* spdmem_superset_types[] = {
     84  1.1  pgoyette 	"unknown",
     85  1.1  pgoyette 	"ESDRAM",
     86  1.1  pgoyette 	"DDR ESDRAM",
     87  1.1  pgoyette 	"PEM EDO",
     88  1.1  pgoyette 	"PEM SDRAM"
     89  1.1  pgoyette };
     90  1.1  pgoyette 
     91  1.1  pgoyette static const char* spdmem_voltage_types[] = {
     92  1.1  pgoyette 	"TTL (5V tolerant)",
     93  1.1  pgoyette 	"LvTTL (not 5V tolerant)",
     94  1.1  pgoyette 	"HSTL 1.5V",
     95  1.1  pgoyette 	"SSTL 3.3V",
     96  1.1  pgoyette 	"SSTL 2.5V",
     97  1.1  pgoyette 	"SSTL 1.8V"
     98  1.1  pgoyette };
     99  1.1  pgoyette 
    100  1.1  pgoyette static const char* spdmem_refresh_types[] = {
    101  1.1  pgoyette 	"15.625us",
    102  1.1  pgoyette 	"3.9us",
    103  1.1  pgoyette 	"7.8us",
    104  1.1  pgoyette 	"31.3us",
    105  1.1  pgoyette 	"62.5us",
    106  1.1  pgoyette 	"125us"
    107  1.1  pgoyette };
    108  1.1  pgoyette 
    109  1.1  pgoyette static const char* spdmem_parity_types[] = {
    110  1.1  pgoyette 	"no parity or ECC",
    111  1.1  pgoyette 	"data parity",
    112  1.1  pgoyette 	"data ECC",
    113  1.1  pgoyette 	"data parity and ECC",
    114  1.1  pgoyette 	"cmd/addr parity",
    115  1.1  pgoyette 	"cmd/addr/data parity",
    116  1.1  pgoyette 	"cmd/addr parity, data ECC",
    117  1.1  pgoyette 	"cmd/addr/data parity, data ECC"
    118  1.1  pgoyette };
    119  1.1  pgoyette 
    120  1.1  pgoyette /* Cycle time fractional values (units of .001 ns) for DDR2 SDRAM */
    121  1.1  pgoyette static const uint16_t spdmem_cycle_frac[] = {
    122  1.1  pgoyette 	0, 100, 200, 300, 400, 500, 600, 700, 800, 900,
    123  1.1  pgoyette 	250, 333, 667, 750, 999, 999
    124  1.1  pgoyette };
    125  1.1  pgoyette 
    126  1.1  pgoyette /* Format string for timing info */
    127  1.1  pgoyette static const char* latency="tAA-tRCD-tRP-tRAS: %d-%d-%d-%d\n";
    128  1.1  pgoyette 
    129  1.1  pgoyette /* sysctl stuff */
    130  1.1  pgoyette static int hw_node = CTL_EOL;
    131  1.1  pgoyette 
    132  1.1  pgoyette /* CRC functions used for certain memory types */
    133  1.1  pgoyette 
    134  1.1  pgoyette static uint16_t spdcrc16 (struct spdmem_softc *sc, int count)
    135  1.1  pgoyette {
    136  1.1  pgoyette 	uint16_t crc;
    137  1.1  pgoyette 	int i, j;
    138  1.1  pgoyette 	uint8_t val;
    139  1.1  pgoyette 	crc = 0;
    140  1.1  pgoyette 	for (j = 0; j <= count; j++) {
    141  1.1  pgoyette 		val = (sc->sc_read)(sc, j);
    142  1.1  pgoyette 		crc = crc ^ val << 8;
    143  1.1  pgoyette 		for (i = 0; i < 8; ++i)
    144  1.1  pgoyette 			if (crc & 0x8000)
    145  1.1  pgoyette 				crc = crc << 1 ^ 0x1021;
    146  1.1  pgoyette 			else
    147  1.1  pgoyette 				crc = crc << 1;
    148  1.1  pgoyette 	}
    149  1.1  pgoyette 	return (crc & 0xFFFF);
    150  1.1  pgoyette }
    151  1.1  pgoyette 
    152  1.1  pgoyette int
    153  1.1  pgoyette spdmem_common_probe(struct spdmem_softc *sc)
    154  1.1  pgoyette {
    155  1.1  pgoyette 	int cksum = 0;
    156  1.1  pgoyette 	uint8_t i, val, spd_type;
    157  1.1  pgoyette 	int spd_len, spd_crc_cover;
    158  1.1  pgoyette 	uint16_t crc_calc, crc_spd;
    159  1.1  pgoyette 
    160  1.1  pgoyette 	spd_type = (sc->sc_read)(sc, 2);
    161  1.1  pgoyette 
    162  1.1  pgoyette 	/* For older memory types, validate the checksum over 1st 63 bytes */
    163  1.1  pgoyette 	if (spd_type <= SPDMEM_MEMTYPE_DDR2SDRAM) {
    164  1.1  pgoyette 		for (i = 0; i < 63; i++)
    165  1.1  pgoyette 			cksum += (sc->sc_read)(sc, i);
    166  1.1  pgoyette 
    167  1.1  pgoyette 		val = (sc->sc_read)(sc, 63);
    168  1.1  pgoyette 
    169  1.1  pgoyette 		if (cksum == 0 || (cksum & 0xff) != val) {
    170  1.1  pgoyette 			aprint_debug("spd checksum failed, calc = 0x%02x, "
    171  1.1  pgoyette 				     "spd = 0x%02x\n", cksum, val);
    172  1.1  pgoyette 			return 0;
    173  1.1  pgoyette 		} else
    174  1.1  pgoyette 			return 1;
    175  1.1  pgoyette 	}
    176  1.1  pgoyette 
    177  1.1  pgoyette 	/* For DDR3 and FBDIMM, verify the CRC */
    178  1.1  pgoyette 	else if (spd_type <= SPDMEM_MEMTYPE_DDR3SDRAM) {
    179  1.1  pgoyette 		spd_len = (sc->sc_read)(sc, 0);
    180  1.2  pgoyette 		if (spd_len & SPDMEM_SPDCRC_116)
    181  1.1  pgoyette 			spd_crc_cover = 116;
    182  1.1  pgoyette 		else
    183  1.1  pgoyette 			spd_crc_cover = 125;
    184  1.1  pgoyette 		switch (spd_len & SPDMEM_SPDLEN_MASK) {
    185  1.1  pgoyette 		case SPDMEM_SPDLEN_128:
    186  1.1  pgoyette 			spd_len = 128;
    187  1.1  pgoyette 			break;
    188  1.1  pgoyette 		case SPDMEM_SPDLEN_176:
    189  1.1  pgoyette 			spd_len = 176;
    190  1.1  pgoyette 			break;
    191  1.1  pgoyette 		case SPDMEM_SPDLEN_256:
    192  1.1  pgoyette 			spd_len = 256;
    193  1.1  pgoyette 			break;
    194  1.1  pgoyette 		default:
    195  1.1  pgoyette 			return 0;
    196  1.1  pgoyette 		}
    197  1.1  pgoyette 		if (spd_crc_cover > spd_len)
    198  1.1  pgoyette 			return 0;
    199  1.1  pgoyette 		crc_calc = spdcrc16(sc, spd_crc_cover);
    200  1.1  pgoyette 		crc_spd = (sc->sc_read)(sc, 127) << 8;
    201  1.1  pgoyette 		crc_spd |= (sc->sc_read)(sc, 126);
    202  1.1  pgoyette 		if (crc_calc != crc_spd) {
    203  1.1  pgoyette 			aprint_debug("crc16 failed, covers %d bytes, "
    204  1.1  pgoyette 				     "calc = 0x%04x, spd = 0x%04x\n",
    205  1.1  pgoyette 				     spd_crc_cover, crc_calc, crc_spd);
    206  1.1  pgoyette 			return 0;
    207  1.1  pgoyette 		}
    208  1.1  pgoyette 		return 1;
    209  1.1  pgoyette 	}
    210  1.1  pgoyette 
    211  1.1  pgoyette 	/* For unrecognized memory types, don't match at all */
    212  1.1  pgoyette 	return 0;
    213  1.1  pgoyette }
    214  1.1  pgoyette 
    215  1.1  pgoyette void
    216  1.1  pgoyette spdmem_common_attach(struct spdmem_softc *sc, device_t self)
    217  1.1  pgoyette {
    218  1.1  pgoyette 	struct spdmem *s = &(sc->sc_spd_data);
    219  1.1  pgoyette 	const char *type;
    220  1.1  pgoyette 	const char *rambus_rev = "Reserved";
    221  1.1  pgoyette 	int dimm_size;
    222  1.1  pgoyette 	int i;
    223  1.1  pgoyette 	unsigned int spd_len, spd_size;
    224  1.1  pgoyette 	const struct sysctlnode *node = NULL;
    225  1.1  pgoyette 
    226  1.1  pgoyette 	/*
    227  1.1  pgoyette 	 * FBDIMM and DDR3 (and probably all newer) have a different
    228  1.1  pgoyette 	 * encoding of the SPD EEPROM used/total sizes
    229  1.1  pgoyette 	 */
    230  1.1  pgoyette 	s->sm_len = (sc->sc_read)(sc, 0);
    231  1.1  pgoyette 	s->sm_size = (sc->sc_read)(sc, 1);
    232  1.1  pgoyette 	s->sm_type = (sc->sc_read)(sc, 2);
    233  1.1  pgoyette 
    234  1.1  pgoyette 	if (s->sm_type >= SPDMEM_MEMTYPE_FBDIMM) {
    235  1.1  pgoyette 		spd_size = 64 << (s->sm_len & SPDMEM_SPDSIZE_MASK);
    236  1.1  pgoyette 		switch (s->sm_len & SPDMEM_SPDLEN_MASK) {
    237  1.1  pgoyette 		case SPDMEM_SPDLEN_128:
    238  1.1  pgoyette 			spd_len = 128;
    239  1.1  pgoyette 			break;
    240  1.1  pgoyette 		case SPDMEM_SPDLEN_176:
    241  1.1  pgoyette 			spd_len = 176;
    242  1.1  pgoyette 			break;
    243  1.1  pgoyette 		case SPDMEM_SPDLEN_256:
    244  1.1  pgoyette 			spd_len = 256;
    245  1.1  pgoyette 			break;
    246  1.1  pgoyette 		default:
    247  1.1  pgoyette 			spd_len = 64;
    248  1.1  pgoyette 			break;
    249  1.1  pgoyette 		}
    250  1.1  pgoyette 	} else {
    251  1.1  pgoyette 		spd_size = 1 << s->sm_size;
    252  1.1  pgoyette 		spd_len = s->sm_len;
    253  1.1  pgoyette 		if (spd_len < 64)
    254  1.1  pgoyette 			spd_len = 64;
    255  1.1  pgoyette 	}
    256  1.1  pgoyette 	if (spd_len > spd_size)
    257  1.1  pgoyette 		spd_len = spd_size;
    258  1.1  pgoyette 	if (spd_len > sizeof(struct spdmem))
    259  1.1  pgoyette 		spd_len = sizeof(struct spdmem);
    260  1.1  pgoyette 	for (i = 3; i < spd_len; i++)
    261  1.1  pgoyette 		((uint8_t *)s)[i] = (sc->sc_read)(sc, i);
    262  1.1  pgoyette 
    263  1.1  pgoyette #ifdef DEBUG
    264  1.1  pgoyette 	for (i = 0; i < spd_len;  i += 16) {
    265  1.1  pgoyette 		int j, k;
    266  1.1  pgoyette 		aprint_debug("\n");
    267  1.1  pgoyette 		aprint_debug_dev(self, "0x%02x:", i);
    268  1.1  pgoyette 		k = (spd_len > i + 16) ? spd_len : i + 16;
    269  1.1  pgoyette 		for (j = i; j < k; j++)
    270  1.1  pgoyette 			aprint_debug(" %02x", ((uint8_t *)s)[j]);
    271  1.1  pgoyette 	}
    272  1.1  pgoyette 	aprint_debug("\n");
    273  1.1  pgoyette 	aprint_debug_dev(self, "");
    274  1.1  pgoyette #endif
    275  1.1  pgoyette 
    276  1.1  pgoyette 	/*
    277  1.1  pgoyette 	 * Setup our sysctl subtree, hw.spdmemN
    278  1.1  pgoyette 	 */
    279  1.1  pgoyette 	if (hw_node != CTL_EOL)
    280  1.1  pgoyette 		sysctl_createv(NULL, 0, NULL, &node,
    281  1.1  pgoyette 		    0, CTLTYPE_NODE,
    282  1.1  pgoyette 		    device_xname(self), NULL, NULL, 0, NULL, 0,
    283  1.1  pgoyette 		    CTL_HW, CTL_CREATE, CTL_EOL);
    284  1.1  pgoyette 	if (node != NULL && spd_len != 0)
    285  1.1  pgoyette                 sysctl_createv(NULL, 0, NULL, NULL,
    286  1.1  pgoyette                     0,
    287  1.1  pgoyette                     CTLTYPE_STRUCT, "spd_data",
    288  1.1  pgoyette 		    SYSCTL_DESCR("raw spd data"), NULL,
    289  1.1  pgoyette                     0, s, spd_len,
    290  1.1  pgoyette                     CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
    291  1.1  pgoyette 
    292  1.1  pgoyette 	/*
    293  1.1  pgoyette 	 * Decode and print key SPD contents
    294  1.1  pgoyette 	 */
    295  1.1  pgoyette 	if (IS_RAMBUS_TYPE) {
    296  1.1  pgoyette 		if (s->sm_type == SPDMEM_MEMTYPE_RAMBUS)
    297  1.1  pgoyette 			type = "Rambus";
    298  1.1  pgoyette 		else if (s->sm_type == SPDMEM_MEMTYPE_DIRECTRAMBUS)
    299  1.1  pgoyette 			type = "Direct Rambus";
    300  1.1  pgoyette 		else
    301  1.1  pgoyette 			type = "Rambus (unknown)";
    302  1.1  pgoyette 
    303  1.1  pgoyette 		switch (s->sm_len) {
    304  1.1  pgoyette 		case 0:
    305  1.1  pgoyette 			rambus_rev = "Invalid";
    306  1.1  pgoyette 			break;
    307  1.1  pgoyette 		case 1:
    308  1.1  pgoyette 			rambus_rev = "0.7";
    309  1.1  pgoyette 			break;
    310  1.1  pgoyette 		case 2:
    311  1.1  pgoyette 			rambus_rev = "1.0";
    312  1.1  pgoyette 			break;
    313  1.1  pgoyette 		default:
    314  1.1  pgoyette 			rambus_rev = "Reserved";
    315  1.1  pgoyette 			break;
    316  1.1  pgoyette 		}
    317  1.1  pgoyette 	} else {
    318  1.1  pgoyette 		if (s->sm_type < __arraycount(spdmem_basic_types))
    319  1.1  pgoyette 			type = spdmem_basic_types[s->sm_type];
    320  1.1  pgoyette 		else
    321  1.1  pgoyette 			type = "unknown memory type";
    322  1.1  pgoyette 
    323  1.1  pgoyette 		if (s->sm_type == SPDMEM_MEMTYPE_EDO &&
    324  1.1  pgoyette 		    s->sm_fpm.fpm_superset == SPDMEM_SUPERSET_EDO_PEM)
    325  1.1  pgoyette 			type = spdmem_superset_types[SPDMEM_SUPERSET_EDO_PEM];
    326  1.1  pgoyette 		if (s->sm_type == SPDMEM_MEMTYPE_SDRAM &&
    327  1.1  pgoyette 		    s->sm_sdr.sdr_superset == SPDMEM_SUPERSET_SDRAM_PEM)
    328  1.1  pgoyette 			type = spdmem_superset_types[SPDMEM_SUPERSET_SDRAM_PEM];
    329  1.1  pgoyette 		if (s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM &&
    330  1.1  pgoyette 		    s->sm_ddr.ddr_superset == SPDMEM_SUPERSET_DDR_ESDRAM)
    331  1.1  pgoyette 			type =
    332  1.1  pgoyette 			    spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM];
    333  1.1  pgoyette 		if (s->sm_type == SPDMEM_MEMTYPE_SDRAM &&
    334  1.1  pgoyette 		    s->sm_sdr.sdr_superset == SPDMEM_SUPERSET_ESDRAM) {
    335  1.1  pgoyette 			type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM];
    336  1.1  pgoyette 		}
    337  1.1  pgoyette 	}
    338  1.1  pgoyette 
    339  1.1  pgoyette 	aprint_naive("\n");
    340  1.1  pgoyette 	aprint_normal("\n");
    341  1.1  pgoyette 	aprint_normal_dev(self, "%s", type);
    342  1.1  pgoyette 	strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN);
    343  1.1  pgoyette 	if (node != NULL)
    344  1.1  pgoyette 		sysctl_createv(NULL, 0, NULL, NULL,
    345  1.1  pgoyette 		    0,
    346  1.1  pgoyette 		    CTLTYPE_STRING, "mem_type",
    347  1.1  pgoyette 		    SYSCTL_DESCR("memory module type"), NULL,
    348  1.1  pgoyette 		    0, sc->sc_type, 0,
    349  1.1  pgoyette 		    CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
    350  1.1  pgoyette 
    351  1.1  pgoyette 	if (IS_RAMBUS_TYPE) {
    352  1.1  pgoyette 		aprint_normal(", SPD Revision %s", rambus_rev);
    353  1.1  pgoyette 		dimm_size = 1 << (s->sm_rdr.rdr_rows + s->sm_rdr.rdr_cols - 13);
    354  1.1  pgoyette 		if (dimm_size >= 1024)
    355  1.1  pgoyette 			aprint_normal(", %dGB\n", dimm_size / 1024);
    356  1.1  pgoyette 		else
    357  1.1  pgoyette 			aprint_normal(", %dMB\n", dimm_size);
    358  1.1  pgoyette 
    359  1.1  pgoyette 		/* No further decode for RAMBUS memory */
    360  1.1  pgoyette 		return;
    361  1.1  pgoyette 	}
    362  1.1  pgoyette 	switch (s->sm_type) {
    363  1.1  pgoyette 	case SPDMEM_MEMTYPE_EDO:
    364  1.1  pgoyette 	case SPDMEM_MEMTYPE_FPM:
    365  1.1  pgoyette 		decode_edofpm(node, self, s);
    366  1.1  pgoyette 		break;
    367  1.1  pgoyette 	case SPDMEM_MEMTYPE_ROM:
    368  1.1  pgoyette 		decode_rom(node, self, s);
    369  1.1  pgoyette 		break;
    370  1.1  pgoyette 	case SPDMEM_MEMTYPE_SDRAM:
    371  1.1  pgoyette 		decode_sdram(node, self, s, spd_len);
    372  1.1  pgoyette 		break;
    373  1.1  pgoyette 	case SPDMEM_MEMTYPE_DDRSDRAM:
    374  1.1  pgoyette 		decode_ddr(node, self, s);
    375  1.1  pgoyette 		break;
    376  1.1  pgoyette 	case SPDMEM_MEMTYPE_DDR2SDRAM:
    377  1.1  pgoyette 		decode_ddr2(node, self, s);
    378  1.1  pgoyette 		break;
    379  1.1  pgoyette 	case SPDMEM_MEMTYPE_DDR3SDRAM:
    380  1.1  pgoyette 		decode_ddr3(node, self, s);
    381  1.1  pgoyette 		break;
    382  1.1  pgoyette 	case SPDMEM_MEMTYPE_FBDIMM:
    383  1.1  pgoyette 	case SPDMEM_MEMTYPE_FBDIMM_PROBE:
    384  1.1  pgoyette 		decode_fbdimm(node, self, s);
    385  1.1  pgoyette 		break;
    386  1.1  pgoyette 	}
    387  1.1  pgoyette }
    388  1.1  pgoyette 
    389  1.1  pgoyette SYSCTL_SETUP(sysctl_spdmem_setup, "sysctl hw.spdmem subtree setup")
    390  1.1  pgoyette {
    391  1.1  pgoyette 	const struct sysctlnode *node;
    392  1.1  pgoyette 
    393  1.1  pgoyette 	if (sysctl_createv(clog, 0, NULL, &node,
    394  1.1  pgoyette 	    CTLFLAG_PERMANENT,
    395  1.1  pgoyette 	    CTLTYPE_NODE, "hw", NULL,
    396  1.1  pgoyette 	    NULL, 0, NULL, 0,
    397  1.1  pgoyette 	    CTL_HW, CTL_EOL) != 0)
    398  1.1  pgoyette 		return;
    399  1.1  pgoyette 
    400  1.1  pgoyette 	hw_node = node->sysctl_num;
    401  1.1  pgoyette }
    402  1.1  pgoyette 
    403  1.1  pgoyette static void
    404  1.1  pgoyette decode_size_speed(const struct sysctlnode *node, int dimm_size, int cycle_time,
    405  1.1  pgoyette 		  int d_clk, int bits, bool round, const char *ddr_type_string,
    406  1.1  pgoyette 		  int speed)
    407  1.1  pgoyette {
    408  1.1  pgoyette 	int p_clk;
    409  1.1  pgoyette 
    410  1.1  pgoyette 	if (dimm_size < 1024)
    411  1.1  pgoyette 		aprint_normal("%dMB", dimm_size);
    412  1.1  pgoyette 	else
    413  1.1  pgoyette 		aprint_normal("%dGB", dimm_size / 1024);
    414  1.1  pgoyette 	if (node != NULL)
    415  1.1  pgoyette 		sysctl_createv(NULL, 0, NULL, NULL,
    416  1.1  pgoyette 		    CTLFLAG_IMMEDIATE,
    417  1.1  pgoyette 		    CTLTYPE_INT, "size",
    418  1.1  pgoyette 		    SYSCTL_DESCR("module size in MB"), NULL,
    419  1.1  pgoyette 		    dimm_size, NULL, 0,
    420  1.1  pgoyette 		    CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
    421  1.1  pgoyette 
    422  1.1  pgoyette 	if (cycle_time == 0) {
    423  1.1  pgoyette 		aprint_normal("\n");
    424  1.1  pgoyette 		return;
    425  1.1  pgoyette 	}
    426  1.1  pgoyette 
    427  1.1  pgoyette 	/*
    428  1.1  pgoyette 	 * Calculate p_clk first, since for DDR3 we need maximum significance.
    429  1.1  pgoyette 	 * DDR3 rating is not rounded to a multiple of 100.  This results in
    430  1.1  pgoyette 	 * cycle_time of 1.5ns displayed as PC3-10666.
    431  1.1  pgoyette 	 *
    432  1.1  pgoyette 	 * For SDRAM, the speed is provided by the caller so we use it.
    433  1.1  pgoyette 	 */
    434  1.1  pgoyette 	d_clk *= 1000 * 1000;
    435  1.1  pgoyette 	if (speed)
    436  1.1  pgoyette 		p_clk = speed;
    437  1.1  pgoyette 	else
    438  1.1  pgoyette 		p_clk = (d_clk * bits) / 8 / cycle_time;
    439  1.1  pgoyette 	d_clk = ((d_clk + cycle_time / 2) ) / cycle_time;
    440  1.1  pgoyette 	if (round) {
    441  1.1  pgoyette 		if ((p_clk % 100) >= 50)
    442  1.1  pgoyette 			p_clk += 50;
    443  1.1  pgoyette 		p_clk -= p_clk % 100;
    444  1.1  pgoyette 	}
    445  1.1  pgoyette 	aprint_normal(", %dMHz (%s-%d)\n",
    446  1.1  pgoyette 		      d_clk, ddr_type_string, p_clk);
    447  1.1  pgoyette 	if (node != NULL)
    448  1.1  pgoyette 		sysctl_createv(NULL, 0, NULL, NULL,
    449  1.1  pgoyette 			       CTLFLAG_IMMEDIATE,
    450  1.1  pgoyette 			       CTLTYPE_INT, "speed",
    451  1.1  pgoyette 			       SYSCTL_DESCR("memory speed in MHz"),
    452  1.1  pgoyette 			       NULL, d_clk, NULL, 0,
    453  1.1  pgoyette 			       CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
    454  1.1  pgoyette }
    455  1.1  pgoyette 
    456  1.1  pgoyette static void
    457  1.1  pgoyette decode_voltage_refresh(device_t self, struct spdmem *s)
    458  1.1  pgoyette {
    459  1.1  pgoyette 	const char *voltage, *refresh;
    460  1.1  pgoyette 
    461  1.1  pgoyette 	if (s->sm_voltage < __arraycount(spdmem_voltage_types))
    462  1.1  pgoyette 		voltage = spdmem_voltage_types[s->sm_voltage];
    463  1.1  pgoyette 	else
    464  1.1  pgoyette 		voltage = "unknown";
    465  1.1  pgoyette 
    466  1.1  pgoyette 	if (s->sm_refresh < __arraycount(spdmem_refresh_types))
    467  1.1  pgoyette 		refresh = spdmem_refresh_types[s->sm_refresh];
    468  1.1  pgoyette 	else
    469  1.1  pgoyette 		refresh = "unknown";
    470  1.1  pgoyette 
    471  1.1  pgoyette 	aprint_verbose_dev(self, "voltage %s, refresh time %s%s\n",
    472  1.1  pgoyette 			voltage, refresh,
    473  1.1  pgoyette 			s->sm_selfrefresh?" (self-refreshing)":"");
    474  1.1  pgoyette }
    475  1.1  pgoyette 
    476  1.1  pgoyette static void
    477  1.1  pgoyette decode_edofpm(const struct sysctlnode *node, device_t self, struct spdmem *s) {
    478  1.1  pgoyette 	aprint_normal("\n");
    479  1.1  pgoyette 	aprint_verbose_dev(self,
    480  1.1  pgoyette 	    "%d rows, %d cols, %d banks, %dns tRAC, %dns tCAC\n",
    481  1.1  pgoyette 	    s->sm_fpm.fpm_rows, s->sm_fpm.fpm_cols, s->sm_fpm.fpm_banks,
    482  1.1  pgoyette 	    s->sm_fpm.fpm_tRAC, s->sm_fpm.fpm_tCAC);
    483  1.1  pgoyette }
    484  1.1  pgoyette 
    485  1.1  pgoyette static void
    486  1.1  pgoyette decode_rom(const struct sysctlnode *node, device_t self, struct spdmem *s) {
    487  1.1  pgoyette 	aprint_normal("\n");
    488  1.1  pgoyette 	aprint_verbose_dev(self, "%d rows, %d cols, %d banks\n",
    489  1.1  pgoyette 	    s->sm_rom.rom_rows, s->sm_rom.rom_cols, s->sm_rom.rom_banks);
    490  1.1  pgoyette }
    491  1.1  pgoyette 
    492  1.1  pgoyette static void
    493  1.1  pgoyette decode_sdram(const struct sysctlnode *node, device_t self, struct spdmem *s,
    494  1.1  pgoyette 	     int spd_len) {
    495  1.1  pgoyette 	int dimm_size, cycle_time, bits, tAA, i, speed, freq;
    496  1.1  pgoyette 
    497  1.1  pgoyette 	aprint_normal("%s, %s, ",
    498  1.1  pgoyette 		(s->sm_sdr.sdr_mod_attrs & SPDMEM_SDR_MASK_REG)?
    499  1.1  pgoyette 			" (registered)":"",
    500  1.1  pgoyette 		(s->sm_config < __arraycount(spdmem_parity_types))?
    501  1.1  pgoyette 			spdmem_parity_types[s->sm_config]:"invalid parity");
    502  1.1  pgoyette 
    503  1.1  pgoyette 	dimm_size = 1 << (s->sm_sdr.sdr_rows + s->sm_sdr.sdr_cols - 17);
    504  1.1  pgoyette 	dimm_size *= s->sm_sdr.sdr_banks * s->sm_sdr.sdr_banks_per_chip;
    505  1.1  pgoyette 
    506  1.1  pgoyette 	cycle_time = s->sm_sdr.sdr_cycle_whole * 1000 +
    507  1.1  pgoyette 		     s->sm_sdr.sdr_cycle_tenths * 100;
    508  1.1  pgoyette 	bits = le16toh(s->sm_sdr.sdr_datawidth);
    509  1.1  pgoyette 	if (s->sm_config == 1 || s->sm_config == 2)
    510  1.1  pgoyette 		bits -= 8;
    511  1.1  pgoyette 
    512  1.1  pgoyette 	/* Calculate speed here - from OpenBSD */
    513  1.1  pgoyette 	if (spd_len >= 128)
    514  1.1  pgoyette 		freq = ((uint8_t *)s)[126];
    515  1.1  pgoyette 	else
    516  1.1  pgoyette 		freq = 0;
    517  1.1  pgoyette 	switch (freq) {
    518  1.1  pgoyette 		/*
    519  1.1  pgoyette 		 * Must check cycle time since some PC-133 DIMMs
    520  1.1  pgoyette 		 * actually report PC-100
    521  1.1  pgoyette 		 */
    522  1.1  pgoyette 	    case 100:
    523  1.1  pgoyette 	    case 133:
    524  1.1  pgoyette 		if (cycle_time < 8000)
    525  1.1  pgoyette 			speed = 133;
    526  1.1  pgoyette 		else
    527  1.1  pgoyette 			speed = 100;
    528  1.1  pgoyette 		break;
    529  1.1  pgoyette 	    case 0x66:		/* Legacy DIMMs use _hex_ 66! */
    530  1.1  pgoyette 	    default:
    531  1.1  pgoyette 		speed = 66;
    532  1.1  pgoyette 	}
    533  1.1  pgoyette 	decode_size_speed(node, dimm_size, cycle_time, 1, bits, FALSE, "PC",
    534  1.1  pgoyette 			  speed);
    535  1.1  pgoyette 
    536  1.1  pgoyette 	aprint_verbose_dev(self,
    537  1.1  pgoyette 	    "%d rows, %d cols, %d banks, %d banks/chip, %d.%dns cycle time\n",
    538  1.1  pgoyette 	    s->sm_sdr.sdr_rows, s->sm_sdr.sdr_cols, s->sm_sdr.sdr_banks,
    539  1.1  pgoyette 	    s->sm_sdr.sdr_banks_per_chip, cycle_time/1000,
    540  1.1  pgoyette 	    (cycle_time % 1000) / 100);
    541  1.1  pgoyette 
    542  1.1  pgoyette 	tAA  = 0;
    543  1.1  pgoyette 	for (i = 0; i < 8; i++)
    544  1.1  pgoyette 		if (s->sm_sdr.sdr_tCAS & (1 << i))
    545  1.1  pgoyette 			tAA = i;
    546  1.1  pgoyette 	tAA++;
    547  1.1  pgoyette 	aprint_verbose_dev(self, latency, tAA, s->sm_sdr.sdr_tRCD,
    548  1.1  pgoyette 	    s->sm_sdr.sdr_tRP, s->sm_sdr.sdr_tRAS);
    549  1.1  pgoyette 
    550  1.1  pgoyette 	decode_voltage_refresh(self, s);
    551  1.1  pgoyette }
    552  1.1  pgoyette 
    553  1.1  pgoyette static void
    554  1.1  pgoyette decode_ddr(const struct sysctlnode *node, device_t self, struct spdmem *s) {
    555  1.1  pgoyette 	int dimm_size, cycle_time, bits, tAA, i;
    556  1.1  pgoyette 
    557  1.1  pgoyette 	aprint_normal("%s, %s, ",
    558  1.1  pgoyette 		(s->sm_ddr.ddr_mod_attrs & SPDMEM_DDR_MASK_REG)?
    559  1.1  pgoyette 			" (registered)":"",
    560  1.1  pgoyette 		(s->sm_config < __arraycount(spdmem_parity_types))?
    561  1.1  pgoyette 			spdmem_parity_types[s->sm_config]:"invalid parity");
    562  1.1  pgoyette 
    563  1.1  pgoyette 	dimm_size = 1 << (s->sm_ddr.ddr_rows + s->sm_ddr.ddr_cols - 17);
    564  1.1  pgoyette 	dimm_size *= s->sm_ddr.ddr_ranks * s->sm_ddr.ddr_banks_per_chip;
    565  1.1  pgoyette 
    566  1.1  pgoyette 	cycle_time = s->sm_ddr.ddr_cycle_whole * 1000 +
    567  1.1  pgoyette 		  spdmem_cycle_frac[s->sm_ddr.ddr_cycle_tenths];
    568  1.1  pgoyette 	bits = le16toh(s->sm_ddr.ddr_datawidth);
    569  1.1  pgoyette 	if (s->sm_config == 1 || s->sm_config == 2)
    570  1.1  pgoyette 		bits -= 8;
    571  1.1  pgoyette 	decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC", 0);
    572  1.1  pgoyette 
    573  1.1  pgoyette 	aprint_verbose_dev(self,
    574  1.1  pgoyette 	    "%d rows, %d cols, %d ranks, %d banks/chip, %d.%dns cycle time\n",
    575  1.1  pgoyette 	    s->sm_ddr.ddr_rows, s->sm_ddr.ddr_cols, s->sm_ddr.ddr_ranks,
    576  1.1  pgoyette 	    s->sm_ddr.ddr_banks_per_chip, cycle_time/1000,
    577  1.1  pgoyette 	    (cycle_time % 1000 + 50) / 100);
    578  1.1  pgoyette 
    579  1.1  pgoyette 	tAA  = 0;
    580  1.1  pgoyette 	for (i = 2; i < 8; i++)
    581  1.1  pgoyette 		if (s->sm_ddr.ddr_tCAS & (1 << i))
    582  1.1  pgoyette 			tAA = i;
    583  1.1  pgoyette 	tAA /= 2;
    584  1.1  pgoyette 
    585  1.1  pgoyette #define __DDR_ROUND(scale, field)	\
    586  1.1  pgoyette 		((scale * s->sm_ddr.field + cycle_time - 1) / cycle_time)
    587  1.1  pgoyette 
    588  1.1  pgoyette 	aprint_verbose_dev(self, latency, tAA, __DDR_ROUND(250, ddr_tRCD),
    589  1.1  pgoyette 		__DDR_ROUND(250, ddr_tRP), __DDR_ROUND(1000, ddr_tRAS));
    590  1.1  pgoyette 
    591  1.1  pgoyette #undef	__DDR_ROUND
    592  1.1  pgoyette 
    593  1.1  pgoyette 	decode_voltage_refresh(self, s);
    594  1.1  pgoyette }
    595  1.1  pgoyette 
    596  1.1  pgoyette static void
    597  1.1  pgoyette decode_ddr2(const struct sysctlnode *node, device_t self, struct spdmem *s) {
    598  1.1  pgoyette 	int dimm_size, cycle_time, bits, tAA, i;
    599  1.1  pgoyette 
    600  1.1  pgoyette 	aprint_normal("%s, %s, ",
    601  1.1  pgoyette 		(s->sm_ddr2.ddr2_mod_attrs & SPDMEM_DDR2_MASK_REG)?
    602  1.1  pgoyette 			" (registered)":"",
    603  1.1  pgoyette 		(s->sm_config < __arraycount(spdmem_parity_types))?
    604  1.1  pgoyette 			spdmem_parity_types[s->sm_config]:"invalid parity");
    605  1.1  pgoyette 
    606  1.1  pgoyette 	dimm_size = 1 << (s->sm_ddr2.ddr2_rows + s->sm_ddr2.ddr2_cols - 17);
    607  1.1  pgoyette 	dimm_size *= (s->sm_ddr2.ddr2_ranks + 1) *
    608  1.1  pgoyette 		     s->sm_ddr2.ddr2_banks_per_chip;
    609  1.1  pgoyette 
    610  1.1  pgoyette 	cycle_time = s->sm_ddr2.ddr2_cycle_whole * 1000 +
    611  1.1  pgoyette 		 spdmem_cycle_frac[s->sm_ddr2.ddr2_cycle_frac];
    612  1.1  pgoyette 	bits = s->sm_ddr2.ddr2_datawidth;
    613  1.1  pgoyette 	if ((s->sm_config & 0x03) != 0)
    614  1.1  pgoyette 		bits -= 8;
    615  1.1  pgoyette 	decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC2", 0);
    616  1.1  pgoyette 
    617  1.1  pgoyette 	aprint_verbose_dev(self,
    618  1.1  pgoyette 	    "%d rows, %d cols, %d ranks, %d banks/chip, %d.%02dns cycle time\n",
    619  1.1  pgoyette 	    s->sm_ddr2.ddr2_rows, s->sm_ddr2.ddr2_cols,
    620  1.1  pgoyette 	    s->sm_ddr2.ddr2_ranks + 1, s->sm_ddr2.ddr2_banks_per_chip,
    621  1.1  pgoyette 	    cycle_time / 1000, (cycle_time % 1000 + 5) /10 );
    622  1.1  pgoyette 
    623  1.1  pgoyette 	tAA  = 0;
    624  1.1  pgoyette 	for (i = 2; i < 8; i++)
    625  1.1  pgoyette 		if (s->sm_ddr2.ddr2_tCAS & (1 << i))
    626  1.1  pgoyette 			tAA = i;
    627  1.1  pgoyette 
    628  1.1  pgoyette #define __DDR2_ROUND(scale, field)	\
    629  1.1  pgoyette 		((scale * s->sm_ddr2.field + cycle_time - 1) / cycle_time)
    630  1.1  pgoyette 
    631  1.1  pgoyette 	aprint_verbose_dev(self, latency, tAA, __DDR2_ROUND(250, ddr2_tRCD),
    632  1.1  pgoyette 		__DDR2_ROUND(250, ddr2_tRP), __DDR2_ROUND(1000, ddr2_tRAS));
    633  1.1  pgoyette 
    634  1.1  pgoyette #undef	__DDR_ROUND
    635  1.1  pgoyette 
    636  1.1  pgoyette 	decode_voltage_refresh(self, s);
    637  1.1  pgoyette }
    638  1.1  pgoyette 
    639  1.1  pgoyette static void
    640  1.1  pgoyette decode_ddr3(const struct sysctlnode *node, device_t self, struct spdmem *s) {
    641  1.1  pgoyette 	int dimm_size, cycle_time, bits;
    642  1.1  pgoyette 
    643  1.1  pgoyette 	if (s->sm_ddr3.ddr3_mod_type ==
    644  1.1  pgoyette 		SPDMEM_DDR3_TYPE_MINI_RDIMM ||
    645  1.1  pgoyette 	    s->sm_ddr3.ddr3_mod_type == SPDMEM_DDR3_TYPE_RDIMM)
    646  1.1  pgoyette 		aprint_normal(" (registered)");
    647  1.1  pgoyette 	aprint_normal(", %sECC, %stemp-sensor, ",
    648  1.1  pgoyette 		(s->sm_ddr3.ddr3_hasECC)?"":"no ",
    649  1.1  pgoyette 		(s->sm_ddr3.ddr3_has_therm_sensor)?"":"no ");
    650  1.1  pgoyette 
    651  1.1  pgoyette 	/*
    652  1.1  pgoyette 	 * DDR3 size specification is quite different from others
    653  1.1  pgoyette 	 *
    654  1.1  pgoyette 	 * Module capacity is defined as
    655  1.1  pgoyette 	 *	Chip_Capacity_in_bits / 8bits-per-byte *
    656  1.1  pgoyette 	 *	external_bus_width / internal_bus_width
    657  1.1  pgoyette 	 * We further divide by 2**20 to get our answer in MB
    658  1.1  pgoyette 	 */
    659  1.1  pgoyette 	dimm_size = (s->sm_ddr3.ddr3_chipsize + 28 - 20) - 3 +
    660  1.1  pgoyette 		    (s->sm_ddr3.ddr3_datawidth + 3) -
    661  1.1  pgoyette 		    (s->sm_ddr3.ddr3_chipwidth + 2);
    662  1.1  pgoyette 	dimm_size = (1 << dimm_size) * (s->sm_ddr3.ddr3_physbanks + 1);
    663  1.1  pgoyette 
    664  1.1  pgoyette 	cycle_time = (1000 * s->sm_ddr3.ddr3_mtb_dividend +
    665  1.1  pgoyette 			    (s->sm_ddr3.ddr3_mtb_divisor / 2)) /
    666  1.1  pgoyette 		     s->sm_ddr3.ddr3_mtb_divisor;
    667  1.1  pgoyette 	cycle_time *= s->sm_ddr3.ddr3_tCKmin;
    668  1.1  pgoyette 	bits = 1 << (s->sm_ddr3.ddr3_datawidth + 3);
    669  1.1  pgoyette 	decode_size_speed(node, dimm_size, cycle_time, 2, bits, FALSE, "PC3", 0);
    670  1.1  pgoyette 
    671  1.1  pgoyette 	aprint_verbose_dev(self,
    672  1.1  pgoyette 	    "%d rows, %d cols, %d log. banks, %d phys. banks, "
    673  1.1  pgoyette 	    "%d.%03dns cycle time\n",
    674  1.1  pgoyette 	    s->sm_ddr3.ddr3_rows + 9, s->sm_ddr3.ddr3_cols + 12,
    675  1.1  pgoyette 	    1 << (s->sm_ddr3.ddr3_logbanks + 3),
    676  1.1  pgoyette 	    s->sm_ddr3.ddr3_physbanks + 1,
    677  1.1  pgoyette 	    cycle_time/1000, cycle_time % 1000);
    678  1.1  pgoyette 
    679  1.1  pgoyette #define	__DDR3_CYCLES(field) (s->sm_ddr3.field / s->sm_ddr3.ddr3_tCKmin)
    680  1.1  pgoyette 
    681  1.1  pgoyette 	aprint_verbose_dev(self, latency, __DDR3_CYCLES(ddr3_tAAmin),
    682  1.1  pgoyette 		__DDR3_CYCLES(ddr3_tRCDmin), __DDR3_CYCLES(ddr3_tRPmin),
    683  1.1  pgoyette 		(s->sm_ddr3.ddr3_tRAS_msb * 256 + s->sm_ddr3.ddr3_tRAS_lsb) /
    684  1.1  pgoyette 		    s->sm_ddr3.ddr3_tCKmin);
    685  1.1  pgoyette 
    686  1.1  pgoyette #undef	__DDR3_CYCLES
    687  1.1  pgoyette }
    688  1.1  pgoyette 
    689  1.1  pgoyette static void
    690  1.1  pgoyette decode_fbdimm(const struct sysctlnode *node, device_t self, struct spdmem *s) {
    691  1.1  pgoyette 	int dimm_size, cycle_time, bits;
    692  1.1  pgoyette 
    693  1.1  pgoyette 	/*
    694  1.1  pgoyette 	 * FB-DIMM module size calculation is very much like DDR3
    695  1.1  pgoyette 	 */
    696  1.1  pgoyette 	dimm_size = s->sm_fbd.fbdimm_rows + 12 +
    697  1.1  pgoyette 		    s->sm_fbd.fbdimm_cols +  9 - 20 - 3;
    698  1.1  pgoyette 	dimm_size = (1 << dimm_size) * (1 << (s->sm_fbd.fbdimm_banks + 2));
    699  1.1  pgoyette 
    700  1.1  pgoyette 	cycle_time = (1000 * s->sm_fbd.fbdimm_mtb_dividend +
    701  1.1  pgoyette 			    (s->sm_fbd.fbdimm_mtb_divisor / 2)) /
    702  1.1  pgoyette 		     s->sm_fbd.fbdimm_mtb_divisor;
    703  1.1  pgoyette 	bits = 1 << (s->sm_fbd.fbdimm_dev_width + 2);
    704  1.1  pgoyette 	decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC2", 0);
    705  1.1  pgoyette 
    706  1.1  pgoyette 	aprint_verbose_dev(self,
    707  1.1  pgoyette 	    "%d rows, %d cols, %d banks, %d.%02dns cycle time\n",
    708  1.1  pgoyette 	    s->sm_fbd.fbdimm_rows, s->sm_fbd.fbdimm_cols,
    709  1.1  pgoyette 	    1 << (s->sm_fbd.fbdimm_banks + 2),
    710  1.1  pgoyette 	    cycle_time / 1000, (cycle_time % 1000 + 5) /10 );
    711  1.1  pgoyette 
    712  1.1  pgoyette #define	__FBDIMM_CYCLES(field) (s->sm_fbd.field / s->sm_fbd.fbdimm_tCKmin)
    713  1.1  pgoyette 
    714  1.1  pgoyette 	aprint_verbose_dev(self, latency, __FBDIMM_CYCLES(fbdimm_tAAmin),
    715  1.1  pgoyette 		__FBDIMM_CYCLES(fbdimm_tRCDmin), __FBDIMM_CYCLES(fbdimm_tRPmin),
    716  1.1  pgoyette 		(s->sm_fbd.fbdimm_tRAS_msb * 256 +
    717  1.1  pgoyette 			s->sm_fbd.fbdimm_tRAS_lsb) /
    718  1.1  pgoyette 		    s->sm_fbd.fbdimm_tCKmin);
    719  1.1  pgoyette 
    720  1.1  pgoyette #undef	__FBDIMM_CYCLES
    721  1.1  pgoyette 
    722  1.1  pgoyette 	decode_voltage_refresh(self, s);
    723  1.1  pgoyette }
    724