blob: 2c74cb1aa1d9f22f1cab2c882387aca08108d785 [file] [log] [blame]
/* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
* OWNER 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.
*
* DDR3 field access for DDR3 SPDs.
*/
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mosys/platform.h"
#include "mosys/kv_pair.h"
#include "mosys/log.h"
#include "lib/string.h"
#include "lib/ddr3.h"
#include "lib/spd.h"
#include "lib/val2str.h"
#include "jedec_id.h"
/*
* spd_print_field_ddr3 - add common DDR SPD fields into key=value pair
*
* @intf: platform interface
* @kv: key=value pair
* @data: raw spd data
* @type: type of field to retrieve
*
* returns 1 to indicate data added to key=value pair
* returns 0 to indicate no data added
* returns <0 to indicate error
*
*/
int spd_print_field_ddr3(struct platform_intf *intf, struct kv_pair *kv,
const void *data, enum spd_field_type type)
{
int ret;
const uint8_t *byte = data;
ret = 0;
switch (type) {
case SPD_GET_DRAM_TYPE:
kv_pair_add(kv, "dram",
(byte[DDR3_SPD_REG_DEVICE_TYPE] ==
SPD_DRAM_TYPE_LPDDR3) ? "LPDDR3" : "DDR3");
ret = 1;
break;
case SPD_GET_MODULE_TYPE:
kv_pair_add(kv, "module",
val2str(byte[DDR3_SPD_REG_MODULE_TYPE],
ddr3_module_type_lut));
ret = 1;
break;
case SPD_GET_MFG_ID:
{
uint8_t manuf_lsb;
uint8_t manuf_msb;
const char *tstr;
manuf_lsb = byte[DDR3_SPD_REG_MODULE_MANUF_JEDEC_ID_LSB] & 0x7f;
manuf_msb = byte[DDR3_SPD_REG_MODULE_MANUF_JEDEC_ID_MSB] & 0x7f;
tstr = jedec_manufacturer(manuf_lsb, manuf_msb);
if (tstr != NULL) {
kv_pair_fmt(kv, "module_mfg", "%u-%u: %s", manuf_lsb + 1,
manuf_msb, tstr);
} else {
kv_pair_fmt(kv, "module_mfg", "%u-%u", manuf_lsb + 1,
manuf_msb);
}
ret = 1;
break;
}
case SPD_GET_PART_NUMBER:
{
char part[19];
memcpy(part, &byte[DDR3_SPD_REG_MODULE_PART_NUM_0], 18);
part[18] = '\0';
kv_pair_fmt(kv, "part_number", "%s", part);
ret = 1;
break;
}
case SPD_GET_SIZE:
{
/* See "Calculating Module Capacity" section in DDR3 SPD
* specification for details. */
unsigned int size;
/* calculate the total size in MB */
size = 256 << (byte[DDR3_SPD_REG_DENSITY_BANKS] & 0xf);
size >>= 3; /* in terms of bytes instead of bits. */
size *= 8 << (byte[DDR3_SPD_REG_MODULE_BUS_WIDTH] & 0x7);
size /= 4 << (byte[DDR3_SPD_REG_MODULE_ORG] & 0x7);
size *= 1 + ((byte[DDR3_SPD_REG_MODULE_ORG] >> 3) & 0x7);
kv_pair_fmt(kv, "size_mb", "%u", size);
ret = 1;
break;
}
case SPD_GET_RANKS:
{
kv_pair_fmt(kv, "ranks", "%d",
1 + ((byte[DDR3_SPD_REG_MODULE_ORG] >> 3) & 0x7));
ret = 1;
break;
}
case SPD_GET_WIDTH:
{
/* Total width including ECC. */
uint8_t width;
width = 8 << (byte[DDR3_SPD_REG_MODULE_BUS_WIDTH] & 0x7);
width += 8 * ((byte[DDR3_SPD_REG_MODULE_BUS_WIDTH] >> 3) & 0x7);
kv_pair_fmt(kv, "width", "%d", width);
ret = 1;
break;
}
default:
{
ret = 0; /* force "we don't handle this here */
break;
}
}
return ret;
}