Module Name:    src
Committed By:   mlelstv
Date:           Mon Dec  7 09:41:37 UTC 2015

Modified Files:
        src/sys/dev/i2c: spdmem_i2c.c
        src/sys/dev/ic: spdmemvar.h

Log Message:
Handle reading of 4kbit EEPROMs in SPD devices. This is needed for DDR4 DIMMs.


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/i2c/spdmem_i2c.c
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/ic/spdmemvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/i2c/spdmem_i2c.c
diff -u src/sys/dev/i2c/spdmem_i2c.c:1.10 src/sys/dev/i2c/spdmem_i2c.c:1.11
--- src/sys/dev/i2c/spdmem_i2c.c:1.10	Sat Mar  7 14:16:51 2015
+++ src/sys/dev/i2c/spdmem_i2c.c	Mon Dec  7 09:41:37 2015
@@ -1,9 +1,10 @@
-/* $NetBSD: spdmem_i2c.c,v 1.10 2015/03/07 14:16:51 jmcneill Exp $ */
+/* $NetBSD: spdmem_i2c.c,v 1.11 2015/12/07 09:41:37 mlelstv Exp $ */
 
 /*
  * Copyright (c) 2007 Nicolas Joly
  * Copyright (c) 2007 Paul Goyette
  * Copyright (c) 2007 Tobias Nygren
+ * Copyright (c) 2015 Michael van Elst
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,10 +33,14 @@
 
 /*
  * Serial Presence Detect (SPD) memory identification
+ *
+ * JEDEC standard No. 21-C
+ * JEDEC document 4_01_06R24
+ * - Definitions of the EE1004-v 4 Kbit Serial Presence Detect EEPROM [...]
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: spdmem_i2c.c,v 1.10 2015/03/07 14:16:51 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spdmem_i2c.c,v 1.11 2015/12/07 09:41:37 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -49,13 +54,38 @@ __KERNEL_RCSID(0, "$NetBSD: spdmem_i2c.c
 #include <dev/ic/spdmemvar.h>
 
 /* Constants for matching i2c bus address */
-#define SPDMEM_I2C_ADDRMASK 0x3f8
+#define SPDMEM_I2C_ADDRMASK 0xfff8
 #define SPDMEM_I2C_ADDR     0x50
+#define SPDCTL_I2C_ADDR     0x30
+
+/* set write protection */
+#define SPDCTL_SWP0         (SPDCTL_I2C_ADDR + 1)
+#define SPDCTL_SWP1         (SPDCTL_I2C_ADDR + 4)
+#define SPDCTL_SWP2         (SPDCTL_I2C_ADDR + 5)
+#define SPDCTL_SWP3         (SPDCTL_I2C_ADDR + 0)
+
+/* clear write protections */
+#define SPDCTL_CWP          (SPDCTL_I2C_ADDR + 3)
+
+/* read protection status */
+#define SPDCTL_RPS0         (SPDCTL_I2C_ADDR + 1)
+#define SPDCTL_RPS1         (SPDCTL_I2C_ADDR + 4)
+#define SPDCTL_RPS2         (SPDCTL_I2C_ADDR + 5)
+#define SPDCTL_RPS3         (SPDCTL_I2C_ADDR + 0)
+
+/* select page address */
+#define SPDCTL_SPA0         (SPDCTL_I2C_ADDR + 6)
+#define SPDCTL_SPA1         (SPDCTL_I2C_ADDR + 7)
+
+/* read page address */
+#define SPDCTL_RPA          (SPDCTL_I2C_ADDR + 6)
 
 struct spdmem_i2c_softc {
 	struct spdmem_softc sc_base;
 	i2c_tag_t sc_tag;
-	i2c_addr_t sc_addr;
+	i2c_addr_t sc_addr; /* EEPROM */
+	i2c_addr_t sc_page0;
+	i2c_addr_t sc_page1;
 };
 
 static int  spdmem_i2c_match(device_t, cfdata_t, void *);
@@ -65,7 +95,7 @@ static int  spdmem_i2c_detach(device_t, 
 CFATTACH_DECL_NEW(spdmem_iic, sizeof(struct spdmem_i2c_softc),
     spdmem_i2c_match, spdmem_i2c_attach, spdmem_i2c_detach, NULL);
 
-static uint8_t spdmem_i2c_read(struct spdmem_softc *, uint8_t);
+static uint8_t spdmem_i2c_read(struct spdmem_softc *, uint16_t);
 
 static int
 spdmem_i2c_match(device_t parent, cfdata_t match, void *aux)
@@ -88,6 +118,8 @@ spdmem_i2c_match(device_t parent, cfdata
 
 	sc.sc_tag = ia->ia_tag;
 	sc.sc_addr = ia->ia_addr;
+	sc.sc_page0 = SPDCTL_SPA0;
+	sc.sc_page1 = SPDCTL_SPA1;
 	sc.sc_base.sc_read = spdmem_i2c_read;
 
 	return spdmem_common_probe(&sc.sc_base);
@@ -101,6 +133,8 @@ spdmem_i2c_attach(device_t parent, devic
 
 	sc->sc_tag = ia->ia_tag;
 	sc->sc_addr = ia->ia_addr;
+	sc->sc_page0 = SPDCTL_SPA0;
+	sc->sc_page1 = SPDCTL_SPA1;
 	sc->sc_base.sc_read = spdmem_i2c_read;
 
 	if (!pmf_device_register(self, NULL, NULL))
@@ -120,14 +154,28 @@ spdmem_i2c_detach(device_t self, int fla
 }
 
 static uint8_t
-spdmem_i2c_read(struct spdmem_softc *softc, uint8_t reg)
+spdmem_i2c_read(struct spdmem_softc *softc, uint16_t addr)
 {
-	uint8_t val;
+	uint8_t reg, val;
 	struct spdmem_i2c_softc *sc = (struct spdmem_i2c_softc *)softc;
+	static uint8_t dummy = 0;
+
+	reg = addr & 0xff;
 
 	iic_acquire_bus(sc->sc_tag, 0);
-	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg, 1,
-		 &val, 1, I2C_F_POLL);
+
+	if (addr & 0x100) {
+		iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_page1,
+			&dummy, 1, NULL, 0, I2C_F_POLL);
+		iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+			&reg, 1, &val, 1, I2C_F_POLL);
+		iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_page0,
+			&dummy, 1, NULL, 0, I2C_F_POLL);
+	} else {
+		iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+			&reg, 1, &val, 1, I2C_F_POLL);
+	}
+
 	iic_release_bus(sc->sc_tag, 0);
 
 	return val;

Index: src/sys/dev/ic/spdmemvar.h
diff -u src/sys/dev/ic/spdmemvar.h:1.8 src/sys/dev/ic/spdmemvar.h:1.9
--- src/sys/dev/ic/spdmemvar.h:1.8	Sun Dec  6 09:31:20 2015
+++ src/sys/dev/ic/spdmemvar.h	Mon Dec  7 09:41:37 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: spdmemvar.h,v 1.8 2015/12/06 09:31:20 msaitoh Exp $ */
+/* $NetBSD: spdmemvar.h,v 1.9 2015/12/07 09:41:37 mlelstv Exp $ */
 
 /*
  * Copyright (c) 2007 Paul Goyette
@@ -885,7 +885,7 @@ struct spdmem {
 #define SPDMEM_TYPE_MAXLEN 24
 
 struct spdmem_softc {
-	uint8_t		(*sc_read)(struct spdmem_softc *, uint8_t);
+	uint8_t		(*sc_read)(struct spdmem_softc *, uint16_t);
 	struct spdmem	sc_spd_data;
 	struct sysctllog *sc_sysctl_log;
 	char		sc_type[SPDMEM_TYPE_MAXLEN];

Reply via email to