Hi List,
with commit 164bcfdd1b0b2cc789203eeb9e3ff842df215a7c ("Add automatic
SMBIOS table generation") i've introduced a new member
'(*get_smbios_data) in struct device_operations / struct chip_operations.
We might use that now to generate SMBIOS tables based on device drivers.
I've just implement a quick'n'dirty pseudo driver, which reads the SPD
EEPROM of memory devices, and automatically generates the SMBIOS
type16/type17 tables.
All what's needed in the devicetree.cb are the following lines:
-----------------------8<-----------------------
device pci 1f.3 on # SMBUS controller the SPD EEPROMs are behind
chip drivers/i2c/dramspd
register "memtype" = "SMBIOS_MEMORY_FORM_FACTOR_SODIMM"
device i2c 50 on end # All possible SPD addresses
device i2c 51 on end # listed here
end
-----------------------8<-----------------------
The generated output looks like this on my Thinkpad T60:
(Handle 0005,0006,0007 are the new ones)
$ sudo dmidecode
# dmidecode 2.11
SMBIOS 2.7 present.
9 structures occupying 389 bytes.
Table at 0xCFEFD820.
Handle 0x0000, DMI type 0, 24 bytes
BIOS Information
Vendor: coreboot
Version: 4.0-1784-gbd6d870-dirty
Release Date: 10/24/2011
ROM Size: 2048 kB
Characteristics:
PCI is supported
PC Card (PCMCIA) is supported
BIOS is upgradeable
Selectable boot is supported
ACPI is supported
Targeted content distribution is supported
BIOS Revision: 4.0
Firmware Revision: 0.0
Handle 0x0001, DMI type 1, 27 bytes
System Information
Manufacturer: Lenovo
Product Name: ThinkPad T60 / T60p
Version: Not Specified
Serial Number: Not Specified
UUID: Not Settable
Wake-up Type: Reserved
SKU Number: Not Specified
Family: Not Specified
Handle 0x0002, DMI type 3, 21 bytes
Chassis Information
Manufacturer: Lenovo
Type: Desktop
Lock: Not Present
Version: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Boot-up State: Safe
Power Supply State: Safe
Thermal State: Safe
Security Status: None
OEM Information: 0x00000000
Height: Unspecified
Number Of Power Cords: Unspecified
Contained Elements: 0
Handle 0x0003, DMI type 4, 42 bytes
Processor Information
Socket Designation: Not Specified
Type: Central Processor
Family: Pentium Pro
Manufacturer: GenuineIntel
ID: F6 06 00 00 FF FB EB BF
Signature: Type 0, Family 6, Model 15, Stepping 6
Flags:
FPU (Floating-point unit on-chip)
VME (Virtual mode extension)
DE (Debugging extension)
PSE (Page size extension)
TSC (Time stamp counter)
MSR (Model specific registers)
PAE (Physical address extension)
MCE (Machine check exception)
CX8 (CMPXCHG8 instruction supported)
APIC (On-chip APIC hardware supported)
SEP (Fast system call)
MTRR (Memory type range registers)
PGE (Page global enable)
MCA (Machine check architecture)
CMOV (Conditional move instruction supported)
PAT (Page attribute table)
PSE-36 (36-bit page size extension)
CLFSH (CLFLUSH instruction supported)
DS (Debug store)
ACPI (ACPI supported)
MMX (MMX technology supported)
FXSR (FXSAVE and FXSTOR instructions supported)
SSE (Streaming SIMD extensions)
SSE2 (Streaming SIMD extensions 2)
SS (Self-snoop)
HTT (Multi-threading)
TM (Thermal monitor supported)
PBE (Pending break enabled)
Version: Intel(R) Core(TM)2 CPU T7200 @ 2.00GHz
Voltage: Unknown
External Clock: Unknown
Max Speed: Unknown
Current Speed: Unknown
Status: Unpopulated
Upgrade: Other
L1 Cache Handle: Not Provided
L2 Cache Handle: Not Provided
L3 Cache Handle: Not Provided
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Core Count: 2
Characteristics: None
Handle 0x0004, DMI type 32, 11 bytes
System Boot Information
Status: No errors detected
Handle 0x0005, DMI type 16, 23 bytes
Physical Memory Array
Location: System Board Or Motherboard
Use: System Memory
Error Correction Type: Unknown
Maximum Capacity: 4 GB
Error Information Handle: Not Provided
Number Of Devices: 2
Handle 0x0006, DMI type 17, 32 bytes
Memory Device
Array Handle: 0x0005
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: SODIMM
Set: None
Locator: I2C: 01:50
Bank Locator: Not Specified
Type: DDR2
Type Detail: Unbuffered (Unregistered)
Speed: Unknown
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Handle 0x0007, DMI type 17, 32 bytes
Memory Device
Array Handle: 0x0005
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: SODIMM
Set: None
Locator: I2C: 01:51
Bank Locator: Not Specified
Type: DDR2
Type Detail: Unbuffered (Unregistered)
Speed: Unknown
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Handle 0x0008, DMI type 127, 4 bytes
End Of Table
There are a few fields missing in the output, which i have to add to the
driver. I'll need to clea nup the patch a bit, and finish it.
I just want to know your opinions on that topic before submitting it.
And here's the Ha^H^Hpatch:
diff --git a/src/drivers/i2c/Kconfig b/src/drivers/i2c/Kconfig
index 91ad025..4aefc96 100644
--- a/src/drivers/i2c/Kconfig
+++ b/src/drivers/i2c/Kconfig
@@ -4,3 +4,4 @@ source src/drivers/i2c/adt7463/Kconfig
source src/drivers/i2c/i2cmux/Kconfig
source src/drivers/i2c/i2cmux2/Kconfig
source src/drivers/i2c/lm63/Kconfig
+source src/drivers/i2c/dramspd/Kconfig
diff --git a/src/drivers/i2c/Makefile.inc b/src/drivers/i2c/Makefile.inc
index d462b69..f2a53fa 100644
--- a/src/drivers/i2c/Makefile.inc
+++ b/src/drivers/i2c/Makefile.inc
@@ -4,3 +4,4 @@ subdirs-y += adt7463
subdirs-y += i2cmux
subdirs-y += i2cmux2
subdirs-y += lm63
+subdirs-y += dramspd
diff --git a/src/drivers/i2c/dramspd/Kconfig
b/src/drivers/i2c/dramspd/Kconfig
new file mode 100644
index 0000000..2f76a85
--- /dev/null
+++ b/src/drivers/i2c/dramspd/Kconfig
@@ -0,0 +1,2 @@
+config DRIVERS_I2C_DRAMSPD
+ bool
diff --git a/src/drivers/i2c/dramspd/Makefile.inc
b/src/drivers/i2c/dramspd/Makefile.inc
new file mode 100644
index 0000000..29fd0ee
--- /dev/null
+++ b/src/drivers/i2c/dramspd/Makefile.inc
@@ -0,0 +1 @@
+driver-$(CONFIG_DRIVERS_I2C_DRAMSPD) += dramspd.c
diff --git a/src/drivers/i2c/dramspd/chip.h b/src/drivers/i2c/dramspd/chip.h
new file mode 100644
index 0000000..25f4a0f
--- /dev/null
+++ b/src/drivers/i2c/dramspd/chip.h
@@ -0,0 +1,7 @@
+extern struct chip_operations drivers_i2c_dramspd_ops;
+
+#include <smbios.h>
+
+struct drivers_i2c_dramspd_config {
+ smbios_memory_form_factor_t memtype;
+};
diff --git a/src/drivers/i2c/dramspd/dramspd.c
b/src/drivers/i2c/dramspd/dramspd.c
new file mode 100644
index 0000000..6a8a06a
--- /dev/null
+++ b/src/drivers/i2c/dramspd/dramspd.c
@@ -0,0 +1,115 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/smbus.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <smbios.h>
+#include <string.h>
+#include <spd.h>
+#include "chip.h"
+
+static struct smbios_type16 *global_smbios_type16;
+
+static int dramspd_fill_type16(device_t dev, int *handle, unsigned long
*current)
+{
+ struct smbios_type16 *t;
+ int len;
+
+ if (global_smbios_type16)
+ return 0;
+
+ t = (struct smbios_type16 *)*current;
+ global_smbios_type16 = t;
+
+ len = sizeof(struct smbios_type16);
+ memset(t, 0, len);
+ t->type = SMBIOS_PHYS_MEMORY_ARRAY;
+ t->length = len - 2;
+ t->handle = (*handle)++;
+ t->location = 3; // System Board
+ t->use = 3; // System Memory
+ t->memory_error_correction = 2;
+ t->memory_error_information_handle = 0xfffe;
+ *current += len;
+ return len;
+}
+
+static int dramspd_get_smbios_data(device_t dev, int *handle, unsigned
long *current)
+{
+ struct smbios_type17 *t;
+ struct drivers_i2c_dramspd_config *config = dev->chip_info;
+ int len, features, eccwidth, type16len;
+ u64 size;
+ int rows, columns, banks, numdimmbanks;
+
+ type16len = dramspd_fill_type16(dev, handle, current);
+
+ t = (struct smbios_type17 *)*current;
+ len = sizeof(struct smbios_type17);
+ memset(t, 0, len);
+ t->type = SMBIOS_MEMORY_DEVICE;
+ t->length = len - 2;
+
+ switch(smbus_read_byte(dev, SPD_MEMORY_TYPE)) {
+ case SPD_MEMORY_TYPE_FPM_DRAM:
+ t->memory_type = SMBIOS_MEMORY_TYPE_DRAM;
+ t->type_detail |= (1 << 3); // FAST PAGED
+ break;
+ case SPD_MEMORY_TYPE_EDO:
+ t->memory_type = SMBIOS_MEMORY_TYPE_EDRAM;
+ t->type_detail |= (1 << 9); // EDO
+ break;
+ case SPD_MEMORY_TYPE_SDRAM:
+ t->memory_type = SMBIOS_MEMORY_TYPE_SDRAM;
+ t->type_detail |= (1 << 7); // SYNC
+ break;
+ case SPD_MEMORY_TYPE_SDRAM_DDR2:
+ t->memory_type = SMBIOS_MEMORY_TYPE_DDR2;
+ t->type_detail |= (1 << 7); // SYNC
+ break;
+ case SPD_MEMORY_TYPE_SDRAM_DDR3:
+ t->memory_type = SMBIOS_MEMORY_TYPE_DDR3;
+ t->type_detail |= (1 << 7); // SYNC
+ default:
+ return 0;
+ }
+
+ t->device_locator = smbios_add_string(t->eos, dev_path(dev));
+ t->data_width = smbus_read_byte(dev, SPD_MODULE_DATA_WIDTH_LSB);
+ t->data_width |= (smbus_read_byte(dev,
SPD_MODULE_DATA_WIDTH_MSB) << 8);
+ eccwidth = smbus_read_byte(dev, SPD_ERROR_CHECKING_SDRAM_WIDTH);
+
+ rows = smbus_read_byte(dev, SPD_NUM_ROWS) & 0xf;
+ columns = smbus_read_byte(dev, SPD_NUM_COLUMNS) & 0xf;
+ banks = smbus_read_byte(dev, SPD_NUM_BANKS_PER_SDRAM);
+ numdimmbanks = (smbus_read_byte(dev, SPD_NUM_DIMM_BANKS) & 0x7) + 1;
+
+ if (!(rows && columns && banks && t->data_width))
+ return 0;
+
+ size = 1ULL << (rows + columns);
+ size *= (u64)((t->data_width / 8) * banks * numdimmbanks);
+
+ printk(BIOS_ERR, "%d rows, %d columns, %d banks, t->data_width
%d %lld\n",
+ rows, columns, banks, t->data_width, size);
+
+ t->total_width = eccwidth ? eccwidth : t->data_width;
+ t->form_factor = config->memtype;
+ t->memory_error_information_handle = 0xfffe;
+ features = smbus_read_byte(dev, SPD_MODULE_ATTRIBUTES);
+ t->type_detail = (features & 9) ? (1 << 13) : (1 << 14);
+ t->handle = (*handle)++;
+ t->phys_memory_array_handle = global_smbios_type16->handle;
+ t->size = (u16)(size/1048576);
+ global_smbios_type16->maximum_capacity += (u32)size/1024;
+ global_smbios_type16->number_of_memory_devices++;
+ len = t->length + smbios_string_table_len(t->eos);
+ *current += len;
+ return len + type16len;
+}
+
+struct chip_operations drivers_i2c_dramspd_ops = {
+ CHIP_NAME("Generic DRAM SPD")
+ .get_smbios_data = dramspd_get_smbios_data,
+};
diff --git a/src/include/smbios.h b/src/include/smbios.h
index f13d621..6ac8628 100644
--- a/src/include/smbios.h
+++ b/src/include/smbios.h
@@ -20,7 +20,35 @@ int smbios_string_table_len(char *start);
#define BIOS_EXT1_CHARACTERISTICS_ACPI (1 << 0)
#define BIOS_EXT2_CHARACTERISTICS_TARGET (1 << 2)
+#define SMBIOS_MEMORY_TYPE_DRAM 0x03
+#define SMBIOS_MEMORY_TYPE_EDRAM 0x04
+#define SMBIOS_MEMORY_TYPE_VRAM 0x05
+#define SMBIOS_MEMORY_TYPE_SRAM 0x06
+#define SMBIOS_MEMORY_TYPE_RAM 0x07
+#define SMBIOS_MEMORY_TYPE_ROM 0x08
+#define SMBIOS_MEMORY_TYPE_FLASH 0x09
+#define SMBIOS_MEMORY_TYPE_EEPROM 0x0a
+#define SMBIOS_MEMORY_TYPE_FEPROM 0x0b
+#define SMBIOS_MEMORY_TYPE_EPROM 0x0c
+#define SMBIOS_MEMORY_TYPE_CDRAM 0x0d
+#define SMBIOS_MEMORY_TYPE_3DRAM 0x0e
+#define SMBIOS_MEMORY_TYPE_SDRAM 0x0f
+#define SMBIOS_MEMORY_TYPE_SGRAM 0x10
+#define SMBIOS_MEMORY_TYPE_RDRAM 0x11
+#define SMBIOS_MEMORY_TYPE_DDR 0x12
+#define SMBIOS_MEMORY_TYPE_DDR2 0x13
+#define SMBIOS_MEMORY_TYPE_DDR2_FBDIMM 0x14
+#define SMBIOS_MEMORY_TYPE_DDR3 0x18
+#define SMBIOS_MEMORY_TYPE_FBD2
+
+
#define SMBIOS_STATE_SAFE 3
+
+typedef enum {
+ SMBIOS_MEMORY_FORM_FACTOR_DIMM=9,
+ SMBIOS_MEMORY_FORM_FACTOR_SODIMM=0x0d,
+ SMBIOS_MEMORY_FORM_FACTOR_FBDIMM=0x0f,
+} smbios_memory_form_factor_t;
+
typedef enum {
SMBIOS_BIOS_INFORMATION=0,
SMBIOS_SYSTEM_INFORMATION=1,
diff --git a/src/mainboard/lenovo/t60/Kconfig
b/src/mainboard/lenovo/t60/Kconfig
index 9deb5a3..864fbf1 100644
--- a/src/mainboard/lenovo/t60/Kconfig
+++ b/src/mainboard/lenovo/t60/Kconfig
@@ -13,6 +13,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
select EC_LENOVO_PMH7
select EC_LENOVO_H8
select DRIVERS_ICS_954309
+ select DRIVERS_I2C_DRAMSPD
select BOARD_HAS_FADT
select HAVE_OPTION_TABLE
select HAVE_PIRQ_TABLE
diff --git a/src/mainboard/lenovo/t60/devicetree.cb
b/src/mainboard/lenovo/t60/devicetree.cb
index dba3fdd..92852c3 100644
--- a/src/mainboard/lenovo/t60/devicetree.cb
+++ b/src/mainboard/lenovo/t60/devicetree.cb
@@ -214,6 +214,11 @@ chip northbridge/intel/i945
register "reg11" = "0x07"
device i2c 69 on end
end
+ chip drivers/i2c/dramspd
+ register "memtype" =
"SMBIOS_MEMORY_FORM_FACTOR_SODIMM"
+ device i2c 50 on end
+ device i2c 51 on end
+ end
end
end
end
Cheers,
Sven