The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/spdmem.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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_MASK             0x0F    /* SPD EEPROM Size   */
   62 
   63 #define SPDMEM_SPDLEN_128               0x00    /* SPD EEPROM Sizes  */
   64 #define SPDMEM_SPDLEN_176               0x10
   65 #define SPDMEM_SPDLEN_256               0x20
   66 #define SPDMEM_SPDLEN_MASK              0x70    /* Bits 4 - 6        */
   67 
   68 #define SPDMEM_DDR4_SPDLEN_128          0x01    /* SPD EEPROM Sizes  */
   69 #define SPDMEM_DDR4_SPDLEN_256          0x02
   70 #define SPDMEM_DDR4_SPDLEN_384          0x03
   71 #define SPDMEM_DDR4_SPDLEN_512          0x04
   72 #define SPDMEM_DDR4_SPDLEN_MASK         0x0f    /* Bits 4 - 6        */
   73 
   74 #define SPDMEM_SPDCRC_116               0x80    /* CRC Bytes covered */
   75 #define SPDMEM_SPDCRC_125               0x00
   76 #define SPDMEM_SPDCRC_MASK              0x80    /* Bit 7             */
   77 
   78 /* possible values for the memory type */
   79 #define SPDMEM_MEMTYPE_FPM              0x01
   80 #define SPDMEM_MEMTYPE_EDO              0x02
   81 #define SPDMEM_MEMTYPE_PIPE_NIBBLE      0x03
   82 #define SPDMEM_MEMTYPE_SDRAM            0x04
   83 #define SPDMEM_MEMTYPE_ROM              0x05
   84 #define SPDMEM_MEMTYPE_DDRSGRAM         0x06
   85 #define SPDMEM_MEMTYPE_DDRSDRAM         0x07
   86 #define SPDMEM_MEMTYPE_DDR2SDRAM        0x08
   87 #define SPDMEM_MEMTYPE_FBDIMM           0x09
   88 #define SPDMEM_MEMTYPE_FBDIMM_PROBE     0x0a
   89 #define SPDMEM_MEMTYPE_DDR3SDRAM        0x0b
   90 #define SPDMEM_MEMTYPE_DDR4SDRAM        0x0c
   91                                         /* 0xd reserved */
   92 #define SPDMEM_MEMTYPE_DDR4ESDRAM       0x0e
   93 #define SPDMEM_MEMTYPE_LPDDR3SDRAM      0x0f
   94 #define SPDMEM_MEMTYPE_LPDDR4SDRAM      0x10
   95 #define SPDMEM_MEMTYPE_LPDDR4XSDRAM     0x11
   96 #define SPDMEM_MEMTYPE_DDR5SDRAM        0x12
   97 #define SPDMEM_MEMTYPE_LPDDR5SDRAM      0x13
   98 
   99 #define SPDMEM_MEMTYPE_NONE             0xff
  100 
  101 #define SPDMEM_MEMTYPE_DIRECT_RAMBUS    0x01
  102 #define SPDMEM_MEMTYPE_RAMBUS           0x11
  103 
  104 /* possible values for the supply voltage */
  105 #define SPDMEM_VOLTAGE_TTL_5V           0x00
  106 #define SPDMEM_VOLTAGE_TTL_LV           0x01
  107 #define SPDMEM_VOLTAGE_HSTTL_1_5V       0x02
  108 #define SPDMEM_VOLTAGE_SSTL_3_3V        0x03
  109 #define SPDMEM_VOLTAGE_SSTL_2_5V        0x04
  110 #define SPDMEM_VOLTAGE_SSTL_1_8V        0x05
  111 
  112 /* possible values for module configuration */
  113 #define SPDMEM_MODCONFIG_PARITY         0x01
  114 #define SPDMEM_MODCONFIG_ECC            0x02
  115 
  116 /* for DDR2, module configuration is a bit-mask field */
  117 #define SPDMEM_MODCONFIG_HAS_DATA_PARITY        0x01
  118 #define SPDMEM_MODCONFIG_HAS_DATA_ECC           0x02
  119 #define SPDMEM_MODCONFIG_HAS_ADDR_CMD_PARITY    0x04
  120 
  121 /* possible values for the refresh field */
  122 #define SPDMEM_REFRESH_STD              0x00
  123 #define SPDMEM_REFRESH_QUARTER          0x01
  124 #define SPDMEM_REFRESH_HALF             0x02
  125 #define SPDMEM_REFRESH_TWOX             0x03
  126 #define SPDMEM_REFRESH_FOURX            0x04
  127 #define SPDMEM_REFRESH_EIGHTX           0x05
  128 #define SPDMEM_REFRESH_SELFREFRESH      0x80
  129 
  130 /* superset types */
  131 #define SPDMEM_SUPERSET_ESDRAM          0x01
  132 #define SPDMEM_SUPERSET_DDR_ESDRAM      0x02
  133 #define SPDMEM_SUPERSET_EDO_PEM         0x03
  134 #define SPDMEM_SUPERSET_SDR_PEM         0x04
  135 
  136 /* FPM and EDO DIMMS */
  137 #define SPDMEM_FPM_ROWS                 0x00
  138 #define SPDMEM_FPM_COLS                 0x01
  139 #define SPDMEM_FPM_BANKS                0x02
  140 #define SPDMEM_FPM_CONFIG               0x08
  141 #define SPDMEM_FPM_REFRESH              0x09
  142 #define SPDMEM_FPM_SUPERSET             0x0c
  143 
  144 /* PC66/PC100/PC133 SDRAM */
  145 #define SPDMEM_SDR_ROWS                 0x00
  146 #define SPDMEM_SDR_COLS                 0x01
  147 #define SPDMEM_SDR_BANKS                0x02
  148 #define SPDMEM_SDR_CYCLE                0x06
  149 #define SPDMEM_SDR_BANKS_PER_CHIP       0x0e
  150 #define SPDMEM_SDR_MOD_ATTRIB           0x12
  151 #define SPDMEM_SDR_SUPERSET             0x1d
  152 
  153 #define SPDMEM_SDR_FREQUENCY            126
  154 #define SPDMEM_SDR_CAS                  127
  155 #define SPDMEM_SDR_FREQ_66              0x66
  156 #define SPDMEM_SDR_FREQ_100             0x64
  157 #define SPDMEM_SDR_FREQ_133             0x85
  158 #define SPDMEM_SDR_CAS2                 (1 << 1)
  159 #define SPDMEM_SDR_CAS3                 (1 << 2)
  160 
  161 /* Rambus Direct DRAM */
  162 #define SPDMEM_RDR_MODULE_TYPE          0x00
  163 #define SPDMEM_RDR_ROWS_COLS            0x01
  164 #define SPDMEM_RDR_BANK                 0x02
  165 
  166 #define SPDMEM_RDR_TYPE_RIMM            1
  167 #define SPDMEM_RDR_TYPE_SORIMM          2
  168 #define SPDMEM_RDR_TYPE_EMBED           3
  169 #define SPDMEM_RDR_TYPE_RIMM32          4
  170 
  171 /* Dual Data Rate SDRAM */
  172 #define SPDMEM_DDR_ROWS                 0x00
  173 #define SPDMEM_DDR_COLS                 0x01
  174 #define SPDMEM_DDR_RANKS                0x02
  175 #define SPDMEM_DDR_DATAWIDTH            0x03
  176 #define SPDMEM_DDR_VOLTAGE              0x05
  177 #define SPDMEM_DDR_CYCLE                0x06
  178 #define SPDMEM_DDR_REFRESH              0x09
  179 #define SPDMEM_DDR_BANKS_PER_CHIP       0x0e
  180 #define SPDMEM_DDR_CAS                  0x0f
  181 #define SPDMEM_DDR_MOD_ATTRIB           0x12
  182 #define SPDMEM_DDR_SUPERSET             0x1d
  183 
  184 #define SPDMEM_DDR_ATTRIB_REG           (1 << 1)
  185 
  186 /* Dual Data Rate 2 SDRAM */
  187 #define SPDMEM_DDR2_ROWS                0x00
  188 #define SPDMEM_DDR2_COLS                0x01
  189 #define SPDMEM_DDR2_RANKS               0x02
  190 #define SPDMEM_DDR2_DATAWIDTH           0x03
  191 #define SPDMEM_DDR2_VOLTAGE             0x05
  192 #define SPDMEM_DDR2_CYCLE               0x06
  193 #define SPDMEM_DDR2_DIMMTYPE            0x11
  194 #define SPDMEM_DDR2_RANK_DENSITY        0x1c
  195 
  196 #define SPDMEM_DDR2_TYPE_REGMASK        ((1 << 4) | (1 << 0))
  197 #define SPDMEM_DDR2_SODIMM              (1 << 2)
  198 #define SPDMEM_DDR2_MICRO_DIMM          (1 << 3)
  199 #define SPDMEM_DDR2_MINI_RDIMM          (1 << 4)
  200 #define SPDMEM_DDR2_MINI_UDIMM          (1 << 5)
  201 
  202 /* DDR2 FB-DIMM SDRAM */
  203 #define SPDMEM_FBDIMM_ADDR              0x01
  204 #define SPDMEM_FBDIMM_RANKS             0x04
  205 #define SPDMEM_FBDIMM_MTB_DIVIDEND      0x06
  206 #define SPDMEM_FBDIMM_MTB_DIVISOR       0x07
  207 #define SPDMEM_FBDIMM_PROTO             0x4e
  208 
  209 #define SPDMEM_FBDIMM_RANKS_WIDTH               0x07
  210 #define SPDMEM_FBDIMM_ADDR_BANKS                0x02
  211 #define SPDMEM_FBDIMM_ADDR_COL                  0x0c
  212 #define SPDMEM_FBDIMM_ADDR_COL_SHIFT            2
  213 #define SPDMEM_FBDIMM_ADDR_ROW                  0xe0
  214 #define SPDMEM_FBDIMM_ADDR_ROW_SHIFT            5
  215 #define SPDMEM_FBDIMM_PROTO_ECC                 (1 << 1)
  216 
  217 
  218 /* Dual Data Rate 3 SDRAM */
  219 #define SPDMEM_DDR3_MODTYPE             0x00
  220 #define SPDMEM_DDR3_DENSITY             0x01
  221 #define SPDMEM_DDR3_MOD_ORG             0x04
  222 #define SPDMEM_DDR3_DATAWIDTH           0x05
  223 #define SPDMEM_DDR3_MTB_DIVIDEND        0x07
  224 #define SPDMEM_DDR3_MTB_DIVISOR         0x08
  225 #define SPDMEM_DDR3_TCKMIN              0x09
  226 #define SPDMEM_DDR3_THERMAL             0x1d
  227 
  228 #define SPDMEM_DDR3_DENSITY_CAPMASK             0x0f
  229 #define SPDMEM_DDR3_MOD_ORG_CHIPWIDTH_MASK      0x07
  230 #define SPDMEM_DDR3_MOD_ORG_BANKS_SHIFT         3
  231 #define SPDMEM_DDR3_MOD_ORG_BANKS_MASK          0x07
  232 #define SPDMEM_DDR3_DATAWIDTH_ECCMASK           (1 << 3)
  233 #define SPDMEM_DDR3_DATAWIDTH_PRIMASK           0x07
  234 #define SPDMEM_DDR3_THERMAL_PRESENT             (1 << 7)
  235 
  236 #define SPDMEM_DDR3_RDIMM               0x01
  237 #define SPDMEM_DDR3_UDIMM               0x02
  238 #define SPDMEM_DDR3_SODIMM              0x03
  239 #define SPDMEM_DDR3_MICRO_DIMM          0x04
  240 #define SPDMEM_DDR3_MINI_RDIMM          0x05
  241 #define SPDMEM_DDR3_MINI_UDIMM          0x06
  242 
  243 /* Dual Data Rate 4 SDRAM */
  244 #define SPDMEM_DDR4_MODTYPE             0x00
  245 #define SPDMEM_DDR4_DENSITY             0x01
  246 #define SPDMEM_DDR4_PACK_TYPE           0x03
  247 #define SPDMEM_DDR4_MOD_ORG             0x09
  248 #define SPDMEM_DDR4_DATAWIDTH           0x0a
  249 #define SPDMEM_DDR4_THERMAL             0x0b
  250 #define SPDMEM_DDR4_TCKMIN_MTB          0x0f
  251 #define SPDMEM_DDR4_TCKMIN_FTB          0x7d    /* not offset by 3 */
  252 
  253 #define SPDMEM_DDR4_DENSITY_CAPMASK             0x0f
  254 #define SPDMEM_DDR4_PACK_TYPE_SIG_LOAD_MASK     0x03
  255 #define SPDMEM_DDR4_PACK_TYPE_SIG_SINGLE_LOAD   0x02
  256 #define SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_SHIFT   4
  257 #define SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_MASK    0x07
  258 #define SPDMEM_DDR4_MOD_ORG_CHIPWIDTH_MASK      0x07
  259 #define SPDMEM_DDR4_MOD_ORG_BANKS_SHIFT         3
  260 #define SPDMEM_DDR4_MOD_ORG_BANKS_MASK          0x07
  261 #define SPDMEM_DDR4_DATAWIDTH_ECCMASK           (1 << 3)
  262 #define SPDMEM_DDR4_DATAWIDTH_PRIMASK           0x07
  263 #define SPDMEM_DDR4_THERMAL_PRESENT             (1 << 7)
  264 
  265 #define SPDMEM_DDR4_RDIMM               0x01
  266 #define SPDMEM_DDR4_UDIMM               0x02
  267 #define SPDMEM_DDR4_SODIMM              0x03
  268 #define SPDMEM_DDR4_LRDIMM              0x04
  269 #define SPDMEM_DDR4_MINI_RDIMM          0x05
  270 #define SPDMEM_DDR4_MINI_UDIMM          0x06
  271 #define SPDMEM_DDR4_LP_DIMM             0x07
  272 #define SPDMEM_DDR4_72B_SO_RDIMM        0x08
  273 #define SPDMEM_DDR4_72B_SO_UDIMM        0x09
  274 #define SPDMEM_DDR4_16B_SO_DIMM         0x0c
  275 #define SPDMEM_DDR4_32B_SO_DIMM         0x0d
  276 #define SPDMEM_DDR4_NON_DIMM            0x0e
  277 #define SPDMEM_DDR4_MODTYPE_MASK        0x0f
  278 #define SPDMEM_DDR4_MODTYPE_HYBRID      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_MAXLEN 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, "spdmem", DV_DULL
  298 };
  299 
  300 #define IS_RAMBUS_TYPE (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_SUPERSET] == SPDMEM_SUPERSET_SDR_PEM)
  381                 type = spdmem_superset_types[SPDMEM_SUPERSET_SDR_PEM];
  382         if (s->sm_data[SPDMEM_SDR_SUPERSET] == SPDMEM_SUPERSET_ESDRAM)
  383                 type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM];
  384 
  385         num_banks = s->sm_data[SPDMEM_SDR_BANKS];
  386         per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP];
  387         rows = s->sm_data[SPDMEM_SDR_ROWS] & 0x0f;
  388         cols = s->sm_data[SPDMEM_SDR_COLS] & 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_ATTRIB] & SPDMEM_DDR_ATTRIB_REG)
  401                 printf(" registered");
  402 
  403         if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
  404                 printf(" %s",
  405                     spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
  406 
  407         p_clk = 66;
  408         if (s->sm_len >= 128) {
  409                 switch (spdmem_read(sc, SPDMEM_SDR_FREQUENCY)) {
  410                 case SPDMEM_SDR_FREQ_100:
  411                 case SPDMEM_SDR_FREQ_133:
  412                         /* We need to check ns to decide here */
  413                         if (s->sm_data[SPDMEM_SDR_CYCLE] < 0x80)
  414                                 p_clk = 133;
  415                         else
  416                                 p_clk = 100;
  417                         break;
  418                 case SPDMEM_SDR_FREQ_66:
  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_CAS) & SPDMEM_SDR_CAS2)
  430                 printf("CL2");
  431         else if (spdmem_read(sc, SPDMEM_SDR_CAS) & SPDMEM_SDR_CAS3)
  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_COLS] >> 4;
  442         col_bits = s->sm_data[SPDMEM_RDR_ROWS_COLS] & 0x0f;
  443         bank_bits = s->sm_data[SPDMEM_RDR_BANK] & 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_TYPE]) {
  454         case SPDMEM_RDR_TYPE_RIMM:
  455                 printf("RIMM");
  456                 break;
  457         case SPDMEM_RDR_TYPE_SORIMM:
  458                 printf("SO-RIMM");
  459                 break;
  460         case SPDMEM_RDR_TYPE_EMBED:
  461                 printf("Embedded Rambus");
  462                 break;
  463         case SPDMEM_RDR_TYPE_RIMM32:
  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_SUPERSET] == SPDMEM_SUPERSET_DDR_ESDRAM)
  480                 type = spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM];
  481 
  482         num_banks = s->sm_data[SPDMEM_SDR_BANKS];
  483         per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP];
  484         rows = s->sm_data[SPDMEM_SDR_ROWS] & 0x0f;
  485         cols = s->sm_data[SPDMEM_SDR_COLS] & 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_ATTRIB] & SPDMEM_DDR_ATTRIB_REG)
  498                 printf(" registered");
  499 
  500         if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
  501                 printf(" %s",
  502                     spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
  503 
  504         /* cycle_time is expressed in units of 0.01 ns */
  505         cycle_time = (s->sm_data[SPDMEM_DDR_CYCLE] >> 4) * 100 +
  506             (s->sm_data[SPDMEM_DDR_CYCLE] & 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_CONFIG];
  517                 bits = s->sm_data[SPDMEM_DDR_DATAWIDTH] |
  518                     (s->sm_data[SPDMEM_DDR_DATAWIDTH + 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_CAS] & (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_RANKS] & 0x7) + 1;
  551         density = (s->sm_data[SPDMEM_DDR2_RANK_DENSITY] & 0xf0) |
  552             ((s->sm_data[SPDMEM_DDR2_RANK_DENSITY] & 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_DIMMTYPE] & SPDMEM_DDR2_TYPE_REGMASK)
  565                 printf(" registered");
  566 
  567         if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
  568                 printf(" %s",
  569                     spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
  570 
  571         /* cycle_time is expressed in units of 0.01 ns */
  572         cycle_time = (s->sm_data[SPDMEM_DDR2_CYCLE] >> 4) * 100 +
  573             ddr2_cycle_tenths[(s->sm_data[SPDMEM_DDR2_CYCLE] & 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_CONFIG];
  584                 bits = s->sm_data[SPDMEM_DDR2_DATAWIDTH];
  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_CAS] & (1 << i)) {
  597                         printf("CL%d", i);
  598                         break;
  599                 }
  600         }
  601 
  602         switch (s->sm_data[SPDMEM_DDR2_DIMMTYPE]) {
  603         case SPDMEM_DDR2_SODIMM:
  604                 printf(" SO-DIMM");
  605                 break;
  606         case SPDMEM_DDR2_MICRO_DIMM:
  607                 printf(" Micro-DIMM");
  608                 break;
  609         case SPDMEM_DDR2_MINI_RDIMM:
  610         case SPDMEM_DDR2_MINI_UDIMM:
  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_ADDR] & SPDMEM_FBDIMM_ADDR_COL) >>
  626             SPDMEM_FBDIMM_ADDR_COL_SHIFT;
  627         rows = (s->sm_data[SPDMEM_FBDIMM_ADDR] & SPDMEM_FBDIMM_ADDR_ROW) >>
  628             SPDMEM_FBDIMM_ADDR_ROW_SHIFT;
  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_DIVIDEND];
  637         divisor = s->sm_data[SPDMEM_FBDIMM_MTB_DIVISOR];
  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_RANKS] &
  652                     SPDMEM_FBDIMM_RANKS_WIDTH) + 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_DENSITY] &
  671             SPDMEM_DDR3_DENSITY_CAPMASK;
  672         datawidth = s->sm_data[SPDMEM_DDR3_DATAWIDTH] &
  673             SPDMEM_DDR3_DATAWIDTH_PRIMASK;
  674         chipwidth = s->sm_data[SPDMEM_DDR3_MOD_ORG] &
  675             SPDMEM_DDR3_MOD_ORG_CHIPWIDTH_MASK;
  676         physbanks = (s->sm_data[SPDMEM_DDR3_MOD_ORG] >> 
  677             SPDMEM_DDR3_MOD_ORG_BANKS_SHIFT) & SPDMEM_DDR3_MOD_ORG_BANKS_MASK;
  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_MODTYPE];
  691         if (mtype == SPDMEM_DDR3_RDIMM || mtype == SPDMEM_DDR3_MINI_RDIMM)
  692                 printf(" registered");
  693 
  694         if (s->sm_data[SPDMEM_DDR3_DATAWIDTH] & SPDMEM_DDR3_DATAWIDTH_ECCMASK) 
  695                 printf(" ECC");
  696 
  697         dividend = s->sm_data[SPDMEM_DDR3_MTB_DIVIDEND];
  698         divisor = s->sm_data[SPDMEM_DDR3_MTB_DIVISOR];
  699         cycle_time = (1000 * dividend +  (divisor / 2)) / divisor;
  700         cycle_time *= s->sm_data[SPDMEM_DDR3_TCKMIN];
  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_DATAWIDTH] &
  712                     SPDMEM_DDR3_DATAWIDTH_PRIMASK) + 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;
  722                 printf(" PC3-%d", p_clk);
  723         }
  724 
  725         switch (s->sm_data[SPDMEM_DDR3_MODTYPE]) {
  726         case SPDMEM_DDR3_SODIMM:
  727                 printf(" SO-DIMM");
  728                 break;
  729         case SPDMEM_DDR3_MICRO_DIMM:
  730                 printf(" Micro-DIMM");
  731                 break;
  732         case SPDMEM_DDR3_MINI_RDIMM:
  733         case SPDMEM_DDR3_MINI_UDIMM:
  734                 printf(" Mini-DIMM");
  735                 break;
  736         }
  737 
  738         if (s->sm_data[SPDMEM_DDR3_THERMAL] & SPDMEM_DDR3_THERMAL_PRESENT)
  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_DENSITY] &
  757             SPDMEM_DDR4_DENSITY_CAPMASK;
  758         datawidth = s->sm_data[SPDMEM_DDR4_DATAWIDTH] &
  759             SPDMEM_DDR4_DATAWIDTH_PRIMASK;
  760         chipwidth = s->sm_data[SPDMEM_DDR4_MOD_ORG] &
  761             SPDMEM_DDR4_MOD_ORG_CHIPWIDTH_MASK;
  762         physbanks = (s->sm_data[SPDMEM_DDR4_MOD_ORG] >> 
  763             SPDMEM_DDR4_MOD_ORG_BANKS_SHIFT) & SPDMEM_DDR4_MOD_ORG_BANKS_MASK;
  764 
  765         if ((s->sm_data[SPDMEM_DDR4_PACK_TYPE] &
  766             SPDMEM_DDR4_PACK_TYPE_SIG_LOAD_MASK) ==
  767             SPDMEM_DDR4_PACK_TYPE_SIG_SINGLE_LOAD) {
  768                 diecount = (s->sm_data[SPDMEM_DDR4_PACK_TYPE] >>
  769                     SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_SHIFT) &
  770                     SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_MASK;
  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_MODTYPE];
  785         if (mtype & SPDMEM_DDR4_MODTYPE_HYBRID)
  786                 printf(" hybrid");
  787         mtype &= SPDMEM_DDR4_MODTYPE_MASK;
  788         if (mtype == SPDMEM_DDR4_RDIMM || mtype == SPDMEM_DDR4_MINI_RDIMM ||
  789             mtype == SPDMEM_DDR4_72B_SO_RDIMM)
  790                 printf(" registered");
  791         if (mtype == SPDMEM_DDR4_72B_SO_UDIMM ||
  792             mtype == SPDMEM_DDR4_72B_SO_RDIMM)
  793                 printf(" 72-bit");
  794         if (mtype == SPDMEM_DDR4_32B_SO_DIMM)
  795                 printf(" 32-bit");
  796         if (mtype == SPDMEM_DDR4_16B_SO_DIMM)
  797                 printf(" 16-bit");
  798 
  799         if (s->sm_data[SPDMEM_DDR4_DATAWIDTH] & SPDMEM_DDR4_DATAWIDTH_ECCMASK) 
  800                 printf(" ECC");
  801 
  802         mtb = s->sm_data[SPDMEM_DDR4_TCKMIN_MTB];
  803         /* SPDMEM_DDR4_TCKMIN_FTB (addr 125) is outside of s->sm_data */
  804         ftb = spdmem_read(sc, SPDMEM_DDR4_TCKMIN_FTB);
  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_DATAWIDTH] &
  817                     SPDMEM_DDR4_DATAWIDTH_PRIMASK) + 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_MODTYPE] & SPDMEM_DDR4_MODTYPE_MASK) {
  825         case SPDMEM_DDR4_SODIMM:
  826         case SPDMEM_DDR4_72B_SO_RDIMM:
  827         case SPDMEM_DDR4_72B_SO_UDIMM:
  828         case SPDMEM_DDR4_16B_SO_DIMM:
  829         case SPDMEM_DDR4_32B_SO_DIMM:
  830                 printf(" SO-DIMM");
  831                 break;
  832         case SPDMEM_DDR4_LRDIMM:
  833                 printf(" LR-DIMM");
  834                 break;
  835         case SPDMEM_DDR4_MINI_RDIMM:
  836         case SPDMEM_DDR4_MINI_UDIMM:
  837                 printf(" Mini-DIMM");
  838                 break;
  839         case SPDMEM_DDR4_LP_DIMM:
  840                 printf(" LP-DIMM");
  841                 break;
  842         case SPDMEM_DDR4_NON_DIMM:
  843                 printf(" non-DIMM solution");
  844                 break;
  845         }
  846 
  847         if (s->sm_data[SPDMEM_DDR4_THERMAL] & SPDMEM_DDR4_THERMAL_PRESENT)
  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_DDR2SDRAM) {
  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_DDR3SDRAM) {
  875                 spd_len = spdmem_read(sc, 0);
  876                 if (spd_len & SPDMEM_SPDCRC_116)
  877                         spd_crc_cover = 116;
  878                 else
  879                         spd_crc_cover = 125;
  880                 switch (spd_len & SPDMEM_SPDLEN_MASK) {
  881                 case SPDMEM_SPDLEN_128:
  882                         spd_len = 128;
  883                         break;
  884                 case SPDMEM_SPDLEN_176:
  885                         spd_len = 176;
  886                         break;
  887                 case SPDMEM_SPDLEN_256:
  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_LPDDR4SDRAM) {
  904                 spd_len = spdmem_read(sc, 0);
  905                 spd_crc_cover = 125;
  906                 switch (spd_len & SPDMEM_DDR4_SPDLEN_MASK) {
  907                 case SPDMEM_DDR4_SPDLEN_128:
  908                         spd_len = 128;
  909                         break;
  910                 case SPDMEM_DDR4_SPDLEN_256:
  911                         spd_len = 256;
  912                         break;
  913                 case SPDMEM_DDR4_SPDLEN_384:
  914                         spd_len = 384;
  915                         break;
  916                 case SPDMEM_DDR4_SPDLEN_512:
  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_RAMBUS)
  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_EDO:
  950                 case SPDMEM_MEMTYPE_SDRAM:
  951                         spdmem_sdram_decode(sc, s);
  952                         break;
  953                 case SPDMEM_MEMTYPE_DDRSDRAM:
  954                         spdmem_ddr_decode(sc, s);
  955                         break;
  956                 case SPDMEM_MEMTYPE_DDR2SDRAM:
  957                         spdmem_ddr2_decode(sc, s);
  958                         break;
  959                 case SPDMEM_MEMTYPE_FBDIMM:
  960                 case SPDMEM_MEMTYPE_FBDIMM_PROBE:
  961                         spdmem_fbdimm_decode(sc, s);
  962                         break;
  963                 case SPDMEM_MEMTYPE_DDR3SDRAM:
  964                         spdmem_ddr3_decode(sc, s);
  965                         break;
  966                 case SPDMEM_MEMTYPE_DDR4SDRAM:
  967                 case SPDMEM_MEMTYPE_DDR4ESDRAM:
  968                 case SPDMEM_MEMTYPE_LPDDR3SDRAM:
  969                 case SPDMEM_MEMTYPE_LPDDR4SDRAM:
  970                         spdmem_ddr4_decode(sc, s);
  971                         break;
  972                 case SPDMEM_MEMTYPE_NONE:
  973                         printf(" no EEPROM found");
  974                         break;
  975                 default:
  976                         if (s->sm_type <= SPDMEM_MEMTYPE_LPDDR5SDRAM)
  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 }

Cache object: ad9e30013e7067040961b2e849888a6a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.