device/dram/ddr2: Add common ddr2 spd decoder
Decode DDR2 SPD similar to DDR3 SPD decoder to ease readability, reduce code complexity and reduce size of maintainable code. Rename dimm_is_registered to spd_dimm_is_registered_ddr3 to avoid compilation errors. Change-Id: I741f0e61ab23e3999ae9e31f57228ba034c2509e Signed-off-by: Patrick Rudolph <siro@das-labor.org> Reviewed-on: https://review.coreboot.org/18273 Reviewed-by: Arthur Heymans <arthur@aheymans.xyz> Tested-by: build bot (Jenkins)
This commit is contained in:
committed by
Martin Roth
parent
7e4d12c5b1
commit
6e53ae6f5c
218
src/include/device/dram/ddr2.h
Normal file
218
src/include/device/dram/ddr2.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2017 Patrick Rudolph <siro@das-labor.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* JEDEC Standard No. 21-C
|
||||
* Annex J: Annex J: Serial Presence Detects for DDR2 SDRAM (Revision 1.3)
|
||||
*/
|
||||
|
||||
#ifndef DEVICE_DRAM_DDR2L_H
|
||||
#define DEVICE_DRAM_DDR2L_H
|
||||
|
||||
/**
|
||||
* @file ddr2.h
|
||||
*
|
||||
* \brief Utilities for decoding DDR2 SPDs
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <spd.h>
|
||||
|
||||
/**
|
||||
* \brief Convenience definitions for TCK values
|
||||
*
|
||||
* Different values for tCK, representing standard DDR2 frequencies.
|
||||
* These values are in 1/256 ns units.
|
||||
* @{
|
||||
*/
|
||||
#define TCK_800MHZ 320
|
||||
#define TCK_700MHZ 365
|
||||
#define TCK_666MHZ 384
|
||||
#define TCK_533MHZ 480
|
||||
#define TCK_400MHZ 640
|
||||
#define TCK_333MHZ 768
|
||||
#define TCK_266MHZ 960
|
||||
#define TCK_200MHZ 1280
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \brief Convenience macro for enabling printk with CONFIG_DEBUG_RAM_SETUP
|
||||
*
|
||||
* Use this macro instead of printk(); for verbose RAM initialization messages.
|
||||
* When CONFIG_DEBUG_RAM_SETUP is not selected, these messages are automatically
|
||||
* disabled.
|
||||
* @{
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_DEBUG_RAM_SETUP)
|
||||
#define printram(x, ...) printk(BIOS_DEBUG, x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define printram(x, ...)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
* Module type (byte 20, bits 5:0) of SPD
|
||||
* This definition is specific to DDR2. DDR3 SPDs have a different structure.
|
||||
*/
|
||||
enum spd_dimm_type {
|
||||
SPD_DIMM_TYPE_UNDEFINED = 0x00,
|
||||
SPD_DIMM_TYPE_RDIMM = 0x01,
|
||||
SPD_DIMM_TYPE_UDIMM = 0x02,
|
||||
SPD_DIMM_TYPE_SO_DIMM = 0x04,
|
||||
SPD_DIMM_TYPE_72B_SO_CDIMM = 0x06,
|
||||
SPD_DIMM_TYPE_72B_SO_RDIMM = 0x07,
|
||||
SPD_DIMM_TYPE_MICRO_DIMM = 0x08,
|
||||
SPD_DIMM_TYPE_MINI_DIMM = 0x10,
|
||||
SPD_DIMM_TYPE_MINI_UDIMM = 0x20,
|
||||
/* Masks to bits 5:0 to give the dimm type */
|
||||
SPD_DIMM_TYPE_MASK = 0x3f,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief DIMM flags
|
||||
*
|
||||
* Characteristic flags for the DIMM, as presented by the SPD
|
||||
*/
|
||||
union dimm_flags_st {
|
||||
/* The whole point of the union/struct construct is to allow us to clear
|
||||
* all the bits with one line: flags.raw = 0.
|
||||
* We do not care how these bits are ordered */
|
||||
struct {
|
||||
/* Module can work at 5.00V */
|
||||
unsigned operable_5_00V:1;
|
||||
/* Module can work at 3.33V */
|
||||
unsigned operable_3_33V:1;
|
||||
/* Module can work at 2.50V */
|
||||
unsigned operable_2_50V:1;
|
||||
/* Module can work at 1.80V - All DIMMS must be 1.8V operable */
|
||||
unsigned operable_1_80V:1;
|
||||
/* Module can work at 1.50V */
|
||||
unsigned operable_1_50V:1;
|
||||
/* Module can work at 1.35V */
|
||||
unsigned operable_1_35V:1;
|
||||
/* Module can work at 1.20V */
|
||||
unsigned operable_1_25V:1;
|
||||
/* Has an 8-bit bus extension, meaning the DIMM supports ECC */
|
||||
unsigned is_ecc:1;
|
||||
/* Supports weak driver */
|
||||
unsigned weak_driver:1;
|
||||
/* Supports terminating at 50 Ohm */
|
||||
unsigned terminate_50ohms:1;
|
||||
/* Partial Array Self Refresh */
|
||||
unsigned pasr:1;
|
||||
/* Supports burst length 8 */
|
||||
unsigned bl8:1;
|
||||
/* Supports burst length 4 */
|
||||
unsigned bl4:1;
|
||||
/* DIMM Package is stack */
|
||||
unsigned stacked:1;
|
||||
};
|
||||
unsigned int raw;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief DIMM characteristics
|
||||
*
|
||||
* The characteristics of each DIMM, as presented by the SPD
|
||||
*/
|
||||
struct dimm_attr_st {
|
||||
enum spd_memory_type dram_type;
|
||||
enum spd_dimm_type dimm_type;
|
||||
/* BCD SPD revision */
|
||||
u8 rev;
|
||||
/* Supported CAS mask, bit 0 == CL0 .. bit7 == CL7 */
|
||||
u8 cas_supported;
|
||||
/* Maximum cloclk to data cycle times for various CAS.
|
||||
* Fields 0 and 1 are unused. */
|
||||
u32 cycle_time[8];
|
||||
/* Maximum data access times for various CAS.
|
||||
* Fields 0 and 1 are unused. */
|
||||
u32 access_time[8];
|
||||
/* Flags extracted from SPD */
|
||||
union dimm_flags_st flags;
|
||||
/* Number of banks */
|
||||
u8 banks;
|
||||
/* SDRAM width */
|
||||
u8 width;
|
||||
/* Module width */
|
||||
u8 mod_width;
|
||||
/* Number of ranks */
|
||||
u8 ranks;
|
||||
/* Number or row address bits */
|
||||
u8 row_bits;
|
||||
/* Number or column address bits */
|
||||
u8 col_bits;
|
||||
/* Number of PLLs on module */
|
||||
u8 plls;
|
||||
/* Size of module in MiB */
|
||||
u16 size_mb;
|
||||
/* Size of one rank in MiB */
|
||||
u16 ranksize_mb;
|
||||
/* Latencies are in units of 1/256 ns */
|
||||
u32 tCK;
|
||||
u32 tWR;
|
||||
u32 tRCD;
|
||||
u32 tRRD;
|
||||
u32 tRP;
|
||||
u32 tRAS;
|
||||
u32 tIS;
|
||||
u32 tIH;
|
||||
u32 tDS;
|
||||
u32 tDH;
|
||||
|
||||
u32 tRC;
|
||||
u32 tRFC;
|
||||
u32 tWTR;
|
||||
u32 tRTP;
|
||||
u32 tDQSQ;
|
||||
u32 tQHS;
|
||||
|
||||
/* Latencies are in units of 1/256 us */
|
||||
u32 tPLL;
|
||||
u32 tRR;
|
||||
|
||||
/* Manufacturer ID */
|
||||
u32 manufacturer_id;
|
||||
/* ASCII part number - NULL terminated */
|
||||
u8 part_number[17];
|
||||
/* Year manufactured */
|
||||
u16 year;
|
||||
/* Week manufactured */
|
||||
u8 weeks;
|
||||
/* Unique serial number */
|
||||
u32 serial;
|
||||
};
|
||||
|
||||
/** Result of the SPD decoding process */
|
||||
enum spd_status {
|
||||
SPD_STATUS_OK = 0,
|
||||
SPD_STATUS_INVALID,
|
||||
SPD_STATUS_CRC_ERROR,
|
||||
SPD_STATUS_INVALID_FIELD,
|
||||
};
|
||||
|
||||
/** Maximum SPD size supported */
|
||||
#define SPD_SIZE_MAX_DDR2 128
|
||||
|
||||
int spd_dimm_is_registered_ddr2(enum spd_dimm_type type);
|
||||
u8 spd_ddr2_calc_checksum(u8 *spd, int len);
|
||||
u32 spd_decode_spd_size_ddr2(u8 byte0);
|
||||
u32 spd_decode_eeprom_size_ddr2(u8 byte1);
|
||||
int spd_decode_ddr2(struct dimm_attr_st *dimm, u8 spd[SPD_SIZE_MAX_DDR2]);
|
||||
void dram_print_spd_ddr2(const struct dimm_attr_st *dimm);
|
||||
|
||||
|
||||
#endif /* DEVICE_DRAM_DDR2L_H */
|
@@ -201,7 +201,7 @@ typedef u8 spd_raw_data[256];
|
||||
u16 spd_ddr3_calc_crc(u8 *spd, int len);
|
||||
u16 spd_ddr3_calc_unique_crc(u8 *spd, int len);
|
||||
int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd_data);
|
||||
int dimm_is_registered(enum spd_dimm_type type);
|
||||
int spd_dimm_is_registered_ddr3(enum spd_dimm_type type);
|
||||
void dram_print_spd_ddr3(const dimm_attr * dimm);
|
||||
int spd_xmp_decode_ddr3(dimm_attr * dimm,
|
||||
spd_raw_data spd,
|
||||
|
Reference in New Issue
Block a user