Project import generated by Copybara.

GitOrigin-RevId: 66dbcc39af1ad8986c9ac5103458f1c058a09401
diff --git a/device.bazelrc b/device.bazelrc
index 19412a2..c678743 100644
--- a/device.bazelrc
+++ b/device.bazelrc
@@ -1,6 +1,6 @@
 build:download_gki --use_prebuilt_gki
 build:download_gki --use_signed_prebuilts
-build:download_gki --action_env=KLEAF_DOWNLOAD_BUILD_NUMBER_MAP="gki_prebuilts=11996345"
+build:download_gki --action_env=KLEAF_DOWNLOAD_BUILD_NUMBER_MAP="gki_prebuilts=12637676"
 build:no_download_gki --use_prebuilt_gki=false
 
 # disable GKI prebuilts by default
diff --git a/drivers/misc/google/usb/typec/tcpm/tcpm.c b/drivers/misc/google/usb/typec/tcpm/tcpm.c
index a720de8..c52408c 100644
--- a/drivers/misc/google/usb/typec/tcpm/tcpm.c
+++ b/drivers/misc/google/usb/typec/tcpm/tcpm.c
@@ -426,6 +426,10 @@ struct tcpm_port {
 	struct power_supply_desc psy_desc;
 	enum power_supply_usb_type usb_type;
 
+	/* Used to export max voltage and current */
+	struct power_supply *max_psy;
+	struct power_supply_desc max_psy_desc;
+
 	u32 bist_request;
 
 	/* PD state for Vendor Defined Messages */
@@ -6326,6 +6330,142 @@ static int tcpm_psy_prop_writeable(struct power_supply *psy,
 	}
 }
 
+/**
+ * functions for max_psy , which reports the max voltage and current from PDO
+ * rather than the current selected PDO
+ */
+static int tcpm_get_max_power_pdo(struct tcpm_port *port, int *out_max_src_mv, int *out_max_src_ma)
+{
+	unsigned int i, max_mw = 0, min_src_mv = 0,	
+			max_mv = 0, src_mw = 0, src_ma = 0;
+	int ret = -EINVAL;
+
+	/* Select the source PDO providing the most power */
+	for (i = 0; i < port->nr_source_caps; i++) {
+		u32 pdo = port->source_caps[i];
+		enum pd_pdo_type type = pdo_type(pdo);
+
+		switch (type) {
+		case PDO_TYPE_FIXED:
+			min_src_mv = pdo_fixed_voltage(pdo);
+			break;
+		case PDO_TYPE_BATT:
+		case PDO_TYPE_VAR:
+			min_src_mv = pdo_min_voltage(pdo);
+			break;
+		case PDO_TYPE_APDO:
+			continue;
+		default:
+			tcpm_log(port, "Invalid source PDO type, ignoring");
+			continue;
+		}
+
+		switch (type) {
+		case PDO_TYPE_FIXED:
+		case PDO_TYPE_VAR:
+			src_ma = pdo_max_current(pdo);
+			src_mw = src_ma * min_src_mv / 1000;
+			break;
+		case PDO_TYPE_BATT:
+			src_mw = pdo_max_power(pdo);
+			src_ma = src_mw * 1000 / min_src_mv;
+			break;
+		case PDO_TYPE_APDO:
+			continue;
+		default:
+			tcpm_log(port, "Invalid source PDO type, ignoring");
+			continue;
+		}
+
+		/* Prefer higher voltages if available */
+		if ((src_mw == max_mw && min_src_mv > max_mv) ||
+					src_mw > max_mw) {
+			max_mw = src_mw;
+			max_mv = min_src_mv;
+			ret = 0;
+
+			/* for function output */
+			*out_max_src_mv = min_src_mv;
+			*out_max_src_ma = src_ma;
+		}
+	}
+
+	return ret;
+}
+
+static enum power_supply_property tcpm_max_psy_props[] = {
+	POWER_SUPPLY_PROP_USB_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static int tcpm_max_psy_get_voltage_max(struct tcpm_port *port,
+				    union power_supply_propval *val)
+{
+	if (port->pps_data.active)
+		val->intval = port->pps_data.max_volt * 1000;
+	else {
+		int max_src_mv, max_src_ma;
+		int ret;
+		ret = tcpm_get_max_power_pdo(port, &max_src_mv, &max_src_ma);
+
+		if (ret < 0) {
+			tcpm_log(port, "Failed to get max_power_pdo: %d", ret);
+			val->intval = 0;
+		} else {
+			val->intval = max_src_mv * 1000;
+		}
+	}
+
+	return 0;
+}
+
+static int tcpm_max_psy_get_current_max(struct tcpm_port *port,
+				    union power_supply_propval *val)
+{
+	if (port->pps_data.active)
+		val->intval = port->pps_data.max_curr * 1000;
+	else {
+		int max_src_mv, max_src_ma;
+		int ret;
+		ret = tcpm_get_max_power_pdo(port, &max_src_mv, &max_src_ma);
+
+		if (ret < 0) {
+			tcpm_log(port, "Failed to get max_power_pdo: %d", ret);
+			val->intval = 0;
+		} else {
+			val->intval = max_src_ma * 1000;
+		}
+	}
+
+	return 0;
+}
+
+static int tcpm_max_psy_get_prop(struct power_supply *psy,
+			     enum power_supply_property psp,
+			     union power_supply_propval *val)
+{
+	struct tcpm_port *port = power_supply_get_drvdata(psy);
+	int ret = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_USB_TYPE:
+		val->intval = port->usb_type;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		ret = tcpm_max_psy_get_voltage_max(port, val);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		ret = tcpm_max_psy_get_current_max(port, val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static enum power_supply_usb_type tcpm_psy_usb_types[] = {
 	POWER_SUPPLY_USB_TYPE_C,
 	POWER_SUPPLY_USB_TYPE_PD,
@@ -6368,6 +6508,40 @@ static int devm_tcpm_psy_register(struct tcpm_port *port)
 	return PTR_ERR_OR_ZERO(port->psy);
 }
 
+static const char *tcpm_max_psy_name_prefix = "tcpm-max-source-psy-";
+
+static int devm_tcpm_max_psy_register(struct tcpm_port *port)
+{
+	struct power_supply_config psy_cfg = {};
+	const char *port_dev_name = dev_name(port->dev);
+	size_t psy_name_len = strlen(tcpm_max_psy_name_prefix) +
+				     strlen(port_dev_name) + 1;
+	char *psy_name;
+
+	psy_cfg.drv_data = port;
+	psy_cfg.fwnode = dev_fwnode(port->dev);
+	psy_name = devm_kzalloc(port->dev, psy_name_len, GFP_KERNEL);
+	if (!psy_name)
+		return -ENOMEM;
+
+	snprintf(psy_name, psy_name_len, "%s%s", tcpm_max_psy_name_prefix,
+		 port_dev_name);
+	port->max_psy_desc.name = psy_name;
+	port->max_psy_desc.type = POWER_SUPPLY_TYPE_USB;
+	port->max_psy_desc.usb_types = tcpm_psy_usb_types;
+	port->max_psy_desc.num_usb_types = ARRAY_SIZE(tcpm_psy_usb_types);
+	port->max_psy_desc.properties = tcpm_max_psy_props;
+	port->max_psy_desc.num_properties = ARRAY_SIZE(tcpm_psy_props);
+	port->max_psy_desc.get_property = tcpm_max_psy_get_prop;
+
+	port->usb_type = POWER_SUPPLY_USB_TYPE_C;
+
+	port->max_psy = devm_power_supply_register(port->dev, &port->max_psy_desc,
+					       &psy_cfg);
+
+	return PTR_ERR_OR_ZERO(port->max_psy);
+}
+
 static enum hrtimer_restart state_machine_timer_handler(struct hrtimer *timer)
 {
 	struct tcpm_port *port = container_of(timer, struct tcpm_port, state_machine_timer);
@@ -6480,6 +6654,10 @@ struct tcpm_port *google_tcpm_register_port(struct device *dev, struct tcpc_dev
 		goto out_role_sw_put;
 	power_supply_changed(port->psy);
 
+	err = devm_tcpm_max_psy_register(port);
+	if (err)
+		goto out_role_sw_put;
+
 	port->typec_port = typec_register_port(port->dev, &port->typec_caps);
 	if (IS_ERR(port->typec_port)) {
 		err = PTR_ERR(port->typec_port);
diff --git a/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmi_drv.c b/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmi_drv.c
index 75ec2f9..499edd6 100644
--- a/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmi_drv.c
+++ b/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmi_drv.c
@@ -1411,6 +1411,7 @@ void vReadHdcpVersion(void)
 		hdcp_max_level = NO_HDCP;
 		hdmi_util.emit_hdmistate_callback(
 			EMIT_HDMISTATE_HDCP_I2C_ERROR, HDMI_EMITSTATE_ON);
+		return;
 	} else if (bTemp & 0x4) {
 		hdcp2_version_flag = TRUE;
 		hdcp_current_level = HDCP_V2_2;
@@ -1422,6 +1423,9 @@ void vReadHdcpVersion(void)
 		hdcp_max_level = HDCP_V1_4;
 		HDMI_PLUG_LOG("sink support hdcp1.x version\n");
 	}
+
+	hdmi_emit_state_callback(
+		EMIT_HDMISTATE_HDCP_I2C_ERROR, HDMI_EMITSTATE_OFF);
 }
 
 void hdmi_internal_power_off(void)
@@ -1516,6 +1520,12 @@ void hdmi_enablehdcp(unsigned char u1hdcponoff)
 {
 	if (hdmi_first_hdcp == 1) {
 		if (_bHdcpOff == 1) {
+			hdmi_util.emit_hdmistate_callback(
+				EMIT_HDMISTATE_HDCP_DISABLE, HDMI_EMITSTATE_ON);
+			hdmi_util.emit_hdmistate_callback(
+				EMIT_HDMISTATE_HDCP_HDCP1_ENABLE, HDMI_EMITSTATE_OFF);
+			hdmi_util.emit_hdmistate_callback(
+				EMIT_HDMISTATE_HDCP_HDCP2_ENABLE, HDMI_EMITSTATE_OFF);
 			hdmi_TmrValue[HDMI_SCDC_DETECT_CMD] = gSCDC_CHK_INTERVAL;
 			return;
 		}
@@ -1928,6 +1938,7 @@ void vNotifyAppHdmiState(unsigned char u1hdmistate)
 {
 	struct HDMI_EDID_T get_info;
 	static unsigned char pre_state;
+	unsigned char u1HdmiState = 0;
 
 	HDMI_EDID_FUNC();
 
@@ -1949,6 +1960,10 @@ void vNotifyAppHdmiState(unsigned char u1hdmistate)
 		hdmi_util.state_callback(HDMI_STATE_NO_DEVICE);
 		hdmi_SetPhysicCECAddress(0xffff, 0x0);
 		hdmi_util.cec_state_callback(HDMI_CEC_STATE_PLUG_OUT);
+
+		for (u1HdmiState = 0; u1HdmiState < EMIT_HDMISTATE_NUM; u1HdmiState++) {
+			hdmi_util.emit_hdmistate_callback(u1HdmiState, HDMI_EMITSTATE_OFF);
+		}
 		break;
 
 	case HDMI_PLUG_IN_AND_SINK_POWER_ON:
@@ -1958,10 +1973,14 @@ void vNotifyAppHdmiState(unsigned char u1hdmistate)
 
 		if (fgTVisHDMI()) {
 			hdmi_util.emit_hdmistate_callback(
+				EMIT_HDMISTATE_EDID_DVI_DEVICE, HDMI_EMITSTATE_OFF);
+			hdmi_util.emit_hdmistate_callback(
 				EMIT_HDMISTATE_EDID_HDMI_DEVICE, HDMI_EMITSTATE_ON);
 		} else {
 			hdmi_util.emit_hdmistate_callback(
 				EMIT_HDMISTATE_EDID_DVI_DEVICE, HDMI_EMITSTATE_ON);
+			hdmi_util.emit_hdmistate_callback(
+				EMIT_HDMISTATE_EDID_HDMI_DEVICE, HDMI_EMITSTATE_OFF);
 		}
 		break;
 
@@ -1970,6 +1989,10 @@ void vNotifyAppHdmiState(unsigned char u1hdmistate)
 		if (pre_state != HDMI_PLUG_IN_AND_SINK_POWER_ON)
 			hdmi_util.cec_state_callback(HDMI_CEC_STATE_GET_PA);
 		hdmi_util.state_callback(HDMI_STATE_NO_DEVICE);
+
+		for (u1HdmiState = 0; u1HdmiState < EMIT_HDMISTATE_NUM; u1HdmiState++) {
+			hdmi_util.emit_hdmistate_callback(u1HdmiState, HDMI_EMITSTATE_OFF);
+		}
 		break;
 
 	case HDMI_PLUG_IN_CEC:
@@ -1978,6 +2001,10 @@ void vNotifyAppHdmiState(unsigned char u1hdmistate)
 
 	case HDMI_PLUG_OUT_POWEROFF:
 		hdmi_util.state_callback(HDMI_STATE_NO_DEVICE);
+
+		for (u1HdmiState = 0; u1HdmiState < EMIT_HDMISTATE_NUM; u1HdmiState++) {
+			hdmi_util.emit_hdmistate_callback(u1HdmiState, HDMI_EMITSTATE_OFF);
+		}
 		break;
 
 	default:
@@ -2082,16 +2109,6 @@ static void vPlugDetectService(enum HDMI_CTRL_STATE_T e_state)
 	case HDMI_STATE_HOT_PLUG_OUT:
 		TX_DEF_LOG("Disable SCDC timer amd reset SCDC\n");
 		hdmi_TmrValue[HDMI_SCDC_DETECT_CMD] = 0;
-		memset(hdmi_emitstate, 0, sizeof(hdmi_emitstate));
-
-		hdmi_util.emit_hdmistate_callback(
-			EMIT_HDMISTATE_SCDC_CH0_ERROR, HDMI_EMITSTATE_OFF);
-
-		hdmi_util.emit_hdmistate_callback(
-			EMIT_HDMISTATE_SCDC_CH1_ERROR, HDMI_EMITSTATE_OFF);
-
-		hdmi_util.emit_hdmistate_callback(
-			EMIT_HDMISTATE_SCDC_CH2_ERROR, HDMI_EMITSTATE_OFF);
 
 		vClearEdidInfo();
 		hdmi_clear_edid_data();
diff --git a/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmi_ioctl.c b/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmi_ioctl.c
index 590bb40..c29cd68 100644
--- a/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmi_ioctl.c
+++ b/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmi_ioctl.c
@@ -617,11 +617,13 @@ void hdmi_hpd_state_callback(unsigned char state)
 
 void hdmi_emit_state_callback(enum EMIT_HDMISTATE_TYPE type, unsigned int state)
 {
-	TX_DEF_LOG("hdmi emit type: %d, state: %d\n", type, state);
 	if (type < EMIT_HDMISTATE_NUM) {
-		hdmi_emitstate[type] = state;
-		notify_uevent_user(
-			&hdmi_emit_state_switch_data[type], state);
+		if (hdmi_emitstate[type] != state) {
+			TX_DEF_LOG("hdmi emit type: %d, state: %d\n", type, state);
+			hdmi_emitstate[type] = state;
+			notify_uevent_user(
+				&hdmi_emit_state_switch_data[type], state);
+		}
 	}
 	else {
 		TX_DEF_LOG("Unknown hdmi emit type: 0x%x\n", type);
diff --git a/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmiedid.c b/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmiedid.c
index cfafbff..324cf46 100644
--- a/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmiedid.c
+++ b/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmiedid.c
@@ -58,6 +58,8 @@ static unsigned char _bEdidData[EDID_SIZE];	/* 4 block 512 Bytes */
 static unsigned char aEDIDHeader[EDID_HEADER_LEN] = {
 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
 };
+static unsigned char u1EdidCtaExtensionTag = 0x02;
+static unsigned char u1EdidCtaExtensionRevision = 0x03;
 static unsigned char aEDIDVSDBHeader[EDID_VSDB_LEN] = {
 	0x03, 0x0c, 0x00};
 static unsigned char aEDIDHFVSDBHeader[EDID_VSDB_LEN] = {
@@ -138,6 +140,8 @@ const unsigned char _cBitdeepStr[][7] = { {"16bit  "},
 unsigned char cDstStr[60];
 unsigned char cDstBitStr[30];
 
+bool isBadYUV420Sink(void);
+
 bool fgIsHdmiNoEDIDCheck(void)
 {
 	HDMI_EDID_FUNC();
@@ -736,6 +740,9 @@ unsigned char fgParserEDID(unsigned char *prbData)
 		hdmi_emit_state_callback(
 			EMIT_HDMISTATE_EDID_CHECKSUM_ERROR, HDMI_EMITSTATE_ON);
 		return FALSE;
+	} else {
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_EDID_CHECKSUM_ERROR, HDMI_EMITSTATE_OFF);
 	}
 
 	_HdmiSinkAvCap
@@ -2581,6 +2588,7 @@ unsigned char fgParserExtEDID(unsigned char *prData)
 	if (bTemp) {
 		hdmi_emit_state_callback(
 			EMIT_HDMISTATE_EDID_CHECKSUM_ERROR, HDMI_EMITSTATE_ON);
+		return FALSE;
 	}
 
 	_HdmiSinkAvCap.ui2_edid_chksum_and_audio_sup &=
@@ -2682,18 +2690,21 @@ void vParserExtEDIDState(unsigned char *prEdid)
 		bTemp++) {
 			if ((EDID_BLOCK_LEN + bTemp * EDID_BLOCK_LEN) <
 				EDID_SIZE) {	/* for Buffer Overflow error */
-				if (*(prEdid + EDID_BLOCK_LEN + bTemp *
-					EDID_BLOCK_LEN) == 0x02) {
-					prData = (prEdid + EDID_BLOCK_LEN +
-						bTemp * EDID_BLOCK_LEN);
-					fgParserExtEDID(prData);
-				} else if (*(prEdid + EDID_BLOCK_LEN +
-				bTemp * EDID_BLOCK_LEN) ==
-					   0xF0) {
-
+				prData = (prEdid + EDID_BLOCK_LEN + bTemp * EDID_BLOCK_LEN);
+				if (*prData == u1EdidCtaExtensionTag) {
+					if (*(prData + 1) >= u1EdidCtaExtensionRevision) {
+						if (!fgParserExtEDID(prData)) {
+							vSetEdidChkError();
+							break;
+						}
+					} else {
+						HDMI_EDID_LOG("CTA Extension Revision is less than 0x3\n");
+						vSetEdidChkError();
+						break;
+					}
+				} else {
+					HDMI_EDID_LOG("The Ext EDID block %d is not the CTA Extension block\n", bTemp);
 				}
-			} else {
-
 			}
 		}
 	}
@@ -2724,7 +2735,8 @@ void hdmi_checkedid(unsigned char i1noedid)
 			if (fgParserEDID(&_bEdidData[0]) == TRUE) {
 				vSetSharedInfo(SI_EDID_PARSING_RESULT, TRUE);
 				_HdmiSinkAvCap.b_sink_edid_ready = TRUE;
-
+				hdmi_emit_state_callback(
+					EMIT_HDMISTATE_EDID_HEAD_ERROR, HDMI_EMITSTATE_OFF);
 				break;
 			}
 
@@ -2755,6 +2767,10 @@ void hdmi_checkedid(unsigned char i1noedid)
 		/* msleep(5); */
 		msleep(20);
 	}
+
+	hdmi_emit_state_callback(
+		EMIT_HDMISTATE_EDID_I2C_ERROR, HDMI_EMITSTATE_OFF);
+
 	/* for Buffer Overflow error */
 	if ((i4SharedInfo(SI_EDID_EXT_BLOCK_NO) *
 		EDID_BLOCK_LEN) < EDID_SIZE)
@@ -2953,10 +2969,10 @@ void vShowEdidInformation(void)
 	else
 		maxTMDSRate = _HdmiSinkAvCap.ui1_sink_max_tmds_clock;
 
-	yuv420Supported = ((_HdmiSinkAvCap.ui2_sink_colorimetry &
-		SINK_YCBCR_420) ||
-		(_HdmiSinkAvCap.ui2_sink_colorimetry &
-		SINK_YCBCR_420_CAPABILITY)) ? 1 : 0;
+	yuv420Supported =
+		(((_HdmiSinkAvCap.ui2_sink_colorimetry & SINK_YCBCR_420) ||
+		  (_HdmiSinkAvCap.ui2_sink_colorimetry & SINK_YCBCR_420_CAPABILITY)) &&
+		 (!isBadYUV420Sink())) ? 1 : 0;
 	if (((yuv420Supported) && (maxTMDSRate >= 297)) ||
 		(maxTMDSRate >= 340)/* HDMI2 modes*/) {
 		if (u4Res & SINK_2160P_50HZ)
@@ -3877,10 +3893,10 @@ long long hdmi_DispGetEdidInfo(void)
 	else
 		maxTMDSRate = _HdmiSinkAvCap.ui1_sink_max_tmds_clock;
 
-	yuv420Supported = ((_HdmiSinkAvCap.ui2_sink_colorimetry &
-		SINK_YCBCR_420) ||
-		(_HdmiSinkAvCap.ui2_sink_colorimetry &
-		SINK_YCBCR_420_CAPABILITY)) ? 1 : 0;
+	yuv420Supported =
+		(((_HdmiSinkAvCap.ui2_sink_colorimetry & SINK_YCBCR_420) ||
+		  (_HdmiSinkAvCap.ui2_sink_colorimetry & SINK_YCBCR_420_CAPABILITY)) &&
+		 (!isBadYUV420Sink())) ? 1 : 0;
 	if (((yuv420Supported) && (maxTMDSRate >= 297)) ||
 		(maxTMDSRate >= 340)/* HDMI2 modes*/) {
 		if (u4Res & SINK_2160P_60HZ)
@@ -3914,6 +3930,19 @@ bool isThomsonUD9_India_TV(void)
 	return false;
 }
 
+bool isBadDDPlusSink(struct HDMI_EDID_T *pv_get_info)
+{
+	/* Sony - 2009 model DD+ TV (Sony KDL 40S5600 TV)
+	 * 00 FF FF FF FF FF FF 00 4D D9 01 C9 01 01 01 01
+	 * Note: The official document states that this sink does not support DD+.
+	 */
+	if ((_bEdidData[0x08] == 0x4d) && (_bEdidData[0x09] ==  0xd9) &&
+	    (_bEdidData[0x0a] ==  0x01) && (_bEdidData[0x0b] ==  0xc9))
+		return true;
+
+	return false;
+}
+
 bool isBadMATSink(struct HDMI_EDID_T *pv_get_info)
 {
 	/* Sony - G/H model MAT TV's has MAT implementation issue
@@ -3973,6 +4002,27 @@ bool isBadMATSink(struct HDMI_EDID_T *pv_get_info)
 		(_bEdidData[0x0a] ==  0x34) && (_bEdidData[0x0b] ==  0x0f) &&
 		((pv_get_info->ui4_hdmi_dolby_truehd_ch_type & (1 << 6)) == (0x1 << 6)))
 		return true;
+	/* Onkyo NR747 - 2015 model AVR
+	 * 00 FF FF FF FF FF FF 00 3D CB 71 0F 00 00 00 00
+	 * Note: This sink does not support MAT audio.
+	 */
+	if ((_bEdidData[0x08] == 0x3D) && (_bEdidData[0x09] ==  0xCB) &&
+		(_bEdidData[0x0a] ==  0x71) && (_bEdidData[0x0b] ==  0x0F) &&
+		((pv_get_info->ui4_hdmi_dolby_truehd_ch_type & (1 << 6)) == (0x1 << 6)))
+		return true;
+
+	return false;
+}
+
+bool isBadYUV420Sink(void)
+{
+	/* Sony - 2018 model Samsung UN50NU6900B TV
+	 * 00 FF FF FF FF FF FF 00 4C 2D 14 0F 00 0E 00 01
+	 * Note: When open UHD, the TV not support YUV420, disable YUV420 mode.
+	 */
+	if ((_bEdidData[0x08] == 0x4C) && (_bEdidData[0x09] ==  0x2D) &&
+	    (_bEdidData[0x0a] ==  0x14) && (_bEdidData[0x0b] ==  0x0F))
+		return true;
 
 	return false;
 }
@@ -4160,11 +4210,10 @@ void hdmi_AppGetEdidInfo(
 		maxTMDSRate =
 		_HdmiSinkAvCap.ui1_sink_max_tmds_clock;
 
-	yuv420Supported = ((
-		_HdmiSinkAvCap.ui2_sink_colorimetry & SINK_YCBCR_420) ||
-					   (
-					   _HdmiSinkAvCap.ui2_sink_colorimetry &
-					   SINK_YCBCR_420_CAPABILITY)) ? 1 : 0;
+	yuv420Supported =
+		(((_HdmiSinkAvCap.ui2_sink_colorimetry & SINK_YCBCR_420) ||
+		  (_HdmiSinkAvCap.ui2_sink_colorimetry & SINK_YCBCR_420_CAPABILITY)) &&
+		 (!isBadYUV420Sink())) ? 1 : 0;
 	if (((yuv420Supported) && (maxTMDSRate >= 297)) ||
 		(maxTMDSRate >= 340)/* HDMI2 modes*/) {
 		pv_get_info->ui4_sink_hdmi_4k2kvic = u4Res;
@@ -4323,6 +4372,15 @@ void hdmi_AppGetEdidInfo(
 			pv_get_info->ui1_sink_dovi_block[i] = 0;
 	}
 
+	if (isBadYUV420Sink()) {
+		HDMI_PLUG_LOG("Known bad YUV420 Sink, remove YUV420 capability\n");
+		pv_get_info->ui2_sink_colorimetry &= ~(
+			SINK_YCBCR_420 |
+			SINK_YCBCR_420_CAPABILITY);
+		HDMI_PLUG_LOG("remove YUV420, pv_get_info->ui2_sink_colorimetry=0x%x\n",
+			pv_get_info->ui2_sink_colorimetry);
+	}
+
 	for (i = 0; i < EDID_LENGTH_MISC; i++)
 		pv_get_info->ui1rawdata_edid[i] = _bEdidData[i];
 
@@ -4335,6 +4393,12 @@ void hdmi_AppGetEdidInfo(
 		pv_get_info->ui4_hdmi_ec3_ch3ch4ch5ch7_type = 0x00;
 	}
 
+	if (isBadDDPlusSink(pv_get_info)) {
+		HDMI_AUDIO_LOG("Known bad DD+ Sink, remove DD+ capability\n");
+		pv_get_info->ui4_hdmi_ec3_ch_type = 0x00;
+		pv_get_info->ui4_hdmi_ec3_ch3ch4ch5ch7_type = 0x00;
+	}
+
 	if ((pv_get_info->ui1_sink_support_mat_profile >= 0x2) &&
 		isBadMATSink(pv_get_info)) {
 		HDMI_AUDIO_LOG("Known bad MAT Sink, remove Dolby MAT audio capability\n");
diff --git a/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmihdcp.c b/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmihdcp.c
index eac3116..e069ecc 100644
--- a/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmihdcp.c
+++ b/drivers/misc/mediatek/hdmi/hdmitx/mt8696/hdmihdcp.c
@@ -533,10 +533,17 @@ void vHDCPInitAuth(void)
 				vSetHDCPTimeOut(HDCP2x_WAIT_RES_CHG_OK_TIMEOUE);
 		}
 		vSetHDCPState(HDCP2x_WAIT_RES_CHG_OK);
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_HDCP_HDCP2_ENABLE, HDMI_EMITSTATE_ON);
 	} else {
 		vHDCP14InitAuth();
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_HDCP_HDCP1_ENABLE, HDMI_EMITSTATE_ON);
 	}
 
+	hdmi_emit_state_callback(
+		EMIT_HDMISTATE_HDCP_DISABLE, HDMI_EMITSTATE_OFF);
+
 	hdmi_hdcp_status = dsHDCP_STATUS_INPROGRESS;
 }
 
@@ -937,6 +944,9 @@ void vReadKSVFIFO(void)
 		hdmi_emit_state_callback(
 			EMIT_HDMISTATE_HDCP_TOPOLOGY_ERROR, HDMI_EMITSTATE_ON);
 		return;
+	} else {
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_HDCP_TOPOLOGY_ERROR, HDMI_EMITSTATE_OFF);
 	}
 
 	if (bDevice_Count > 32) {
@@ -1230,7 +1240,16 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 		vSetHDCPState(HDCP_RECEIVER_NOT_READY);
 		vHDMIAVUnMute();
 		hdmi_hdcp22_monitor_stop();
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_HDCP_DISABLE, HDMI_EMITSTATE_ON);
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_HDCP_HDCP1_ENABLE, HDMI_EMITSTATE_OFF);
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_HDCP_HDCP2_ENABLE, HDMI_EMITSTATE_OFF);
 		return;
+	} else {
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_HDCP_DISABLE, HDMI_EMITSTATE_OFF);
 	}
 
 	switch (e_hdcp_state) {
@@ -1296,6 +1315,9 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 			hdmi_emit_state_callback(
 				EMIT_HDMISTATE_HDCP_I2C_ERROR, HDMI_EMITSTATE_ON);
 			break;
+		} else {
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_I2C_ERROR, HDMI_EMITSTATE_OFF);
 		}
 		if (!vIsDviMode()) {
 			fgDDCDataRead(RX_ID, RX_REG_BSTATUS1, 2, BStatus);
@@ -1357,6 +1379,9 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 			if(!isKsvLegal(_bTxBKAV)) {
 				hdmi_emit_state_callback(
 					EMIT_HDMISTATE_HDCP_BKSV_ERROR, HDMI_EMITSTATE_ON);
+			} else {
+				hdmi_emit_state_callback(
+					EMIT_HDMISTATE_HDCP_BKSV_ERROR, HDMI_EMITSTATE_OFF);
 			}
 			break;
 		}
@@ -1387,6 +1412,9 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 		if(!fgCaHDMILoadHDCPKey()) {
 			hdmi_emit_state_callback(
 				EMIT_HDMISTATE_HDCP_NO_14_KEY, HDMI_EMITSTATE_ON);
+		} else {
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_NO_14_KEY, HDMI_EMITSTATE_OFF);
 		}
 #else
 		vSendAKey(&bHdcpKeyBuff[6]);	/* around 190msec */
@@ -1424,6 +1452,8 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 			vSetHDCPState(HDCP_CHECK_REPEATER);
 			vSendHdmiCmd(HDMI_HDCP_PROTOCAL_CMD);
 			vSetSharedInfo(SI_HDMI_HDCP_RESULT, 0x01);
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_R0_MISMATCH, HDMI_EMITSTATE_OFF);
 		} else {
 			vSetHDCPState(HDCP_RE_COMPARE_R0);
 			vSendHdmiCmd(HDMI_HDCP_PROTOCAL_CMD);
@@ -1455,8 +1485,12 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 				vSetHDCPState(HDCP_CHECK_REPEATER);
 				vSendHdmiCmd(HDMI_HDCP_PROTOCAL_CMD);
 				vSetSharedInfo(SI_HDMI_HDCP_RESULT, 0x01);
+				hdmi_emit_state_callback(
+					EMIT_HDMISTATE_HDCP_R0_MISMATCH, HDMI_EMITSTATE_OFF);
 			} else {
 				vSendHdmiCmd(HDMI_HDCP_PROTOCAL_CMD);
+				hdmi_emit_state_callback(
+					EMIT_HDMISTATE_HDCP_R0_MISMATCH, HDMI_EMITSTATE_ON);
 			}
 
 		}
@@ -1489,6 +1523,11 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 		if ((bTemp & RX_BIT_ADDR_READY)) {
 			_bReCheckReadyBit = 0;
 			vSetHDCPState(HDCP_READ_KSV_LIST);
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_DEVICE_NOT_READY, HDMI_EMITSTATE_OFF);
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_REPEATER_DELAY_ERROR,
+				HDMI_EMITSTATE_OFF);
 		} else if (_bReCheckReadyBit >
 			HDCP_CHECK_KSV_LIST_RDY_RETRY_COUNT) {
 			vSetHDCPState(HDCP_RE_DO_AUTHENTICATION);
@@ -1556,6 +1595,8 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 					       (i4SharedInfo(
 					       SI_HDMI_HDCP_RESULT) |
 					       0x02));
+				hdmi_emit_state_callback(
+					EMIT_HDMISTATE_HDCP_V_PRIME_MISMATCH, HDMI_EMITSTATE_OFF);
 				/* step 2 OK. */
 			} else {
 				vSetHDCPState(HDCP_RE_DO_AUTHENTICATION);
@@ -1592,6 +1633,8 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 		vHDCPEncryptState(1); /* for audio notify */
 		hdmi_emit_state_callback(
 			EMIT_HDMISTATE_HDCP_SUCCESS, HDMI_EMITSTATE_ON);
+		hdmi_emit_state_callback(
+			EMIT_HDMISTATE_HDCP_FAILURE, HDMI_EMITSTATE_OFF);
 		/* Enable SCDC timer and set the timer 3 sec*/
 		hdmi_TmrValue[HDMI_SCDC_DETECT_CMD] = gSCDC_CHK_INTERVAL;
 		break;
@@ -1804,6 +1847,9 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 			if(!fgCaHDMILoadROM()) {
 				hdmi_emit_state_callback(
 					EMIT_HDMISTATE_HDCP_NO_22_KEY, HDMI_EMITSTATE_ON);
+			} else {
+				hdmi_emit_state_callback(
+					EMIT_HDMISTATE_HDCP_NO_22_KEY, HDMI_EMITSTATE_OFF);
 			}
 #else
 			TX_DEF_LOG("[HDMI]Normal Mode fgCaHDMILoadROM\n");
@@ -2066,7 +2112,9 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 			_bReRepeaterPollCnt = 0;
 			vSetHDCPState(HDCP2x_RESET_RECEIVER);
 			vSetHDCPTimeOut(HDCP2x_WAIT_RESET_RECEIVER_TIMEOUE);
-
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_REPEATER_DELAY_ERROR,
+				HDMI_EMITSTATE_OFF);
 		} else if ((_bReRepeaterPollCnt <= 30) &&
 		(fgHDMIHdcp2Err() == FALSE)) {
 			_bReRepeaterPollCnt++;
@@ -2090,6 +2138,9 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 			if (((RxStatus[1] << 8) & RX_RXSTATUS_READY) != RX_RXSTATUS_READY) {
 				hdmi_emit_state_callback(
 					EMIT_HDMISTATE_HDCP_DEVICE_NOT_READY, HDMI_EMITSTATE_ON);
+			} else {
+				hdmi_emit_state_callback(
+					EMIT_HDMISTATE_HDCP_DEVICE_NOT_READY, HDMI_EMITSTATE_OFF);
 			}
 			vSetHDCPTimeOut(HDCP2x_WAIT_LOADBIN_TIMEOUE);
 			vSetHDCPState(HDCP2x_WAIT_RES_CHG_OK);
@@ -2164,6 +2215,10 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 			hdmi_emit_state_callback(
 				EMIT_HDMISTATE_HDCP_TOPOLOGY_ERROR,
 				HDMI_EMITSTATE_ON);
+		} else {
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_TOPOLOGY_ERROR,
+				HDMI_EMITSTATE_OFF);
 		}
 
 		if (fgRepeaterError) {
@@ -2172,6 +2227,8 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 				vHDMIAVMute();
 			hdmi_emit_state_callback(
 				EMIT_HDMISTATE_HDCP_FAILURE, HDMI_EMITSTATE_ON);
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_SUCCESS, HDMI_EMITSTATE_OFF);
 			vHDCPReset();
 			vHDCPInitAuth();
 			break;
@@ -2274,6 +2331,9 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 			vSetHDCPState(HDCP2x_ENCRYPTION);
 			vSetHDCPTimeOut(HDCP2x_WAIT_AITHEN_DEALY_TIMEOUE);
 			_bReAuthCnt = 0;
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_REPEATER_DELAY_ERROR,
+				HDMI_EMITSTATE_OFF);
 		} else if (((readvalue & HDCP2X_AUTH_FAIL_INT_STA) &&
 				(_bReAuthCnt != 0))
 			   || (_bReAuthCnt > REPEAT_CHECK_AUTHHDCP_VALUE) ||
@@ -2295,6 +2355,8 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 				HDMI_EMITSTATE_ON);
 			hdmi_emit_state_callback(
 				EMIT_HDMISTATE_HDCP_FAILURE, HDMI_EMITSTATE_ON);
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_SUCCESS, HDMI_EMITSTATE_OFF);
 		} else {
 			if ((readvalue & HDCP2X_AUTH_FAIL_INT_STA) &&
 				(_bReAuthCnt == 0)) {
@@ -2337,6 +2399,8 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 				(_u2TxBStatus & 0x1)? "HDCP14":"HDCP2x");
 			hdmi_emit_state_callback(
 				EMIT_HDMISTATE_HDCP_SUCCESS, HDMI_EMITSTATE_ON);
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_FAILURE, HDMI_EMITSTATE_OFF);
 			/* Enable SCDC timer and set the timer 3 sec*/
 			hdmi_TmrValue[HDMI_SCDC_DETECT_CMD] = gSCDC_CHK_INTERVAL;
 		}
@@ -2351,6 +2415,8 @@ void HdcpService(enum HDCP_CTRL_STATE_T e_hdcp_state)
 		if (u1HdcpStatus != SV_OK) {
 			hdmi_emit_state_callback(
 				EMIT_HDMISTATE_HDCP_FAILURE, HDMI_EMITSTATE_ON);
+			hdmi_emit_state_callback(
+				EMIT_HDMISTATE_HDCP_SUCCESS, HDMI_EMITSTATE_OFF);
 		}
 	}
 }
diff --git a/drivers/misc/mediatek/video/mt8696/dispsys/adl/disp_adl_if.c b/drivers/misc/mediatek/video/mt8696/dispsys/adl/disp_adl_if.c
index a9f77b4..1275930 100644
--- a/drivers/misc/mediatek/video/mt8696/dispsys/adl/disp_adl_if.c
+++ b/drivers/misc/mediatek/video/mt8696/dispsys/adl/disp_adl_if.c
@@ -93,7 +93,7 @@ int disp_adl_thread_init(void)
 			kthread_create(disp_adl_routine,
 			NULL, "disp_adl_thread");
 
-		sched_setscheduler(disp_adl_thread, SCHED_RR, &adl_param);
+		sched_setscheduler_nocheck(disp_adl_thread, SCHED_RR, &adl_param);
 
 		wake_up_process(disp_adl_thread);
 
diff --git a/drivers/misc/mediatek/video/mt8696/dispsys/hdr/disp_hdr_main.c b/drivers/misc/mediatek/video/mt8696/dispsys/hdr/disp_hdr_main.c
index e2b3dd1..132792d 100644
--- a/drivers/misc/mediatek/video/mt8696/dispsys/hdr/disp_hdr_main.c
+++ b/drivers/misc/mediatek/video/mt8696/dispsys/hdr/disp_hdr_main.c
@@ -307,7 +307,7 @@ int disp_hdr_thread_init(void)
 			kthread_create(disp_hdr_routine4,
 			NULL, "disp_hdr_thread4");
 
-		sched_setscheduler(disp_hdr_thread0, SCHED_RR, &hdr_param);
+		sched_setscheduler_nocheck(disp_hdr_thread0, SCHED_RR, &hdr_param);
 
 		wake_up_process(disp_hdr_thread0);
 		wake_up_process(disp_hdr_thread1);
diff --git a/drivers/misc/mediatek/video/mt8696/dispsys/osd/disp_osd_if.c b/drivers/misc/mediatek/video/mt8696/dispsys/osd/disp_osd_if.c
index b248dc7..31f9242 100644
--- a/drivers/misc/mediatek/video/mt8696/dispsys/osd/disp_osd_if.c
+++ b/drivers/misc/mediatek/video/mt8696/dispsys/osd/disp_osd_if.c
@@ -848,7 +848,7 @@ static int osd_init(struct disp_hw_common_info *info)
 		wake_up_process(osd_irq_task[OSD_PLANE_1]);
 		OSDDBG("kthread_create disp_osd1_irq_kthread\n");
 	}
-	sched_setscheduler(osd_irq_task[OSD_PLANE_1], SCHED_RR, &irq_param);
+	sched_setscheduler_nocheck(osd_irq_task[OSD_PLANE_1], SCHED_RR, &irq_param);
 
 	init_waitqueue_head(&osd_irq_wq[OSD_PLANE_2]);
 	if (!osd_irq_task[OSD_PLANE_2]) {
@@ -858,7 +858,7 @@ static int osd_init(struct disp_hw_common_info *info)
 		wake_up_process(osd_irq_task[OSD_PLANE_2]);
 		OSDDBG("kthread_create disp_osd2_irq_kthread\n");
 	}
-	sched_setscheduler(osd_irq_task[OSD_PLANE_2], SCHED_RR, &irq_param);
+	sched_setscheduler_nocheck(osd_irq_task[OSD_PLANE_2], SCHED_RR, &irq_param);
 
 	osd_stop_config = vmalloc(sizeof(struct mtk_disp_buffer));
 	memset(osd_stop_config, 0, sizeof(struct mtk_disp_buffer));
diff --git a/drivers/misc/mediatek/vq/mtk_di_hal.c b/drivers/misc/mediatek/vq/mtk_di_hal.c
index 98d7921..2640c68 100644
--- a/drivers/misc/mediatek/vq/mtk_di_hal.c
+++ b/drivers/misc/mediatek/vq/mtk_di_hal.c
@@ -475,6 +475,15 @@ irqreturn_t _di_vsync_irq_handle(int irq, void *dev_id)
 {
 	/* DISPSYSCFG_W_INT_CLR(0xD); */
 	/* DISPSYSCFG_W_INT_CLR(0x0); */
+	REG_W_BITS(DISPSYSCFG_REG, BITS(28, 28), 28, 1);
+	REG_W_BITS(DISPSYSCFG_REG, BITS(28, 28), 28, 0);
+#if DI_TIME_CHECK
+	DI_TIME_REC(7);
+#endif
+	atomic_set(&di_init.di_event_Irq_flag, 1);
+
+	wake_up_interruptible(&di_init.di_event_irq_handle);
+
 	return IRQ_HANDLED;
 }
 
@@ -530,7 +539,7 @@ int di_hal_request_irq(struct platform_device *pdev, struct di_info *di)
 	DI_IRQ("di_under_run_irq value is %d", di->di_under_run_irq);
 
 	if (request_irq
-	    (di->wrch_frame_end_irq, (irq_handler_t) _di_wrch_end_irq_handler,
+	    (di->di_vsync_irq, (irq_handler_t) _di_vsync_irq_handle,
 	     IRQF_TRIGGER_NONE,
 	     "di", (void *)di)
 	    < 0) {
@@ -974,15 +983,18 @@ static int di_dispfmt_trigger(struct DISPFMT_PARAM_T *prParam)
 		if (wait_event_interruptible_timeout
 		    (di_init.di_event_irq_handle,
 		     atomic_read(&di_init.di_event_Irq_flag),
-		     HZ / 10) == 0) {
+		     1000) == 0) {
 
 			di_init.di_event_irq_timeout_count++;
 
 			if (di_init.di_event_irq_timeout_count == 1)
-				DI_ERR("timeout St %d Flag %d count %d",
+				DI_ERR("timeout St %d Flag %d count %d 0x%08x 0x%08x",
 					di_init.di_reg_irq_st,
 					di_init.di_event_Irq_flag.counter,
-					di_init.di_event_irq_timeout_count);
+					di_init.di_event_irq_timeout_count, REG_R(DISPFMT_REG + 0xBC),
+					REG_R(DISPSYSCFG_REG + 0x4));
+
+			di_init.di_event_irq_timeout_count = 0;
 		} else {
 			#if DI_TIME_CHECK
 			DI_TIME_REC(8);
@@ -992,13 +1004,13 @@ static int di_dispfmt_trigger(struct DISPFMT_PARAM_T *prParam)
 			DI_IRQ("hw time is %ld wait IRQ",
 				(end_timer - start_timer) / 1000000);
 
-			DI_IRQ("OK, St%d Flag %d count %d",
+			DI_IRQ("OK, St%d Flag %d count %d 0x%08x 0x%08x",
 				di_init.di_reg_irq_st,
 				di_init.di_event_Irq_flag.counter,
-				di_init.di_event_irq_timeout_count);
+				di_init.di_event_irq_timeout_count, REG_R(DISPFMT_REG + 0xBC),
+				REG_R(DISPSYSCFG_REG + 0x4));
 
 			di_init.di_event_irq_timeout_count = 0;
-
 			break;
 		}
 	}
@@ -1036,8 +1048,7 @@ static int di_vdo_config_base(struct DI_VDO_PARAM_T *prParam)
 	DI_VDO_W_PICHEIGHT(height);	/* check */
 	DI_VDO_W_DW_NEED(align_width / 4);	/* check */
 	DI_VDO_W_HBLOCK_7_0(align_width / 8);	/* check */
-
-	DI_VDO_W_VSCALE(0x80000800);	/* 0x414 */
+	DI_VDO_W_VSCALE(0x800);	/* 0x414 */
 	DI_VDO_W_STAMBR(0x1e1e0000);	/* 0x418 */
 	DI_VDO_W_VMODE(0x00600003);	/* 0x41c */
 	DI_VDO_W_YSL(0x0ffd0ffc);	/* 0x420 */
@@ -1781,9 +1792,10 @@ static int di_wch_config_set_param(struct DI_WC_PARAM_T *prParam)
 		DI_ERR("not support dst color %d", prParam->dst_fmt);
 		return DI_RET_ERR_PARAM;
 	}
-	DI_FLOW("[WCH] y[0x%x,0x%x] c[0x%x,0x%x]",
+	DI_FLOW("[WCH] y[0x%x,0x%x] c[0x%x,0x%x] %d %d",
 		prParam->output_addr_y, prParam->output_addr_y / 4,
-		prParam->output_addr_cbcr, prParam->output_addr_cbcr / 4);
+		prParam->output_addr_cbcr, prParam->output_addr_cbcr / 4,
+		prParam->width, prParam->height);
 
 	DI_WC_W_VDOIN_MODE(0x38000040);	/* 0x004 */
 
diff --git a/drivers/misc/mediatek/vq/mtk_di_m2m.c b/drivers/misc/mediatek/vq/mtk_di_m2m.c
index 170e3a3..6d5237e 100644
--- a/drivers/misc/mediatek/vq/mtk_di_m2m.c
+++ b/drivers/misc/mediatek/vq/mtk_di_m2m.c
@@ -350,9 +350,8 @@ static void mtk_di_m2m_stop_streaming(struct vb2_queue *q)
 		vb = mtk_di_m2m_buf_remove(ctx, q->type);
 	}
 
-	mutex_unlock(&ctx->di_job_lock);
-
 	pm_runtime_put_sync(&ctx->di_dev->pdev->dev);
+	mutex_unlock(&ctx->di_job_lock);
 }
 
 static void mtk_di_m2m_job_abort(void *priv)
@@ -378,7 +377,7 @@ static int mtk_di_prepare_addr(struct mtk_di_ctx *ctx, struct vb2_buffer *vb,
 		return 1;
 	}
 
-	pix_size = frame->f_width * frame->f_height;
+	pix_size = ((frame->f_width + 15) / 16 * 16) * ((frame->crop.height + 31) / 32 * 32);
 	addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
 
 	if (frame->fmt->num_planes == 1U) {
@@ -655,7 +654,7 @@ static void mtk_di_prepare_config_param(
 	p_config->outputaddr_y = p_param->outputaddr_y.mva_cur;
 	p_config->outputaddr_cbcr = p_param->outputaddr_cbcr.mva_cur;
 
-	p_config->di_config->path_mode = DI_DI_NR_DIRECTLINK_ALL_ENABLE;
+	p_config->di_config->path_mode = DI_DI_STANDALONE;
 	p_config->di_config->bnr_level = 1;
 	p_config->di_config->mnr_level = 1;
 	p_config->di_config->cur_field = p_param->curr_field;
@@ -665,9 +664,14 @@ static void mtk_di_prepare_config_param(
 	p_config->di_config->h265_enable = 0;
 	p_config->di_config->src_width = p_param->srcpic_width;
 	p_config->di_config->src_height = p_param->srcpic_height;
-	p_config->di_config->src_align_width = p_param->srcpic_width;
-	p_config->di_config->src_align_height = p_param->srcpic_height;
+	p_config->di_config->src_align_width = (p_param->srcpic_width + 15) / 16 * 16;
+	p_config->di_config->src_align_height = (p_param->srcpic_height + 31) / 32 * 32;
 	p_config->di_config->topfield_first_enable = p_param->top_filed_first;
+	DI_INFO("%d %d %d %d %d %d %d %d\n",
+		p_config->di_config->src_width, p_config->di_config->src_height,
+		p_config->di_config->src_align_width, p_config->di_config->src_align_height,
+		p_config->di_config->src_fmt, p_config->di_config->dst_fmt,
+		p_param->srcfmt_width, p_param->srcfmt_height);
 }
 
 static void mtk_di_m2m_worker(struct work_struct *work)
@@ -709,7 +713,7 @@ static void mtk_di_m2m_worker(struct work_struct *work)
 		process_param.srcfmt_height =
 		(unsigned int)ctx->s_frame.payload[0] / ctx->s_frame.pitch[0];
 		process_param.srcpic_width = ctx->s_frame.f_width;
-		process_param.srcpic_height = ctx->s_frame.f_height;
+		process_param.srcpic_height = ctx->s_frame.crop.height;
 		process_param.inputaddr_y.mva_prev =
 			(unsigned int)
 			ctx->s_buf[S_IDX_PREV((ctx->s_idx_next))].addr.y;
@@ -1077,7 +1081,7 @@ static int mtk_di_m2m_g_fmt_mplane(struct file *file,
 		pix_mp->plane_fmt[i].bytesperline =
 			(frame->f_width * frame->fmt->depth[i]) / 8U;
 		pix_mp->plane_fmt[i].sizeimage =
-		    pix_mp->plane_fmt[i].bytesperline * frame->f_height;
+		    pix_mp->plane_fmt[i].bytesperline * frame->crop.height;
 	}
 	return DI_RET_OK;
 }
diff --git a/drivers/misc/mediatek/vq/mtk_di_reg.h b/drivers/misc/mediatek/vq/mtk_di_reg.h
index 406296e..8a22fd4 100644
--- a/drivers/misc/mediatek/vq/mtk_di_reg.h
+++ b/drivers/misc/mediatek/vq/mtk_di_reg.h
@@ -39,7 +39,7 @@
 
 /* reg */
 #define BITS(high, low)		((1 << (high - low + 1)) - 1)
-#define REG_R(dAddr)		readl((void *)dAddr)
+#define REG_R(dAddr)		readl((void *)(dAddr))
 #define REG_W(reg, val)		writel(val, (void *)(reg))
 #define REG_R_BITS(reg, bits, shift)          (((REG_R(reg))>>(shift))&(bits))
 #define REG_W_BITS(reg, bits, shift, val) \
diff --git a/mgk.bzl b/mgk.bzl
index d9a5e7d..7bbfa7c 100644
--- a/mgk.bzl
+++ b/mgk.bzl
@@ -157,6 +157,16 @@
             kleaf_internal.append(m)
     return kleaf_internal, kleaf_customer
 
+def _generate_system_dlkm_insmod_cfg(gki_modules):
+    hdr = "# Auto-generated file. Please edit GKI modules list in mgk_modules.bzl instead.\n"
+    insmod_cfg_strs = [hdr]
+
+    for module in gki_modules:
+        name = paths.basename(module).removesuffix(".ko")
+        insmod_cfg_strs += ["modprobe|system {}".format(name)]
+
+    return insmod_cfg_strs
+
 def define_mgk(
         name,
         device_build_config,
@@ -351,6 +361,14 @@
         content = gki_modules,
     )
 
+    # Add an empty string at the end of the list of strings so that
+    # all lines are terminated by a new-line
+    write_file(
+        name = "system_dlkm_insmod_cfg",
+        out = "init.insmod.system_dlkm.cfg",
+        content = _generate_system_dlkm_insmod_cfg(gki_modules) + [""],
+    )
+
     kernel_images(
         name = "{}_images".format(name),
         build_boot = False,
@@ -372,7 +390,7 @@
         vendor_dlkm_modules_blocklist = ":vendor_dlkm_blocklist",
         vendor_dlkm_modules_list = ":vendor_dlkm_modules",
         vendor_dlkm_props = "//{}:vendor_dlkm.props".format(device_modules_dir),
-        vendor_dlkm_etc_files = insmod_cfgs,
+        vendor_dlkm_etc_files = insmod_cfgs + [":system_dlkm_insmod_cfg"],
         deps = [
             "//{}:vendor_dlkm_file_contexts".format(device_modules_dir),
             "//{}:system_dlkm_file_contexts".format(device_modules_dir),
@@ -386,6 +404,7 @@
         ":{}_unstripped_modules_archive".format(name),
         ":gki_kernel_artifacts",
         ":{}_images".format(name),
+        ":system_dlkm_insmod_cfg",
     ]
 
     copy_to_dist_dir(