123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) Marvell International Ltd. and its affiliates
- */
- #include "mv_ddr_spd.h"
- #define MV_DDR_SPD_DATA_MTB 125 /* medium timebase, ps */
- #define MV_DDR_SPD_DATA_FTB 1 /* fine timebase, ps */
- #define MV_DDR_SPD_MSB_OFFS 8 /* most significant byte offset, bits */
- #define MV_DDR_SPD_SUPPORTED_CLS_NUM 30
- static unsigned int mv_ddr_spd_supported_cls[MV_DDR_SPD_SUPPORTED_CLS_NUM];
- int mv_ddr_spd_supported_cls_calc(union mv_ddr_spd_data *spd_data)
- {
- unsigned int byte, bit, start_cl;
- start_cl = (spd_data->all_bytes[23] & 0x8) ? 23 : 7;
- for (byte = 20; byte < 23; byte++) {
- for (bit = 0; bit < 8; bit++) {
- if (spd_data->all_bytes[byte] & (1 << bit))
- mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = start_cl + (byte - 20) * 8 + bit;
- else
- mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = 0;
- }
- }
- for (byte = 23, bit = 0; bit < 6; bit++) {
- if (spd_data->all_bytes[byte] & (1 << bit))
- mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = start_cl + (byte - 20) * 8 + bit;
- else
- mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = 0;
- }
- return 0;
- }
- unsigned int mv_ddr_spd_supported_cl_get(unsigned int cl)
- {
- unsigned int supported_cl;
- int i = 0;
- while (i < MV_DDR_SPD_SUPPORTED_CLS_NUM &&
- mv_ddr_spd_supported_cls[i] < cl)
- i++;
- if (i < MV_DDR_SPD_SUPPORTED_CLS_NUM)
- supported_cl = mv_ddr_spd_supported_cls[i];
- else
- supported_cl = 0;
- return supported_cl;
- }
- int mv_ddr_spd_timing_calc(union mv_ddr_spd_data *spd_data, unsigned int timing_data[])
- {
- int calc_val;
- /* t ck avg min, ps */
- calc_val = spd_data->byte_fields.byte_18 * MV_DDR_SPD_DATA_MTB +
- (signed char)spd_data->byte_fields.byte_125 * MV_DDR_SPD_DATA_FTB;
- if (calc_val < 0)
- return 1;
- timing_data[MV_DDR_TCK_AVG_MIN] = calc_val;
- /* t aa min, ps */
- calc_val = spd_data->byte_fields.byte_24 * MV_DDR_SPD_DATA_MTB +
- (signed char)spd_data->byte_fields.byte_123 * MV_DDR_SPD_DATA_FTB;
- if (calc_val < 0)
- return 1;
- timing_data[MV_DDR_TAA_MIN] = calc_val;
- /* t rfc1 min, ps */
- timing_data[MV_DDR_TRFC1_MIN] = (spd_data->byte_fields.byte_30 +
- (spd_data->byte_fields.byte_31 << MV_DDR_SPD_MSB_OFFS)) * MV_DDR_SPD_DATA_MTB;
- /* t wr min, ps */
- timing_data[MV_DDR_TWR_MIN] = (spd_data->byte_fields.byte_42 +
- (spd_data->byte_fields.byte_41.bit_fields.t_wr_min_msn << MV_DDR_SPD_MSB_OFFS)) *
- MV_DDR_SPD_DATA_MTB;
- /* FIXME: wa: set twr to a default value, if it's unset on spd */
- if (timing_data[MV_DDR_TWR_MIN] == 0)
- timing_data[MV_DDR_TWR_MIN] = 15000;
- /* t rcd min, ps */
- calc_val = spd_data->byte_fields.byte_25 * MV_DDR_SPD_DATA_MTB +
- (signed char)spd_data->byte_fields.byte_122 * MV_DDR_SPD_DATA_FTB;
- if (calc_val < 0)
- return 1;
- timing_data[MV_DDR_TRCD_MIN] = calc_val;
- /* t rp min, ps */
- calc_val = spd_data->byte_fields.byte_26 * MV_DDR_SPD_DATA_MTB +
- (signed char)spd_data->byte_fields.byte_121 * MV_DDR_SPD_DATA_FTB;
- if (calc_val < 0)
- return 1;
- timing_data[MV_DDR_TRP_MIN] = calc_val;
- /* t rc min, ps */
- calc_val = (spd_data->byte_fields.byte_29 +
- (spd_data->byte_fields.byte_27.bit_fields.t_rc_min_msn << MV_DDR_SPD_MSB_OFFS)) *
- MV_DDR_SPD_DATA_MTB +
- (signed char)spd_data->byte_fields.byte_120 * MV_DDR_SPD_DATA_FTB;
- if (calc_val < 0)
- return 1;
- timing_data[MV_DDR_TRC_MIN] = calc_val;
- /* t ras min, ps */
- timing_data[MV_DDR_TRAS_MIN] = (spd_data->byte_fields.byte_28 +
- (spd_data->byte_fields.byte_27.bit_fields.t_ras_min_msn << MV_DDR_SPD_MSB_OFFS)) *
- MV_DDR_SPD_DATA_MTB;
- /* t rrd s min, ps */
- calc_val = spd_data->byte_fields.byte_38 * MV_DDR_SPD_DATA_MTB +
- (signed char)spd_data->byte_fields.byte_119 * MV_DDR_SPD_DATA_FTB;
- if (calc_val < 0)
- return 1;
- timing_data[MV_DDR_TRRD_S_MIN] = calc_val;
- /* t rrd l min, ps */
- calc_val = spd_data->byte_fields.byte_39 * MV_DDR_SPD_DATA_MTB +
- (signed char)spd_data->byte_fields.byte_118 * MV_DDR_SPD_DATA_FTB;
- if (calc_val < 0)
- return 1;
- timing_data[MV_DDR_TRRD_L_MIN] = calc_val;
- /* t faw min, ps */
- timing_data[MV_DDR_TFAW_MIN] = (spd_data->byte_fields.byte_37 +
- (spd_data->byte_fields.byte_36.bit_fields.t_faw_min_msn << MV_DDR_SPD_MSB_OFFS)) *
- MV_DDR_SPD_DATA_MTB;
- /* t wtr s min, ps */
- timing_data[MV_DDR_TWTR_S_MIN] = (spd_data->byte_fields.byte_44 +
- (spd_data->byte_fields.byte_43.bit_fields.t_wtr_s_min_msn << MV_DDR_SPD_MSB_OFFS)) *
- MV_DDR_SPD_DATA_MTB;
- /* FIXME: wa: set twtr_s to a default value, if it's unset on spd */
- if (timing_data[MV_DDR_TWTR_S_MIN] == 0)
- timing_data[MV_DDR_TWTR_S_MIN] = 2500;
- /* t wtr l min, ps */
- timing_data[MV_DDR_TWTR_L_MIN] = (spd_data->byte_fields.byte_45 +
- (spd_data->byte_fields.byte_43.bit_fields.t_wtr_l_min_msn << MV_DDR_SPD_MSB_OFFS)) *
- MV_DDR_SPD_DATA_MTB;
- /* FIXME: wa: set twtr_l to a default value, if it's unset on spd */
- if (timing_data[MV_DDR_TWTR_L_MIN] == 0)
- timing_data[MV_DDR_TWTR_L_MIN] = 7500;
- return 0;
- }
- enum mv_ddr_dev_width mv_ddr_spd_dev_width_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char dev_width = spd_data->byte_fields.byte_12.bit_fields.device_width;
- enum mv_ddr_dev_width ret_val;
- switch (dev_width) {
- case 0x00:
- ret_val = MV_DDR_DEV_WIDTH_4BIT;
- break;
- case 0x01:
- ret_val = MV_DDR_DEV_WIDTH_8BIT;
- break;
- case 0x02:
- ret_val = MV_DDR_DEV_WIDTH_16BIT;
- break;
- case 0x03:
- ret_val = MV_DDR_DEV_WIDTH_32BIT;
- break;
- default:
- ret_val = MV_DDR_DEV_WIDTH_LAST;
- }
- return ret_val;
- }
- enum mv_ddr_die_capacity mv_ddr_spd_die_capacity_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char die_cap = spd_data->byte_fields.byte_4.bit_fields.die_capacity;
- enum mv_ddr_die_capacity ret_val;
- switch (die_cap) {
- case 0x00:
- ret_val = MV_DDR_DIE_CAP_256MBIT;
- break;
- case 0x01:
- ret_val = MV_DDR_DIE_CAP_512MBIT;
- break;
- case 0x02:
- ret_val = MV_DDR_DIE_CAP_1GBIT;
- break;
- case 0x03:
- ret_val = MV_DDR_DIE_CAP_2GBIT;
- break;
- case 0x04:
- ret_val = MV_DDR_DIE_CAP_4GBIT;
- break;
- case 0x05:
- ret_val = MV_DDR_DIE_CAP_8GBIT;
- break;
- case 0x06:
- ret_val = MV_DDR_DIE_CAP_16GBIT;
- break;
- case 0x07:
- ret_val = MV_DDR_DIE_CAP_32GBIT;
- break;
- case 0x08:
- ret_val = MV_DDR_DIE_CAP_12GBIT;
- break;
- case 0x09:
- ret_val = MV_DDR_DIE_CAP_24GBIT;
- break;
- default:
- ret_val = MV_DDR_DIE_CAP_LAST;
- }
- return ret_val;
- }
- unsigned char mv_ddr_spd_mem_mirror_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char mem_mirror = spd_data->byte_fields.byte_131.bit_fields.rank_1_mapping;
- return mem_mirror;
- }
- enum mv_ddr_pkg_rank mv_ddr_spd_pri_bus_width_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char pri_bus_width = spd_data->byte_fields.byte_13.bit_fields.primary_bus_width;
- enum mv_ddr_pri_bus_width ret_val;
- switch (pri_bus_width) {
- case 0x00:
- ret_val = MV_DDR_PRI_BUS_WIDTH_8;
- break;
- case 0x01:
- ret_val = MV_DDR_PRI_BUS_WIDTH_16;
- break;
- case 0x02:
- ret_val = MV_DDR_PRI_BUS_WIDTH_32;
- break;
- case 0x03:
- ret_val = MV_DDR_PRI_BUS_WIDTH_64;
- break;
- default:
- ret_val = MV_DDR_PRI_BUS_WIDTH_LAST;
- }
- return ret_val;
- }
- enum mv_ddr_pkg_rank mv_ddr_spd_bus_width_ext_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char bus_width_ext = spd_data->byte_fields.byte_13.bit_fields.bus_width_ext;
- enum mv_ddr_bus_width_ext ret_val;
- switch (bus_width_ext) {
- case 0x00:
- ret_val = MV_DDR_BUS_WIDTH_EXT_0;
- break;
- case 0x01:
- ret_val = MV_DDR_BUS_WIDTH_EXT_8;
- break;
- default:
- ret_val = MV_DDR_BUS_WIDTH_EXT_LAST;
- }
- return ret_val;
- }
- static enum mv_ddr_pkg_rank mv_ddr_spd_pkg_rank_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char pkg_rank = spd_data->byte_fields.byte_12.bit_fields.dimm_pkg_ranks_num;
- enum mv_ddr_pkg_rank ret_val;
- switch (pkg_rank) {
- case 0x00:
- ret_val = MV_DDR_PKG_RANK_1;
- break;
- case 0x01:
- ret_val = MV_DDR_PKG_RANK_2;
- break;
- case 0x02:
- ret_val = MV_DDR_PKG_RANK_3;
- break;
- case 0x03:
- ret_val = MV_DDR_PKG_RANK_4;
- break;
- case 0x04:
- ret_val = MV_DDR_PKG_RANK_5;
- break;
- case 0x05:
- ret_val = MV_DDR_PKG_RANK_6;
- break;
- case 0x06:
- ret_val = MV_DDR_PKG_RANK_7;
- break;
- case 0x07:
- ret_val = MV_DDR_PKG_RANK_8;
- break;
- default:
- ret_val = MV_DDR_PKG_RANK_LAST;
- }
- return ret_val;
- }
- static enum mv_ddr_die_count mv_ddr_spd_die_count_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char die_count = spd_data->byte_fields.byte_6.bit_fields.die_count;
- enum mv_ddr_die_count ret_val;
- switch (die_count) {
- case 0x00:
- ret_val = MV_DDR_DIE_CNT_1;
- break;
- case 0x01:
- ret_val = MV_DDR_DIE_CNT_2;
- break;
- case 0x02:
- ret_val = MV_DDR_DIE_CNT_3;
- break;
- case 0x03:
- ret_val = MV_DDR_DIE_CNT_4;
- break;
- case 0x04:
- ret_val = MV_DDR_DIE_CNT_5;
- break;
- case 0x05:
- ret_val = MV_DDR_DIE_CNT_6;
- break;
- case 0x06:
- ret_val = MV_DDR_DIE_CNT_7;
- break;
- case 0x07:
- ret_val = MV_DDR_DIE_CNT_8;
- break;
- default:
- ret_val = MV_DDR_DIE_CNT_LAST;
- }
- return ret_val;
- }
- unsigned char mv_ddr_spd_cs_bit_mask_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char cs_bit_mask = 0x0;
- enum mv_ddr_pkg_rank pkg_rank = mv_ddr_spd_pkg_rank_get(spd_data);
- enum mv_ddr_die_count die_cnt = mv_ddr_spd_die_count_get(spd_data);
- if (pkg_rank == MV_DDR_PKG_RANK_1 && die_cnt == MV_DDR_DIE_CNT_1)
- cs_bit_mask = 0x1;
- else if (pkg_rank == MV_DDR_PKG_RANK_1 && die_cnt == MV_DDR_DIE_CNT_2)
- cs_bit_mask = 0x3;
- else if (pkg_rank == MV_DDR_PKG_RANK_2 && die_cnt == MV_DDR_DIE_CNT_1)
- cs_bit_mask = 0x3;
- else if (pkg_rank == MV_DDR_PKG_RANK_2 && die_cnt == MV_DDR_DIE_CNT_2)
- cs_bit_mask = 0xf;
- return cs_bit_mask;
- }
- unsigned char mv_ddr_spd_dev_type_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char dev_type = spd_data->byte_fields.byte_2;
- return dev_type;
- }
- unsigned char mv_ddr_spd_module_type_get(union mv_ddr_spd_data *spd_data)
- {
- unsigned char module_type = spd_data->byte_fields.byte_3.bit_fields.module_type;
- return module_type;
- }
|