diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index c39e39d..1f33cb2 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -34,6 +34,19 @@
 #define DSI_DUAL_LINK_FRONT_BACK	1
 #define DSI_DUAL_LINK_PIXEL_ALT		2
 
+#define CABC_OFF			(0 << 0)
+#define CABC_USER_INTERFACE_IMAGE	(1 << 0)
+#define CABC_STILL_PICTURE		(2 << 0)
+#define CABC_VIDEO_MODE			(3 << 0)
+
+#define CABC_BACKLIGHT			(1 << 2)
+#define CABC_DIMMING_DISPLAY		(1 << 3)
+#define CABC_BCTRL			(1 << 5)
+
+#define CABC_PORT_A			0x00
+#define CABC_PORT_C			0x01
+#define CABC_PORT_A_AND_C		0x02
+
 struct intel_dsi_host;
 
 struct intel_dsi {
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 55aad23..7aa211e 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -32,7 +32,10 @@
 
 #include <linux/kernel.h>
 #include <linux/moduleparam.h>
+#include <video/mipi_display.h>
+#include <drm/drm_mipi_dsi.h>
 #include "intel_drv.h"
+#include "intel_dsi.h"
 
 void
 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
@@ -536,6 +539,37 @@ static u32 vlv_get_backlight(struct intel_connector *connector)
 	return _vlv_get_backlight(dev, pipe);
 }
 
+static u32 cabc_get_backlight(struct intel_connector *connector)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct intel_dsi *intel_dsi = NULL;
+	struct drm_crtc *crtc = NULL;
+	struct intel_encoder *encoder = NULL;
+	struct mipi_dsi_device *dsi_device;
+	u8 data[2] = {0};
+	enum port port = PORT_A;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		for_each_encoder_on_crtc(dev, crtc, encoder) {
+			if (encoder->type == INTEL_OUTPUT_DSI)
+				intel_dsi = enc_to_intel_dsi(&encoder->base);
+		}
+	}
+
+	if (intel_dsi->dual_link) {
+		if (intel_dsi->dl_cabc_port == CABC_PORT_A ||
+				intel_dsi->dl_cabc_port == CABC_PORT_A_AND_C)
+			port = PORT_A;
+		else if (intel_dsi->dl_cabc_port == CABC_PORT_C)
+			port = PORT_C;
+	}
+
+	dsi_device = intel_dsi->dsi_hosts[port]->device;
+	mipi_dsi_dcs_read(dsi_device, MIPI_DCS_CABC_LEVEL_RD, data, 2);
+
+	return data[1];
+}
+
 static u32 bxt_get_backlight(struct intel_connector *connector)
 {
 	struct drm_device *dev = connector->base.dev;
@@ -624,6 +658,47 @@ static void vlv_set_backlight(struct intel_connector *connector, u32 level)
 	I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level);
 }
 
+static void cabc_set_backlight(struct intel_connector *connector, u32 level)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct intel_dsi *intel_dsi = NULL;
+	struct drm_crtc *crtc = NULL;
+	struct intel_encoder *encoder = NULL;
+	struct mipi_dsi_device *dsi_device;
+	u8 data[2] = {0};
+	enum port port = PORT_A;
+	u8 count = 1;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		for_each_encoder_on_crtc(dev, crtc, encoder) {
+			if (encoder->type == INTEL_OUTPUT_DSI)
+				intel_dsi = enc_to_intel_dsi(&encoder->base);
+		}
+	}
+
+	if (intel_dsi->dual_link) {
+		if (intel_dsi->dl_cabc_port == CABC_PORT_A)
+			port = PORT_A;
+		else if (intel_dsi->dl_cabc_port == CABC_PORT_C)
+			port = PORT_C;
+		else if (intel_dsi->dl_cabc_port == CABC_PORT_A_AND_C)
+			port = PORT_A;
+	}
+
+	if (intel_dsi->dual_link && intel_dsi->dl_cabc_port ==
+			CABC_PORT_A_AND_C)
+		count = 2;
+
+	do {
+		dsi_device = intel_dsi->dsi_hosts[port]->device;
+		data[1] = level;
+		data[0] = MIPI_DCS_CABC_LEVEL_WR;
+		mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
+		if (count == 2)
+			port = PORT_C;
+	} while (--count > 0);
+}
+
 static void bxt_set_backlight(struct intel_connector *connector, u32 level)
 {
 	struct drm_device *dev = connector->base.dev;
@@ -757,6 +832,52 @@ static void vlv_disable_backlight(struct intel_connector *connector)
 	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE);
 }
 
+static void cabc_disable_backlight(struct intel_connector *connector)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct intel_dsi *intel_dsi = NULL;
+	struct drm_crtc *crtc = NULL;
+	struct intel_encoder *encoder = NULL;
+	struct mipi_dsi_device *dsi_device;
+	enum port port = PORT_A;
+	u8 data[2] = {0};
+	u8 count = 1;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		for_each_encoder_on_crtc(dev, crtc, encoder) {
+			if (encoder->type == INTEL_OUTPUT_DSI)
+				intel_dsi = enc_to_intel_dsi(&encoder->base);
+		}
+	}
+
+	if (intel_dsi->dual_link) {
+		if (intel_dsi->dl_cabc_port == CABC_PORT_A)
+			port = PORT_A;
+		else if (intel_dsi->dl_cabc_port == CABC_PORT_C)
+			port = PORT_C;
+		else if (intel_dsi->dl_cabc_port == CABC_PORT_A_AND_C)
+			port = PORT_A;
+	}
+
+	if (intel_dsi->dual_link && intel_dsi->dl_cabc_port ==
+			CABC_PORT_A_AND_C)
+		count = 2;
+
+	do {
+		dsi_device = intel_dsi->dsi_hosts[port]->device;
+
+		intel_panel_actually_set_backlight(connector, 0);
+		data[1] = CABC_OFF;
+		data[0] = MIPI_DCS_CABC_CONTROL_WR;
+		mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
+		data[0] = MIPI_DCS_CABC_CONTROL_BRIGHT_WR;
+		mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
+
+		if (count == 2)
+			port = PORT_C;
+	} while (--count > 0);
+}
+
 static void bxt_disable_backlight(struct intel_connector *connector)
 {
 	struct drm_device *dev = connector->base.dev;
@@ -1043,6 +1164,56 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
 	mutex_unlock(&dev_priv->backlight_lock);
 }
 
+static void cabc_enable_backlight(struct intel_connector *connector)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct intel_dsi *intel_dsi = NULL;
+	struct drm_crtc *crtc = NULL;
+	struct intel_encoder *encoder = NULL;
+	struct intel_panel *panel = &connector->panel;
+	struct mipi_dsi_device *dsi_device;
+	enum port port = PORT_A;
+	u8 data[2] = {0};
+	u8 count = 1;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		for_each_encoder_on_crtc(dev, crtc, encoder) {
+			if (encoder->type == INTEL_OUTPUT_DSI)
+				intel_dsi = enc_to_intel_dsi(&encoder->base);
+		}
+	}
+
+	if (intel_dsi->dual_link) {
+		if (intel_dsi->dl_cabc_port == CABC_PORT_A)
+			port = PORT_A;
+		else if (intel_dsi->dl_cabc_port == CABC_PORT_C)
+			port = PORT_C;
+		else if (intel_dsi->dl_cabc_port == CABC_PORT_A_AND_C)
+			port = PORT_A;
+	}
+
+	if (intel_dsi->dual_link && intel_dsi->dl_cabc_port ==
+			CABC_PORT_A_AND_C)
+		count = 2;
+
+	do {
+		dsi_device = intel_dsi->dsi_hosts[port]->device;
+
+
+		data[0] = MIPI_DCS_CABC_CONTROL_BRIGHT_WR;
+		data[1] = CABC_BACKLIGHT | CABC_DIMMING_DISPLAY | CABC_BCTRL;
+		mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
+		data[0] = MIPI_DCS_CABC_CONTROL_WR;
+		data[1] = CABC_VIDEO_MODE;
+		mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
+
+		if (count == 2)
+			port = PORT_C;
+	} while (--count > 0);
+
+	intel_panel_actually_set_backlight(connector, panel->backlight.level);
+}
+
 #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
 static int intel_backlight_device_update_status(struct backlight_device *bd)
 {
@@ -1362,6 +1533,33 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
 	return 0;
 }
 
+static int cabc_setup_backlight(struct intel_connector *connector,
+					enum pipe unused)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct intel_dsi *intel_dsi = NULL;
+	struct drm_crtc *crtc = NULL;
+	struct intel_encoder *encoder = NULL;
+	struct intel_panel *panel = &connector->panel;
+	struct mipi_dsi_device *dsi_device;
+	u8 level;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		for_each_encoder_on_crtc(dev, crtc, encoder) {
+			if (encoder->type == INTEL_OUTPUT_DSI)
+				intel_dsi = enc_to_intel_dsi(&encoder->base);
+		}
+	}
+	dsi_device = intel_dsi->dsi_hosts[0]->device;
+	panel->backlight.max = 0xFF;
+	panel->backlight.level = 0xFF;
+
+	level = 255;
+	panel->backlight.enabled =
+		(level & 0x02) && panel->backlight.level != 0;
+	return 0;
+}
+
 static int
 bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
 {
@@ -1438,11 +1636,29 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (IS_BROXTON(dev)) {
-		dev_priv->display.setup_backlight = bxt_setup_backlight;
-		dev_priv->display.enable_backlight = bxt_enable_backlight;
-		dev_priv->display.disable_backlight = bxt_disable_backlight;
-		dev_priv->display.set_backlight = bxt_set_backlight;
-		dev_priv->display.get_backlight = bxt_get_backlight;
+		if (dev_priv->vbt.dsi.config->cabc_supported) {
+			dev_priv->display.setup_backlight =
+					cabc_setup_backlight;
+			dev_priv->display.enable_backlight =
+					cabc_enable_backlight;
+			dev_priv->display.disable_backlight =
+					cabc_disable_backlight;
+			dev_priv->display.set_backlight =
+					cabc_set_backlight;
+			dev_priv->display.get_backlight =
+					cabc_get_backlight;
+		} else {
+			dev_priv->display.setup_backlight =
+					bxt_setup_backlight;
+			dev_priv->display.enable_backlight =
+					bxt_enable_backlight;
+			dev_priv->display.disable_backlight =
+					bxt_disable_backlight;
+			dev_priv->display.set_backlight =
+					bxt_set_backlight;
+			dev_priv->display.get_backlight =
+					bxt_get_backlight;
+		}
 	} else if (IS_BROADWELL(dev) || IS_SKYLAKE(dev)) {
 		dev_priv->display.setup_backlight = bdw_setup_backlight;
 		dev_priv->display.enable_backlight = bdw_enable_backlight;
diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h
index ddcc8ca..5b8eeec 100644
--- a/include/video/mipi_display.h
+++ b/include/video/mipi_display.h
@@ -117,6 +117,14 @@ enum {
 	MIPI_DCS_GET_SCANLINE		= 0x45,
 	MIPI_DCS_READ_DDB_START		= 0xA1,
 	MIPI_DCS_READ_DDB_CONTINUE	= 0xA8,
+	MIPI_DCS_CABC_LEVEL_RD          = 0x52,
+	MIPI_DCS_CABC_MIN_BRIGHTNESS_RD = 0x5F,
+	MIPI_DCS_CABC_CONTROL_RD        = 0x56,
+	MIPI_DCS_CABC_CONTROL_BRIGHT_RD = 0x54,
+	MIPI_DCS_CABC_LEVEL_WR          = 0x51,
+	MIPI_DCS_CABC_MIN_BRIGHTNESS_WR = 0x5E,
+	MIPI_DCS_CABC_CONTROL_WR        = 0x55,
+	MIPI_DCS_CABC_CONTROL_BRIGHT_WR = 0x53,
 };
 
 /* MIPI DCS pixel formats */
