soc/mediatek/mt8183: Support byte mode and single rank DDR

1. Add emi setting to support byte mode and single rank ddr sample
2. Modify initial setting for DDR with different architecture

BUG=b:165768895
BRANCH=kukui
TEST=DDR boot up correctly on Kukui

Signed-off-by: Shaoming Chen <shaoming.chen@mediatek.corp-partner.google.com>
Change-Id: Id2845b2b60e2c447486ee25259dc6a05a0bb619b
Reviewed-on: https://review.coreboot.org/c/coreboot/+/48300
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
diff --git a/src/soc/mediatek/mt8183/dramc_init_setting.c b/src/soc/mediatek/mt8183/dramc_init_setting.c
index 8a5d319..99c87a5 100644
--- a/src/soc/mediatek/mt8183/dramc_init_setting.c
+++ b/src/soc/mediatek/mt8183/dramc_init_setting.c
@@ -735,7 +735,8 @@
 	return 0;
 }
 
-static void dramc_mode_reg_init(u8 freq_group, struct mr_value *mr)
+static void dramc_mode_reg_init(u8 freq_group, struct mr_value *mr,
+				const struct sdram_params *params)
 {
 	u8 *MR01Value = mr->MR01Value;
 	u8 MR02Value[FSP_MAX] = {0x12, 0x12};
@@ -744,12 +745,13 @@
 	u8 MR12Value[CHANNEL_MAX][RANK_MAX][FSP_MAX] = {
 		{{0x5d, 0x5d}, {0x5d, 0x5d} }, {{0x5d, 0x5d}, {0x5d, 0x5d} },
 	};
-	u8 MR13Value;
+	u8 MR13Value = 0x18;
 	u8 MR14Value[CHANNEL_MAX][RANK_MAX][FSP_MAX] = {
 		{{0x5d, 0x10}, {0x5d, 0x10} }, {{0x5d, 0x10}, {0x5d, 0x10} },
 	};
 
 	u8 MR22Value[FSP_MAX] = {0x38, 0x34};
+	u32 cbt_mode = params->cbt_mode_extern;
 
 	MR01Value[FSP_0] = 0x6;
 	MR01Value[FSP_1] = 0x6;
@@ -767,7 +769,7 @@
 		MR01Value[FSP_0] |= (0x5 << 4);
 		MR01Value[FSP_1] |= (0x5 << 4);
 	} else if (freq_group == LP4X_DDR3200) {
-		MR02Value[0] = 0x12;
+		MR02Value[0] = 0x1a;
 		MR02Value[1] = 0x2d;
 
 		MR01Value[FSP_0] |= (0x5 << 4);
@@ -780,6 +782,9 @@
 		MR01Value[FSP_1] |= (0x6 << 4);
 	}
 
+	if (cbt_mode)
+		MR11Value[FSP_1] = 0x13;
+
 	u8 operate_fsp = get_freq_fsq(freq_group);
 	dramc_dbg("%s operate_fsp:%d, freq:%d\n", __func__, operate_fsp, freq_group);
 
@@ -789,7 +794,7 @@
 	dramc_power_on_sequence();
 
 	for (chn = 0; chn < CHANNEL_MAX; chn++) {
-		for (rank = 0; rank < 2; rank++) {
+		for (rank = 0; rank < params->rank_num; rank++) {
 			clrsetbits32(&ch[chn].ao.mrs, 0x3 << 24, rank << 24);
 
 			dramc_zq_calibration(chn, rank);
@@ -808,6 +813,15 @@
 				dramc_mode_reg_write(chn, 0x2, MR02Value[fsp]);
 				dramc_mode_reg_write(chn, 0xb, MR11Value[fsp]);
 
+				if (cbt_mode == CBT_R0_NORMAL_R1_BYTE) {
+					if (rank == 0)
+						MR22Value[FSP_1] = 0x3c;
+					else
+						MR22Value[FSP_1] = 0x34;
+				} else {
+					MR22Value[FSP_1] = 0x34;
+				}
+
 				dramc_mode_reg_write(chn, 0x16, MR22Value[fsp]);
 				dramc_mode_reg_write(chn, 0xe,
 					MR14Value[chn][rank][fsp]);
@@ -856,7 +870,7 @@
 	dramc_set_broadcast(broadcast_bak);
 }
 
-static void dramc_setting_DDR1600(void)
+static void dramc_setting_DDR1600(u32 cbt_mode)
 {
 	clrsetbits32(&ch[0].ao.shu[0].rankctl,
 		(0xf << 20) | (0xf << 24) | (0xf << 28),
@@ -869,8 +883,13 @@
 
 	clrsetbits32(&ch[0].ao.shu[0].selph_dqs0, 0x77777777, SELPH_DQS0_1600);
 	clrsetbits32(&ch[0].ao.shu[0].selph_dqs1, 0x77777777, SELPH_DQS1_1600);
-	clrsetbits32(&ch[0].ao.shu[0].wodt, (0x1 << 29) | (0x1 << 31),
-		(0x0 << 29) | (0x1 << 31));
+
+	if (cbt_mode)
+		clrsetbits32(&ch[0].ao.shu[0].wodt, (0x1 << 31), (0x1 << 31));
+	else
+		clrsetbits32(&ch[0].ao.shu[0].wodt, (0x1 << 29) | (0x1 << 31),
+			(0x0 << 29) | (0x1 << 31));
+
 	clrsetbits32(&ch[0].ao.shu[0].dqs2dq_tx, 0x1f << 0, 0x4 << 0);
 
 	for (size_t rank = 0; rank < 2; rank++) {
@@ -880,16 +899,21 @@
 			(0x3f << 0) | (0x3f << 8) | (0x3f << 16) | (0x3f << 24),
 			(value << 0) | (value << 8) | (value << 16) | (value << 24));
 
-		clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[0],
-			(0x7 << 8) | (0x7 << 12) |
-			(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
-			(0x2 << 8) | (0x2 << 12) |
-			(0x1 << 16) | (0x1 << 20) | (0x1 << 24) | (0x1 << 28));
-		clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[1],
-			(0x7 << 8) | (0x7 << 12) |
-			(0x7 << 16) | (0x7 << 20) | (0x7 << 24)	| (0x7 << 28),
-			(0x2 << 8) | (0x2 << 12) |
-			(0x1 << 16) | (0x1 << 20) | (0x1 << 24) | (0x1 << 28));
+		for (size_t b = 0; b < 2; b++) {
+			if (cbt_mode) {
+				clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[b],
+					(0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+					(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+					(0x2 << 0) | (0x2 << 4) | (0x2 << 8) | (0x2 << 12) |
+					(0x1 << 16) | (0x1 << 20) | (0x1 << 24) | (0x1 << 28));
+			} else {
+				clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[b],
+					(0x7 << 8) | (0x7 << 12) |
+					(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+					(0x2 << 8) | (0x2 << 12) |
+					(0x1 << 16) | (0x1 << 20) | (0x1 << 24) | (0x1 << 28));
+			}
+		}
 		clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[2],
 			0x77777777, _SELPH_DQS_BITS(0x1, 0x7));
 		clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[3],
@@ -899,11 +923,20 @@
 	clrsetbits32(&ch[0].ao.shu[0].dqsg_retry, (0x1 << 2) | (0xf << 8),
 		(0x0 << 2) | (0x3 << 8));
 	clrsetbits32(&ch[0].phy.shu[0].b[0].dq[5], 0x7 << 20, 0x4 << 20);
-	clrsetbits32(&ch[0].phy.shu[0].b[0].dq[7],
-		(0x3 << 4) | (0x1 << 7) | (0x1 << 13),
-		(0x2 << 4) | (0x0 << 7) | (0x0 << 13));
+
+	if (cbt_mode)
+		clrsetbits32(&ch[0].phy.shu[0].b[0].dq[7], (0x3 << 4),
+			(0x2 << 4));
+	else
+		clrsetbits32(&ch[0].phy.shu[0].b[0].dq[7],
+			(0x3 << 4) | (0x1 << 7) | (0x1 << 13),
+			(0x2 << 4) | (0x0 << 7) | (0x0 << 13));
+
 	clrsetbits32(&ch[0].phy.shu[0].b[1].dq[5], 0x7 << 20, 0x4 << 20);
-	clrbits32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 7) | (0x1 << 13));
+
+	if (cbt_mode == 0)
+		clrbits32(&ch[0].phy.shu[0].b[1].dq[7],
+			(0x1 << 7) | (0x1 << 13));
 
 	for (size_t r = 0; r < 2; r++) {
 		int value = ((r == 0) ? 0x1a : 0x26);
@@ -914,7 +947,7 @@
 	}
 }
 
-static void dramc_setting_DDR2400(void)
+static void dramc_setting_DDR2400(u32 cbt_mode)
 {
 	clrsetbits32(&ch[0].ao.shu[0].rankctl,
 		(0xf << 20) | (0xf << 24) | (0xf << 28),
@@ -927,8 +960,13 @@
 
 	clrsetbits32(&ch[0].ao.shu[0].selph_dqs0, 0x77777777, SELPH_DQS0_2400);
 	clrsetbits32(&ch[0].ao.shu[0].selph_dqs1, 0x77777777, SELPH_DQS1_2400);
-	clrsetbits32(&ch[0].ao.shu[0].wodt,
-		(0x1 << 29) | (0x1 << 31), (0x1 << 29) | (0x0 << 31));
+
+	if (cbt_mode)
+		clrsetbits32(&ch[0].ao.shu[0].wodt, (0x1 << 31), (0x0 << 31));
+	else
+		clrsetbits32(&ch[0].ao.shu[0].wodt,
+			(0x1 << 29) | (0x1 << 31), (0x1 << 29) | (0x0 << 31));
+
 	clrsetbits32(&ch[0].ao.shu[0].dqs2dq_tx, 0x1f << 0, 0x7 << 0);
 
 	for (size_t rank = 0; rank < 2; rank++) {
@@ -939,16 +977,21 @@
 			(0x3f << 0) | (0x3f << 8) | (0x3f << 16) | (0x3f << 24),
 			(0x14 << 0) | (0x14 << 8) | (0x14 << 16) | (0x14 << 24));
 
-		clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[0],
-			(0x7 << 8) | (0x7 << 12) |
-			(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
-			(0x3 << 8) | (0x3 << 12) |
-			(0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28));
-		clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[1],
-			(0x7 << 8) | (0x7 << 12) |
-			(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
-			(0x3 << 8) | (0x3 << 12) |
-			(0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28));
+		for (size_t b = 0; b < 2; b++) {
+			if (cbt_mode) {
+				clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[b],
+					(0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+					(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+					(0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) |
+					(0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28));
+			} else {
+				clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[b],
+					(0x7 << 8) | (0x7 << 12) |
+					(0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28),
+					(0x3 << 8) | (0x3 << 12) |
+					(0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28));
+			}
+		}
 		clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[2],
 			0x77777777, _SELPH_DQS_BITS(0x2, 0x0));
 		clrsetbits32(&ch[0].ao.shu[0].rk[rank].selph_dq[3],
@@ -958,12 +1001,19 @@
 	clrsetbits32(&ch[0].ao.shu[0].dqsg_retry,
 		(0x1 << 2) | (0xf << 8), (0x1 << 2) | (0x4 << 8));
 	clrsetbits32(&ch[0].phy.shu[0].b[0].dq[5], 0x7 << 20, 0x3 << 20);
-	clrsetbits32(&ch[0].phy.shu[0].b[0].dq[7],
-		(0x3 << 4) | (0x1 << 7) | (0x1 << 13),
-		(0x1 << 4) | (0x1 << 7) | (0x1 << 13));
+
+	if (cbt_mode)
+		clrsetbits32(&ch[0].phy.shu[0].b[0].dq[7],
+			(0x3 << 4), (0x1 << 4));
+	else
+		clrsetbits32(&ch[0].phy.shu[0].b[0].dq[7],
+			(0x3 << 4) | (0x1 << 7) | (0x1 << 13),
+			(0x1 << 4) | (0x1 << 7) | (0x1 << 13));
+
 	clrsetbits32(&ch[0].phy.shu[0].b[1].dq[5], 0x7 << 20, 0x3 << 20);
-	clrsetbits32(&ch[0].phy.shu[0].b[1].dq[7],
-		(0x1 << 7) | (0x1 << 13), (0x1 << 7) | (0x1 << 13));
+
+	if (cbt_mode == 0)
+		setbits32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 7) | (0x1 << 13));
 
 	for (size_t r = 0; r < 2; r++) {
 		for (size_t b = 0; b < 2; b++)
@@ -1288,11 +1338,13 @@
 		(0x4 << 20) | (0x4 << 24) | (0x6 << 28));
 	udelay(2);
 
-	clrsetbits32(&ch[0].ao.shu[0].rk[0].dqsien,
-		(0x7f << 0) | (0x7f << 8), (0x19 << 0) | (0x19 << 8));
-	clrsetbits32(&ch[0].ao.shu[0].rk[1].dqsien,
-		(0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24),
-		(0x1b << 0) | (0x1b << 8) | (0x0 << 16) | (0x0 << 24));
+	if (params->cbt_mode_extern == CBT_R0_R1_NORMAL) {
+		clrsetbits32(&ch[0].ao.shu[0].rk[0].dqsien,
+			(0x7f << 0) | (0x7f << 8), (0x19 << 0) | (0x19 << 8));
+		clrsetbits32(&ch[0].ao.shu[0].rk[1].dqsien,
+			(0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24),
+			(0x1b << 0) | (0x1b << 8) | (0x0 << 16) | (0x0 << 24));
+	}
 
 	setbits32(&ch[0].ao.dramctrl, 0x1 << 19);
 	clrsetbits32(&ch[0].ao.zqcs, 0xff << 0, 0x56 << 0);
@@ -1317,25 +1369,34 @@
 	udelay(1);
 	clrsetbits32(&ch[0].ao.hw_mrr_fun, (0xf << 0) | (0xf << 4), (0x8 << 0) | (0x6 << 4));
 
-	clrbits32(&ch[0].ao.dramctrl, 0x1 << 0);
-	clrsetbits32(&ch[0].ao.perfctl0,
-		(0x1 << 18) | (0x1 << 19), (0x0 << 18) | (0x1 << 19));
-	setbits32(&ch[0].ao.spcmdctrl, 0x1 << 28);
-	clrbits32(&ch[0].ao.rstmask, 0x1 << 28);
-	setbits32(&ch[0].ao.rkcfg, 0x1 << 11);
-	setbits32(&ch[0].ao.mpc_option, 0x1 << 17);
-	setbits32(&ch[0].ao.eyescan, 0x1 << 2);
-	setbits32(&ch[0].ao.shu[0].wodt, 0x1 << 29);
-	setbits32(&ch[0].phy.shu[0].b[0].dq[7], 0x1 << 7);
-	setbits32(&ch[0].phy.shu[0].b[1].dq[7], 0x1 << 7);
-	clrsetbits32(&ch[0].ao.shu[0].rankctl, 0xf << 20, 0x4 << 20);
+	if (params->cbt_mode_extern != CBT_R0_R1_NORMAL) {
+		clrsetbits32(&ch[0].ao.perfctl0,
+			(0x1 << 18) | (0x1 << 19) | (0x1 << 27),
+			(0x0 << 18) | (0x1 << 19) | (0x1 << 27));
+		clrbits32(&ch[0].ao.rstmask, 0x1 << 28);
+		setbits32(&ch[0].ao.rkcfg, 0x1 << 11);
+		setbits32(&ch[0].ao.spcmdctrl, 0x1 << 28);
+		setbits32(&ch[0].ao.eyescan, 0x1 << 2);
+	} else {
+		clrbits32(&ch[0].ao.dramctrl, 0x1 << 0);
+		clrsetbits32(&ch[0].ao.perfctl0,
+			(0x1 << 18) | (0x1 << 19), (0x0 << 18) | (0x1 << 19));
+		setbits32(&ch[0].ao.spcmdctrl, 0x1 << 28);
+		clrbits32(&ch[0].ao.rstmask, 0x1 << 28);
+		setbits32(&ch[0].ao.rkcfg, 0x1 << 11);
+		setbits32(&ch[0].ao.mpc_option, 0x1 << 17);
+		setbits32(&ch[0].ao.eyescan, 0x1 << 2);
+		setbits32(&ch[0].ao.shu[0].wodt, 0x1 << 29);
+		setbits32(&ch[0].phy.shu[0].b[0].dq[7], 0x1 << 7);
+		setbits32(&ch[0].phy.shu[0].b[1].dq[7], 0x1 << 7);
+		clrsetbits32(&ch[0].ao.shu[0].rankctl, 0xf << 20, 0x4 << 20);
 
-	for (size_t r = 0; r < 2; r++) {
-		clrsetbits32(&ch[0].ao.shu[0].rk[r].selph_dq[0],
-			(0x7 << 0) | (0x7 << 4), (0x2 << 0) | (0x2 << 4));
-		clrsetbits32(&ch[0].ao.shu[0].rk[r].selph_dq[1],
-			(0x7 << 0) | (0x7 << 4), (0x2 << 0) | (0x2 << 4));
+		for (size_t r = 0; r < 2; r++)
+			for (size_t b = 0; b < 2; b++)
+				clrsetbits32(&ch[0].ao.shu[0].rk[r].selph_dq[b],
+					(0x7 << 0) | (0x7 << 4), (0x2 << 0) | (0x2 << 4));
 	}
+
 	udelay(5);
 
 	clrsetbits32(&ch[0].ao.stbcal1, 0xffff << 16, 0x3 << 16);
@@ -1363,9 +1424,26 @@
 	clrsetbits32(&ch[0].ao.rkcfg, 0x7 << 4, 0x1 << 4);
 	udelay(12);
 
-	clrsetbits32(&ch[0].ao.shu[0].rankctl,
-		(0xf << 24) | (0xf << 28), (0x4 << 24) | 0x6 << 28);
+	if (params->cbt_mode_extern != CBT_R0_R1_NORMAL)
+		clrsetbits32(&ch[0].ao.shu[0].rankctl,
+			(0xf << 20) | (0xf << 24) | (0xf << 28),
+				(0x3 << 20) | (0x3 << 24) | (0x5 << 28));
+	else
+		clrsetbits32(&ch[0].ao.shu[0].rankctl,
+			(0xf << 24) | (0xf << 28),
+			(0x4 << 24) | (0x6 << 28));
+
 	clrbits32(&ch[0].ao.shu[0].wodt, 0x1 << 31);
+
+	if (params->cbt_mode_extern != CBT_R0_R1_NORMAL) {
+		clrsetbits32(&ch[0].ao.shu[0].rk[0].dqsien,
+			(0x7f << 0) | (0x7f << 8),
+			(0x19 << 0) | (0x19 << 8));
+		clrsetbits32(&ch[0].ao.shu[0].rk[1].dqsien,
+			(0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24),
+			(0x1b << 0) | (0x1b << 8) | (0x0 << 16) | (0x0 << 24));
+	}
+
 	clrsetbits32(&ch[0].ao.shu[0].rk[0].fine_tune,
 		(0x3f << 0) | (0x3f << 8) | (0x3f << 16) | (0x3f << 24),
 		(0x1a << 0) | (0x1a << 8) | (0x1a << 16) | (0x1a << 24));
@@ -1383,8 +1461,16 @@
 	clrsetbits32(&ch[0].ao.shu[0].dqsg_retry,
 		(0x1 << 2) | (0xf << 8) | (0x1 << 14) | (0x3 << 24),
 		(0x1 << 2) | (0x5 << 8) | (0x0 << 14) | (0x1 << 24));
-	setbits32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 12) | (0x1 << 13));
-	setbits32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 12) | (0x1 << 13));
+
+	if (params->cbt_mode_extern != CBT_R0_R1_NORMAL) {
+		setbits32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 12));
+		setbits32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 12));
+	} else {
+		setbits32(&ch[0].phy.shu[0].b[0].dq[7],
+			(0x1 << 12) | (0x1 << 13));
+		setbits32(&ch[0].phy.shu[0].b[1].dq[7],
+			(0x1 << 12) | (0x1 << 13));
+	}
 	clrbits32(&ch[0].ao.shu[0].dqs2dq_tx, 0x1f << 0);
 
 	/* The default dramc init settings were tuned at frequency of 3200Mbps.
@@ -1392,10 +1478,10 @@
 	   the default settings. */
 	switch (freq_group) {
 	case LP4X_DDR1600:
-		dramc_setting_DDR1600();
+		dramc_setting_DDR1600(params->cbt_mode_extern);
 		break;
 	case LP4X_DDR2400:
-		dramc_setting_DDR2400();
+		dramc_setting_DDR2400(params->cbt_mode_extern);
 		break;
 	case LP4X_DDR3200:
 		/* Do nothing */
@@ -1423,7 +1509,7 @@
 		(0x1 << 4) | (0x1 << 11) | (0x1 << 13) |
 		(0x1 << 14) | (0x3 << 16) | (0x1 << 22),
 		(0x1 << 4) | (0x1 << 11) | (0x1 << 13) |
-		(0x1 << 14) | (0x2 << 16) | (0x1 << 22));
+		(0x1 << 14) | (params->rank_num << 16) | (0x1 << 22));
 	clrsetbits32(&ch[0].ao.test2_4, 0x7 << 28, 0x4 << 28);
 	clrbits32(&ch[0].ao.dramctrl, 0x1 << 0);
 	udelay(1);
@@ -1630,7 +1716,150 @@
 	},
 };
 
-static void ddr_update_ac_timing(u8 freq_group)
+static const struct ac_time ac_timing_cbt_tbl[LP4X_DDRFREQ_MAX] = {
+	/* LP4x-1600, 800MHz, RDBI_OFF, byte mode */
+	[LP4X_DDR1600] = {
+		.tras = 0,	.tras_05T = 0,
+		.trp = 2,	.trp_05T = 0,
+		.trpab = 0,	.trpab_05T = 1,
+		.trc = 4,	.trc_05T = 0,
+		.trfc = 44,	.trfc_05T = 0,
+		.trfcpb = 16,	.trfcpb_05T = 0,
+		.txp = 0,	.txp_05T = 0,
+		.trtp = 1,	.trtp_05T = 1,
+		.trcd = 3,	.trcd_05T = 0,
+		.twr = 7,	.twr_05T = 0,
+		.twtr = 4,	.twtr_05T = 0,
+		.trrd = 0,	.trrd_05T = 0,
+		.tfaw = 0,	.tfaw_05T = 0,
+		.trtw_odt_on = 4,	.trtw_odt_on_05T = 0,
+		.refcnt = 48,
+		.refcnt_fr_clk = 101,
+		.txrefcnt = 62,
+		.tzqcs = 16,
+		.xrtw2w = 5,
+		.xrtw2r = 3,
+		.xrtr2w = 3,
+		.xrtr2r = 8,
+		.r_dmcatrain_intv = 8,
+		.r_dmmrw_intv = 0xf,
+		.r_dmfspchg_prdcnt = 50,
+		.trtpd = 7,	.trtpd_05T = 0,
+		.twtpd = 7,	.twtpd_05T = 1,
+		.tmrr2w_odt_on = 6,
+		.ckeprd = 1,
+		.ckelckcnt = 0,
+		.zqlat2 = 6,
+		.dqsinctl = 2,	 .datlat = 11,
+	},
+	/* LP4x-2400, 1200MHz, RDBI_OFF, byte mode */
+	[LP4X_DDR2400] = {
+		.tras = 4,	.tras_05T = 1,
+		.trp = 3,	.trp_05T = 1,
+		.trpab = 1,	.trpab_05T = 0,
+		.trc = 10,	.trc_05T = 0,
+		.trfc = 72,	.trfc_05T = 0,
+		.trfcpb = 30,	.trfcpb_05T = 0,
+		.txp = 0,	.txp_05T = 1,
+		.trtp = 1,	.trtp_05T = 0,
+		.trcd = 4,	.trcd_05T = 1,
+		.twr = 10,	.twr_05T = 1,
+		.twtr = 6,	.twtr_05T = 1,
+		.trrd = 1,	.trrd_05T = 0,
+		.tfaw = 3,	.tfaw_05T = 0,
+		.trtw_odt_on = 7,	.trtw_odt_on_05T = 0,
+		.refcnt = 73,
+		.refcnt_fr_clk = 101,
+		.txrefcnt = 91,
+		.tzqcs = 25,
+		.xrtw2w = 5,
+		.xrtw2r = 3,
+		.xrtr2w = 6,
+		.xrtr2r = 8,
+		.r_dmcatrain_intv = 9,
+		.r_dmmrw_intv = 0xf,
+		.r_dmfspchg_prdcnt = 75,
+		.trtpd = 10,	.trtpd_05T = 0,
+		.twtpd = 10,	.twtpd_05T = 0,
+		.tmrr2w_odt_on = 9,
+		.ckeprd = 2,
+		.ckelckcnt = 0,
+		.zqlat2 = 9,
+		.dqsinctl = 4,	 .datlat = 14,
+	},
+	/* LP4x-3200, 1600MHz, RDBI_OFF, byte mode */
+	[LP4X_DDR3200] = {
+		.tras = 8,	.tras_05T = 1,
+		.trp = 5,	.trp_05T = 1,
+		.trpab = 1,	.trpab_05T = 0,
+		.trc = 16,	.trc_05T = 1,
+		.trfc = 100,	.trfc_05T = 0,
+		.trfcpb = 44,	.trfcpb_05T = 0,
+		.txp = 1,	.txp_05T = 0,
+		.trtp = 2,	.trtp_05T = 1,
+		.trcd = 6,	.trcd_05T = 1,
+		.twr = 13,	.twr_05T = 1,
+		.twtr = 8,	.twtr_05T = 0,
+		.trrd = 2,	.trrd_05T = 0,
+		.tfaw = 7,	.tfaw_05T = 0,
+		.trtw_odt_on = 8,	.trtw_odt_on_05T = 0,
+		.refcnt = 97,
+		.refcnt_fr_clk = 101,
+		.txrefcnt = 119,
+		.tzqcs = 34,
+		.xrtw2w = 5,
+		.xrtw2r = 3,
+		.xrtr2w = 7,
+		.xrtr2r = 9,
+		.r_dmcatrain_intv = 11,
+		.r_dmmrw_intv = 0xf,
+		.r_dmfspchg_prdcnt = 100,
+		.trtpd = 12,	.trtpd_05T = 0,
+		.twtpd = 12,	.twtpd_05T = 0,
+		.tmrr2w_odt_on = 11,
+		.ckeprd = 2,
+		.ckelckcnt = 0,
+		.zqlat2 = 12,
+		.dqsinctl = 5,	 .datlat = 16,
+	},
+	/* LP4x-3600, 1800MHz, RDBI_OFF, byte mode */
+	[LP4X_DDR3600] = {
+		.tras = 11,	.tras_05T = 1,
+		.trp = 6,	.trp_05T = 1,
+		.trpab = 1,	.trpab_05T = 1,
+		.trc = 20,	.trc_05T = 1,
+		.trfc = 118,	.trfc_05T = 1,
+		.trfcpb = 53,	.trfcpb_05T = 1,
+		.txp = 1,	.txp_05T = 1,
+		.trtp = 2,	.trtp_05T = 0,
+		.trcd = 7,	.trcd_05T = 1,
+		.twr = 15,	.twr_05T = 1,
+		.twtr = 9,	.twtr_05T = 0,
+		.trrd = 3,	.trrd_05T = 0,
+		.tfaw = 10,	.tfaw_05T = 0,
+		.trtw_odt_on = 9,	.trtw_odt_on_05T = 0,
+		.refcnt = 113,
+		.refcnt_fr_clk = 101,
+		.txrefcnt = 138,
+		.tzqcs = 40,
+		.xrtw2w = 5,
+		.xrtw2r = 3,
+		.xrtr2w = 8,
+		.xrtr2r = 9,
+		.r_dmcatrain_intv = 13,
+		.r_dmmrw_intv = 0xf,
+		.r_dmfspchg_prdcnt = 117,
+		.trtpd = 13,	.trtpd_05T = 0,
+		.twtpd = 14,	.twtpd_05T = 0,
+		.tmrr2w_odt_on = 10,
+		.ckeprd = 3,
+		.ckelckcnt = 0,
+		.zqlat2 = 14,
+		.dqsinctl = 7,	 .datlat = 17,
+	},
+};
+
+static void ddr_update_ac_timing(u8 freq_group, u32 cbt_mode)
 {
 	struct ac_time ac_t;
 	u32 temp, r2w_odt_onoff = ODT_ON;
@@ -1638,8 +1867,12 @@
 	u8 root = 0, tx_rank_inctl = 0, tx_dly = 0;
 	u8 trtw = 0, trtw_05t = 0, tmrr2w = 0;
 
-	memcpy(&ac_t, &ac_timing_tbl[freq_group], sizeof(struct ac_time));
-	new_datlat = ac_timing_tbl[freq_group].datlat - 2;
+	if (cbt_mode)
+		memcpy(&ac_t, &ac_timing_cbt_tbl[freq_group], sizeof(struct ac_time));
+	else
+		memcpy(&ac_t, &ac_timing_tbl[freq_group], sizeof(struct ac_time));
+
+	new_datlat = ac_t.datlat - 2;
 
 	if (freq_group == LP4X_DDR1600) {
 		root = 0; tx_rank_inctl = 0; tx_dly = 1;
@@ -1729,10 +1962,13 @@
 			(root << 16) | (tx_rank_inctl << 12) | (tx_dly << 8));
 	}
 
-	u8 dram_cbt_mode = 0;
 	clrsetbits32(&ch[0].ao.arbctl, 0x7 << 10, 0x3 << 10);
-	clrsetbits32(&ch[0].ao.rstmask, 0x3 << 13, dram_cbt_mode);
-	clrsetbits32(&ch[0].ao.arbctl, 0x1 << 13, dram_cbt_mode);
+	clrsetbits32(&ch[0].ao.rstmask, 0x3 << 13, cbt_mode << 13);
+
+	if (cbt_mode == 0)
+		clrsetbits32(&ch[0].ao.arbctl, 0x1 << 13, 0 << 13);
+	else
+		clrsetbits32(&ch[0].ao.arbctl, 0x1 << 13, 1 << 13);
 }
 
 void dramc_init(const struct sdram_params *params, u8 freq_group,
@@ -1743,6 +1979,6 @@
 	dramc_duty_calibration(params, freq_group);
 	dvfs_settings(freq_group);
 
-	dramc_mode_reg_init(freq_group, &shared->mr);
-	ddr_update_ac_timing(freq_group);
+	dramc_mode_reg_init(freq_group, &shared->mr, params);
+	ddr_update_ac_timing(freq_group, params->cbt_mode_extern);
 }
diff --git a/src/soc/mediatek/mt8183/dramc_pi_basic_api.c b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
index 4a884b1..d992371 100644
--- a/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
+++ b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
@@ -347,9 +347,9 @@
 		(chn == CHANNEL_A) ? 0xba000 : 0x3a000);
 }
 
-static void dramc_dummy_read_for_tracking_enable(u8 chn)
+static void dramc_dummy_read_for_tracking_enable(u8 chn, u32 rk_num)
 {
-	setbits32(&ch[chn].ao.dummy_rd, 0x3 << 16);
+	setbits32(&ch[chn].ao.dummy_rd, rk_num << 16);
 
 	for (size_t r = 0; r < 2; r++)
 		for (size_t i = 0; i < 4; i++)
@@ -403,7 +403,7 @@
 	}
 }
 
-void dramc_runtime_config(void)
+void dramc_runtime_config(u32 rk_num)
 {
 	for (u8 chn = 0; chn < CHANNEL_MAX; chn++)
 		clrbits32(&ch[chn].ao.refctrl0, 0x1 << 29);
@@ -412,7 +412,7 @@
 	setbits32(&mtk_spm->spm_power_on_val0, 0x1 << 25);
 
 	for (u8 chn = 0; chn < CHANNEL_MAX; chn++) {
-		dramc_hw_dqsosc(chn);
+		dramc_hw_dqsosc(chn, rk_num);
 
 		/* RX_TRACKING: ON */
 		dramc_rx_input_delay_tracking(chn);
@@ -426,7 +426,7 @@
 			  (0x3 << 4) | (0x3 << 8) | (0x1 << 28));
 
 		/* DUMMY_READ_FOR_TRACKING: ON */
-		dramc_dummy_read_for_tracking_enable(chn);
+		dramc_dummy_read_for_tracking_enable(chn, rk_num);
 
 		/* ZQCS_ENABLE_LP4: ON */
 		clrbits32(&ch[chn].ao.spcmdctrl, 0x1 << 30);
diff --git a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
index 17fa230..ec39049 100644
--- a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
+++ b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
@@ -266,7 +266,7 @@
 }
 
 static void set_dram_mr_cbt_on_off(u8 chn, u8 rank, u8 fsp,
-	u8 cbt_on, struct mr_value *mr)
+	bool cbt_on, struct mr_value *mr, u32 cbt_mode)
 {
 	u8 MR13Value = mr->MR13Value;
 
@@ -276,6 +276,9 @@
 			MR13Value &= 0x7f;
 		else
 			MR13Value |= 0x80;
+
+		if (cbt_mode)
+			SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_BYTEMODECBTEN, 1);
 	} else {
 		MR13Value &= 0xfe;
 		if (fsp == FSP_1)
@@ -322,7 +325,7 @@
 	udelay(1);
 }
 
-static void cbt_entry(u8 chn, u8 rank, u8 fsp, struct mr_value *mr)
+static void cbt_entry(u8 chn, u8 rank, u8 fsp, struct mr_value *mr, u32 cbt_mode)
 {
 	SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl,
 		DRAMC_PD_CTRL_PHYCLKDYNGEN, 0,
@@ -331,26 +334,31 @@
 	SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl, DRAMC_PD_CTRL_MIOCKCTRLOFF, 1);
 
 	dramc_cke_fix_onoff(CKE_FIXON, chn);
-	set_dram_mr_cbt_on_off(chn, rank, fsp, 1, mr);
-	SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_WRITE_LEVEL_EN, 1);
+	set_dram_mr_cbt_on_off(chn, rank, fsp, true, mr, cbt_mode);
+
+	if (cbt_mode == 0)
+		SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_WRITE_LEVEL_EN, 1);
 
 	udelay(1);
 	dramc_cke_fix_onoff(CKE_FIXOFF, chn);
 	o1_path_on_off(1);
 }
 
-static void cbt_exit(u8 chn, u8 rank, u8 fsp, struct mr_value *mr)
+static void cbt_exit(u8 chn, u8 rank, u8 fsp, struct mr_value *mr, u32 cbt_mode)
 {
 	dramc_cke_fix_onoff(CKE_FIXON, chn);
 
 	udelay(1);
-	set_dram_mr_cbt_on_off(chn, rank, fsp, 0, mr);
+	set_dram_mr_cbt_on_off(chn, rank, fsp, false, mr, cbt_mode);
 	o1_path_on_off(0);
+
+	if (cbt_mode)
+		SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_BYTEMODECBTEN, 0);
 }
 
-static void cbt_set_vref(u8 chn, u8 rank, u8 vref, bool is_final)
+static void cbt_set_vref(u8 chn, u8 rank, u8 vref, bool is_final, u32 cbt_mode)
 {
-	if (!is_final) {
+	if (cbt_mode == 0 && !is_final) {
 		SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_DMVREFCA, vref);
 		SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_DQS_SEL, 1);
 		SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_DQSBX_G, 0xa);
@@ -394,12 +402,18 @@
 	}
 }
 
-static u8 get_cbt_vref_pinmux_value(u8 chn, u8 vref_level)
+static u8 get_cbt_vref_pinmux_value(u8 chn, u8 vref_level, u32 cbt_mode)
 {
 	u8 vref_bit, vref_new, vref_org;
 
 	vref_new = 0;
 	vref_org = BIT(6) | (vref_level & 0x3f);
+
+	if (cbt_mode) {
+		dramc_dbg("vref_org: %#x for byte mode\n", vref_org);
+
+		return vref_org;
+	}
 	for (vref_bit = 0; vref_bit < 8; vref_bit++) {
 		if (vref_org & (1 << vref_bit))
 			vref_new |=  (1 << phy_mapping[chn][vref_bit]);
@@ -410,11 +424,14 @@
 	return vref_new;
 }
 
-static void cbt_dramc_dfs_direct_jump(u8 shu_level)
+static void cbt_dramc_dfs_direct_jump(u8 shu_level, bool run_dvfs)
 {
 	u8 shu_ack = 0;
 	static bool phy_pll_en = true;
 
+	if (!run_dvfs)
+		return;
+
 	for (u8 chn = 0; chn < CHANNEL_MAX; chn++)
 		shu_ack |= (0x1 << chn);
 
@@ -490,20 +507,21 @@
 	phy_pll_en = !phy_pll_en;
 }
 
-static void cbt_switch_freq(cbt_freq freq)
+static void cbt_switch_freq(cbt_freq freq, bool run_dvfs)
 {
 	if (freq == CBT_LOW_FREQ)
-		cbt_dramc_dfs_direct_jump(DRAM_DFS_SHUFFLE_MAX - 1);
+		cbt_dramc_dfs_direct_jump(DRAM_DFS_SHUFFLE_MAX - 1, run_dvfs);
 	else
-		cbt_dramc_dfs_direct_jump(DRAM_DFS_SHUFFLE_1);
+		cbt_dramc_dfs_direct_jump(DRAM_DFS_SHUFFLE_1, run_dvfs);
 }
 
 static void dramc_cmd_bus_training(u8 chn, u8 rank, u8 freq_group,
-	const struct sdram_params *params, const bool fast_calib,
-	struct mr_value *mr)
+				   const struct sdram_params *params, struct mr_value *mr,
+				   bool run_dvfs)
 {
 	u8 final_vref, cs_dly;
 	u8 fsp = get_freq_fsq(freq_group);
+	u32 cbt_mode = params->cbt_mode_extern;
 
 	cs_dly = params->cbt_cs_dly[chn][rank];
 	final_vref = params->cbt_final_vref[chn][rank];
@@ -521,6 +539,7 @@
 		regs_bak[i].value = read32(regs_bak[i].addr);
 
 	dramc_auto_refresh_switch(chn, false);
+
 	if (rank == RANK_1) {
 		SET32_BITFIELDS(&ch[chn].ao.mrs, MRS_MRSRK, rank);
 		SET32_BITFIELDS(&ch[chn].ao.rkcfg, RKCFG_TXRANK, rank);
@@ -530,16 +549,35 @@
 
 	cbt_set_perbit_delay_cell(chn, rank);
 
-	if (fsp == FSP_1)
-		cbt_switch_freq(CBT_LOW_FREQ);
-	cbt_entry(chn, rank, fsp, mr);
-	if (fsp == FSP_1)
-		cbt_switch_freq(CBT_HIGH_FREQ);
+	if (cbt_mode == 0) {
+		cbt_mrr_pinmux_mapping();
+		if (fsp == FSP_1)
+			cbt_switch_freq(CBT_LOW_FREQ, run_dvfs);
+		cbt_entry(chn, rank, fsp, mr, cbt_mode);
+		udelay(1);
+		if (fsp == FSP_1)
+			cbt_switch_freq(CBT_HIGH_FREQ, run_dvfs);
+	}
 
-	u8 new_vref = get_cbt_vref_pinmux_value(chn, final_vref);
-	cbt_set_vref(chn, rank, new_vref, 0);
+	u8 new_vref = get_cbt_vref_pinmux_value(chn, final_vref, cbt_mode);
+
+	if (cbt_mode) {
+		if (fsp == FSP_1)
+			cbt_switch_freq(CBT_LOW_FREQ, run_dvfs);
+
+		cbt_set_fsp(chn, rank, fsp, mr);
+		cbt_set_vref(chn, rank, new_vref, true, cbt_mode);
+		cbt_entry(chn, rank, fsp, mr, cbt_mode);
+		udelay(1);
+
+		if (fsp == FSP_1)
+			cbt_switch_freq(CBT_HIGH_FREQ, run_dvfs);
+	} else {
+		cbt_set_vref(chn, rank, new_vref, false, cbt_mode);
+	}
 
 	cbt_set_ca_clk_result(chn, rank, params);
+	udelay(1);
 
 	for (u8 rk = 0; rk < rank + 1; rk++) {
 		/* Set CLK and CS delay */
@@ -548,14 +586,16 @@
 	}
 
 	if (fsp == FSP_1)
-		cbt_switch_freq(CBT_LOW_FREQ);
-	cbt_exit(chn, rank, fsp, mr);
+		cbt_switch_freq(CBT_LOW_FREQ, run_dvfs);
+	cbt_exit(chn, rank, fsp, mr, cbt_mode);
 
-	cbt_set_fsp(chn, rank, fsp, mr);
-	cbt_set_vref(chn, rank, final_vref, 1);
+	if (cbt_mode == 0) {
+		cbt_set_fsp(chn, rank, fsp, mr);
+		cbt_set_vref(chn, rank, final_vref, true, cbt_mode);
+	}
 
 	if (fsp == FSP_1)
-		cbt_switch_freq(CBT_HIGH_FREQ);
+		cbt_switch_freq(CBT_HIGH_FREQ, run_dvfs);
 
 	/* restore MRR pinmux */
 	set_mrr_pinmux_mapping();
@@ -693,7 +733,7 @@
 	clrbits32(&shu->b[1].dq[7], (0x1 << 12) | (0x1 << 13));
 }
 
-void dramc_apply_config_before_calibration(u8 freq_group)
+void dramc_apply_config_before_calibration(u8 freq_group, u32 cbt_mode)
 {
 	for (u8 chn = 0; chn < CHANNEL_MAX; chn++) {
 		dramc_enable_phy_dcm(chn, false);
@@ -710,8 +750,20 @@
 		clrbits32(&ch[chn].ao.dramctrl, 0x1 << 18);
 		clrbits32(&ch[chn].ao.spcmdctrl, 0x1 << 31);
 		clrbits32(&ch[chn].ao.spcmdctrl, 0x1 << 30);
-		clrbits32(&ch[chn].ao.dqsoscr, 0x1 << 26);
-		clrbits32(&ch[chn].ao.dqsoscr, 0x1 << 25);
+
+		if (cbt_mode == CBT_R0_R1_NORMAL) {
+			clrbits32(&ch[chn].ao.dqsoscr, 0x1 << 26);
+			clrbits32(&ch[chn].ao.dqsoscr, 0x1 << 25);
+		} else if (cbt_mode == CBT_R0_R1_BYTE) {
+			setbits32(&ch[chn].ao.dqsoscr, 0x1 << 26);
+			setbits32(&ch[chn].ao.dqsoscr, 0x1 << 25);
+		} else if (cbt_mode == CBT_R0_NORMAL_R1_BYTE) {
+			clrbits32(&ch[chn].ao.dqsoscr, 0x1 << 26);
+			setbits32(&ch[chn].ao.dqsoscr, 0x1 << 25);
+		} else if (cbt_mode == CBT_R0_BYTE_R1_NORMAL) {
+			setbits32(&ch[chn].ao.dqsoscr, 0x1 << 26);
+			clrbits32(&ch[chn].ao.dqsoscr, 0x1 << 25);
+		}
 
 		dramc_write_dbi_onoff(chn, false);
 		dramc_read_dbi_onoff(chn, false);
@@ -751,9 +803,9 @@
 	}
 }
 
-static void dramc_set_mr13_vrcg_to_Normal(u8 chn, const struct mr_value *mr)
+static void dramc_set_mr13_vrcg_to_normal(u8 chn, const struct mr_value *mr, u32 rk_num)
 {
-	for (u8 rank = 0; rank < RANK_MAX; rank++)
+	for (u8 rank = 0; rank < rk_num; rank++)
 		dramc_mode_reg_write_by_rank(chn, rank, 13,
 					     mr->MR13Value & ~(0x1 << 3));
 
@@ -761,14 +813,14 @@
 		clrbits32(&ch[chn].ao.shu[shu].hwset_vrcg, 0x1 << 19);
 }
 
-void dramc_apply_config_after_calibration(const struct mr_value *mr)
+void dramc_apply_config_after_calibration(const struct mr_value *mr, u32 rk_num)
 {
 	for (size_t chn = 0; chn < CHANNEL_MAX; chn++) {
 		write32(&ch[chn].phy.misc_cg_ctrl4, 0x11400000);
 		clrbits32(&ch[chn].ao.refctrl1, 0x1 << 7);
 		clrbits32(&ch[chn].ao.shuctrl, 0x1 << 2);
 		clrbits32(&ch[chn].phy.ca_cmd[6], 0x1 << 6);
-		dramc_set_mr13_vrcg_to_Normal(chn, mr);
+		dramc_set_mr13_vrcg_to_normal(chn, mr, rk_num);
 
 		clrbits32(&ch[chn].phy.b[0].dq[6], 0x3);
 		clrbits32(&ch[chn].phy.b[1].dq[6], 0x3);
@@ -2358,7 +2410,7 @@
 	dramc_dle_factor_handler(chn, final_datlat, freq_group);
 }
 
-static void dramc_rx_dqs_gating_post_process(u8 chn, u8 freq_group)
+static void dramc_rx_dqs_gating_post_process(u8 chn, u8 freq_group, u32 rk_num)
 {
 	s8 dqsinctl;
 	u32 read_dqsinctl, rankinctl_root, reg_tx_dly_dqsgated_min = 3;
@@ -2372,7 +2424,7 @@
 		reg_tx_dly_dqsgated_min = 1;
 
 	/* get TXDLY_Cal_min and TXDLY_Cal_max value */
-	for (size_t rank = 0; rank < RANK_MAX; rank++) {
+	for (size_t rank = 0; rank < rk_num; rank++) {
 		u32 dqsg0 = read32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0);
 		for (size_t dqs = 0; dqs < DQS_NUMBER; dqs++) {
 			best_coarse_tune2t[rank][dqs] = (dqsg0 >> (dqs * 8)) & 0x7;
@@ -2397,7 +2449,7 @@
 		txdly_cal_min += dqsinctl;
 		txdly_cal_max += dqsinctl;
 
-		for (size_t rank = 0; rank < RANK_MAX; rank++) {
+		for (size_t rank = 0; rank < rk_num; rank++) {
 			dramc_dbg("Rank: %zd\n", rank);
 			for (size_t dqs = 0; dqs < DQS_NUMBER; dqs++) {
 				best_coarse_tune2t[rank][dqs] += dqsinctl;
@@ -2515,7 +2567,7 @@
 			SHU1RK0_DQSOSC_DQSOSC_BASE_RK0_B1, dqsosc_cnt[1]);
 }
 
-void dramc_hw_dqsosc(u8 chn)
+void dramc_hw_dqsosc(u8 chn, u32 rk_num)
 {
 	u32 freq_shu1 = get_shu_freq(DRAM_DFS_SHUFFLE_1);
 	u32 freq_shu2 = get_shu_freq(DRAM_DFS_SHUFFLE_2);
@@ -2544,7 +2596,10 @@
 	SET32_BITFIELDS(&ch[chn].ao.dqsoscr, DQSOSCR_DQSOSCRDIS, 1);
 
 	SET32_BITFIELDS(&ch[chn].ao.rk[0].dqsosc, RK0_DQSOSC_DQSOSCR_RK0EN, 1);
-	SET32_BITFIELDS(&ch[chn].ao.rk[1].dqsosc, RK1_DQSOSC_DQSOSCR_RK1EN, 1);
+
+	if (rk_num == RANK_MAX)
+		SET32_BITFIELDS(&ch[chn].ao.rk[1].dqsosc, RK1_DQSOSC_DQSOSCR_RK1EN, 1);
+
 	SET32_BITFIELDS(&ch[chn].ao.dqsoscr, DQSOSCR_DQSOSC_CALEN, 1);
 
 	for (u8 shu = 0; shu < DRAM_DFS_SHUFFLE_MAX; shu++)
@@ -2994,7 +3049,7 @@
 	}
 }
 
-void get_dram_info_after_cal(u8 *density_result)
+void get_dram_info_after_cal(u8 *density_result, u32 rk_num)
 {
 	u8 vendor_id, density, max_density = 0;
 	u32 ddr_size, max_size = 0;
@@ -3002,7 +3057,7 @@
 	vendor_id = dramc_mode_reg_read_by_rank(CHANNEL_A, RANK_0, 5);
 	dramc_show("Vendor id is %#x\n", vendor_id);
 
-	for (u8 rk = RANK_0; rk < RANK_MAX; rk++) {
+	for (u8 rk = RANK_0; rk < rk_num; rk++) {
 		density = dramc_mode_reg_read_by_rank(CHANNEL_A, rk, 8);
 		dramc_dbg("MR8 %#x\n", density);
 		density = (density >> 2) & 0xf;
@@ -3044,7 +3099,7 @@
 }
 
 int dramc_calibrate_all_channels(const struct sdram_params *pams,
-				 u8 freq_group, struct mr_value *mr)
+				 u8 freq_group, struct mr_value *mr, bool run_dvfs)
 {
 	bool fast_calib;
 	switch (pams->source) {
@@ -3064,11 +3119,11 @@
 	u16 osc_thrd_inc[RANK_MAX];
 	u16 osc_thrd_dec[RANK_MAX];
 	for (u8 chn = 0; chn < CHANNEL_MAX; chn++) {
-		for (u8 rk = RANK_0; rk < RANK_MAX; rk++) {
+		for (u8 rk = RANK_0; rk < pams->rank_num; rk++) {
 			dramc_dbg("Start K: freq=%d, ch=%d, rank=%d\n",
 				  freq_group, chn, rk);
 			dramc_cmd_bus_training(chn, rk, freq_group, pams,
-				fast_calib, mr);
+				mr, run_dvfs);
 			dramc_write_leveling(chn, rk, freq_group, pams->wr_level);
 			dramc_auto_refresh_switch(chn, true);
 
@@ -3092,7 +3147,7 @@
 		}
 
 		dqsosc_shu_settings(chn, freq_group, osc_thrd_inc, osc_thrd_dec);
-		dramc_rx_dqs_gating_post_process(chn, freq_group);
+		dramc_rx_dqs_gating_post_process(chn, freq_group, pams->rank_num);
 		dramc_dual_rank_rx_datlat_cal(chn, freq_group, rx_datlat[0], rx_datlat[1]);
 	}
 	return 0;
diff --git a/src/soc/mediatek/mt8183/emi.c b/src/soc/mediatek/mt8183/emi.c
index 8afbef0..5e4f01531 100644
--- a/src/soc/mediatek/mt8183/emi.c
+++ b/src/soc/mediatek/mt8183/emi.c
@@ -157,6 +157,19 @@
 			(is_dual_rank ? 0 : 1) << 12);
 }
 
+void cbt_mrr_pinmux_mapping(void)
+{
+	for (size_t chn = 0; chn < CHANNEL_MAX; chn++) {
+		const u8 *map = phy_mapping[chn];
+		write32(&ch[chn].ao.mrr_bit_mux1,
+			(map[8] << 0) | (map[9] << 8) |
+			(map[10] << 16) | (map[11] << 24));
+
+		write32(&ch[chn].ao.mrr_bit_mux2,
+			(map[12] << 0) | (map[13] << 8));
+	}
+}
+
 void set_mrr_pinmux_mapping(void)
 {
 	for (size_t chn = 0; chn < CHANNEL_MAX; chn++) {
@@ -432,7 +445,7 @@
 				     struct dram_shared_data *shared)
 {
 	dramc_init(params, freq_group, shared);
-	dramc_apply_config_before_calibration(freq_group);
+	dramc_apply_config_before_calibration(freq_group, params->cbt_mode_extern);
 }
 
 static void init_dram(const struct sdram_params *params, u8 freq_group,
@@ -449,7 +462,7 @@
 	dramc_sw_impedance_cal(params, ODT_ON, &shared->impedance);
 
 	dramc_init(params, freq_group, shared);
-	dramc_apply_config_before_calibration(freq_group);
+	dramc_apply_config_before_calibration(freq_group, params->cbt_mode_extern);
 	emi_init2(params);
 }
 
@@ -589,9 +602,10 @@
 	*first_run = false;
 
 	dramc_dbg("Start K (current clock: %u\n", params->frequency);
-	if (dramc_calibrate_all_channels(params, freq_group, &shared->mr) != 0)
+	if (dramc_calibrate_all_channels(params, freq_group, &shared->mr,
+					 !!(dparam->header.config & DRAMC_CONFIG_DVFS)) != 0)
 		return -1;
-	get_dram_info_after_cal(&density);
+	get_dram_info_after_cal(&density, params->rank_num);
 	dramc_ac_timing_optimize(freq_group, density);
 	dramc_dbg("K finished (current clock: %u\n", params->frequency);
 
@@ -599,10 +613,10 @@
 	return 0;
 }
 
-static void after_calib(const struct mr_value *mr)
+static void after_calib(const struct mr_value *mr, u32 rk_num)
 {
-	dramc_apply_config_after_calibration(mr);
-	dramc_runtime_config();
+	dramc_apply_config_after_calibration(mr, rk_num);
+	dramc_runtime_config(rk_num);
 }
 
 int mt_set_emi(const struct dramc_param *dparam)
@@ -623,6 +637,6 @@
 	if (run_calib(dparam, &shared, DRAM_DFS_SHUFFLE_1, &first_run) != 0)
 		return -1;
 
-	after_calib(&shared.mr);
+	after_calib(&shared.mr, dparam->freq_params[DRAM_DFS_SHUFFLE_1].rank_num);
 	return 0;
 }
diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h b/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h
index c630b5a..9ab889b 100644
--- a/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h
+++ b/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h
@@ -48,6 +48,13 @@
 };
 
 enum {
+	CBT_R0_R1_NORMAL = 0,	/* Normal mode */
+	CBT_R0_R1_BYTE,		/* Byte mode */
+	CBT_R0_NORMAL_R1_BYTE,	/* Mixed mode R0: Normal R1: Byte */
+	CBT_R0_BYTE_R1_NORMAL	/* Mixed mode R0: Byte R1: Normal */
+};
+
+enum {
 	FSP_0 = 0,
 	FSP_1,
 	FSP_MAX
diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_param.h b/src/soc/mediatek/mt8183/include/soc/dramc_param.h
index f925162..3758547 100644
--- a/src/soc/mediatek/mt8183/include/soc/dramc_param.h
+++ b/src/soc/mediatek/mt8183/include/soc/dramc_param.h
@@ -10,7 +10,7 @@
 
 enum {
 	DRAMC_PARAM_HEADER_MAGIC = 0x44524d4b,
-	DRAMC_PARAM_HEADER_VERSION = 4,
+	DRAMC_PARAM_HEADER_VERSION = 5,
 };
 
 enum DRAMC_PARAM_STATUS_CODES {
@@ -38,9 +38,13 @@
 };
 
 enum DRAMC_PARAM_GEOMETRY_TYPE {
+	DDR_TYPE_2CH_1RK_4GB_4,
 	DDR_TYPE_2CH_2RK_4GB_2_2,
 	DDR_TYPE_2CH_2RK_6GB_3_3,
 	DDR_TYPE_2CH_2RK_8GB_4_4,
+	DDR_TYPE_2CH_RK0_RK1_BYTE_8GB_4_4,
+	DDR_TYPE_2CH_RK0_NORMAL_RK1_BYTE_8GB_4_4,
+	DDR_TYPE_2CH_RK0_BYTE_RK1_NORMAL_8GB_4_4,
 };
 
 struct dramc_param_header {
diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
index a0937d0..b1a0c74 100644
--- a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
+++ b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
@@ -97,7 +97,7 @@
 };
 
 void dramc_get_rank_size(u64 *dram_rank_size);
-void dramc_runtime_config(void);
+void dramc_runtime_config(u32 rk_num);
 void dramc_set_broadcast(u32 onoff);
 u32 dramc_get_broadcast(void);
 u8 get_freq_fsq(u8 freq_group);
@@ -107,18 +107,19 @@
 				 const struct dram_impedance *impedance);
 void dramc_sw_impedance_cal(const struct sdram_params *params, u8 term_option,
 			    struct dram_impedance *impedance);
-void dramc_apply_config_before_calibration(u8 freq_group);
-void dramc_apply_config_after_calibration(const struct mr_value *mr);
+void dramc_apply_config_before_calibration(u8 freq_group, u32 cbt_mode);
+void dramc_apply_config_after_calibration(const struct mr_value *mr, u32 rk_num);
 int dramc_calibrate_all_channels(const struct sdram_params *pams,
-				 u8 freq_group, struct mr_value *mr);
+				 u8 freq_group, struct mr_value *mr, bool run_dvfs);
 void dramc_hw_gating_onoff(u8 chn, bool onoff);
 void dramc_enable_phy_dcm(u8 chn, bool bEn);
 void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value);
 u32 get_shu_freq(u8 shu);
-void dramc_hw_dqsosc(u8 chn);
+void dramc_hw_dqsosc(u8 chn, u32 rk_num);
 void dramc_dqs_precalculation_preset(void);
-void get_dram_info_after_cal(u8 *density);
+void get_dram_info_after_cal(u8 *density, u32 rk_num);
 void set_mrr_pinmux_mapping(void);
 void dramc_cke_fix_onoff(enum cke_type option, u8 chn);
+void cbt_mrr_pinmux_mapping(void);
 
 #endif /* _DRAMC_PI_API_MT8183_H */
diff --git a/src/soc/mediatek/mt8183/include/soc/emi.h b/src/soc/mediatek/mt8183/include/soc/emi.h
index 6931d5b..16f0b2e 100644
--- a/src/soc/mediatek/mt8183/include/soc/emi.h
+++ b/src/soc/mediatek/mt8183/include/soc/emi.h
@@ -15,6 +15,7 @@
 struct sdram_params {
 	u16 source;		/* DRAMC_PARAM_SOURCE */
 	u16 frequency;
+	u32 rank_num;
 	u32 ddr_geometry;	/* DRAMC_PARAM_GEOMETRY_TYPE */
 	u8 wr_level[CHANNEL_MAX][RANK_MAX][DQS_NUMBER];