| File: | dev/spdmem.c |
| Warning: | line 721, column 3 Value stored to 'd_clk' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: spdmem.c,v 1.7 2019/12/21 12:33:03 kettenis Exp $ */ |
| 2 | /* $NetBSD: spdmem.c,v 1.3 2007/09/20 23:09:59 xtraeme Exp $ */ |
| 3 | |
| 4 | /* |
| 5 | * Copyright (c) 2007 Jonathan Gray <jsg@openbsd.org> |
| 6 | * |
| 7 | * Permission to use, copy, modify, and distribute this software for any |
| 8 | * purpose with or without fee is hereby granted, provided that the above |
| 9 | * copyright notice and this permission notice appear in all copies. |
| 10 | * |
| 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 18 | */ |
| 19 | |
| 20 | /* |
| 21 | * Copyright (c) 2007 Nicolas Joly |
| 22 | * Copyright (c) 2007 Paul Goyette |
| 23 | * Copyright (c) 2007 Tobias Nygren |
| 24 | * All rights reserved. |
| 25 | * |
| 26 | * Redistribution and use in source and binary forms, with or without |
| 27 | * modification, are permitted provided that the following conditions |
| 28 | * are met: |
| 29 | * 1. Redistributions of source code must retain the above copyright |
| 30 | * notice, this list of conditions and the following disclaimer. |
| 31 | * 2. Redistributions in binary form must reproduce the above copyright |
| 32 | * notice, this list of conditions and the following disclaimer in the |
| 33 | * documentation and/or other materials provided with the distribution. |
| 34 | * 3. The name of the author may not be used to endorse or promote products |
| 35 | * derived from this software without specific prior written permission. |
| 36 | * |
| 37 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS |
| 38 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| 39 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 40 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
| 41 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 42 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 43 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 44 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 45 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 46 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 47 | * POSSIBILITY OF SUCH DAMAGE. |
| 48 | */ |
| 49 | |
| 50 | /* |
| 51 | * Serial Presence Detect (SPD) memory identification |
| 52 | */ |
| 53 | |
| 54 | #include <sys/param.h> |
| 55 | #include <sys/systm.h> |
| 56 | #include <sys/device.h> |
| 57 | |
| 58 | #include <dev/spdmemvar.h> |
| 59 | |
| 60 | /* Encodings of the size used/total byte for certain memory types */ |
| 61 | #define SPDMEM_SPDSIZE_MASK0x0F 0x0F /* SPD EEPROM Size */ |
| 62 | |
| 63 | #define SPDMEM_SPDLEN_1280x00 0x00 /* SPD EEPROM Sizes */ |
| 64 | #define SPDMEM_SPDLEN_1760x10 0x10 |
| 65 | #define SPDMEM_SPDLEN_2560x20 0x20 |
| 66 | #define SPDMEM_SPDLEN_MASK0x70 0x70 /* Bits 4 - 6 */ |
| 67 | |
| 68 | #define SPDMEM_DDR4_SPDLEN_1280x01 0x01 /* SPD EEPROM Sizes */ |
| 69 | #define SPDMEM_DDR4_SPDLEN_2560x02 0x02 |
| 70 | #define SPDMEM_DDR4_SPDLEN_3840x03 0x03 |
| 71 | #define SPDMEM_DDR4_SPDLEN_5120x04 0x04 |
| 72 | #define SPDMEM_DDR4_SPDLEN_MASK0x0f 0x0f /* Bits 4 - 6 */ |
| 73 | |
| 74 | #define SPDMEM_SPDCRC_1160x80 0x80 /* CRC Bytes covered */ |
| 75 | #define SPDMEM_SPDCRC_1250x00 0x00 |
| 76 | #define SPDMEM_SPDCRC_MASK0x80 0x80 /* Bit 7 */ |
| 77 | |
| 78 | /* possible values for the memory type */ |
| 79 | #define SPDMEM_MEMTYPE_FPM0x01 0x01 |
| 80 | #define SPDMEM_MEMTYPE_EDO0x02 0x02 |
| 81 | #define SPDMEM_MEMTYPE_PIPE_NIBBLE0x03 0x03 |
| 82 | #define SPDMEM_MEMTYPE_SDRAM0x04 0x04 |
| 83 | #define SPDMEM_MEMTYPE_ROM0x05 0x05 |
| 84 | #define SPDMEM_MEMTYPE_DDRSGRAM0x06 0x06 |
| 85 | #define SPDMEM_MEMTYPE_DDRSDRAM0x07 0x07 |
| 86 | #define SPDMEM_MEMTYPE_DDR2SDRAM0x08 0x08 |
| 87 | #define SPDMEM_MEMTYPE_FBDIMM0x09 0x09 |
| 88 | #define SPDMEM_MEMTYPE_FBDIMM_PROBE0x0a 0x0a |
| 89 | #define SPDMEM_MEMTYPE_DDR3SDRAM0x0b 0x0b |
| 90 | #define SPDMEM_MEMTYPE_DDR4SDRAM0x0c 0x0c |
| 91 | /* 0xd reserved */ |
| 92 | #define SPDMEM_MEMTYPE_DDR4ESDRAM0x0e 0x0e |
| 93 | #define SPDMEM_MEMTYPE_LPDDR3SDRAM0x0f 0x0f |
| 94 | #define SPDMEM_MEMTYPE_LPDDR4SDRAM0x10 0x10 |
| 95 | #define SPDMEM_MEMTYPE_LPDDR4XSDRAM0x11 0x11 |
| 96 | #define SPDMEM_MEMTYPE_DDR5SDRAM0x12 0x12 |
| 97 | #define SPDMEM_MEMTYPE_LPDDR5SDRAM0x13 0x13 |
| 98 | |
| 99 | #define SPDMEM_MEMTYPE_NONE0xff 0xff |
| 100 | |
| 101 | #define SPDMEM_MEMTYPE_DIRECT_RAMBUS0x01 0x01 |
| 102 | #define SPDMEM_MEMTYPE_RAMBUS0x11 0x11 |
| 103 | |
| 104 | /* possible values for the supply voltage */ |
| 105 | #define SPDMEM_VOLTAGE_TTL_5V0x00 0x00 |
| 106 | #define SPDMEM_VOLTAGE_TTL_LV0x01 0x01 |
| 107 | #define SPDMEM_VOLTAGE_HSTTL_1_5V0x02 0x02 |
| 108 | #define SPDMEM_VOLTAGE_SSTL_3_3V0x03 0x03 |
| 109 | #define SPDMEM_VOLTAGE_SSTL_2_5V0x04 0x04 |
| 110 | #define SPDMEM_VOLTAGE_SSTL_1_8V0x05 0x05 |
| 111 | |
| 112 | /* possible values for module configuration */ |
| 113 | #define SPDMEM_MODCONFIG_PARITY0x01 0x01 |
| 114 | #define SPDMEM_MODCONFIG_ECC0x02 0x02 |
| 115 | |
| 116 | /* for DDR2, module configuration is a bit-mask field */ |
| 117 | #define SPDMEM_MODCONFIG_HAS_DATA_PARITY0x01 0x01 |
| 118 | #define SPDMEM_MODCONFIG_HAS_DATA_ECC0x02 0x02 |
| 119 | #define SPDMEM_MODCONFIG_HAS_ADDR_CMD_PARITY0x04 0x04 |
| 120 | |
| 121 | /* possible values for the refresh field */ |
| 122 | #define SPDMEM_REFRESH_STD0x00 0x00 |
| 123 | #define SPDMEM_REFRESH_QUARTER0x01 0x01 |
| 124 | #define SPDMEM_REFRESH_HALF0x02 0x02 |
| 125 | #define SPDMEM_REFRESH_TWOX0x03 0x03 |
| 126 | #define SPDMEM_REFRESH_FOURX0x04 0x04 |
| 127 | #define SPDMEM_REFRESH_EIGHTX0x05 0x05 |
| 128 | #define SPDMEM_REFRESH_SELFREFRESH0x80 0x80 |
| 129 | |
| 130 | /* superset types */ |
| 131 | #define SPDMEM_SUPERSET_ESDRAM0x01 0x01 |
| 132 | #define SPDMEM_SUPERSET_DDR_ESDRAM0x02 0x02 |
| 133 | #define SPDMEM_SUPERSET_EDO_PEM0x03 0x03 |
| 134 | #define SPDMEM_SUPERSET_SDR_PEM0x04 0x04 |
| 135 | |
| 136 | /* FPM and EDO DIMMS */ |
| 137 | #define SPDMEM_FPM_ROWS0x00 0x00 |
| 138 | #define SPDMEM_FPM_COLS0x01 0x01 |
| 139 | #define SPDMEM_FPM_BANKS0x02 0x02 |
| 140 | #define SPDMEM_FPM_CONFIG0x08 0x08 |
| 141 | #define SPDMEM_FPM_REFRESH0x09 0x09 |
| 142 | #define SPDMEM_FPM_SUPERSET0x0c 0x0c |
| 143 | |
| 144 | /* PC66/PC100/PC133 SDRAM */ |
| 145 | #define SPDMEM_SDR_ROWS0x00 0x00 |
| 146 | #define SPDMEM_SDR_COLS0x01 0x01 |
| 147 | #define SPDMEM_SDR_BANKS0x02 0x02 |
| 148 | #define SPDMEM_SDR_CYCLE0x06 0x06 |
| 149 | #define SPDMEM_SDR_BANKS_PER_CHIP0x0e 0x0e |
| 150 | #define SPDMEM_SDR_MOD_ATTRIB0x12 0x12 |
| 151 | #define SPDMEM_SDR_SUPERSET0x1d 0x1d |
| 152 | |
| 153 | #define SPDMEM_SDR_FREQUENCY126 126 |
| 154 | #define SPDMEM_SDR_CAS127 127 |
| 155 | #define SPDMEM_SDR_FREQ_660x66 0x66 |
| 156 | #define SPDMEM_SDR_FREQ_1000x64 0x64 |
| 157 | #define SPDMEM_SDR_FREQ_1330x85 0x85 |
| 158 | #define SPDMEM_SDR_CAS2(1 << 1) (1 << 1) |
| 159 | #define SPDMEM_SDR_CAS3(1 << 2) (1 << 2) |
| 160 | |
| 161 | /* Rambus Direct DRAM */ |
| 162 | #define SPDMEM_RDR_MODULE_TYPE0x00 0x00 |
| 163 | #define SPDMEM_RDR_ROWS_COLS0x01 0x01 |
| 164 | #define SPDMEM_RDR_BANK0x02 0x02 |
| 165 | |
| 166 | #define SPDMEM_RDR_TYPE_RIMM1 1 |
| 167 | #define SPDMEM_RDR_TYPE_SORIMM2 2 |
| 168 | #define SPDMEM_RDR_TYPE_EMBED3 3 |
| 169 | #define SPDMEM_RDR_TYPE_RIMM324 4 |
| 170 | |
| 171 | /* Dual Data Rate SDRAM */ |
| 172 | #define SPDMEM_DDR_ROWS0x00 0x00 |
| 173 | #define SPDMEM_DDR_COLS0x01 0x01 |
| 174 | #define SPDMEM_DDR_RANKS0x02 0x02 |
| 175 | #define SPDMEM_DDR_DATAWIDTH0x03 0x03 |
| 176 | #define SPDMEM_DDR_VOLTAGE0x05 0x05 |
| 177 | #define SPDMEM_DDR_CYCLE0x06 0x06 |
| 178 | #define SPDMEM_DDR_REFRESH0x09 0x09 |
| 179 | #define SPDMEM_DDR_BANKS_PER_CHIP0x0e 0x0e |
| 180 | #define SPDMEM_DDR_CAS0x0f 0x0f |
| 181 | #define SPDMEM_DDR_MOD_ATTRIB0x12 0x12 |
| 182 | #define SPDMEM_DDR_SUPERSET0x1d 0x1d |
| 183 | |
| 184 | #define SPDMEM_DDR_ATTRIB_REG(1 << 1) (1 << 1) |
| 185 | |
| 186 | /* Dual Data Rate 2 SDRAM */ |
| 187 | #define SPDMEM_DDR2_ROWS0x00 0x00 |
| 188 | #define SPDMEM_DDR2_COLS0x01 0x01 |
| 189 | #define SPDMEM_DDR2_RANKS0x02 0x02 |
| 190 | #define SPDMEM_DDR2_DATAWIDTH0x03 0x03 |
| 191 | #define SPDMEM_DDR2_VOLTAGE0x05 0x05 |
| 192 | #define SPDMEM_DDR2_CYCLE0x06 0x06 |
| 193 | #define SPDMEM_DDR2_DIMMTYPE0x11 0x11 |
| 194 | #define SPDMEM_DDR2_RANK_DENSITY0x1c 0x1c |
| 195 | |
| 196 | #define SPDMEM_DDR2_TYPE_REGMASK((1 << 4) | (1 << 0)) ((1 << 4) | (1 << 0)) |
| 197 | #define SPDMEM_DDR2_SODIMM(1 << 2) (1 << 2) |
| 198 | #define SPDMEM_DDR2_MICRO_DIMM(1 << 3) (1 << 3) |
| 199 | #define SPDMEM_DDR2_MINI_RDIMM(1 << 4) (1 << 4) |
| 200 | #define SPDMEM_DDR2_MINI_UDIMM(1 << 5) (1 << 5) |
| 201 | |
| 202 | /* DDR2 FB-DIMM SDRAM */ |
| 203 | #define SPDMEM_FBDIMM_ADDR0x01 0x01 |
| 204 | #define SPDMEM_FBDIMM_RANKS0x04 0x04 |
| 205 | #define SPDMEM_FBDIMM_MTB_DIVIDEND0x06 0x06 |
| 206 | #define SPDMEM_FBDIMM_MTB_DIVISOR0x07 0x07 |
| 207 | #define SPDMEM_FBDIMM_PROTO0x4e 0x4e |
| 208 | |
| 209 | #define SPDMEM_FBDIMM_RANKS_WIDTH0x07 0x07 |
| 210 | #define SPDMEM_FBDIMM_ADDR_BANKS0x02 0x02 |
| 211 | #define SPDMEM_FBDIMM_ADDR_COL0x0c 0x0c |
| 212 | #define SPDMEM_FBDIMM_ADDR_COL_SHIFT2 2 |
| 213 | #define SPDMEM_FBDIMM_ADDR_ROW0xe0 0xe0 |
| 214 | #define SPDMEM_FBDIMM_ADDR_ROW_SHIFT5 5 |
| 215 | #define SPDMEM_FBDIMM_PROTO_ECC(1 << 1) (1 << 1) |
| 216 | |
| 217 | |
| 218 | /* Dual Data Rate 3 SDRAM */ |
| 219 | #define SPDMEM_DDR3_MODTYPE0x00 0x00 |
| 220 | #define SPDMEM_DDR3_DENSITY0x01 0x01 |
| 221 | #define SPDMEM_DDR3_MOD_ORG0x04 0x04 |
| 222 | #define SPDMEM_DDR3_DATAWIDTH0x05 0x05 |
| 223 | #define SPDMEM_DDR3_MTB_DIVIDEND0x07 0x07 |
| 224 | #define SPDMEM_DDR3_MTB_DIVISOR0x08 0x08 |
| 225 | #define SPDMEM_DDR3_TCKMIN0x09 0x09 |
| 226 | #define SPDMEM_DDR3_THERMAL0x1d 0x1d |
| 227 | |
| 228 | #define SPDMEM_DDR3_DENSITY_CAPMASK0x0f 0x0f |
| 229 | #define SPDMEM_DDR3_MOD_ORG_CHIPWIDTH_MASK0x07 0x07 |
| 230 | #define SPDMEM_DDR3_MOD_ORG_BANKS_SHIFT3 3 |
| 231 | #define SPDMEM_DDR3_MOD_ORG_BANKS_MASK0x07 0x07 |
| 232 | #define SPDMEM_DDR3_DATAWIDTH_ECCMASK(1 << 3) (1 << 3) |
| 233 | #define SPDMEM_DDR3_DATAWIDTH_PRIMASK0x07 0x07 |
| 234 | #define SPDMEM_DDR3_THERMAL_PRESENT(1 << 7) (1 << 7) |
| 235 | |
| 236 | #define SPDMEM_DDR3_RDIMM0x01 0x01 |
| 237 | #define SPDMEM_DDR3_UDIMM0x02 0x02 |
| 238 | #define SPDMEM_DDR3_SODIMM0x03 0x03 |
| 239 | #define SPDMEM_DDR3_MICRO_DIMM0x04 0x04 |
| 240 | #define SPDMEM_DDR3_MINI_RDIMM0x05 0x05 |
| 241 | #define SPDMEM_DDR3_MINI_UDIMM0x06 0x06 |
| 242 | |
| 243 | /* Dual Data Rate 4 SDRAM */ |
| 244 | #define SPDMEM_DDR4_MODTYPE0x00 0x00 |
| 245 | #define SPDMEM_DDR4_DENSITY0x01 0x01 |
| 246 | #define SPDMEM_DDR4_PACK_TYPE0x03 0x03 |
| 247 | #define SPDMEM_DDR4_MOD_ORG0x09 0x09 |
| 248 | #define SPDMEM_DDR4_DATAWIDTH0x0a 0x0a |
| 249 | #define SPDMEM_DDR4_THERMAL0x0b 0x0b |
| 250 | #define SPDMEM_DDR4_TCKMIN_MTB0x0f 0x0f |
| 251 | #define SPDMEM_DDR4_TCKMIN_FTB0x7d 0x7d /* not offset by 3 */ |
| 252 | |
| 253 | #define SPDMEM_DDR4_DENSITY_CAPMASK0x0f 0x0f |
| 254 | #define SPDMEM_DDR4_PACK_TYPE_SIG_LOAD_MASK0x03 0x03 |
| 255 | #define SPDMEM_DDR4_PACK_TYPE_SIG_SINGLE_LOAD0x02 0x02 |
| 256 | #define SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_SHIFT4 4 |
| 257 | #define SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_MASK0x07 0x07 |
| 258 | #define SPDMEM_DDR4_MOD_ORG_CHIPWIDTH_MASK0x07 0x07 |
| 259 | #define SPDMEM_DDR4_MOD_ORG_BANKS_SHIFT3 3 |
| 260 | #define SPDMEM_DDR4_MOD_ORG_BANKS_MASK0x07 0x07 |
| 261 | #define SPDMEM_DDR4_DATAWIDTH_ECCMASK(1 << 3) (1 << 3) |
| 262 | #define SPDMEM_DDR4_DATAWIDTH_PRIMASK0x07 0x07 |
| 263 | #define SPDMEM_DDR4_THERMAL_PRESENT(1 << 7) (1 << 7) |
| 264 | |
| 265 | #define SPDMEM_DDR4_RDIMM0x01 0x01 |
| 266 | #define SPDMEM_DDR4_UDIMM0x02 0x02 |
| 267 | #define SPDMEM_DDR4_SODIMM0x03 0x03 |
| 268 | #define SPDMEM_DDR4_LRDIMM0x04 0x04 |
| 269 | #define SPDMEM_DDR4_MINI_RDIMM0x05 0x05 |
| 270 | #define SPDMEM_DDR4_MINI_UDIMM0x06 0x06 |
| 271 | #define SPDMEM_DDR4_LP_DIMM0x07 0x07 |
| 272 | #define SPDMEM_DDR4_72B_SO_RDIMM0x08 0x08 |
| 273 | #define SPDMEM_DDR4_72B_SO_UDIMM0x09 0x09 |
| 274 | #define SPDMEM_DDR4_16B_SO_DIMM0x0c 0x0c |
| 275 | #define SPDMEM_DDR4_32B_SO_DIMM0x0d 0x0d |
| 276 | #define SPDMEM_DDR4_NON_DIMM0x0e 0x0e |
| 277 | #define SPDMEM_DDR4_MODTYPE_MASK0x0f 0x0f |
| 278 | #define SPDMEM_DDR4_MODTYPE_HYBRID0x80 0x80 |
| 279 | |
| 280 | static const uint8_t ddr2_cycle_tenths[] = { |
| 281 | 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 25, 33, 66, 75, 0, 0 |
| 282 | }; |
| 283 | |
| 284 | #define SPDMEM_TYPE_MAXLEN16 16 |
| 285 | |
| 286 | uint16_t spdmem_crc16(struct spdmem_softc *, int); |
| 287 | static inline |
| 288 | uint8_t spdmem_read(struct spdmem_softc *, uint8_t); |
| 289 | void spdmem_sdram_decode(struct spdmem_softc *, struct spdmem *); |
| 290 | void spdmem_rdr_decode(struct spdmem_softc *, struct spdmem *); |
| 291 | void spdmem_ddr_decode(struct spdmem_softc *, struct spdmem *); |
| 292 | void spdmem_ddr2_decode(struct spdmem_softc *, struct spdmem *); |
| 293 | void spdmem_fbdimm_decode(struct spdmem_softc *, struct spdmem *); |
| 294 | void spdmem_ddr3_decode(struct spdmem_softc *, struct spdmem *); |
| 295 | |
| 296 | struct cfdriver spdmem_cd = { |
| 297 | NULL((void *)0), "spdmem", DV_DULL |
| 298 | }; |
| 299 | |
| 300 | #define IS_RAMBUS_TYPE(s->sm_len < 4) (s->sm_len < 4) |
| 301 | |
| 302 | static const char *spdmem_basic_types[] = { |
| 303 | "unknown", |
| 304 | "FPM", |
| 305 | "EDO", |
| 306 | "Pipelined Nibble", |
| 307 | "SDRAM", |
| 308 | "ROM", |
| 309 | "DDR SGRAM", |
| 310 | "DDR SDRAM", |
| 311 | "DDR2 SDRAM", |
| 312 | "DDR2 SDRAM FB-DIMM", |
| 313 | "DDR2 SDRAM FB-DIMM Probe", |
| 314 | "DDR3 SDRAM", |
| 315 | "DDR4 SDRAM", |
| 316 | "unknown", |
| 317 | "DDR4E SDRAM", |
| 318 | "LPDDR3 SDRAM", |
| 319 | "LPDDR4 SDRAM", |
| 320 | "LPDDR4X SDRAM", |
| 321 | "DDR5 SDRAM", |
| 322 | "LPDDR5 SDRAM" |
| 323 | }; |
| 324 | |
| 325 | static const char *spdmem_superset_types[] = { |
| 326 | "unknown", |
| 327 | "ESDRAM", |
| 328 | "DDR ESDRAM", |
| 329 | "PEM EDO", |
| 330 | "PEM SDRAM" |
| 331 | }; |
| 332 | |
| 333 | static const char *spdmem_parity_types[] = { |
| 334 | "non-parity", |
| 335 | "data parity", |
| 336 | "ECC", |
| 337 | "data parity and ECC", |
| 338 | "cmd/addr parity", |
| 339 | "cmd/addr/data parity", |
| 340 | "cmd/addr parity, data ECC", |
| 341 | "cmd/addr/data parity, data ECC" |
| 342 | }; |
| 343 | |
| 344 | static inline uint8_t |
| 345 | spdmem_read(struct spdmem_softc *sc, uint8_t reg) |
| 346 | { |
| 347 | return (*sc->sc_read)(sc, reg); |
| 348 | } |
| 349 | |
| 350 | /* CRC functions used for certain memory types */ |
| 351 | uint16_t |
| 352 | spdmem_crc16(struct spdmem_softc *sc, int count) |
| 353 | { |
| 354 | uint16_t crc; |
| 355 | int i, j; |
| 356 | uint8_t val; |
| 357 | crc = 0; |
| 358 | for (j = 0; j <= count; j++) { |
| 359 | val = spdmem_read(sc, j); |
| 360 | crc = crc ^ val << 8; |
| 361 | for (i = 0; i < 8; ++i) |
| 362 | if (crc & 0x8000) |
| 363 | crc = crc << 1 ^ 0x1021; |
| 364 | else |
| 365 | crc = crc << 1; |
| 366 | } |
| 367 | return (crc & 0xFFFF); |
| 368 | } |
| 369 | |
| 370 | void |
| 371 | spdmem_sdram_decode(struct spdmem_softc *sc, struct spdmem *s) |
| 372 | { |
| 373 | const char *type; |
| 374 | int dimm_size, p_clk; |
| 375 | int num_banks, per_chip; |
| 376 | uint8_t rows, cols; |
| 377 | |
| 378 | type = spdmem_basic_types[s->sm_type]; |
| 379 | |
| 380 | if (s->sm_data[SPDMEM_SDR_SUPERSET0x1d] == SPDMEM_SUPERSET_SDR_PEM0x04) |
| 381 | type = spdmem_superset_types[SPDMEM_SUPERSET_SDR_PEM0x04]; |
| 382 | if (s->sm_data[SPDMEM_SDR_SUPERSET0x1d] == SPDMEM_SUPERSET_ESDRAM0x01) |
| 383 | type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM0x01]; |
| 384 | |
| 385 | num_banks = s->sm_data[SPDMEM_SDR_BANKS0x02]; |
| 386 | per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP0x0e]; |
| 387 | rows = s->sm_data[SPDMEM_SDR_ROWS0x00] & 0x0f; |
| 388 | cols = s->sm_data[SPDMEM_SDR_COLS0x01] & 0x0f; |
| 389 | dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip; |
| 390 | |
| 391 | if (dimm_size > 0) { |
| 392 | if (dimm_size < 1024) |
| 393 | printf(" %dMB", dimm_size); |
| 394 | else |
| 395 | printf(" %dGB", dimm_size / 1024); |
| 396 | } |
| 397 | |
| 398 | printf(" %s", type); |
| 399 | |
| 400 | if (s->sm_data[SPDMEM_DDR_MOD_ATTRIB0x12] & SPDMEM_DDR_ATTRIB_REG(1 << 1)) |
| 401 | printf(" registered"); |
| 402 | |
| 403 | if (s->sm_data[SPDMEM_FPM_CONFIG0x08] < 8) |
| 404 | printf(" %s", |
| 405 | spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG0x08]]); |
| 406 | |
| 407 | p_clk = 66; |
| 408 | if (s->sm_len >= 128) { |
| 409 | switch (spdmem_read(sc, SPDMEM_SDR_FREQUENCY126)) { |
| 410 | case SPDMEM_SDR_FREQ_1000x64: |
| 411 | case SPDMEM_SDR_FREQ_1330x85: |
| 412 | /* We need to check ns to decide here */ |
| 413 | if (s->sm_data[SPDMEM_SDR_CYCLE0x06] < 0x80) |
| 414 | p_clk = 133; |
| 415 | else |
| 416 | p_clk = 100; |
| 417 | break; |
| 418 | case SPDMEM_SDR_FREQ_660x66: |
| 419 | default: |
| 420 | p_clk = 66; |
| 421 | break; |
| 422 | } |
| 423 | } |
| 424 | printf(" PC%d", p_clk); |
| 425 | |
| 426 | /* Print CAS latency */ |
| 427 | if (s->sm_len < 128) |
| 428 | return; |
| 429 | if (spdmem_read(sc, SPDMEM_SDR_CAS127) & SPDMEM_SDR_CAS2(1 << 1)) |
| 430 | printf("CL2"); |
| 431 | else if (spdmem_read(sc, SPDMEM_SDR_CAS127) & SPDMEM_SDR_CAS3(1 << 2)) |
| 432 | printf("CL3"); |
| 433 | } |
| 434 | |
| 435 | void |
| 436 | spdmem_rdr_decode(struct spdmem_softc *sc, struct spdmem *s) |
| 437 | { |
| 438 | int rimm_size; |
| 439 | uint8_t row_bits, col_bits, bank_bits; |
| 440 | |
| 441 | row_bits = s->sm_data[SPDMEM_RDR_ROWS_COLS0x01] >> 4; |
| 442 | col_bits = s->sm_data[SPDMEM_RDR_ROWS_COLS0x01] & 0x0f; |
| 443 | bank_bits = s->sm_data[SPDMEM_RDR_BANK0x02] & 0x07; |
| 444 | |
| 445 | /* subtracting 13 here is a cheaper way of dividing by 8k later */ |
| 446 | rimm_size = 1 << (row_bits + col_bits + bank_bits - 13); |
| 447 | |
| 448 | if (rimm_size < 1024) |
| 449 | printf(" %dMB ", rimm_size); |
| 450 | else |
| 451 | printf(" %dGB ", rimm_size / 1024); |
| 452 | |
| 453 | switch(s->sm_data[SPDMEM_RDR_MODULE_TYPE0x00]) { |
| 454 | case SPDMEM_RDR_TYPE_RIMM1: |
| 455 | printf("RIMM"); |
| 456 | break; |
| 457 | case SPDMEM_RDR_TYPE_SORIMM2: |
| 458 | printf("SO-RIMM"); |
| 459 | break; |
| 460 | case SPDMEM_RDR_TYPE_EMBED3: |
| 461 | printf("Embedded Rambus"); |
| 462 | break; |
| 463 | case SPDMEM_RDR_TYPE_RIMM324: |
| 464 | printf("RIMM32"); |
| 465 | break; |
| 466 | } |
| 467 | } |
| 468 | |
| 469 | void |
| 470 | spdmem_ddr_decode(struct spdmem_softc *sc, struct spdmem *s) |
| 471 | { |
| 472 | const char *type; |
| 473 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
| 474 | int i, num_banks, per_chip; |
| 475 | uint8_t config, rows, cols, cl; |
| 476 | |
| 477 | type = spdmem_basic_types[s->sm_type]; |
| 478 | |
| 479 | if (s->sm_data[SPDMEM_DDR_SUPERSET0x1d] == SPDMEM_SUPERSET_DDR_ESDRAM0x02) |
| 480 | type = spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM0x02]; |
| 481 | |
| 482 | num_banks = s->sm_data[SPDMEM_SDR_BANKS0x02]; |
| 483 | per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP0x0e]; |
| 484 | rows = s->sm_data[SPDMEM_SDR_ROWS0x00] & 0x0f; |
| 485 | cols = s->sm_data[SPDMEM_SDR_COLS0x01] & 0x0f; |
| 486 | dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip; |
| 487 | |
| 488 | if (dimm_size > 0) { |
| 489 | if (dimm_size < 1024) |
| 490 | printf(" %dMB", dimm_size); |
| 491 | else |
| 492 | printf(" %dGB", dimm_size / 1024); |
| 493 | } |
| 494 | |
| 495 | printf(" %s", type); |
| 496 | |
| 497 | if (s->sm_data[SPDMEM_DDR_MOD_ATTRIB0x12] & SPDMEM_DDR_ATTRIB_REG(1 << 1)) |
| 498 | printf(" registered"); |
| 499 | |
| 500 | if (s->sm_data[SPDMEM_FPM_CONFIG0x08] < 8) |
| 501 | printf(" %s", |
| 502 | spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG0x08]]); |
| 503 | |
| 504 | /* cycle_time is expressed in units of 0.01 ns */ |
| 505 | cycle_time = (s->sm_data[SPDMEM_DDR_CYCLE0x06] >> 4) * 100 + |
| 506 | (s->sm_data[SPDMEM_DDR_CYCLE0x06] & 0x0f) * 10; |
| 507 | |
| 508 | if (cycle_time != 0) { |
| 509 | /* |
| 510 | * cycle time is scaled by a factor of 100 to avoid using |
| 511 | * floating point. Calculate memory speed as the number |
| 512 | * of cycles per microsecond. |
| 513 | * DDR uses dual-pumped clock |
| 514 | */ |
| 515 | d_clk = 100 * 1000 * 2; |
| 516 | config = s->sm_data[SPDMEM_FPM_CONFIG0x08]; |
| 517 | bits = s->sm_data[SPDMEM_DDR_DATAWIDTH0x03] | |
| 518 | (s->sm_data[SPDMEM_DDR_DATAWIDTH0x03 + 1] << 8); |
| 519 | if (config == 1 || config == 2) |
| 520 | bits -= 8; |
| 521 | |
| 522 | d_clk /= cycle_time; |
| 523 | p_clk = d_clk * bits / 8; |
| 524 | if ((p_clk % 100) >= 50) |
| 525 | p_clk += 50; |
| 526 | p_clk -= p_clk % 100; |
| 527 | printf(" PC%d", p_clk); |
| 528 | } |
| 529 | |
| 530 | /* Print CAS latency */ |
| 531 | for (i = 6; i >= 0; i--) { |
| 532 | if (s->sm_data[SPDMEM_DDR_CAS0x0f] & (1 << i)) { |
| 533 | cl = ((i * 10) / 2) + 10; |
| 534 | printf("CL%d.%d", cl / 10, cl % 10); |
| 535 | break; |
| 536 | } |
| 537 | } |
| 538 | } |
| 539 | |
| 540 | void |
| 541 | spdmem_ddr2_decode(struct spdmem_softc *sc, struct spdmem *s) |
| 542 | { |
| 543 | const char *type; |
| 544 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
| 545 | int i, num_ranks, density; |
| 546 | uint8_t config; |
| 547 | |
| 548 | type = spdmem_basic_types[s->sm_type]; |
| 549 | |
| 550 | num_ranks = (s->sm_data[SPDMEM_DDR2_RANKS0x02] & 0x7) + 1; |
| 551 | density = (s->sm_data[SPDMEM_DDR2_RANK_DENSITY0x1c] & 0xf0) | |
| 552 | ((s->sm_data[SPDMEM_DDR2_RANK_DENSITY0x1c] & 0x0f) << 8); |
| 553 | dimm_size = num_ranks * density * 4; |
| 554 | |
| 555 | if (dimm_size > 0) { |
| 556 | if (dimm_size < 1024) |
| 557 | printf(" %dMB", dimm_size); |
| 558 | else |
| 559 | printf(" %dGB", dimm_size / 1024); |
| 560 | } |
| 561 | |
| 562 | printf(" %s", type); |
| 563 | |
| 564 | if (s->sm_data[SPDMEM_DDR2_DIMMTYPE0x11] & SPDMEM_DDR2_TYPE_REGMASK((1 << 4) | (1 << 0))) |
| 565 | printf(" registered"); |
| 566 | |
| 567 | if (s->sm_data[SPDMEM_FPM_CONFIG0x08] < 8) |
| 568 | printf(" %s", |
| 569 | spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG0x08]]); |
| 570 | |
| 571 | /* cycle_time is expressed in units of 0.01 ns */ |
| 572 | cycle_time = (s->sm_data[SPDMEM_DDR2_CYCLE0x06] >> 4) * 100 + |
| 573 | ddr2_cycle_tenths[(s->sm_data[SPDMEM_DDR2_CYCLE0x06] & 0x0f)]; |
| 574 | |
| 575 | if (cycle_time != 0) { |
| 576 | /* |
| 577 | * cycle time is scaled by a factor of 100 to avoid using |
| 578 | * floating point. Calculate memory speed as the number |
| 579 | * of cycles per microsecond. |
| 580 | * DDR2 uses quad-pumped clock |
| 581 | */ |
| 582 | d_clk = 100 * 1000 * 4; |
| 583 | config = s->sm_data[SPDMEM_FPM_CONFIG0x08]; |
| 584 | bits = s->sm_data[SPDMEM_DDR2_DATAWIDTH0x03]; |
| 585 | if ((config & 0x03) != 0) |
| 586 | bits -= 8; |
| 587 | d_clk /= cycle_time; |
| 588 | d_clk = (d_clk + 1) / 2; |
| 589 | p_clk = d_clk * bits / 8; |
| 590 | p_clk -= p_clk % 100; |
| 591 | printf(" PC2-%d", p_clk); |
| 592 | } |
| 593 | |
| 594 | /* Print CAS latency */ |
| 595 | for (i = 7; i >= 2; i--) { |
| 596 | if (s->sm_data[SPDMEM_DDR_CAS0x0f] & (1 << i)) { |
| 597 | printf("CL%d", i); |
| 598 | break; |
| 599 | } |
| 600 | } |
| 601 | |
| 602 | switch (s->sm_data[SPDMEM_DDR2_DIMMTYPE0x11]) { |
| 603 | case SPDMEM_DDR2_SODIMM(1 << 2): |
| 604 | printf(" SO-DIMM"); |
| 605 | break; |
| 606 | case SPDMEM_DDR2_MICRO_DIMM(1 << 3): |
| 607 | printf(" Micro-DIMM"); |
| 608 | break; |
| 609 | case SPDMEM_DDR2_MINI_RDIMM(1 << 4): |
| 610 | case SPDMEM_DDR2_MINI_UDIMM(1 << 5): |
| 611 | printf(" Mini-DIMM"); |
| 612 | break; |
| 613 | } |
| 614 | } |
| 615 | |
| 616 | void |
| 617 | spdmem_fbdimm_decode(struct spdmem_softc *sc, struct spdmem *s) |
| 618 | { |
| 619 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
| 620 | uint8_t rows, cols, dividend, divisor; |
| 621 | /* |
| 622 | * FB-DIMM is very much like DDR3 |
| 623 | */ |
| 624 | |
| 625 | cols = (s->sm_data[SPDMEM_FBDIMM_ADDR0x01] & SPDMEM_FBDIMM_ADDR_COL0x0c) >> |
| 626 | SPDMEM_FBDIMM_ADDR_COL_SHIFT2; |
| 627 | rows = (s->sm_data[SPDMEM_FBDIMM_ADDR0x01] & SPDMEM_FBDIMM_ADDR_ROW0xe0) >> |
| 628 | SPDMEM_FBDIMM_ADDR_ROW_SHIFT5; |
| 629 | dimm_size = rows + 12 + cols + 9 - 20 - 3; |
| 630 | |
| 631 | if (dimm_size < 1024) |
| 632 | printf(" %dMB", dimm_size); |
| 633 | else |
| 634 | printf(" %dGB", dimm_size / 1024); |
| 635 | |
| 636 | dividend = s->sm_data[SPDMEM_FBDIMM_MTB_DIVIDEND0x06]; |
| 637 | divisor = s->sm_data[SPDMEM_FBDIMM_MTB_DIVISOR0x07]; |
| 638 | |
| 639 | cycle_time = (1000 * dividend + (divisor / 2)) / divisor; |
| 640 | |
| 641 | if (cycle_time != 0) { |
| 642 | /* |
| 643 | * cycle time is scaled by a factor of 1000 to avoid using |
| 644 | * floating point. Calculate memory speed as the number |
| 645 | * of cycles per microsecond. |
| 646 | */ |
| 647 | d_clk = 1000 * 1000; |
| 648 | |
| 649 | /* DDR2 FB-DIMM uses a dual-pumped clock */ |
| 650 | d_clk *= 2; |
| 651 | bits = 1 << ((s->sm_data[SPDMEM_FBDIMM_RANKS0x04] & |
| 652 | SPDMEM_FBDIMM_RANKS_WIDTH0x07) + 2); |
| 653 | |
| 654 | p_clk = (d_clk * bits) / 8 / cycle_time; |
| 655 | p_clk -= p_clk % 100; |
| 656 | printf(" PC2-%d", p_clk); |
| 657 | } |
| 658 | } |
| 659 | |
| 660 | void |
| 661 | spdmem_ddr3_decode(struct spdmem_softc *sc, struct spdmem *s) |
| 662 | { |
| 663 | const char *type; |
| 664 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
| 665 | uint8_t mtype, chipsize, dividend, divisor; |
| 666 | uint8_t datawidth, chipwidth, physbanks; |
| 667 | |
| 668 | type = spdmem_basic_types[s->sm_type]; |
| 669 | |
| 670 | chipsize = s->sm_data[SPDMEM_DDR3_DENSITY0x01] & |
| 671 | SPDMEM_DDR3_DENSITY_CAPMASK0x0f; |
| 672 | datawidth = s->sm_data[SPDMEM_DDR3_DATAWIDTH0x05] & |
| 673 | SPDMEM_DDR3_DATAWIDTH_PRIMASK0x07; |
| 674 | chipwidth = s->sm_data[SPDMEM_DDR3_MOD_ORG0x04] & |
| 675 | SPDMEM_DDR3_MOD_ORG_CHIPWIDTH_MASK0x07; |
| 676 | physbanks = (s->sm_data[SPDMEM_DDR3_MOD_ORG0x04] >> |
| 677 | SPDMEM_DDR3_MOD_ORG_BANKS_SHIFT3) & SPDMEM_DDR3_MOD_ORG_BANKS_MASK0x07; |
| 678 | |
| 679 | dimm_size = (chipsize + 28 - 20) - 3 + (datawidth + 3) - |
| 680 | (chipwidth + 2); |
| 681 | dimm_size = (1 << dimm_size) * (physbanks + 1); |
| 682 | |
| 683 | if (dimm_size < 1024) |
| 684 | printf(" %dMB", dimm_size); |
| 685 | else |
| 686 | printf(" %dGB", dimm_size / 1024); |
| 687 | |
| 688 | printf(" %s", type); |
| 689 | |
| 690 | mtype = s->sm_data[SPDMEM_DDR3_MODTYPE0x00]; |
| 691 | if (mtype == SPDMEM_DDR3_RDIMM0x01 || mtype == SPDMEM_DDR3_MINI_RDIMM0x05) |
| 692 | printf(" registered"); |
| 693 | |
| 694 | if (s->sm_data[SPDMEM_DDR3_DATAWIDTH0x05] & SPDMEM_DDR3_DATAWIDTH_ECCMASK(1 << 3)) |
| 695 | printf(" ECC"); |
| 696 | |
| 697 | dividend = s->sm_data[SPDMEM_DDR3_MTB_DIVIDEND0x07]; |
| 698 | divisor = s->sm_data[SPDMEM_DDR3_MTB_DIVISOR0x08]; |
| 699 | cycle_time = (1000 * dividend + (divisor / 2)) / divisor; |
| 700 | cycle_time *= s->sm_data[SPDMEM_DDR3_TCKMIN0x09]; |
| 701 | |
| 702 | if (cycle_time != 0) { |
| 703 | /* |
| 704 | * cycle time is scaled by a factor of 1000 to avoid using |
| 705 | * floating point. Calculate memory speed as the number |
| 706 | * of cycles per microsecond. |
| 707 | * DDR3 uses a dual-pumped clock |
| 708 | */ |
| 709 | d_clk = 1000 * 1000; |
| 710 | d_clk *= 2; |
| 711 | bits = 1 << ((s->sm_data[SPDMEM_DDR3_DATAWIDTH0x05] & |
| 712 | SPDMEM_DDR3_DATAWIDTH_PRIMASK0x07) + 3); |
| 713 | /* |
| 714 | * Calculate p_clk first, since for DDR3 we need maximum |
| 715 | * significance. DDR3 rating is not rounded to a multiple |
| 716 | * of 100. This results in cycle_time of 1.5ns displayed |
| 717 | * as p_clk PC3-10666 (d_clk DDR3-1333) |
| 718 | */ |
| 719 | p_clk = (d_clk * bits) / 8 / cycle_time; |
| 720 | p_clk -= (p_clk % 100); |
| 721 | d_clk = ((d_clk + cycle_time / 2) ) / cycle_time; |
Value stored to 'd_clk' is never read | |
| 722 | printf(" PC3-%d", p_clk); |
| 723 | } |
| 724 | |
| 725 | switch (s->sm_data[SPDMEM_DDR3_MODTYPE0x00]) { |
| 726 | case SPDMEM_DDR3_SODIMM0x03: |
| 727 | printf(" SO-DIMM"); |
| 728 | break; |
| 729 | case SPDMEM_DDR3_MICRO_DIMM0x04: |
| 730 | printf(" Micro-DIMM"); |
| 731 | break; |
| 732 | case SPDMEM_DDR3_MINI_RDIMM0x05: |
| 733 | case SPDMEM_DDR3_MINI_UDIMM0x06: |
| 734 | printf(" Mini-DIMM"); |
| 735 | break; |
| 736 | } |
| 737 | |
| 738 | if (s->sm_data[SPDMEM_DDR3_THERMAL0x1d] & SPDMEM_DDR3_THERMAL_PRESENT(1 << 7)) |
| 739 | printf(" with thermal sensor"); |
| 740 | } |
| 741 | |
| 742 | void |
| 743 | spdmem_ddr4_decode(struct spdmem_softc *sc, struct spdmem *s) |
| 744 | { |
| 745 | static const int ddr4_chipsize[16] = { 256, 512, 1024, 2048, 4096, |
| 746 | 8 * 1024, 16 * 1024, 32 * 1024, 12 * 1024, 24 * 1024, |
| 747 | 3 * 1024, 6 * 1024, 18 * 1024 }; |
| 748 | const char *type; |
| 749 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
| 750 | uint8_t mtype, chipsize, mtb; |
| 751 | int8_t ftb; |
| 752 | uint8_t datawidth, chipwidth, physbanks, diecount = 0; |
| 753 | |
| 754 | type = spdmem_basic_types[s->sm_type]; |
| 755 | |
| 756 | chipsize = s->sm_data[SPDMEM_DDR4_DENSITY0x01] & |
| 757 | SPDMEM_DDR4_DENSITY_CAPMASK0x0f; |
| 758 | datawidth = s->sm_data[SPDMEM_DDR4_DATAWIDTH0x0a] & |
| 759 | SPDMEM_DDR4_DATAWIDTH_PRIMASK0x07; |
| 760 | chipwidth = s->sm_data[SPDMEM_DDR4_MOD_ORG0x09] & |
| 761 | SPDMEM_DDR4_MOD_ORG_CHIPWIDTH_MASK0x07; |
| 762 | physbanks = (s->sm_data[SPDMEM_DDR4_MOD_ORG0x09] >> |
| 763 | SPDMEM_DDR4_MOD_ORG_BANKS_SHIFT3) & SPDMEM_DDR4_MOD_ORG_BANKS_MASK0x07; |
| 764 | |
| 765 | if ((s->sm_data[SPDMEM_DDR4_PACK_TYPE0x03] & |
| 766 | SPDMEM_DDR4_PACK_TYPE_SIG_LOAD_MASK0x03) == |
| 767 | SPDMEM_DDR4_PACK_TYPE_SIG_SINGLE_LOAD0x02) { |
| 768 | diecount = (s->sm_data[SPDMEM_DDR4_PACK_TYPE0x03] >> |
| 769 | SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_SHIFT4) & |
| 770 | SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_MASK0x07; |
| 771 | } |
| 772 | |
| 773 | dimm_size = (datawidth + 3) - (chipwidth + 2); |
| 774 | dimm_size = (ddr4_chipsize[chipsize] / 8) * (1 << dimm_size) * |
| 775 | (physbanks + 1) * (diecount + 1); |
| 776 | |
| 777 | if (dimm_size < 1024) |
| 778 | printf(" %dMB", dimm_size); |
| 779 | else |
| 780 | printf(" %dGB", dimm_size / 1024); |
| 781 | |
| 782 | printf(" %s", type); |
| 783 | |
| 784 | mtype = s->sm_data[SPDMEM_DDR4_MODTYPE0x00]; |
| 785 | if (mtype & SPDMEM_DDR4_MODTYPE_HYBRID0x80) |
| 786 | printf(" hybrid"); |
| 787 | mtype &= SPDMEM_DDR4_MODTYPE_MASK0x0f; |
| 788 | if (mtype == SPDMEM_DDR4_RDIMM0x01 || mtype == SPDMEM_DDR4_MINI_RDIMM0x05 || |
| 789 | mtype == SPDMEM_DDR4_72B_SO_RDIMM0x08) |
| 790 | printf(" registered"); |
| 791 | if (mtype == SPDMEM_DDR4_72B_SO_UDIMM0x09 || |
| 792 | mtype == SPDMEM_DDR4_72B_SO_RDIMM0x08) |
| 793 | printf(" 72-bit"); |
| 794 | if (mtype == SPDMEM_DDR4_32B_SO_DIMM0x0d) |
| 795 | printf(" 32-bit"); |
| 796 | if (mtype == SPDMEM_DDR4_16B_SO_DIMM0x0c) |
| 797 | printf(" 16-bit"); |
| 798 | |
| 799 | if (s->sm_data[SPDMEM_DDR4_DATAWIDTH0x0a] & SPDMEM_DDR4_DATAWIDTH_ECCMASK(1 << 3)) |
| 800 | printf(" ECC"); |
| 801 | |
| 802 | mtb = s->sm_data[SPDMEM_DDR4_TCKMIN_MTB0x0f]; |
| 803 | /* SPDMEM_DDR4_TCKMIN_FTB (addr 125) is outside of s->sm_data */ |
| 804 | ftb = spdmem_read(sc, SPDMEM_DDR4_TCKMIN_FTB0x7d); |
| 805 | cycle_time = mtb * 125 + ftb; /* in ps */ |
| 806 | |
| 807 | if (cycle_time != 0) { |
| 808 | /* |
| 809 | * cycle time is scaled by a factor of 1000 to avoid using |
| 810 | * floating point. Calculate memory speed as the number |
| 811 | * of cycles per microsecond. |
| 812 | * DDR4 uses a dual-pumped clock |
| 813 | */ |
| 814 | d_clk = 1000 * 1000; |
| 815 | d_clk *= 2; |
| 816 | bits = 1 << ((s->sm_data[SPDMEM_DDR4_DATAWIDTH0x0a] & |
| 817 | SPDMEM_DDR4_DATAWIDTH_PRIMASK0x07) + 3); |
| 818 | |
| 819 | p_clk = (d_clk * bits) / 8 / cycle_time; |
| 820 | p_clk -= (p_clk % 100); |
| 821 | printf(" PC4-%d", p_clk); |
| 822 | } |
| 823 | |
| 824 | switch (s->sm_data[SPDMEM_DDR4_MODTYPE0x00] & SPDMEM_DDR4_MODTYPE_MASK0x0f) { |
| 825 | case SPDMEM_DDR4_SODIMM0x03: |
| 826 | case SPDMEM_DDR4_72B_SO_RDIMM0x08: |
| 827 | case SPDMEM_DDR4_72B_SO_UDIMM0x09: |
| 828 | case SPDMEM_DDR4_16B_SO_DIMM0x0c: |
| 829 | case SPDMEM_DDR4_32B_SO_DIMM0x0d: |
| 830 | printf(" SO-DIMM"); |
| 831 | break; |
| 832 | case SPDMEM_DDR4_LRDIMM0x04: |
| 833 | printf(" LR-DIMM"); |
| 834 | break; |
| 835 | case SPDMEM_DDR4_MINI_RDIMM0x05: |
| 836 | case SPDMEM_DDR4_MINI_UDIMM0x06: |
| 837 | printf(" Mini-DIMM"); |
| 838 | break; |
| 839 | case SPDMEM_DDR4_LP_DIMM0x07: |
| 840 | printf(" LP-DIMM"); |
| 841 | break; |
| 842 | case SPDMEM_DDR4_NON_DIMM0x0e: |
| 843 | printf(" non-DIMM solution"); |
| 844 | break; |
| 845 | } |
| 846 | |
| 847 | if (s->sm_data[SPDMEM_DDR4_THERMAL0x0b] & SPDMEM_DDR4_THERMAL_PRESENT(1 << 7)) |
| 848 | printf(" with thermal sensor"); |
| 849 | } |
| 850 | |
| 851 | int |
| 852 | spdmem_probe(struct spdmem_softc *sc) |
| 853 | { |
| 854 | uint8_t i, val, type; |
| 855 | int cksum = 0; |
| 856 | int spd_len, spd_crc_cover; |
| 857 | uint16_t crc_calc, crc_spd; |
| 858 | |
| 859 | type = spdmem_read(sc, 2); |
| 860 | /* For older memory types, validate the checksum over 1st 63 bytes */ |
| 861 | if (type <= SPDMEM_MEMTYPE_DDR2SDRAM0x08) { |
| 862 | for (i = 0; i < 63; i++) |
| 863 | cksum += spdmem_read(sc, i); |
| 864 | |
| 865 | val = spdmem_read(sc, 63); |
| 866 | |
| 867 | if (cksum == 0 || (cksum & 0xff) != val) { |
| 868 | return 0; |
| 869 | } else |
| 870 | return 1; |
| 871 | } |
| 872 | |
| 873 | /* For DDR3 and FBDIMM, verify the CRC */ |
| 874 | else if (type <= SPDMEM_MEMTYPE_DDR3SDRAM0x0b) { |
| 875 | spd_len = spdmem_read(sc, 0); |
| 876 | if (spd_len & SPDMEM_SPDCRC_1160x80) |
| 877 | spd_crc_cover = 116; |
| 878 | else |
| 879 | spd_crc_cover = 125; |
| 880 | switch (spd_len & SPDMEM_SPDLEN_MASK0x70) { |
| 881 | case SPDMEM_SPDLEN_1280x00: |
| 882 | spd_len = 128; |
| 883 | break; |
| 884 | case SPDMEM_SPDLEN_1760x10: |
| 885 | spd_len = 176; |
| 886 | break; |
| 887 | case SPDMEM_SPDLEN_2560x20: |
| 888 | spd_len = 256; |
| 889 | break; |
| 890 | default: |
| 891 | return 0; |
| 892 | } |
| 893 | calc_crc: |
| 894 | if (spd_crc_cover > spd_len) |
| 895 | return 0; |
| 896 | crc_calc = spdmem_crc16(sc, spd_crc_cover); |
| 897 | crc_spd = spdmem_read(sc, 127) << 8; |
| 898 | crc_spd |= spdmem_read(sc, 126); |
| 899 | if (crc_calc != crc_spd) { |
| 900 | return 0; |
| 901 | } |
| 902 | return 1; |
| 903 | } else if (type <= SPDMEM_MEMTYPE_LPDDR4SDRAM0x10) { |
| 904 | spd_len = spdmem_read(sc, 0); |
| 905 | spd_crc_cover = 125; |
| 906 | switch (spd_len & SPDMEM_DDR4_SPDLEN_MASK0x0f) { |
| 907 | case SPDMEM_DDR4_SPDLEN_1280x01: |
| 908 | spd_len = 128; |
| 909 | break; |
| 910 | case SPDMEM_DDR4_SPDLEN_2560x02: |
| 911 | spd_len = 256; |
| 912 | break; |
| 913 | case SPDMEM_DDR4_SPDLEN_3840x03: |
| 914 | spd_len = 384; |
| 915 | break; |
| 916 | case SPDMEM_DDR4_SPDLEN_5120x04: |
| 917 | spd_len = 512; |
| 918 | break; |
| 919 | default: |
| 920 | return 0; |
| 921 | } |
| 922 | goto calc_crc; |
| 923 | } |
| 924 | |
| 925 | return 0; |
| 926 | } |
| 927 | |
| 928 | void |
| 929 | spdmem_attach_common(struct spdmem_softc *sc) |
| 930 | { |
| 931 | struct spdmem *s = &(sc->sc_spd_data); |
| 932 | int i; |
| 933 | |
| 934 | /* All SPD have at least 64 bytes of data including checksum */ |
| 935 | for (i = 0; i < 64; i++) { |
| 936 | ((uint8_t *)s)[i] = spdmem_read(sc, i); |
| 937 | } |
| 938 | |
| 939 | /* |
| 940 | * Decode and print SPD contents |
| 941 | */ |
| 942 | if (s->sm_len < 4) { |
| 943 | if (s->sm_type == SPDMEM_MEMTYPE_DIRECT_RAMBUS0x01) |
| 944 | spdmem_rdr_decode(sc, s); |
| 945 | else |
| 946 | printf(" no decode method for Rambus memory"); |
| 947 | } else { |
| 948 | switch(s->sm_type) { |
| 949 | case SPDMEM_MEMTYPE_EDO0x02: |
| 950 | case SPDMEM_MEMTYPE_SDRAM0x04: |
| 951 | spdmem_sdram_decode(sc, s); |
| 952 | break; |
| 953 | case SPDMEM_MEMTYPE_DDRSDRAM0x07: |
| 954 | spdmem_ddr_decode(sc, s); |
| 955 | break; |
| 956 | case SPDMEM_MEMTYPE_DDR2SDRAM0x08: |
| 957 | spdmem_ddr2_decode(sc, s); |
| 958 | break; |
| 959 | case SPDMEM_MEMTYPE_FBDIMM0x09: |
| 960 | case SPDMEM_MEMTYPE_FBDIMM_PROBE0x0a: |
| 961 | spdmem_fbdimm_decode(sc, s); |
| 962 | break; |
| 963 | case SPDMEM_MEMTYPE_DDR3SDRAM0x0b: |
| 964 | spdmem_ddr3_decode(sc, s); |
| 965 | break; |
| 966 | case SPDMEM_MEMTYPE_DDR4SDRAM0x0c: |
| 967 | case SPDMEM_MEMTYPE_DDR4ESDRAM0x0e: |
| 968 | case SPDMEM_MEMTYPE_LPDDR3SDRAM0x0f: |
| 969 | case SPDMEM_MEMTYPE_LPDDR4SDRAM0x10: |
| 970 | spdmem_ddr4_decode(sc, s); |
| 971 | break; |
| 972 | case SPDMEM_MEMTYPE_NONE0xff: |
| 973 | printf(" no EEPROM found"); |
| 974 | break; |
| 975 | default: |
| 976 | if (s->sm_type <= SPDMEM_MEMTYPE_LPDDR5SDRAM0x13) |
| 977 | printf(" no decode method for %s memory", |
| 978 | spdmem_basic_types[s->sm_type]); |
| 979 | else |
| 980 | printf(" unknown memory type %d", s->sm_type); |
| 981 | break; |
| 982 | } |
| 983 | } |
| 984 | |
| 985 | printf("\n"); |
| 986 | } |