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