soc/mediatek/mt8186: Support DRAM fast calibration using blob
For most MediaTek SoCs (MT8183, MT8192, MT8195) we rely on an external program (e.g., the "DRAM blob") to do the full DRAM calibration first, then store and and apply the generated parameters to the reference "fast DRAM calibration" in the vendor/mediatek folder for normal system boot. Starting with MT8186 the implementation of fast calibration may need to be changed, and a "DRAM blob" only path is introduced for devices that have to do both full and fast calibration using the external blob. TEST=fast calibration pass on kingler/krabby BUG=b:204226005 Signed-off-by: Xi Chen <xixi.chen@mediatek.corp-partner.google.com> Change-Id: If25a7dd6aa6261ecff79a1b4df8b1f2e53d896dc Reviewed-on: https://review.coreboot.org/c/coreboot/+/61133 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Yu-Ping Wu <yupingso@google.com>
This commit is contained in:
parent
e0f0801802
commit
5c7a923757
|
@ -22,6 +22,13 @@ config MEDIATEK_DRAM_DVFS_LIMIT_FREQ_CNT
|
||||||
This options limit DRAM frequency calibration count from total 7 to 3,
|
This options limit DRAM frequency calibration count from total 7 to 3,
|
||||||
other frequency will directly use the low frequency shu result.
|
other frequency will directly use the low frequency shu result.
|
||||||
|
|
||||||
|
config MEDIATEK_BLOB_FAST_INIT
|
||||||
|
bool "Enable running fast calibration by blob"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This option allows performing fast calibration through different
|
||||||
|
open-source policy.
|
||||||
|
|
||||||
config MEMORY_TEST
|
config MEMORY_TEST
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <bootmode.h>
|
#include <bootmode.h>
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
|
#include <soc/dramc_common.h>
|
||||||
#include <ip_checksum.h>
|
#include <ip_checksum.h>
|
||||||
#include <mrc_cache.h>
|
#include <mrc_cache.h>
|
||||||
#include <soc/dramc_param.h>
|
#include <soc/dramc_param.h>
|
||||||
|
@ -95,31 +96,11 @@ const char *get_dram_type_str(u32 ddr_type)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dram_run_fast_calibration(struct dramc_param *dparam)
|
static int run_dram_blob(struct dramc_param *dparam)
|
||||||
{
|
|
||||||
const u16 config = CONFIG(MEDIATEK_DRAM_DVFS) ? DRAMC_ENABLE_DVFS : DRAMC_DISABLE_DVFS;
|
|
||||||
if (dparam->dramc_datas.ddr_info.config_dvfs != config) {
|
|
||||||
printk(BIOS_WARNING,
|
|
||||||
"DRAM-K: Incompatible config for calibration data from flash "
|
|
||||||
"(expected: %#x, saved: %#x)\n",
|
|
||||||
config, dparam->dramc_datas.ddr_info.config_dvfs);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk(BIOS_INFO, "DRAM-K: DRAM calibration data valid pass\n");
|
|
||||||
init_dram_by_params(dparam);
|
|
||||||
if (mt_mem_test(&dparam->dramc_datas) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return DRAMC_ERR_FAST_CALIBRATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dram_run_full_calibration(struct dramc_param *dparam)
|
|
||||||
{
|
{
|
||||||
/* Load and run the provided blob for full-calibration if available */
|
/* Load and run the provided blob for full-calibration if available */
|
||||||
struct prog dram = PROG_INIT(PROG_REFCODE, CONFIG_CBFS_PREFIX "/dram");
|
struct prog dram = PROG_INIT(PROG_REFCODE, CONFIG_CBFS_PREFIX "/dram");
|
||||||
|
|
||||||
initialize_dramc_param(dparam);
|
|
||||||
dump_param_header(dparam);
|
dump_param_header(dparam);
|
||||||
|
|
||||||
if (cbfs_prog_stage_load(&dram)) {
|
if (cbfs_prog_stage_load(&dram)) {
|
||||||
|
@ -132,12 +113,13 @@ static int dram_run_full_calibration(struct dramc_param *dparam)
|
||||||
prog_set_entry(&dram, prog_entry(&dram), dparam);
|
prog_set_entry(&dram, prog_entry(&dram), dparam);
|
||||||
prog_run(&dram);
|
prog_run(&dram);
|
||||||
if (dparam->header.status != DRAMC_SUCCESS) {
|
if (dparam->header.status != DRAMC_SUCCESS) {
|
||||||
printk(BIOS_ERR, "DRAM-K: Full calibration failed: status = %d\n",
|
printk(BIOS_ERR, "DRAM-K: calibration failed: status = %d\n",
|
||||||
dparam->header.status);
|
dparam->header.status);
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(dparam->header.flags & DRAMC_FLAG_HAS_SAVED_DATA)) {
|
if (!(dparam->header.config & DRAMC_CONFIG_FAST_K)
|
||||||
|
&& !(dparam->header.flags & DRAMC_FLAG_HAS_SAVED_DATA)) {
|
||||||
printk(BIOS_ERR,
|
printk(BIOS_ERR,
|
||||||
"DRAM-K: Full calibration executed without saving parameters. "
|
"DRAM-K: Full calibration executed without saving parameters. "
|
||||||
"Please ensure the blob is built properly.\n");
|
"Please ensure the blob is built properly.\n");
|
||||||
|
@ -147,6 +129,49 @@ static int dram_run_full_calibration(struct dramc_param *dparam)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dram_run_fast_calibration(struct dramc_param *dparam)
|
||||||
|
{
|
||||||
|
const u16 config = CONFIG(MEDIATEK_DRAM_DVFS) ? DRAMC_ENABLE_DVFS : DRAMC_DISABLE_DVFS;
|
||||||
|
|
||||||
|
if (dparam->dramc_datas.ddr_info.config_dvfs != config) {
|
||||||
|
printk(BIOS_WARNING,
|
||||||
|
"DRAM-K: Incompatible config for calibration data from flash "
|
||||||
|
"(expected: %#x, saved: %#x)\n",
|
||||||
|
config, dparam->dramc_datas.ddr_info.config_dvfs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(BIOS_INFO, "DRAM-K: DRAM calibration data valid pass\n");
|
||||||
|
|
||||||
|
if (CONFIG(MEDIATEK_BLOB_FAST_INIT)) {
|
||||||
|
printk(BIOS_INFO, "DRAM-K: Run fast calibration run in blob mode\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The loaded config should not contain FAST_K (done in full calibration),
|
||||||
|
* so we have to set that now to indicate the blob taking the config instead
|
||||||
|
* of generating a new config.
|
||||||
|
*/
|
||||||
|
dparam->header.config |= DRAMC_CONFIG_FAST_K;
|
||||||
|
|
||||||
|
if (run_dram_blob(dparam) < 0)
|
||||||
|
return -3;
|
||||||
|
} else {
|
||||||
|
init_dram_by_params(dparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mt_mem_test(&dparam->dramc_datas) < 0)
|
||||||
|
return -4;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dram_run_full_calibration(struct dramc_param *dparam)
|
||||||
|
{
|
||||||
|
initialize_dramc_param(dparam);
|
||||||
|
|
||||||
|
return run_dram_blob(dparam);
|
||||||
|
}
|
||||||
|
|
||||||
static void mem_init_set_default_config(struct dramc_param *dparam,
|
static void mem_init_set_default_config(struct dramc_param *dparam,
|
||||||
const struct sdram_info *dram_info)
|
const struct sdram_info *dram_info)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@ config SOC_MEDIATEK_MT8186
|
||||||
select CACHE_MRC_SETTINGS
|
select CACHE_MRC_SETTINGS
|
||||||
select HAVE_UART_SPECIAL
|
select HAVE_UART_SPECIAL
|
||||||
select SOC_MEDIATEK_COMMON
|
select SOC_MEDIATEK_COMMON
|
||||||
|
select MEDIATEK_BLOB_FAST_INIT
|
||||||
|
|
||||||
if SOC_MEDIATEK_MT8186
|
if SOC_MEDIATEK_MT8186
|
||||||
|
|
||||||
|
|
|
@ -59,48 +59,53 @@ struct sdram_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sdram_params {
|
struct sdram_params {
|
||||||
|
/* Sometimes, we may need to compare params member
|
||||||
|
* between coreboot and blob for analysis. Here,
|
||||||
|
* add member size using xxxB.
|
||||||
|
*/
|
||||||
|
/* 4 + 4 = 8B */
|
||||||
u32 rank_num;
|
u32 rank_num;
|
||||||
u16 num_dlycell_perT;
|
u16 num_dlycell_perT;
|
||||||
u16 delay_cell_timex100;
|
u16 delay_cell_timex100;
|
||||||
|
|
||||||
/* duty */
|
/* duty 16B */
|
||||||
s8 duty_clk_delay[CHANNEL_MAX][RANK_MAX];
|
s8 duty_clk_delay[CHANNEL_MAX][RANK_MAX];
|
||||||
s8 duty_dqs_delay[CHANNEL_MAX][DQS_NUMBER_LP4];
|
s8 duty_dqs_delay[CHANNEL_MAX][DQS_NUMBER_LP4];
|
||||||
s8 duty_wck_delay[CHANNEL_MAX][DQS_NUMBER_LP4];
|
|
||||||
s8 duty_dq_delay[CHANNEL_MAX][DQS_NUMBER_LP4];
|
s8 duty_dq_delay[CHANNEL_MAX][DQS_NUMBER_LP4];
|
||||||
s8 duty_dqm_delay[CHANNEL_MAX][DQS_NUMBER_LP4];
|
s8 duty_dqm_delay[CHANNEL_MAX][DQS_NUMBER_LP4];
|
||||||
|
|
||||||
/* CBT */
|
/* CBT 48B */
|
||||||
u8 cbt_final_vref[CHANNEL_MAX][RANK_MAX];
|
u8 cbt_final_vref[CHANNEL_MAX][RANK_MAX];
|
||||||
s8 cbt_cmd_dly[CHANNEL_MAX][RANK_MAX];
|
u8 cbt_clk_dly[CHANNEL_MAX][RANK_MAX];
|
||||||
|
u8 cbt_cmd_dly[CHANNEL_MAX][RANK_MAX];
|
||||||
u8 cbt_cs_dly[CHANNEL_MAX][RANK_MAX];
|
u8 cbt_cs_dly[CHANNEL_MAX][RANK_MAX];
|
||||||
u8 cbt_ca_prebit_dly[CHANNEL_MAX][RANK_MAX][DQS_BIT_NUMBER];
|
u8 cbt_ca_prebit_dly[CHANNEL_MAX][RANK_MAX][DQS_BIT_NUMBER];
|
||||||
|
|
||||||
/* write leveling */
|
/* write leveling 8B */
|
||||||
u8 wr_level[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 wr_level[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
|
|
||||||
/* Gating */
|
/* Gating 32B */
|
||||||
u8 gating_MCK[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 gating_MCK[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u8 gating_UI[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 gating_UI[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u8 gating_PI[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 gating_PI[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u8 gating_pass_count[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 gating_pass_count[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
|
|
||||||
/* TX perbit */
|
/* TX perbit 164B */
|
||||||
u8 tx_window_vref[CHANNEL_MAX][RANK_MAX];
|
u8 tx_window_vref[CHANNEL_MAX][RANK_MAX];
|
||||||
u16 tx_center_min[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u16 tx_center_min[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u16 tx_center_max[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u16 tx_center_max[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u16 tx_win_center[CHANNEL_MAX][RANK_MAX][DQ_DATA_WIDTH_LP4];
|
u16 tx_win_center[CHANNEL_MAX][RANK_MAX][DQ_DATA_WIDTH_LP4];
|
||||||
|
|
||||||
/* rx datlat */
|
/* rx datlat 4B */
|
||||||
u8 rx_datlat[CHANNEL_MAX][RANK_MAX];
|
u8 rx_datlat[CHANNEL_MAX][RANK_MAX];
|
||||||
|
|
||||||
/* RX perbit */
|
/* RX perbit 88B */
|
||||||
u8 rx_best_vref[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 rx_best_vref[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u16 rx_perbit_dqs[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 rx_perbit_dqs[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u16 rx_perbit_dqm[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 rx_perbit_dqm[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u16 rx_perbit_dq[CHANNEL_MAX][RANK_MAX][DQ_DATA_WIDTH_LP4];
|
u8 rx_perbit_dq[CHANNEL_MAX][RANK_MAX][DQ_DATA_WIDTH_LP4];
|
||||||
|
|
||||||
/* TX OE */
|
/* TX OE 16B */
|
||||||
u8 tx_oe_dq_mck[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 tx_oe_dq_mck[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
u8 tx_oe_dq_ui[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
u8 tx_oe_dq_ui[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
|
||||||
};
|
};
|
||||||
|
@ -112,6 +117,15 @@ struct emi_mdl {
|
||||||
u32 chn_cona_val;
|
u32 chn_cona_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ddr_mrr_info {
|
||||||
|
u16 mr5_vendor_id;
|
||||||
|
u16 mr6_revision_id;
|
||||||
|
u16 mr7_revision_id;
|
||||||
|
u64 mr8_density[RANK_MAX];
|
||||||
|
u32 rank_nums;
|
||||||
|
u8 die_num[RANK_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
struct ddr_base_info {
|
struct ddr_base_info {
|
||||||
u32 config_dvfs; /* SDRAM_DVFS_FLAG */
|
u32 config_dvfs; /* SDRAM_DVFS_FLAG */
|
||||||
struct sdram_info sdram;
|
struct sdram_info sdram;
|
||||||
|
@ -120,6 +134,8 @@ struct ddr_base_info {
|
||||||
u64 rank_size[RANK_MAX];
|
u64 rank_size[RANK_MAX];
|
||||||
struct emi_mdl emi_config;
|
struct emi_mdl emi_config;
|
||||||
DRAM_CBT_MODE_T cbt_mode[RANK_MAX];
|
DRAM_CBT_MODE_T cbt_mode[RANK_MAX];
|
||||||
|
struct ddr_mrr_info mrr_info;
|
||||||
|
u32 data_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dramc_data {
|
struct dramc_data {
|
||||||
|
|
|
@ -15,6 +15,11 @@ typedef enum {
|
||||||
RANK_MAX,
|
RANK_MAX,
|
||||||
} DRAM_RANK_T;
|
} DRAM_RANK_T;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RANK_SINGLE = 1,
|
||||||
|
RANK_DUAL,
|
||||||
|
} DRAM_RANK_NUMBER_T;
|
||||||
|
|
||||||
/* DRAM SHUFFLE RG type */
|
/* DRAM SHUFFLE RG type */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DRAM_DFS_SHUFFLE_1 = 0,
|
DRAM_DFS_SHUFFLE_1 = 0,
|
||||||
|
|
Loading…
Reference in New Issue