summaryrefslogtreecommitdiff
path: root/sys/dev/i2c
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2010-03-22 21:20:59 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2010-03-22 21:20:59 +0000
commitddc208ed863c50de1b0049f18eda0963a62ec0ec (patch)
treedf373fe0cf590e86620e2377b2bea4c9c6670214 /sys/dev/i2c
parent1e86b809c6226672cae0ddc3755bd59698638488 (diff)
Split existing spdmem@i2c code into bus-agnostic spd record decoding code,
and an i2c attachment. No functional change; ok jsg@ deraadt@
Diffstat (limited to 'sys/dev/i2c')
-rw-r--r--sys/dev/i2c/files.i2c7
-rw-r--r--sys/dev/i2c/spdmem.c840
-rw-r--r--sys/dev/i2c/spdmem_i2c.c123
3 files changed, 126 insertions, 844 deletions
diff --git a/sys/dev/i2c/files.i2c b/sys/dev/i2c/files.i2c
index d1c69642cd5..ae5e5376af5 100644
--- a/sys/dev/i2c/files.i2c
+++ b/sys/dev/i2c/files.i2c
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i2c,v 1.48 2009/08/12 20:41:21 deraadt Exp $
+# $OpenBSD: files.i2c,v 1.49 2010/03/22 21:20:58 miod Exp $
# $NetBSD: files.i2c,v 1.3 2003/10/20 16:24:10 briggs Exp $
define i2c {[addr = -1], [size = -1]}
@@ -149,9 +149,8 @@ attach thmc at i2c
file dev/i2c/thmc50.c thmc
# SPD Memory EEPROM
-device spdmem
-attach spdmem at i2c
-file dev/i2c/spdmem.c spdmem
+attach spdmem at i2c with spdmem_iic
+file dev/i2c/spdmem_i2c.c spdmem
# SO-DIMM (JC-42.4) temperature sensor
device sdtemp
diff --git a/sys/dev/i2c/spdmem.c b/sys/dev/i2c/spdmem.c
deleted file mode 100644
index 48bc924751a..00000000000
--- a/sys/dev/i2c/spdmem.c
+++ /dev/null
@@ -1,840 +0,0 @@
-/* $OpenBSD: spdmem.c,v 1.33 2009/09/13 23:36:10 jsg Exp $ */
-/* $NetBSD: spdmem.c,v 1.3 2007/09/20 23:09:59 xtraeme Exp $ */
-
-/*
- * Copyright (c) 2007 Jonathan Gray <jsg@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * Copyright (c) 2007 Nicolas Joly
- * Copyright (c) 2007 Paul Goyette
- * Copyright (c) 2007 Tobias Nygren
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Serial Presence Detect (SPD) memory identification
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/device.h>
-
-#include <dev/i2c/i2cvar.h>
-
-/* Encodings of the size used/total byte for certain memory types */
-#define SPDMEM_SPDSIZE_MASK 0x0F /* SPD EEPROM Size */
-
-#define SPDMEM_SPDLEN_128 0x00 /* SPD EEPROM Sizes */
-#define SPDMEM_SPDLEN_176 0x10
-#define SPDMEM_SPDLEN_256 0x20
-#define SPDMEM_SPDLEN_MASK 0x70 /* Bits 4 - 6 */
-
-#define SPDMEM_SPDCRC_116 0x80 /* CRC Bytes covered */
-#define SPDMEM_SPDCRC_125 0x00
-#define SPDMEM_SPDCRC_MASK 0x80 /* Bit 7 */
-
-
-/* possible values for the memory type */
-#define SPDMEM_MEMTYPE_FPM 0x01
-#define SPDMEM_MEMTYPE_EDO 0x02
-#define SPDMEM_MEMTYPE_PIPE_NIBBLE 0x03
-#define SPDMEM_MEMTYPE_SDRAM 0x04
-#define SPDMEM_MEMTYPE_ROM 0x05
-#define SPDMEM_MEMTYPE_DDRSGRAM 0x06
-#define SPDMEM_MEMTYPE_DDRSDRAM 0x07
-#define SPDMEM_MEMTYPE_DDR2SDRAM 0x08
-#define SPDMEM_MEMTYPE_FBDIMM 0x09
-#define SPDMEM_MEMTYPE_FBDIMM_PROBE 0x0a
-#define SPDMEM_MEMTYPE_DDR3SDRAM 0x0b
-#define SPDMEM_MEMTYPE_NONE 0xff
-
-#define SPDMEM_MEMTYPE_DIRECT_RAMBUS 0x01
-#define SPDMEM_MEMTYPE_RAMBUS 0x11
-
-/* possible values for the supply voltage */
-#define SPDMEM_VOLTAGE_TTL_5V 0x00
-#define SPDMEM_VOLTAGE_TTL_LV 0x01
-#define SPDMEM_VOLTAGE_HSTTL_1_5V 0x02
-#define SPDMEM_VOLTAGE_SSTL_3_3V 0x03
-#define SPDMEM_VOLTAGE_SSTL_2_5V 0x04
-#define SPDMEM_VOLTAGE_SSTL_1_8V 0x05
-
-/* possible values for module configuration */
-#define SPDMEM_MODCONFIG_PARITY 0x01
-#define SPDMEM_MODCONFIG_ECC 0x02
-
-/* for DDR2, module configuration is a bit-mask field */
-#define SPDMEM_MODCONFIG_HAS_DATA_PARITY 0x01
-#define SPDMEM_MODCONFIG_HAS_DATA_ECC 0x02
-#define SPDMEM_MODCONFIG_HAS_ADDR_CMD_PARITY 0x04
-
-/* possible values for the refresh field */
-#define SPDMEM_REFRESH_STD 0x00
-#define SPDMEM_REFRESH_QUARTER 0x01
-#define SPDMEM_REFRESH_HALF 0x02
-#define SPDMEM_REFRESH_TWOX 0x03
-#define SPDMEM_REFRESH_FOURX 0x04
-#define SPDMEM_REFRESH_EIGHTX 0x05
-#define SPDMEM_REFRESH_SELFREFRESH 0x80
-
-/* superset types */
-#define SPDMEM_SUPERSET_ESDRAM 0x01
-#define SPDMEM_SUPERSET_DDR_ESDRAM 0x02
-#define SPDMEM_SUPERSET_EDO_PEM 0x03
-#define SPDMEM_SUPERSET_SDR_PEM 0x04
-
-/* FPM and EDO DIMMS */
-#define SPDMEM_FPM_ROWS 0x00
-#define SPDMEM_FPM_COLS 0x01
-#define SPDMEM_FPM_BANKS 0x02
-#define SPDMEM_FPM_CONFIG 0x08
-#define SPDMEM_FPM_REFRESH 0x09
-#define SPDMEM_FPM_SUPERSET 0x0c
-
-/* PC66/PC100/PC133 SDRAM */
-#define SPDMEM_SDR_ROWS 0x00
-#define SPDMEM_SDR_COLS 0x01
-#define SPDMEM_SDR_BANKS 0x02
-#define SPDMEM_SDR_CYCLE 0x06
-#define SPDMEM_SDR_BANKS_PER_CHIP 0x0e
-#define SPDMEM_SDR_MOD_ATTRIB 0x12
-#define SPDMEM_SDR_SUPERSET 0x1d
-
-#define SPDMEM_SDR_FREQUENCY 126
-#define SPDMEM_SDR_CAS 127
-#define SPDMEM_SDR_FREQ_66 0x66
-#define SPDMEM_SDR_FREQ_100 0x64
-#define SPDMEM_SDR_FREQ_133 0x85
-#define SPDMEM_SDR_CAS2 (1 << 1)
-#define SPDMEM_SDR_CAS3 (1 << 2)
-
-/* Rambus Direct DRAM */
-#define SPDMEM_RDR_MODULE_TYPE 0x00
-#define SPDMEM_RDR_ROWS_COLS 0x01
-#define SPDMEM_RDR_BANK 0x02
-
-#define SPDMEM_RDR_TYPE_RIMM 1
-#define SPDMEM_RDR_TYPE_SORIMM 2
-#define SPDMEM_RDR_TYPE_EMBED 3
-#define SPDMEM_RDR_TYPE_RIMM32 4
-
-/* Dual Data Rate SDRAM */
-#define SPDMEM_DDR_ROWS 0x00
-#define SPDMEM_DDR_COLS 0x01
-#define SPDMEM_DDR_RANKS 0x02
-#define SPDMEM_DDR_DATAWIDTH 0x03
-#define SPDMEM_DDR_VOLTAGE 0x05
-#define SPDMEM_DDR_CYCLE 0x06
-#define SPDMEM_DDR_REFRESH 0x09
-#define SPDMEM_DDR_BANKS_PER_CHIP 0x0e
-#define SPDMEM_DDR_CAS 0x0f
-#define SPDMEM_DDR_MOD_ATTRIB 0x12
-#define SPDMEM_DDR_SUPERSET 0x1d
-
-#define SPDMEM_DDR_ATTRIB_REG (1 << 1)
-
-/* Dual Data Rate 2 SDRAM */
-#define SPDMEM_DDR2_ROWS 0x00
-#define SPDMEM_DDR2_COLS 0x01
-#define SPDMEM_DDR2_RANKS 0x02
-#define SPDMEM_DDR2_DATAWIDTH 0x03
-#define SPDMEM_DDR2_VOLTAGE 0x05
-#define SPDMEM_DDR2_CYCLE 0x06
-#define SPDMEM_DDR2_DIMMTYPE 0x11
-#define SPDMEM_DDR2_RANK_DENSITY 0x1c
-
-#define SPDMEM_DDR2_TYPE_REGMASK ((1 << 4) | (1 << 0))
-#define SPDMEM_DDR2_SODIMM (1 << 2)
-#define SPDMEM_DDR2_MICRO_DIMM (1 << 3)
-#define SPDMEM_DDR2_MINI_RDIMM (1 << 4)
-#define SPDMEM_DDR2_MINI_UDIMM (1 << 5)
-
-/* DDR2 FB-DIMM SDRAM */
-#define SPDMEM_FBDIMM_ADDR 0x01
-#define SPDMEM_FBDIMM_RANKS 0x04
-#define SPDMEM_FBDIMM_MTB_DIVIDEND 0x06
-#define SPDMEM_FBDIMM_MTB_DIVISOR 0x07
-#define SPDMEM_FBDIMM_PROTO 0x4e
-
-#define SPDMEM_FBDIMM_RANKS_WIDTH 0x07
-#define SPDMEM_FBDIMM_ADDR_BANKS 0x02
-#define SPDMEM_FBDIMM_ADDR_COL 0x0c
-#define SPDMEM_FBDIMM_ADDR_COL_SHIFT 2
-#define SPDMEM_FBDIMM_ADDR_ROW 0xe0
-#define SPDMEM_FBDIMM_ADDR_ROW_SHIFT 5
-#define SPDMEM_FBDIMM_PROTO_ECC (1 << 1)
-
-
-/* Dual Data Rate 3 SDRAM */
-#define SPDMEM_DDR3_MODTYPE 0x00
-#define SPDMEM_DDR3_DENSITY 0x01
-#define SPDMEM_DDR3_MOD_ORG 0x04
-#define SPDMEM_DDR3_DATAWIDTH 0x05
-#define SPDMEM_DDR3_MTB_DIVIDEND 0x07
-#define SPDMEM_DDR3_MTB_DIVISOR 0x08
-#define SPDMEM_DDR3_TCKMIN 0x09
-#define SPDMEM_DDR3_THERMAL 0x1d
-
-#define SPDMEM_DDR3_DENSITY_CAPMASK 0x0f
-#define SPDMEM_DDR3_MOD_ORG_CHIPWIDTH_MASK 0x07
-#define SPDMEM_DDR3_MOD_ORG_BANKS_SHIFT 3
-#define SPDMEM_DDR3_MOD_ORG_BANKS_MASK 0x07
-#define SPDMEM_DDR3_DATAWIDTH_ECCMASK (1 << 3)
-#define SPDMEM_DDR3_DATAWIDTH_PRIMASK 0x07
-#define SPDMEM_DDR3_THERMAL_PRESENT (1 << 7)
-
-#define SPDMEM_DDR3_RDIMM 0x01
-#define SPDMEM_DDR3_UDIMM 0x02
-#define SPDMEM_DDR3_SODIMM 0x03
-#define SPDMEM_DDR3_MICRO_DIMM 0x04
-#define SPDMEM_DDR3_MINI_RDIMM 0x05
-#define SPDMEM_DDR3_MINI_UDIMM 0x06
-
-static const uint8_t ddr2_cycle_tenths[] = {
- 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 25, 33, 66, 75, 0, 0
-};
-
-struct spdmem {
- uint8_t sm_len;
- uint8_t sm_size;
- uint8_t sm_type;
- uint8_t sm_data[60];
- uint8_t sm_cksum;
-} __packed;
-
-#define SPDMEM_TYPE_MAXLEN 16
-struct spdmem_softc {
- struct device sc_dev;
- i2c_tag_t sc_tag;
- i2c_addr_t sc_addr;
- struct spdmem sc_spd_data;
-};
-
-uint16_t spdmem_crc16(struct spdmem_softc *, int);
-int spdmem_match(struct device *, void *, void *);
-void spdmem_attach(struct device *, struct device *, void *);
-uint8_t spdmem_read(struct spdmem_softc *, uint8_t);
-void spdmem_sdram_decode(struct spdmem_softc *, struct spdmem *);
-void spdmem_rdr_decode(struct spdmem_softc *, struct spdmem *);
-void spdmem_ddr_decode(struct spdmem_softc *, struct spdmem *);
-void spdmem_ddr2_decode(struct spdmem_softc *, struct spdmem *);
-void spdmem_fbdimm_decode(struct spdmem_softc *, struct spdmem *);
-void spdmem_ddr3_decode(struct spdmem_softc *, struct spdmem *);
-
-struct cfattach spdmem_ca = {
- sizeof(struct spdmem_softc), spdmem_match, spdmem_attach
-};
-
-struct cfdriver spdmem_cd = {
- NULL, "spdmem", DV_DULL
-};
-
-#define IS_RAMBUS_TYPE (s->sm_len < 4)
-
-static const char *spdmem_basic_types[] = {
- "unknown",
- "FPM",
- "EDO",
- "Pipelined Nibble",
- "SDRAM",
- "ROM",
- "DDR SGRAM",
- "DDR SDRAM",
- "DDR2 SDRAM",
- "DDR2 SDRAM FB-DIMM",
- "DDR2 SDRAM FB-DIMM Probe",
- "DDR3 SDRAM"
-};
-
-static const char *spdmem_superset_types[] = {
- "unknown",
- "ESDRAM",
- "DDR ESDRAM",
- "PEM EDO",
- "PEM SDRAM"
-};
-
-static const char *spdmem_parity_types[] = {
- "non-parity",
- "data parity",
- "ECC",
- "data parity and ECC",
- "cmd/addr parity",
- "cmd/addr/data parity",
- "cmd/addr parity, data ECC",
- "cmd/addr/data parity, data ECC"
-};
-
-/* CRC functions used for certain memory types */
-uint16_t
-spdmem_crc16(struct spdmem_softc *sc, int count)
-{
- uint16_t crc;
- int i, j;
- uint8_t val;
- crc = 0;
- for (j = 0; j <= count; j++) {
- val = spdmem_read(sc, j);
- crc = crc ^ val << 8;
- for (i = 0; i < 8; ++i)
- if (crc & 0x8000)
- crc = crc << 1 ^ 0x1021;
- else
- crc = crc << 1;
- }
- return (crc & 0xFFFF);
-}
-
-int
-spdmem_match(struct device *parent, void *match, void *aux)
-{
- struct i2c_attach_args *ia = aux;
- struct spdmem_softc sc;
- uint8_t i, val, type;
- int cksum = 0;
- int spd_len, spd_crc_cover;
- uint16_t crc_calc, crc_spd;
-
- /* clever attachments like openfirmware informed macppc */
- if (strcmp(ia->ia_name, "spd") == 0)
- return (1);
-
- /* dumb, need sanity checks */
- if (strcmp(ia->ia_name, "eeprom") != 0)
- return (0);
-
- sc.sc_tag = ia->ia_tag;
- sc.sc_addr = ia->ia_addr;
-
- type = spdmem_read(&sc, 2);
- /* For older memory types, validate the checksum over 1st 63 bytes */
- if (type <= SPDMEM_MEMTYPE_DDR2SDRAM) {
- for (i = 0; i < 63; i++)
- cksum += spdmem_read(&sc, i);
-
- val = spdmem_read(&sc, 63);
-
- if (cksum == 0 || (cksum & 0xff) != val) {
- return 0;
- } else
- return 1;
- }
-
- /* For DDR3 and FBDIMM, verify the CRC */
- else if (type <= SPDMEM_MEMTYPE_DDR3SDRAM) {
- spd_len = spdmem_read(&sc, 0);
- if (spd_len && SPDMEM_SPDCRC_116)
- spd_crc_cover = 116;
- else
- spd_crc_cover = 125;
- switch (spd_len & SPDMEM_SPDLEN_MASK) {
- case SPDMEM_SPDLEN_128:
- spd_len = 128;
- break;
- case SPDMEM_SPDLEN_176:
- spd_len = 176;
- break;
- case SPDMEM_SPDLEN_256:
- spd_len = 256;
- break;
- default:
- return 0;
- }
- if (spd_crc_cover > spd_len)
- return 0;
- crc_calc = spdmem_crc16(&sc, spd_crc_cover);
- crc_spd = spdmem_read(&sc, 127) << 8;
- crc_spd |= spdmem_read(&sc, 126);
- if (crc_calc != crc_spd) {
- return 0;
- }
- return 1;
- }
-
- return (0);
-}
-
-void
-spdmem_sdram_decode(struct spdmem_softc *sc, struct spdmem *s)
-{
- const char *type;
- int dimm_size, p_clk;
- int num_banks, per_chip;
- uint8_t rows, cols;
-
- type = spdmem_basic_types[s->sm_type];
-
- if (s->sm_data[SPDMEM_SDR_SUPERSET] == SPDMEM_SUPERSET_SDR_PEM)
- type = spdmem_superset_types[SPDMEM_SUPERSET_SDR_PEM];
- if (s->sm_data[SPDMEM_SDR_SUPERSET] == SPDMEM_SUPERSET_ESDRAM)
- type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM];
-
- num_banks = s->sm_data[SPDMEM_SDR_BANKS];
- per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP];
- rows = s->sm_data[SPDMEM_SDR_ROWS] & 0x0f;
- cols = s->sm_data[SPDMEM_SDR_COLS] & 0x0f;
- dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip;
-
- if (dimm_size > 0) {
- if (dimm_size < 1024)
- printf(" %dMB", dimm_size);
- else
- printf(" %dGB", dimm_size / 1024);
- }
-
- printf(" %s", type);
-
- if (s->sm_data[SPDMEM_DDR_MOD_ATTRIB] & SPDMEM_DDR_ATTRIB_REG)
- printf(" registered");
-
- if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
- printf(" %s",
- spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
-
- p_clk = 66;
- if (s->sm_len >= 128) {
- switch (spdmem_read(sc, SPDMEM_SDR_FREQUENCY)) {
- case SPDMEM_SDR_FREQ_100:
- case SPDMEM_SDR_FREQ_133:
- /* We need to check ns to decide here */
- if (s->sm_data[SPDMEM_SDR_CYCLE] < 0x80)
- p_clk = 133;
- else
- p_clk = 100;
- break;
- case SPDMEM_SDR_FREQ_66:
- default:
- p_clk = 66;
- break;
- }
- }
- printf(" PC%d", p_clk);
-
- /* Print CAS latency */
- if (s->sm_len < 128)
- return;
- if (spdmem_read(sc, SPDMEM_SDR_CAS) & SPDMEM_SDR_CAS2)
- printf("CL2");
- else if (spdmem_read(sc, SPDMEM_SDR_CAS) & SPDMEM_SDR_CAS3)
- printf("CL3");
-}
-
-void
-spdmem_rdr_decode(struct spdmem_softc *sc, struct spdmem *s)
-{
- int rimm_size;
- uint8_t row_bits, col_bits, bank_bits;
-
- row_bits = s->sm_data[SPDMEM_RDR_ROWS_COLS] >> 4;
- col_bits = s->sm_data[SPDMEM_RDR_ROWS_COLS] & 0x0f;
- bank_bits = s->sm_data[SPDMEM_RDR_BANK] & 0x07;
-
- /* subtracting 13 here is a cheaper way of dividing by 8k later */
- rimm_size = 1 << (row_bits + col_bits + bank_bits - 13);
-
- if (rimm_size < 1024)
- printf(" %dMB ", rimm_size);
- else
- printf(" %dGB ", rimm_size / 1024);
-
- switch(s->sm_data[SPDMEM_RDR_MODULE_TYPE]) {
- case SPDMEM_RDR_TYPE_RIMM:
- printf("RIMM");
- break;
- case SPDMEM_RDR_TYPE_SORIMM:
- printf("SO-RIMM");
- break;
- case SPDMEM_RDR_TYPE_EMBED:
- printf("Embedded Rambus");
- break;
- case SPDMEM_RDR_TYPE_RIMM32:
- printf("RIMM32");
- break;
- }
-}
-
-void
-spdmem_ddr_decode(struct spdmem_softc *sc, struct spdmem *s)
-{
- const char *type;
- int dimm_size, cycle_time, d_clk, p_clk, bits;
- int i, num_banks, per_chip;
- uint8_t config, rows, cols, cl;
-
- type = spdmem_basic_types[s->sm_type];
-
- if (s->sm_data[SPDMEM_DDR_SUPERSET] == SPDMEM_SUPERSET_DDR_ESDRAM)
- type = spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM];
-
- num_banks = s->sm_data[SPDMEM_SDR_BANKS];
- per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP];
- rows = s->sm_data[SPDMEM_SDR_ROWS] & 0x0f;
- cols = s->sm_data[SPDMEM_SDR_COLS] & 0x0f;
- dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip;
-
- if (dimm_size > 0) {
- if (dimm_size < 1024)
- printf(" %dMB", dimm_size);
- else
- printf(" %dGB", dimm_size / 1024);
- }
-
- printf(" %s", type);
-
- if (s->sm_data[SPDMEM_DDR_MOD_ATTRIB] & SPDMEM_DDR_ATTRIB_REG)
- printf(" registered");
-
- if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
- printf(" %s",
- spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
-
- /* cycle_time is expressed in units of 0.01 ns */
- cycle_time = (s->sm_data[SPDMEM_DDR_CYCLE] >> 4) * 100 +
- (s->sm_data[SPDMEM_DDR_CYCLE] & 0x0f) * 10;
-
- if (cycle_time != 0) {
- /*
- * cycle time is scaled by a factor of 100 to avoid using
- * floating point. Calculate memory speed as the number
- * of cycles per microsecond.
- * DDR uses dual-pumped clock
- */
- d_clk = 100 * 1000 * 2;
- config = s->sm_data[SPDMEM_FPM_CONFIG];
- bits = s->sm_data[SPDMEM_DDR_DATAWIDTH] |
- (s->sm_data[SPDMEM_DDR_DATAWIDTH + 1] << 8);
- if (config == 1 || config == 2)
- bits -= 8;
-
- d_clk /= cycle_time;
- p_clk = d_clk * bits / 8;
- if ((p_clk % 100) >= 50)
- p_clk += 50;
- p_clk -= p_clk % 100;
- printf(" PC%d", p_clk);
- }
-
- /* Print CAS latency */
- for (i = 6; i >= 0; i--) {
- if (s->sm_data[SPDMEM_DDR_CAS] & (1 << i)) {
- cl = ((i * 10) / 2) + 10;
- printf("CL%d.%d", cl / 10, cl % 10);
- break;
- }
- }
-}
-
-void
-spdmem_ddr2_decode(struct spdmem_softc *sc, struct spdmem *s)
-{
- const char *type;
- int dimm_size, cycle_time, d_clk, p_clk, bits;
- int i, num_ranks, density;
- uint8_t config;
-
- type = spdmem_basic_types[s->sm_type];
-
- num_ranks = (s->sm_data[SPDMEM_DDR2_RANKS] & 0x7) + 1;
- density = (s->sm_data[SPDMEM_DDR2_RANK_DENSITY] & 0xf0) |
- ((s->sm_data[SPDMEM_DDR2_RANK_DENSITY] & 0x0f) << 8);
- dimm_size = num_ranks * density * 4;
-
- if (dimm_size > 0) {
- if (dimm_size < 1024)
- printf(" %dMB", dimm_size);
- else
- printf(" %dGB", dimm_size / 1024);
- }
-
- printf(" %s", type);
-
- if (s->sm_data[SPDMEM_DDR2_DIMMTYPE] & SPDMEM_DDR2_TYPE_REGMASK)
- printf(" registered");
-
- if (s->sm_data[SPDMEM_FPM_CONFIG] < 8)
- printf(" %s",
- spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG]]);
-
- /* cycle_time is expressed in units of 0.01 ns */
- cycle_time = (s->sm_data[SPDMEM_DDR2_CYCLE] >> 4) * 100 +
- ddr2_cycle_tenths[(s->sm_data[SPDMEM_DDR2_CYCLE] & 0x0f)];
-
- if (cycle_time != 0) {
- /*
- * cycle time is scaled by a factor of 100 to avoid using
- * floating point. Calculate memory speed as the number
- * of cycles per microsecond.
- * DDR2 uses quad-pumped clock
- */
- d_clk = 100 * 1000 * 4;
- config = s->sm_data[SPDMEM_FPM_CONFIG];
- bits = s->sm_data[SPDMEM_DDR2_DATAWIDTH];
- if ((config & 0x03) != 0)
- bits -= 8;
- d_clk /= cycle_time;
- d_clk = (d_clk + 1) / 2;
- p_clk = d_clk * bits / 8;
- p_clk -= p_clk % 100;
- printf(" PC2-%d", p_clk);
- }
-
- /* Print CAS latency */
- for (i = 5; i >= 2; i--) {
- if (s->sm_data[SPDMEM_DDR_CAS] & (i << i)) {
- printf("CL%d", i);
- break;
- }
- }
-
- switch (s->sm_data[SPDMEM_DDR2_DIMMTYPE]) {
- case SPDMEM_DDR2_SODIMM:
- printf(" SO-DIMM");
- break;
- case SPDMEM_DDR2_MICRO_DIMM:
- printf(" Micro-DIMM");
- break;
- case SPDMEM_DDR2_MINI_RDIMM:
- case SPDMEM_DDR2_MINI_UDIMM:
- printf(" Mini-DIMM");
- break;
- }
-}
-
-void
-spdmem_fbdimm_decode(struct spdmem_softc *sc, struct spdmem *s)
-{
- int dimm_size, num_banks, cycle_time, d_clk, p_clk, bits;
- uint8_t rows, cols, banks, dividend, divisor;
- /*
- * FB-DIMM is very much like DDR3
- */
-
- banks = s->sm_data[SPDMEM_FBDIMM_ADDR] & SPDMEM_FBDIMM_ADDR_BANKS;
- cols = (s->sm_data[SPDMEM_FBDIMM_ADDR] & SPDMEM_FBDIMM_ADDR_COL) >>
- SPDMEM_FBDIMM_ADDR_COL_SHIFT;
- rows = (s->sm_data[SPDMEM_FBDIMM_ADDR] & SPDMEM_FBDIMM_ADDR_ROW) >>
- SPDMEM_FBDIMM_ADDR_ROW_SHIFT;
- dimm_size = rows + 12 + cols + 9 - 20 - 3;
- num_banks = 1 << (banks + 2);
-
- if (dimm_size < 1024)
- printf(" %dMB", dimm_size);
- else
- printf(" %dGB", dimm_size / 1024);
-
- dividend = s->sm_data[SPDMEM_FBDIMM_MTB_DIVIDEND];
- divisor = s->sm_data[SPDMEM_FBDIMM_MTB_DIVISOR];
-
- cycle_time = (1000 * dividend + (divisor / 2)) / divisor;
-
- if (cycle_time != 0) {
- /*
- * cycle time is scaled by a factor of 1000 to avoid using
- * floating point. Calculate memory speed as the number
- * of cycles per microsecond.
- */
- d_clk = 1000 * 1000;
-
- /* DDR2 FB-DIMM uses a dual-pumped clock */
- d_clk *= 2;
- bits = 1 << ((s->sm_data[SPDMEM_FBDIMM_RANKS] &
- SPDMEM_FBDIMM_RANKS_WIDTH) + 2);
-
- p_clk = (d_clk * bits) / 8 / cycle_time;
- d_clk = ((d_clk + cycle_time / 2) ) / cycle_time;
- p_clk -= p_clk % 100;
- printf(" PC2-%d", p_clk);
- }
-}
-
-void
-spdmem_ddr3_decode(struct spdmem_softc *sc, struct spdmem *s)
-{
- const char *type;
- int dimm_size, cycle_time, d_clk, p_clk, bits;
- uint8_t mtype, chipsize, dividend, divisor;
- uint8_t datawidth, chipwidth, physbanks;
-
- type = spdmem_basic_types[s->sm_type];
-
- chipsize = s->sm_data[SPDMEM_DDR3_DENSITY] &
- SPDMEM_DDR3_DENSITY_CAPMASK;
- datawidth = s->sm_data[SPDMEM_DDR3_DATAWIDTH] &
- SPDMEM_DDR3_DATAWIDTH_PRIMASK;
- chipwidth = s->sm_data[SPDMEM_DDR3_MOD_ORG] &
- SPDMEM_DDR3_MOD_ORG_CHIPWIDTH_MASK;
- physbanks = (s->sm_data[SPDMEM_DDR3_MOD_ORG] >>
- SPDMEM_DDR3_MOD_ORG_BANKS_SHIFT) & SPDMEM_DDR3_MOD_ORG_BANKS_MASK;
-
- dimm_size = (chipsize + 28 - 20) - 3 + (datawidth + 3) -
- (chipwidth + 2);
- dimm_size = (1 << dimm_size) * (physbanks + 1);
-
- if (dimm_size < 1024)
- printf(" %dMB", dimm_size);
- else
- printf(" %dGB", dimm_size / 1024);
-
- printf(" %s", type);
-
- mtype = s->sm_data[SPDMEM_DDR3_MODTYPE];
- if (mtype == SPDMEM_DDR3_RDIMM || mtype == SPDMEM_DDR3_MINI_RDIMM)
- printf(" registered");
-
- if (s->sm_data[SPDMEM_DDR3_DATAWIDTH] & SPDMEM_DDR3_DATAWIDTH_ECCMASK)
- printf(" ECC");
-
- dividend = s->sm_data[SPDMEM_DDR3_MTB_DIVIDEND];
- divisor = s->sm_data[SPDMEM_DDR3_MTB_DIVISOR];
- cycle_time = (1000 * dividend + (divisor / 2)) / divisor;
- cycle_time *= s->sm_data[SPDMEM_DDR3_TCKMIN];
-
- if (cycle_time != 0) {
- /*
- * cycle time is scaled by a factor of 1000 to avoid using
- * floating point. Calculate memory speed as the number
- * of cycles per microsecond.
- * DDR3 uses a dual-pumped clock
- */
- d_clk = 1000 * 1000;
- d_clk *= 2;
- bits = 1 << ((s->sm_data[SPDMEM_DDR3_DATAWIDTH] &
- SPDMEM_DDR3_DATAWIDTH_PRIMASK) + 3);
- /*
- * Calculate p_clk first, since for DDR3 we need maximum
- * significance. DDR3 rating is not rounded to a multiple
- * of 100. This results in cycle_time of 1.5ns displayed
- * as p_clk PC3-10666 (d_clk DDR3-1333)
- */
- p_clk = (d_clk * bits) / 8 / cycle_time;
- p_clk -= (p_clk % 100);
- d_clk = ((d_clk + cycle_time / 2) ) / cycle_time;
- printf(" PC3-%d", p_clk);
- }
-
- switch (s->sm_data[SPDMEM_DDR3_MODTYPE]) {
- case SPDMEM_DDR3_SODIMM:
- printf(" SO-DIMM");
- break;
- case SPDMEM_DDR3_MICRO_DIMM:
- printf(" Micro-DIMM");
- break;
- case SPDMEM_DDR3_MINI_RDIMM:
- case SPDMEM_DDR3_MINI_UDIMM:
- printf(" Mini-DIMM");
- break;
- }
-
- if (s->sm_data[SPDMEM_DDR3_THERMAL] & SPDMEM_DDR3_THERMAL_PRESENT)
- printf(" with thermal sensor");
-}
-
-void
-spdmem_attach(struct device *parent, struct device *self, void *aux)
-{
- struct spdmem_softc *sc = (struct spdmem_softc *)self;
- struct i2c_attach_args *ia = aux;
- struct spdmem *s = &(sc->sc_spd_data);
- int i;
-
- sc->sc_tag = ia->ia_tag;
- sc->sc_addr = ia->ia_addr;
-
- printf(":");
-
- /* All SPD have at least 64 bytes of data including checksum */
- for (i = 0; i < 64; i++) {
- ((uint8_t *)s)[i] = spdmem_read(sc, i);
- }
-
- /*
- * Decode and print SPD contents
- */
- if (s->sm_len < 4) {
- if (s->sm_type == SPDMEM_MEMTYPE_DIRECT_RAMBUS)
- spdmem_rdr_decode(sc, s);
- else
- printf(" no decode method for Rambus memory");
- } else {
- switch(s->sm_type) {
- case SPDMEM_MEMTYPE_EDO:
- case SPDMEM_MEMTYPE_SDRAM:
- spdmem_sdram_decode(sc, s);
- break;
- case SPDMEM_MEMTYPE_DDRSDRAM:
- spdmem_ddr_decode(sc, s);
- break;
- case SPDMEM_MEMTYPE_DDR2SDRAM:
- spdmem_ddr2_decode(sc, s);
- break;
- case SPDMEM_MEMTYPE_FBDIMM:
- case SPDMEM_MEMTYPE_FBDIMM_PROBE:
- spdmem_fbdimm_decode(sc, s);
- break;
- case SPDMEM_MEMTYPE_DDR3SDRAM:
- spdmem_ddr3_decode(sc, s);
- break;
- case SPDMEM_MEMTYPE_NONE:
- printf(" no EEPROM found");
- break;
- default:
- if (s->sm_type <= 10)
- printf(" no decode method for %s memory",
- spdmem_basic_types[s->sm_type]);
- else
- printf(" unknown memory type %d", s->sm_type);
- break;
- }
- }
-
- printf("\n");
-}
-
-uint8_t
-spdmem_read(struct spdmem_softc *sc, uint8_t reg)
-{
- uint8_t val = 0xff;
-
- iic_acquire_bus(sc->sc_tag,0);
- iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
- &reg, sizeof reg, &val, sizeof val, 0);
- iic_release_bus(sc->sc_tag, 0);
-
- return val;
-}
diff --git a/sys/dev/i2c/spdmem_i2c.c b/sys/dev/i2c/spdmem_i2c.c
new file mode 100644
index 00000000000..d4df0d8b647
--- /dev/null
+++ b/sys/dev/i2c/spdmem_i2c.c
@@ -0,0 +1,123 @@
+/* $OpenBSD: spdmem_i2c.c,v 1.1 2010/03/22 21:20:58 miod Exp $ */
+/* $NetBSD: spdmem.c,v 1.3 2007/09/20 23:09:59 xtraeme Exp $ */
+
+/*
+ * Copyright (c) 2007 Jonathan Gray <jsg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2007 Nicolas Joly
+ * Copyright (c) 2007 Paul Goyette
+ * Copyright (c) 2007 Tobias Nygren
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Serial Presence Detect (SPD) memory identification
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <dev/spdmemvar.h>
+#include <dev/i2c/i2cvar.h>
+
+struct spdmem_iic_softc {
+ struct spdmem_softc sc_base;
+ i2c_tag_t sc_tag;
+ i2c_addr_t sc_addr;
+};
+
+int spdmem_iic_match(struct device *, void *, void *);
+void spdmem_iic_attach(struct device *, struct device *, void *);
+uint8_t spdmem_iic_read(struct spdmem_softc *, uint8_t);
+
+struct cfattach spdmem_iic_ca = {
+ sizeof(struct spdmem_iic_softc), spdmem_iic_match, spdmem_iic_attach
+};
+
+int
+spdmem_iic_match(struct device *parent, void *match, void *aux)
+{
+ struct i2c_attach_args *ia = aux;
+ struct spdmem_iic_softc sc;
+
+ /* clever attachments like openfirmware informed macppc */
+ if (strcmp(ia->ia_name, "spd") == 0)
+ return (1);
+
+ /* dumb, need sanity checks */
+ if (strcmp(ia->ia_name, "eeprom") != 0)
+ return (0);
+
+ sc.sc_tag = ia->ia_tag;
+ sc.sc_addr = ia->ia_addr;
+ sc.sc_base.sc_read = spdmem_iic_read;
+
+ return spdmem_probe(&sc.sc_base);
+}
+
+void
+spdmem_iic_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct spdmem_iic_softc *sc = (struct spdmem_iic_softc *)self;
+ struct i2c_attach_args *ia = aux;
+
+ sc->sc_tag = ia->ia_tag;
+ sc->sc_addr = ia->ia_addr;
+ sc->sc_base.sc_read = spdmem_iic_read;
+
+ printf(":");
+
+ spdmem_attach_common(&sc->sc_base);
+}
+
+uint8_t
+spdmem_iic_read(struct spdmem_softc *v, uint8_t reg)
+{
+ struct spdmem_iic_softc *sc = (struct spdmem_iic_softc *)v;
+ uint8_t val = 0xff;
+
+ iic_acquire_bus(sc->sc_tag,0);
+ iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+ &reg, sizeof reg, &val, sizeof val, 0);
+ iic_release_bus(sc->sc_tag, 0);
+
+ return val;
+}