soc/mediatek/common: Move DRAM implementation from mt8192 to common

To reduce duplicated dram sources on seperate SOCs,
add dpm, dram_init, dramc_params, memory(fast-k or full-k)
implementations, also add dramc log level macro header files.

Signed-off-by: Xi Chen <xixi.chen@mediatek.com>
Change-Id: I557c96b3d09828472b8b6f932b0192a90894043e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51203
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
diff --git a/src/soc/mediatek/common/Kconfig b/src/soc/mediatek/common/Kconfig
new file mode 100644
index 0000000..543bc02
--- /dev/null
+++ b/src/soc/mediatek/common/Kconfig
@@ -0,0 +1,32 @@
+config SOC_MEDIATEK_COMMON
+	bool
+	help
+	  common code blocks for Mediatek SOCs
+
+if SOC_MEDIATEK_COMMON
+
+config MEDIATEK_DRAM_DVFS
+	bool
+	default n
+	help
+	  This option enables DRAM calibration with multiple frequencies (low,
+	  medium and high frequency groups, with total 7 frequencies) for DVFS
+	  feature. All supported data rates are: 800, 1200, 1600, 1866, 2400,
+	  3200, 4266.
+
+config MEDIATEK_DRAM_DVFS_LIMIT_FREQ_CNT
+	bool
+	default y
+	select MEDIATEK_DRAM_DVFS
+	help
+	  This options limit DRAM frequency calibration count from total 7 to 3,
+	  other frequency will directly use the low frequency shu result.
+
+config MEMORY_TEST
+	bool
+	default y
+	help
+	  This option enables memory basic compare test to verify the DRAM read
+	  or write is as expected.
+
+endif
diff --git a/src/soc/mediatek/common/dpm.c b/src/soc/mediatek/common/dpm.c
new file mode 100644
index 0000000..991441e
--- /dev/null
+++ b/src/soc/mediatek/common/dpm.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/mmio.h>
+#include <soc/dpm.h>
+#include <soc/mcu_common.h>
+#include <soc/symbols.h>
+
+static void reset_dpm(struct mtk_mcu *mcu)
+{
+	/* write bootargs */
+	write32(&mtk_dpm->twam_window_len, 0x0);
+	write32(&mtk_dpm->twam_mon_type, 0x0);
+
+	/* free RST */
+	setbits32(&mtk_dpm->sw_rstn, DPM_SW_RSTN_RESET);
+}
+
+static struct mtk_mcu dpm_mcu[] = {
+	{
+		.firmware_name = CONFIG_DPM_DM_FIRMWARE,
+		.run_address = (void *)DPM_DM_SRAM_BASE,
+	},
+	{
+		.firmware_name = CONFIG_DPM_PM_FIRMWARE,
+		.run_address = (void *)DPM_PM_SRAM_BASE,
+		.reset = reset_dpm,
+	},
+};
+
+int dpm_init(void)
+{
+	int i;
+	struct mtk_mcu *dpm;
+
+	/* config DPM SRAM layout */
+	clrsetbits32(&mtk_dpm->sw_rstn, DPM_MEM_RATIO_MASK, DPM_MEM_RATIO_CFG1);
+
+	for (i = 0; i < ARRAY_SIZE(dpm_mcu); i++) {
+		dpm = &dpm_mcu[i];
+		dpm->load_buffer = _dram_dma;
+		dpm->buffer_size = REGION_SIZE(dram_dma);
+		if (mtk_init_mcu(dpm))
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/src/soc/mediatek/common/dram_init.c b/src/soc/mediatek/common/dram_init.c
new file mode 100644
index 0000000..accc7ac
--- /dev/null
+++ b/src/soc/mediatek/common/dram_init.c
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <delay.h>
+#include <stdint.h>
+#include <soc/dramc_common.h>
+#include <soc/dramc_param.h>
+#include <soc/emi.h>
+
+struct dramc_param *dramc_params;
+
+bool is_dvfs_enabled(void)
+{
+	dramc_info("dram_init: config_dvfs: %d\n",
+		   dramc_params->dramc_datas.ddr_info.config_dvfs);
+	return !!(dramc_params->dramc_datas.ddr_info.config_dvfs);
+}
+
+u32 get_ddr_geometry(void)
+{
+	dramc_info("dram_init: ddr_geometry: %d\n",
+		   dramc_params->dramc_datas.ddr_info.ddr_geometry);
+	return dramc_params->dramc_datas.ddr_info.ddr_geometry;
+}
+
+u32 get_ddr_type(void)
+{
+	dramc_info("dram_init: ddr_type: %d\n",
+		   dramc_params->dramc_datas.ddr_info.ddr_type);
+	return dramc_params->dramc_datas.ddr_info.ddr_type;
+}
+
+void init_dram_by_params(struct dramc_param *dparam)
+{
+	dramc_params = dparam;
+	mt_set_emi(dramc_params);
+}
diff --git a/src/soc/mediatek/common/dramc_param.c b/src/soc/mediatek/common/dramc_param.c
new file mode 100644
index 0000000..8548dbc
--- /dev/null
+++ b/src/soc/mediatek/common/dramc_param.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <string.h>
+#include <soc/dramc_param.h>
+
+#define print(_x_...) printk(BIOS_INFO, _x_)
+
+struct dramc_param *get_dramc_param_from_blob(void *blob)
+{
+	return (struct dramc_param *)blob;
+}
+
+void dump_param_header(const void *blob)
+{
+	const struct dramc_param *dparam = blob;
+	const struct dramc_param_header *header = &dparam->header;
+
+	print("header.status = %#x\n", header->status);
+	print("header.version = %#x (expected: %#x)\n",
+	      header->version, DRAMC_PARAM_HEADER_VERSION);
+	print("header.size = %#x (expected: %#lx)\n",
+	      header->size, sizeof(*dparam));
+	print("header.flags = %#x\n", header->flags);
+	print("header.checksum = %#x\n", header->checksum);
+}
+
+int validate_dramc_param(const void *blob)
+{
+	const struct dramc_param *param = blob;
+	const struct dramc_param_header *hdr = &param->header;
+
+	if (hdr->version != DRAMC_PARAM_HEADER_VERSION)
+		return DRAMC_ERR_INVALID_VERSION;
+
+	if (hdr->size != sizeof(*param))
+		return DRAMC_ERR_INVALID_SIZE;
+
+	return DRAMC_SUCCESS;
+}
+
+int is_valid_dramc_param(const void *blob)
+{
+	return validate_dramc_param(blob) == DRAMC_SUCCESS;
+}
+
+int initialize_dramc_param(void *blob)
+{
+	struct dramc_param *param = blob;
+	struct dramc_param_header *hdr = &param->header;
+
+	memset(hdr, 0, sizeof(*hdr));
+	hdr->version = DRAMC_PARAM_HEADER_VERSION;
+	hdr->size = sizeof(*param);
+	return 0;
+}
diff --git a/src/soc/mediatek/common/include/soc/dpm.h b/src/soc/mediatek/common/include/soc/dpm.h
new file mode 100644
index 0000000..7262e09
--- /dev/null
+++ b/src/soc/mediatek/common/include/soc/dpm.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_DPM_H__
+#define __SOC_MEDIATEK_DPM_H__
+
+#include <soc/addressmap.h>
+#include <stdint.h>
+#include <types.h>
+
+struct dpm_regs {
+	u32 sw_rstn;
+	u32 rsvd_0[3072];
+	u32 mclk_div;
+	u32 rsvd_1[3071];
+	u32 twam_window_len;
+	u32 twam_mon_type;
+	u32 rsvd_2[1022];
+	u32 low_power_cfg_0;
+	u32 low_power_cfg_1;
+	u32 rsvd_3[1];
+	u32 fsm_out_ctrl_0;
+	u32 rsvd_4[8];
+	u32 fsm_cfg_1;
+	u32 low_power_cfg_3;
+	u32 dfd_dbug_0;
+	u32 rsvd_5[28];
+	u32 status_4;
+};
+
+check_member(dpm_regs, mclk_div, 0x3004);
+check_member(dpm_regs, twam_window_len, 0x6004);
+check_member(dpm_regs, low_power_cfg_0, 0x7004);
+check_member(dpm_regs, low_power_cfg_1, 0x7008);
+check_member(dpm_regs, fsm_out_ctrl_0, 0x7010);
+check_member(dpm_regs, fsm_cfg_1, 0x7034);
+check_member(dpm_regs, low_power_cfg_3, 0x7038);
+check_member(dpm_regs, dfd_dbug_0, 0x703C);
+check_member(dpm_regs, status_4, 0x70B0);
+
+#define DPM_SW_RSTN_RESET	BIT(0)
+#define DPM_MEM_RATIO_OFFSET	28
+#define DPM_MEM_RATIO_MASK	(0x3 << DPM_MEM_RATIO_OFFSET)
+#define DPM_MEM_RATIO_CFG1	(1 << DPM_MEM_RATIO_OFFSET)
+
+static struct dpm_regs *const mtk_dpm = (void *)DPM_CFG_BASE;
+
+int dpm_init(void);
+
+#endif  /* __SOC_MEDIATEK_MT8192_DPM_H__ */
diff --git a/src/soc/mediatek/common/include/soc/dramc_common.h b/src/soc/mediatek/common/include/soc/dramc_common.h
new file mode 100644
index 0000000..a5716dc
--- /dev/null
+++ b/src/soc/mediatek/common/include/soc/dramc_common.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_DRAMC_COMMON_H__
+#define __SOC_MEDIATEK_DRAMC_COMMON_H__
+
+#include <console/console.h>
+
+#define dramc_err(_x_...)  printk(BIOS_ERR, _x_)
+#define dramc_info(_x_...) printk(BIOS_INFO, _x_)
+#define dramc_show         dramc_info
+#define dramc_dbg(_x_...) \
+	do { \
+		if (CONFIG(DEBUG_RAM_SETUP)) \
+			printk(BIOS_INFO, _x_); \
+	} while (0)
+
+#endif
diff --git a/src/soc/mediatek/common/include/soc/dramc_param.h b/src/soc/mediatek/common/include/soc/dramc_param.h
new file mode 100644
index 0000000..d3eda8d
--- /dev/null
+++ b/src/soc/mediatek/common/include/soc/dramc_param.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_DRAMC_PARAM_H__
+#define __SOC_MEDIATEK_DRAMC_PARAM_H__
+
+/* any change in this file should sync to blob dramc_param.h */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <soc/dramc_soc.h>
+
+enum {
+	DRAMC_PARAM_HEADER_VERSION = 5,
+};
+
+enum DRAMC_PARAM_STATUS_CODES {
+	DRAMC_SUCCESS = 0,
+	DRAMC_ERR_INVALID_VERSION,
+	DRAMC_ERR_INVALID_SIZE,
+	DRAMC_ERR_INVALID_CHECKSUM,
+	DRAMC_ERR_INVALID_FLAGS,
+	DRAMC_ERR_RECALIBRATE,
+	DRAMC_ERR_INIT_DRAM,
+	DRAMC_ERR_COMPLEX_RW_MEM_TEST,
+	DRAMC_ERR_1ST_COMPLEX_RW_MEM_TEST,
+	DRAMC_ERR_2ND_COMPLEX_RW_MEM_TEST,
+	DRAMC_ERR_FAST_CALIBRATION,
+};
+
+enum DRAMC_PARAM_DVFS_FLAG {
+	DRAMC_DISABLE_DVFS,
+	DRAMC_ENABLE_DVFS,
+};
+
+enum DRAMC_PARAM_FLAGS {
+	DRAMC_FLAG_HAS_SAVED_DATA = 0x0001,
+};
+
+enum DRAMC_PARAM_DDR_TYPE {
+	DDR_TYPE_DISCRETE,
+	DDR_TYPE_EMCP,
+};
+
+/* Don't change the order, which is matched with blob */
+enum DRAMC_PARAM_GEOMETRY_TYPE {
+	DDR_TYPE_2CH_2RK_4GB_2_2,
+	DDR_TYPE_2CH_2RK_6GB_3_3,
+	DDR_TYPE_2CH_2RK_8GB_4_4_BYTE,
+	DDR_TYPE_2CH_1RK_4GB_4_0,
+	DDR_TYPE_2CH_2RK_6GB_2_4,
+	DDR_TYPE_2CH_2RK_8GB_4_4,
+};
+
+enum DRAM_PARAM_VOLTAGE_TYPE {
+	DRAM_VOLTAGE_NVCORE_NVDRAM,
+	DRAM_VOLTAGE_HVCORE_HVDRAM,
+	DRAM_VOLTAGE_LVCORE_LVDRAM,
+};
+
+struct dramc_param_header {
+	u32 checksum;	/* checksum of dramc_datas, update in the coreboot */
+	u16 version;	/* DRAMC_PARAM_HEADER_VERSION, update in the coreboot */
+	u16 size;	/* size of whole dramc_param, update in the coreboot */
+	u16 status;	/* DRAMC_PARAM_STATUS_CODES, update in the dram blob */
+	u16 flags;	/* DRAMC_PARAM_FLAGS, update in the dram blob */
+};
+
+struct sdram_params {
+	u32 rank_num;
+	u16 num_dlycell_perT;
+	u16 delay_cell_timex100;
+
+	/* duty */
+	s8 duty_clk_delay[CHANNEL_MAX][RANK_MAX];
+	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_dqm_delay[CHANNEL_MAX][DQS_NUMBER_LP4];
+
+	/* CBT */
+	u8 cbt_final_vref[CHANNEL_MAX][RANK_MAX];
+	s8 cbt_cmd_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];
+
+	/* write leveling */
+	u8 wr_level[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
+
+	/* Gating */
+	u8 gating_MCK[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_pass_count[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
+
+	/* TX perbit */
+	u8 tx_window_vref[CHANNEL_MAX][RANK_MAX];
+	u16 tx_center_min[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];
+
+	/* rx datlat */
+	u8 rx_datlat[CHANNEL_MAX][RANK_MAX];
+
+	/* RX perbit */
+	u8 rx_best_vref[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
+	u16 rx_perbit_dqs[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
+	u16 rx_perbit_dqm[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
+	u16 rx_perbit_dq[CHANNEL_MAX][RANK_MAX][DQ_DATA_WIDTH_LP4];
+
+	/* TX OE */
+	u8 tx_oe_dq_mck[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
+	u8 tx_oe_dq_ui[CHANNEL_MAX][RANK_MAX][DQS_NUMBER_LP4];
+};
+
+struct emi_mdl {
+	u32 cona_val;
+	u32 conh_val;
+	u32 conf_val;
+	u32 chn_cona_val;
+};
+
+struct ddr_base_info {
+	u32 config_dvfs;		/* DRAMC_PARAM_DVFS_FLAG */
+	u32 ddr_type;			/* DRAMC_PARAM_DDR_TYPE */
+	u32 ddr_geometry;		/* DRAMC_PARAM_GEOMETRY_TYPE */
+	u32 voltage_type;		/* DRAM_PARAM_VOLTAGE_TYPE */
+	u32 support_ranks;
+	u64 rank_size[RANK_MAX];
+	struct emi_mdl emi_config;
+	dram_cbt_mode cbt_mode[RANK_MAX];
+};
+
+struct dramc_data {
+	struct ddr_base_info ddr_info;
+	struct sdram_params freq_params[DRAM_DFS_SHU_MAX];
+};
+
+struct dramc_param {
+	struct dramc_param_header header;
+	void (*do_putc)(unsigned char c);
+	struct dramc_data dramc_datas;
+};
+
+struct dramc_param_ops {
+	struct dramc_param *param;
+	bool (*read_from_flash)(struct dramc_param *dparam);
+	bool (*write_to_flash)(const struct dramc_param *dparam);
+};
+
+struct sdram_info {
+	u32 ddr_geometry;		/* DRAMC_PARAM_GEOMETRY_TYPE */
+	u32 ddr_type;			/* DRAMC_PARAM_DDR_TYPE */
+};
+
+const struct sdram_info *get_sdram_config(void);
+struct dramc_param *get_dramc_param_from_blob(void *blob);
+void dump_param_header(const void *blob);
+int validate_dramc_param(const void *blob);
+int is_valid_dramc_param(const void *blob);
+int initialize_dramc_param(void *blob);
+#endif  /* __SOC_MEDIATEK_DRAMC_PARAM_H__ */
diff --git a/src/soc/mediatek/common/include/soc/emi.h b/src/soc/mediatek/common/include/soc/emi.h
new file mode 100644
index 0000000..c91c870
--- /dev/null
+++ b/src/soc/mediatek/common/include/soc/emi.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SOC_MEDIATEK_EMI_H
+#define SOC_MEDIATEK_EMI_H
+
+#include <soc/dramc_param.h>
+
+size_t sdram_size(void);
+void mt_set_emi(struct dramc_param *dparam);
+void mt_mem_init(struct dramc_param_ops *dparam_ops);
+int complex_mem_test(u8 *start, unsigned int len);
+
+bool is_dvfs_enabled(void);
+u32 get_ddr_geometry(void);
+u32 get_ddr_type(void);
+void init_dram_by_params(struct dramc_param *dparam);
+
+#endif /* SOC_MEDIATEK_MT8192_EMI_H */
diff --git a/src/soc/mediatek/common/memory.c b/src/soc/mediatek/common/memory.c
new file mode 100644
index 0000000..2cc0571
--- /dev/null
+++ b/src/soc/mediatek/common/memory.c
@@ -0,0 +1,244 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <assert.h>
+#include <bootmode.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <ip_checksum.h>
+#include <soc/emi.h>
+#include <symbols.h>
+#include <timer.h>
+
+const char *get_dram_geometry_str(u32 ddr_geometry);
+const char *get_dram_type_str(u32 ddr_type);
+
+static int mt_mem_test(const struct dramc_data *dparam)
+{
+	if (CONFIG(MEMORY_TEST)) {
+		u8 *addr = _dram;
+		const struct ddr_base_info *ddr_info = &dparam->ddr_info;
+
+		for (u8 rank = RANK_0; rank < ddr_info->support_ranks; rank++) {
+			int result = complex_mem_test(addr, 0x2000);
+
+			if (result != 0) {
+				printk(BIOS_ERR,
+				       "[MEM] complex R/W mem test failed: %d\n", result);
+				return -1;
+			}
+			printk(BIOS_DEBUG, "[MEM] rank %u complex R/W mem test passed\n", rank);
+
+			addr += ddr_info->rank_size[rank];
+		}
+	}
+
+	return 0;
+}
+
+static u32 compute_checksum(const struct dramc_param *dparam)
+{
+	return (u32)compute_ip_checksum(&dparam->dramc_datas,
+					sizeof(dparam->dramc_datas));
+}
+
+const char *get_dram_geometry_str(u32 ddr_geometry)
+{
+	const char *s;
+
+	switch (ddr_geometry) {
+	case DDR_TYPE_2CH_2RK_4GB_2_2:
+		s = "2CH_2RK_4GB_2_2";
+		break;
+	case DDR_TYPE_2CH_2RK_6GB_3_3:
+		s = "2CH_2RK_6GB_3_3";
+		break;
+	case DDR_TYPE_2CH_2RK_8GB_4_4:
+		s = "2CH_2RK_8GB_4_4";
+		break;
+	case DDR_TYPE_2CH_2RK_8GB_4_4_BYTE:
+		s = "2CH_2RK_8GB_4_4_BYTE";
+		break;
+	case DDR_TYPE_2CH_1RK_4GB_4_0:
+		s = "2CH_1RK_4GB_4_0";
+		break;
+	case DDR_TYPE_2CH_2RK_6GB_2_4:
+		s = "2CH_2RK_6GB_2_4";
+		break;
+	default:
+		s = "";
+		break;
+	}
+
+	return s;
+}
+
+const char *get_dram_type_str(u32 ddr_type)
+{
+	const char *s;
+
+	switch (ddr_type) {
+	case DDR_TYPE_DISCRETE:
+		s = "DSC";
+		break;
+	case DDR_TYPE_EMCP:
+		s = "EMCP";
+		break;
+	default:
+		s = "";
+		break;
+	}
+
+	return s;
+}
+
+static int dram_run_fast_calibration(struct dramc_param *dparam)
+{
+	if (!is_valid_dramc_param(dparam)) {
+		printk(BIOS_WARNING, "DRAM-K: Invalid DRAM calibration data from flash\n");
+		dump_param_header((void *)dparam);
+		return -1;
+	}
+
+	const u32 checksum = compute_checksum(dparam);
+	if (dparam->header.checksum != checksum) {
+		printk(BIOS_ERR,
+		       "DRAM-K: Invalid DRAM calibration checksum from flash "
+		       "(expected: %#x, saved: %#x)\n",
+		       checksum, dparam->header.checksum);
+		return DRAMC_ERR_INVALID_CHECKSUM;
+	}
+
+	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 */
+	struct prog dram = PROG_INIT(PROG_REFCODE, CONFIG_CBFS_PREFIX "/dram");
+
+	initialize_dramc_param(dparam);
+
+	if (prog_locate(&dram)) {
+		printk(BIOS_ERR, "DRAM-K: Locate program failed\n");
+		return -1;
+	}
+
+	if (cbfs_prog_stage_load(&dram)) {
+		printk(BIOS_ERR, "DRAM-K: CBFS load program failed\n");
+		return -2;
+	}
+
+	dparam->do_putc = do_putchar;
+
+	prog_set_entry(&dram, prog_entry(&dram), dparam);
+	prog_run(&dram);
+	if (dparam->header.status != DRAMC_SUCCESS) {
+		printk(BIOS_ERR, "DRAM-K: Full calibration failed: status = %d\n",
+		       dparam->header.status);
+		return -3;
+	}
+
+	if (!(dparam->header.flags & DRAMC_FLAG_HAS_SAVED_DATA)) {
+		printk(BIOS_ERR,
+		       "DRAM-K: Full calibration executed without saving parameters. "
+		       "Please ensure the blob is built properly.\n");
+		return -4;
+	}
+
+	return 0;
+}
+
+static void mem_init_set_default_config(struct dramc_param *dparam,
+					const struct sdram_info *dram_info)
+{
+	u32 type, geometry;
+	memset(dparam, 0, sizeof(*dparam));
+
+	type = dram_info->ddr_type;
+	geometry = dram_info->ddr_geometry;
+
+	dparam->dramc_datas.ddr_info.ddr_type = type;
+
+	if (CONFIG(MEDIATEK_DRAM_DVFS))
+		dparam->dramc_datas.ddr_info.config_dvfs = DRAMC_ENABLE_DVFS;
+
+	dparam->dramc_datas.ddr_info.ddr_geometry = geometry;
+
+	printk(BIOS_INFO, "DRAM-K: ddr_type: %s, config_dvfs: %d, ddr_geometry: %s\n",
+	       get_dram_type_str(type),
+	       dparam->dramc_datas.ddr_info.config_dvfs,
+	       get_dram_geometry_str(geometry));
+}
+
+static void mt_mem_init_run(struct dramc_param_ops *dparam_ops,
+			    const struct sdram_info *dram_info)
+{
+	struct dramc_param *dparam = dparam_ops->param;
+	struct stopwatch sw;
+	int ret;
+
+	/* Load calibration params from flash and run fast calibration */
+	mem_init_set_default_config(dparam, dram_info);
+	if (dparam_ops->read_from_flash(dparam)) {
+		printk(BIOS_INFO, "DRAM-K: Running fast calibration\n");
+		stopwatch_init(&sw);
+
+		ret = dram_run_fast_calibration(dparam);
+		if (ret != 0) {
+			printk(BIOS_ERR, "DRAM-K: Failed to run fast calibration "
+			       "in %ld msecs, error: %d\n",
+			       stopwatch_duration_msecs(&sw), ret);
+
+			/* Erase flash data after fast calibration failed */
+			memset(dparam, 0xa5, sizeof(*dparam));
+			dparam_ops->write_to_flash(dparam);
+		} else {
+			printk(BIOS_INFO, "DRAM-K: Fast calibration passed in %ld msecs\n",
+			       stopwatch_duration_msecs(&sw));
+			return;
+		}
+	} else {
+		printk(BIOS_WARNING, "DRAM-K: Failed to read calibration data from flash\n");
+	}
+
+	/* Run full calibration */
+	printk(BIOS_INFO, "DRAM-K: Running full calibration\n");
+	mem_init_set_default_config(dparam, dram_info);
+
+	stopwatch_init(&sw);
+	int err = dram_run_full_calibration(dparam);
+	if (err == 0) {
+		printk(BIOS_INFO, "DRAM-K: Full calibration passed in %ld msecs\n",
+		       stopwatch_duration_msecs(&sw));
+
+		dparam->header.checksum = compute_checksum(dparam);
+		dparam_ops->write_to_flash(dparam);
+		printk(BIOS_DEBUG, "DRAM-K: Calibration params saved to flash: "
+		       "version=%#x, size=%#x\n",
+		       dparam->header.version, dparam->header.size);
+	} else {
+		printk(BIOS_ERR, "DRAM-K: Full calibration failed in %ld msecs\n",
+		       stopwatch_duration_msecs(&sw));
+	}
+}
+
+void mt_mem_init(struct dramc_param_ops *dparam_ops)
+{
+	const struct sdram_info *sdram_param = get_sdram_config();
+
+	mt_mem_init_run(dparam_ops, sdram_param);
+}