Split spdmem driver into a bus attachment and a common back-end
probe and ROM decode, to follow similar changes made in OpenBSD: http://article.gmane.org/gmane.os.openbsd.cvs/94948 http://article.gmane.org/gmane.os.openbsd.cvs/94956 There exists at least one alternative attachment (for SGI IP35 systems; see http://article.gmane.org/gmane.os.openbsd.cvs/94947), and there could be more in the future. Thanks to Christoph Egger for pointing out the OpenBSD activity.
This commit is contained in:
parent
8183d39c9c
commit
d41a3cef46
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files,v 1.983 2010/03/15 20:35:19 christos Exp $
|
||||
# $NetBSD: files,v 1.984 2010/03/24 00:31:41 pgoyette Exp $
|
||||
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
|
||||
|
||||
version 20090313
|
||||
@ -328,6 +328,13 @@ attach video at videobus
|
||||
device lm: sysmon_envsys
|
||||
file dev/ic/nslm7x.c lm needs-flag
|
||||
|
||||
# JEDEC standard SPD EPROM
|
||||
#
|
||||
# (included here so files.i2c can define an attachment)
|
||||
|
||||
device spdmem
|
||||
file dev/ic/spdmem.c spdmem
|
||||
|
||||
# I2C device support
|
||||
include "dev/i2c/files.i2c"
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.i2c,v 1.26 2010/02/22 03:50:56 pgoyette Exp $
|
||||
# $NetBSD: files.i2c,v 1.27 2010/03/24 00:31:41 pgoyette Exp $
|
||||
|
||||
defflag opt_i2cbus.h I2C_SCAN
|
||||
define i2cbus { }
|
||||
@ -102,9 +102,8 @@ attach xbseeprom at iic
|
||||
file dev/i2c/xbseeprom.c xbseeprom
|
||||
|
||||
# Memory Serial Presence Detect
|
||||
device spdmem
|
||||
attach spdmem at iic
|
||||
file dev/i2c/spdmem.c spdmem
|
||||
attach spdmem at iic with spdmem_iic
|
||||
file dev/i2c/spdmem_i2c.c spdmem_iic
|
||||
|
||||
# Memory Temp Sensor
|
||||
device sdtemp: sysmon_envsys
|
||||
|
122
sys/dev/i2c/spdmem_i2c.c
Normal file
122
sys/dev/i2c/spdmem_i2c.c
Normal file
@ -0,0 +1,122 @@
|
||||
/* $NetBSD: spdmem_i2c.c,v 1.1 2010/03/24 00:31:41 pgoyette Exp $ */
|
||||
|
||||
/*
|
||||
* 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/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: spdmem_i2c.c,v 1.1 2010/03/24 00:31:41 pgoyette Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <machine/bswap.h>
|
||||
|
||||
#include <dev/i2c/i2cvar.h>
|
||||
#include <dev/ic/spdmemreg.h>
|
||||
#include <dev/ic/spdmemvar.h>
|
||||
|
||||
/* Constants for matching i2c bus address */
|
||||
#define SPDMEM_I2C_ADDRMASK 0x78
|
||||
#define SPDMEM_I2C_ADDR 0x50
|
||||
|
||||
struct spdmem_i2c_softc {
|
||||
struct spdmem_softc sc_base;
|
||||
i2c_tag_t sc_tag;
|
||||
i2c_addr_t sc_addr;
|
||||
};
|
||||
|
||||
static int spdmem_i2c_match(device_t, cfdata_t, void *);
|
||||
static void spdmem_i2c_attach(device_t, device_t, void *);
|
||||
SYSCTL_SETUP_PROTO(sysctl_spdmem_setup);
|
||||
|
||||
static uint8_t spdmem_i2c_read(struct spdmem_softc *, uint8_t);
|
||||
|
||||
CFATTACH_DECL_NEW(spdmem_iic, sizeof(struct spdmem_i2c_softc),
|
||||
spdmem_i2c_match, spdmem_i2c_attach, NULL, NULL);
|
||||
|
||||
static int
|
||||
spdmem_i2c_match(device_t parent, cfdata_t match, void *aux)
|
||||
{
|
||||
struct i2c_attach_args *ia = aux;
|
||||
struct spdmem_i2c_softc sc;
|
||||
|
||||
if (ia->ia_name) {
|
||||
/* add other names as we find more firmware variations */
|
||||
if (strcmp(ia->ia_name, "dimm-spd"))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* only do this lame test when not using direct config */
|
||||
if (ia->ia_name == NULL) {
|
||||
if ((ia->ia_addr & SPDMEM_I2C_ADDRMASK) != SPDMEM_I2C_ADDR)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sc.sc_tag = ia->ia_tag;
|
||||
sc.sc_addr = ia->ia_addr;
|
||||
sc.sc_base.sc_read = spdmem_i2c_read;
|
||||
|
||||
return spdmem_common_probe(&sc.sc_base);
|
||||
}
|
||||
|
||||
static void
|
||||
spdmem_i2c_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
struct spdmem_i2c_softc *sc = device_private(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_i2c_read;
|
||||
|
||||
if (!pmf_device_register(self, NULL, NULL))
|
||||
aprint_error_dev(self, "couldn't establish power handler\n");
|
||||
|
||||
spdmem_common_attach(&sc->sc_base, self);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
spdmem_i2c_read(struct spdmem_softc *softc, uint8_t reg)
|
||||
{
|
||||
uint8_t val;
|
||||
struct spdmem_i2c_softc *sc = (struct spdmem_i2c_softc *)softc;
|
||||
|
||||
iic_acquire_bus(sc->sc_tag, 0);
|
||||
iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, ®, 1,
|
||||
&val, 1, 0);
|
||||
iic_release_bus(sc->sc_tag, 0);
|
||||
|
||||
return val;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: spdmem.c,v 1.18 2010/03/23 12:13:28 njoly Exp $ */
|
||||
/* $NetBSD: spdmem.c,v 1.1 2010/03/24 00:31:41 pgoyette Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicolas Joly
|
||||
@ -35,7 +35,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.18 2010/03/23 12:13:28 njoly Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.1 2010/03/24 00:31:41 pgoyette Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/device.h>
|
||||
@ -44,15 +44,11 @@ __KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.18 2010/03/23 12:13:28 njoly Exp $");
|
||||
#include <machine/bswap.h>
|
||||
|
||||
#include <dev/i2c/i2cvar.h>
|
||||
#include <dev/i2c/spdmemreg.h>
|
||||
#include <dev/i2c/spdmemvar.h>
|
||||
#include <dev/ic/spdmemreg.h>
|
||||
#include <dev/ic/spdmemvar.h>
|
||||
|
||||
static int spdmem_match(device_t, cfdata_t, void *);
|
||||
static void spdmem_attach(device_t, device_t, void *);
|
||||
SYSCTL_SETUP_PROTO(sysctl_spdmem_setup);
|
||||
|
||||
static uint8_t spdmem_read(struct spdmem_softc *, uint8_t);
|
||||
|
||||
/* Routines for decoding spd data */
|
||||
static void decode_edofpm(const struct sysctlnode *, device_t, struct spdmem *);
|
||||
static void decode_rom(const struct sysctlnode *, device_t, struct spdmem *);
|
||||
@ -67,9 +63,6 @@ static void decode_size_speed(const struct sysctlnode *, int, int, int, int,
|
||||
bool, const char *, int);
|
||||
static void decode_voltage_refresh(device_t, struct spdmem *);
|
||||
|
||||
CFATTACH_DECL_NEW(spdmem, sizeof(struct spdmem_softc),
|
||||
spdmem_match, spdmem_attach, NULL, NULL);
|
||||
|
||||
#define IS_RAMBUS_TYPE (s->sm_len < 4)
|
||||
|
||||
static const char* spdmem_basic_types[] = {
|
||||
@ -145,7 +138,7 @@ static uint16_t spdcrc16 (struct spdmem_softc *sc, int count)
|
||||
uint8_t val;
|
||||
crc = 0;
|
||||
for (j = 0; j <= count; j++) {
|
||||
val = spdmem_read(sc, j);
|
||||
val = (sc->sc_read)(sc, j);
|
||||
crc = crc ^ val << 8;
|
||||
for (i = 0; i < 8; ++i)
|
||||
if (crc & 0x8000)
|
||||
@ -156,42 +149,24 @@ static uint16_t spdcrc16 (struct spdmem_softc *sc, int count)
|
||||
return (crc & 0xFFFF);
|
||||
}
|
||||
|
||||
static int
|
||||
spdmem_match(device_t parent, cfdata_t match, void *aux)
|
||||
int
|
||||
spdmem_common_probe(struct spdmem_softc *sc)
|
||||
{
|
||||
struct i2c_attach_args *ia = aux;
|
||||
struct spdmem_softc sc;
|
||||
int cksum = 0;
|
||||
uint8_t i, val, spd_type;
|
||||
int spd_len, spd_crc_cover;
|
||||
uint16_t crc_calc, crc_spd;
|
||||
|
||||
if (ia->ia_name) {
|
||||
/* add other names as we find more firmware variations */
|
||||
if (strcmp(ia->ia_name, "dimm-spd"))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* only do this lame test when not using direct config */
|
||||
if (ia->ia_name == NULL) {
|
||||
if ((ia->ia_addr & SPDMEM_ADDRMASK) != SPDMEM_ADDR)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sc.sc_tag = ia->ia_tag;
|
||||
sc.sc_addr = ia->ia_addr;
|
||||
|
||||
spd_type = spdmem_read(&sc, 2);
|
||||
spd_type = (sc->sc_read)(sc, 2);
|
||||
|
||||
/* For older memory types, validate the checksum over 1st 63 bytes */
|
||||
if (spd_type <= SPDMEM_MEMTYPE_DDR2SDRAM) {
|
||||
for (i = 0; i < 63; i++)
|
||||
cksum += spdmem_read(&sc, i);
|
||||
cksum += (sc->sc_read)(sc, i);
|
||||
|
||||
val = spdmem_read(&sc, 63);
|
||||
val = (sc->sc_read)(sc, 63);
|
||||
|
||||
if (cksum == 0 || (cksum & 0xff) != val) {
|
||||
aprint_debug("spd addr 0x%2x: ", sc.sc_addr);
|
||||
aprint_debug("spd checksum failed, calc = 0x%02x, "
|
||||
"spd = 0x%02x\n", cksum, val);
|
||||
return 0;
|
||||
@ -201,7 +176,7 @@ spdmem_match(device_t parent, cfdata_t match, void *aux)
|
||||
|
||||
/* For DDR3 and FBDIMM, verify the CRC */
|
||||
else if (spd_type <= SPDMEM_MEMTYPE_DDR3SDRAM) {
|
||||
spd_len = spdmem_read(&sc, 0);
|
||||
spd_len = (sc->sc_read)(sc, 0);
|
||||
if (spd_len && SPDMEM_SPDCRC_116)
|
||||
spd_crc_cover = 116;
|
||||
else
|
||||
@ -221,11 +196,10 @@ spdmem_match(device_t parent, cfdata_t match, void *aux)
|
||||
}
|
||||
if (spd_crc_cover > spd_len)
|
||||
return 0;
|
||||
crc_calc = spdcrc16(&sc, spd_crc_cover);
|
||||
crc_spd = spdmem_read(&sc, 127) << 8;
|
||||
crc_spd |= spdmem_read(&sc, 126);
|
||||
crc_calc = spdcrc16(sc, spd_crc_cover);
|
||||
crc_spd = (sc->sc_read)(sc, 127) << 8;
|
||||
crc_spd |= (sc->sc_read)(sc, 126);
|
||||
if (crc_calc != crc_spd) {
|
||||
aprint_debug("spd addr 0x%2x: ", sc.sc_addr);
|
||||
aprint_debug("crc16 failed, covers %d bytes, "
|
||||
"calc = 0x%04x, spd = 0x%04x\n",
|
||||
spd_crc_cover, crc_calc, crc_spd);
|
||||
@ -238,11 +212,9 @@ spdmem_match(device_t parent, cfdata_t match, void *aux)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
spdmem_attach(device_t parent, device_t self, void *aux)
|
||||
void
|
||||
spdmem_common_attach(struct spdmem_softc *sc, device_t self)
|
||||
{
|
||||
struct spdmem_softc *sc = device_private(self);
|
||||
struct i2c_attach_args *ia = aux;
|
||||
struct spdmem *s = &(sc->sc_spd_data);
|
||||
const char *type;
|
||||
const char *rambus_rev = "Reserved";
|
||||
@ -251,19 +223,13 @@ spdmem_attach(device_t parent, device_t self, void *aux)
|
||||
unsigned int spd_len, spd_size;
|
||||
const struct sysctlnode *node = NULL;
|
||||
|
||||
sc->sc_tag = ia->ia_tag;
|
||||
sc->sc_addr = ia->ia_addr;
|
||||
|
||||
if (!pmf_device_register(self, NULL, NULL))
|
||||
aprint_error_dev(self, "couldn't establish power handler\n");
|
||||
|
||||
/*
|
||||
* FBDIMM and DDR3 (and probably all newer) have a different
|
||||
* encoding of the SPD EEPROM used/total sizes
|
||||
*/
|
||||
s->sm_len = spdmem_read(sc, 0);
|
||||
s->sm_size = spdmem_read(sc, 1);
|
||||
s->sm_type = spdmem_read(sc, 2);
|
||||
s->sm_len = (sc->sc_read)(sc, 0);
|
||||
s->sm_size = (sc->sc_read)(sc, 1);
|
||||
s->sm_type = (sc->sc_read)(sc, 2);
|
||||
|
||||
if (s->sm_type >= SPDMEM_MEMTYPE_FBDIMM) {
|
||||
spd_size = 64 << (s->sm_len & SPDMEM_SPDSIZE_MASK);
|
||||
@ -292,7 +258,7 @@ spdmem_attach(device_t parent, device_t self, void *aux)
|
||||
if (spd_len > sizeof(struct spdmem))
|
||||
spd_len = sizeof(struct spdmem);
|
||||
for (i = 3; i < spd_len; i++)
|
||||
((uint8_t *)s)[i] = spdmem_read(sc, i);
|
||||
((uint8_t *)s)[i] = (sc->sc_read)(sc, i);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (i = 0; i < spd_len; i += 16) {
|
||||
@ -420,19 +386,6 @@ spdmem_attach(device_t parent, device_t self, void *aux)
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
spdmem_read(struct spdmem_softc *sc, uint8_t reg)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
iic_acquire_bus(sc->sc_tag, 0);
|
||||
iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, ®, 1,
|
||||
&val, 1, 0);
|
||||
iic_release_bus(sc->sc_tag, 0);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
SYSCTL_SETUP(sysctl_spdmem_setup, "sysctl hw.spdmem subtree setup")
|
||||
{
|
||||
const struct sysctlnode *node;
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: spdmemreg.h,v 1.3 2009/02/22 17:28:50 pgoyette Exp $ */
|
||||
/* $NetBSD: spdmemreg.h,v 1.1 2010/03/24 00:31:41 pgoyette Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Paul Goyette
|
||||
@ -28,10 +28,6 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Constants for matching i2c bus address */
|
||||
#define SPDMEM_ADDRMASK 0x78
|
||||
#define SPDMEM_ADDR 0x50
|
||||
|
||||
/* possible values for the memory type */
|
||||
#define SPDMEM_MEMTYPE_FPM 0x01
|
||||
#define SPDMEM_MEMTYPE_EDO 0x02
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: spdmemvar.h,v 1.7 2008/11/22 19:25:38 pgoyette Exp $ */
|
||||
/* $NetBSD: spdmemvar.h,v 1.1 2010/03/24 00:31:41 pgoyette Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Paul Goyette
|
||||
@ -514,9 +514,12 @@ struct spdmem {
|
||||
#define sm_selfrefresh sm_fpm.fpm_selfrefresh
|
||||
|
||||
#define SPDMEM_TYPE_MAXLEN 16
|
||||
|
||||
struct spdmem_softc {
|
||||
i2c_tag_t sc_tag;
|
||||
i2c_addr_t sc_addr;
|
||||
uint8_t (*sc_read)(struct spdmem_softc *, uint8_t);
|
||||
struct spdmem sc_spd_data;
|
||||
char sc_type[SPDMEM_TYPE_MAXLEN];
|
||||
};
|
||||
|
||||
int spdmem_common_probe(struct spdmem_softc *);
|
||||
void spdmem_common_attach(struct spdmem_softc *, device_t);
|
Loading…
Reference in New Issue
Block a user