intel-gfx.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [CABC PATCH v1 0/3][RFC] CABC patch list
@ 2015-07-06  4:16 Deepak M
  2015-07-06  4:16 ` [CABC PATCH v1 1/3][RFC] drm/i915: Store the CABC enabled field parsed from VBT to dev_priv structure Deepak M
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Deepak M @ 2015-07-06  4:16 UTC (permalink / raw)
  To: intel-gfx; +Cc: Deepak M

CABC stands for the Content Adaptive Backlight Control.
In the normal display the backlight which we see is due to the
backlight which is being modulated by the filter, which is inturn
dependent on the image. In brief the CABC does the histogram
analysis of the image and then controls the filter and backlight.
For example in CABC to display the dark image the backlight is dimmed
and then controlls the filter to allow more light, because of
which is power consuption will be reduced.

Below are the inital set of patches which supports the CABC.
A field exits in the mipi configuration of the VBT which
when enabled indiactes the CABC is supported. Depending on
this filed the backlight control function pointer are
initalized in the intel_panel.c file.

In case of dual link panels depending on the panel
the DCS commands have to be send to either PORT A,
PORT C or both PORT A and PORT C. Again a filed is
added in the VBT to get this data from the version 197 onwards.
One of the below patches parses these fields from the
VBT.

Please review the below patches.

Deepak M (3):
  drm/i915: Store the CABC enabled field parsed from VBT to dev_priv
    structure
  drm/i915: Parsing the PWM cntrl and CABC ON/OFF fileds in VBT
  drm/i915: CABC support for backlight control

 drivers/gpu/drm/i915/i915_drv.h    |    1 +
 drivers/gpu/drm/i915/intel_bios.c  |   15 +++
 drivers/gpu/drm/i915/intel_bios.h  |    5 +-
 drivers/gpu/drm/i915/intel_dsi.h   |   15 +++
 drivers/gpu/drm/i915/intel_panel.c |  225 +++++++++++++++++++++++++++++++++++-
 include/video/mipi_display.h       |    8 ++
 6 files changed, 263 insertions(+), 6 deletions(-)

-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [CABC PATCH v1 1/3][RFC] drm/i915: Store the CABC enabled field parsed from VBT to dev_priv structure
  2015-07-06  4:16 [CABC PATCH v1 0/3][RFC] CABC patch list Deepak M
@ 2015-07-06  4:16 ` Deepak M
  2015-07-06  4:16 ` [CABC PATCH v1 2/3][RFC] drm/i915: Parsing the PWM cntrl and CABC ON/OFF fileds in VBT Deepak M
  2015-07-06  4:16 ` [CABC PATCH v1 3/3][RFC] drm/i915: CABC support for backlight control Deepak M
  2 siblings, 0 replies; 8+ messages in thread
From: Deepak M @ 2015-07-06  4:16 UTC (permalink / raw)
  To: intel-gfx; +Cc: Deepak M

Signed-off-by: Deepak M <m.deepak@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h   |    1 +
 drivers/gpu/drm/i915/intel_bios.c |    2 ++
 2 files changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1dbd957..1d30cb7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1470,6 +1470,7 @@ struct intel_vbt_data {
 		struct mipi_config *config;
 		struct mipi_pps_data *pps;
 		u8 seq_version;
+		u8 cabc_supported;
 		u32 size;
 		u8 *data;
 		u8 *sequence[MIPI_SEQ_MAX];
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 2ff9eb0..6d8f0d4 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -845,6 +845,8 @@ parse_mipi(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
 	if (!dev_priv->vbt.dsi.data)
 		return;
 
+	dev_priv->vbt.dsi.config->cabc_supported = config->cabc_supported;
+
 	/*
 	 * loop into the sequence data and split into multiple sequneces
 	 * There are only 5 types of sequences as of now
-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [CABC PATCH v1 2/3][RFC] drm/i915: Parsing the PWM cntrl and CABC ON/OFF fileds in VBT
  2015-07-06  4:16 [CABC PATCH v1 0/3][RFC] CABC patch list Deepak M
  2015-07-06  4:16 ` [CABC PATCH v1 1/3][RFC] drm/i915: Store the CABC enabled field parsed from VBT to dev_priv structure Deepak M
@ 2015-07-06  4:16 ` Deepak M
  2015-07-06  4:16 ` [CABC PATCH v1 3/3][RFC] drm/i915: CABC support for backlight control Deepak M
  2 siblings, 0 replies; 8+ messages in thread
From: Deepak M @ 2015-07-06  4:16 UTC (permalink / raw)
  To: intel-gfx; +Cc: Deepak M

For dual link panel scenarios there are new fileds added in the
VBT which indicate on which port the PWM cntrl and CABC ON/OFF
commands needs to be sent.

Signed-off-by: Deepak M <m.deepak@intel.com>
---
 drivers/gpu/drm/i915/intel_bios.c |   13 +++++++++++++
 drivers/gpu/drm/i915/intel_bios.h |    5 ++++-
 drivers/gpu/drm/i915/intel_dsi.h  |    2 ++
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 6d8f0d4..fe4c9ed 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -789,6 +789,19 @@ parse_mipi(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
 		return;
 	}
 
+	/*
+	 * These below bits will inform us on which port the panel blk_cntrl and
+	 * CABC ON/OFF commands needs to be sent in case of dual link panels
+	 *	u16 dl_cabc_port:2;
+	 *	u16 pwm_bkl_ctrl:2;
+	 * But these are introduced from the VBT version 197 onwards, so making
+	 * sure that these bits are zero in the pervious versions.
+	 */
+	if (dev_priv->vbt.dsi.config->dual_link && bdb->version < 197) {
+		dev_priv->vbt.dsi.config->dl_cabc_port = 0;
+		dev_priv->vbt.dsi.config->pwm_bkl_ctrl = 0;
+	}
+
 	/* We have mandatory mipi config blocks. Initialize as generic panel */
 	dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
 
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index af0b476..492be9c 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -820,7 +820,10 @@ struct mipi_config {
 	u16 dual_link:2;
 	u16 lane_cnt:2;
 	u16 pixel_overlap:3;
-	u16 rsvd3:9;
+	u16 rgb_flip:1;
+	u16 dl_cabc_port:2;
+	u16 pwm_bkl_ctrl:2;
+	u16 rsvd3:4;
 
 	u16 rsvd4;
 
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index 2784ac4..c39e39d 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -71,6 +71,8 @@ struct intel_dsi {
 
 	u8 escape_clk_div;
 	u8 dual_link;
+	u8 dl_cabc_port;
+	u8 pwm_blk_ctrl;
 	u8 pixel_overlap;
 	u32 port_bits;
 	u32 bw_timer;
-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [CABC PATCH v1 3/3][RFC] drm/i915: CABC support for backlight control
  2015-07-06  4:16 [CABC PATCH v1 0/3][RFC] CABC patch list Deepak M
  2015-07-06  4:16 ` [CABC PATCH v1 1/3][RFC] drm/i915: Store the CABC enabled field parsed from VBT to dev_priv structure Deepak M
  2015-07-06  4:16 ` [CABC PATCH v1 2/3][RFC] drm/i915: Parsing the PWM cntrl and CABC ON/OFF fileds in VBT Deepak M
@ 2015-07-06  4:16 ` Deepak M
  2015-07-06 12:51   ` Daniel Vetter
  2 siblings, 1 reply; 8+ messages in thread
From: Deepak M @ 2015-07-06  4:16 UTC (permalink / raw)
  To: intel-gfx; +Cc: Deepak M

In CABC (Content Adaptive Brightness Control) content grey level
scale can be increased while simultaneously decreasing
brightness of the backlight to achieve same perceived brightness.

The CABC is not standardized and panel vendors are free to follow
their implementation. The CABC implementaion here assumes that the
panels use standard SW register for control.

In this design there will be no PWM signal from the SoC and DCS
commands are sent to enable and control the backlight brightness.

Signed-off-by: Deepak M <m.deepak@intel.com>
---
 drivers/gpu/drm/i915/intel_dsi.h   |   13 +++
 drivers/gpu/drm/i915/intel_panel.c |  226 +++++++++++++++++++++++++++++++++++-
 include/video/mipi_display.h       |    8 ++
 3 files changed, 242 insertions(+), 5 deletions(-)

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 */
-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [CABC PATCH v1 3/3][RFC] drm/i915: CABC support for backlight control
  2015-07-06  4:16 ` [CABC PATCH v1 3/3][RFC] drm/i915: CABC support for backlight control Deepak M
@ 2015-07-06 12:51   ` Daniel Vetter
  2015-07-24 12:24     ` [RFC CABC PATCH v2 3/3] " Deepak M
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Vetter @ 2015-07-06 12:51 UTC (permalink / raw)
  To: Deepak M; +Cc: intel-gfx

On Mon, Jul 06, 2015 at 09:46:07AM +0530, Deepak M wrote:
> In CABC (Content Adaptive Brightness Control) content grey level
> scale can be increased while simultaneously decreasing
> brightness of the backlight to achieve same perceived brightness.
> 
> The CABC is not standardized and panel vendors are free to follow
> their implementation. The CABC implementaion here assumes that the
> panels use standard SW register for control.
> 
> In this design there will be no PWM signal from the SoC and DCS
> commands are sent to enable and control the backlight brightness.
> 
> Signed-off-by: Deepak M <m.deepak@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dsi.h   |   13 +++
>  drivers/gpu/drm/i915/intel_panel.c |  226 +++++++++++++++++++++++++++++++++++-
>  include/video/mipi_display.h       |    8 ++
>  3 files changed, 242 insertions(+), 5 deletions(-)
> 
> 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);
> +		}
> +	}

We seem to have a bit a layering violation going on here: The
dev_priv->display.*_backlight functions are for the device global
backlight. But this here controls a sink-specific backlight.

Another example of a sink-specific backlight control would be the optional
backlight stuff for eDP. In linux we have a few backlight classes like
firmware, platform or raw. The i915 backlight is a raw one and last in the
priority chain userspace uses to figure out which backlight to use.

I think the right approach here for the CABC dsi sink backlight is to
register a new dsi backlight driver (if and only if the panel supports it
of course) of type firmware (or something else suitable). Then it will
automatically take precendence over the i915 raw backlight. It would also
be good to have an explicit link from the sysfs connector to this
connector-specific backlight so that userspace knows about it.

Or something along those lines, linux backlight control is one giant mess.

At least with that approach we don't need to have any interaction with the
panel backlight code and this should all more-or-less cleanly integrate.
-Daniel

> +
> +	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 */
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [RFC CABC PATCH v2 3/3] drm/i915: CABC support for backlight control
  2015-07-06 12:51   ` Daniel Vetter
@ 2015-07-24 12:24     ` Deepak M
  2015-07-30 10:48       ` Singh, Gaurav K
  0 siblings, 1 reply; 8+ messages in thread
From: Deepak M @ 2015-07-24 12:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: Deepak M

In CABC (Content Adaptive Brightness Control) content grey level
scale can be increased while simultaneously decreasing
brightness of the backlight to achieve same perceived brightness.

The CABC is not standardized and panel vendors are free to follow
their implementation. The CABC implementaion here assumes that the
panels use standard SW register for control.

In this design there will be no PWM signal from the SoC and DCS
commands are sent to enable and control the backlight brightness.

v2:
- Created a new backlight driver for cabc, which will be registered
  only when it cabc is supported by panel.
  (Addressed comment from Daniel Vetter)

Signed-off-by: Deepak M <m.deepak@intel.com>
---
 drivers/gpu/drm/i915/Makefile         |    1 +
 drivers/gpu/drm/i915/intel_drv.h      |    3 +-
 drivers/gpu/drm/i915/intel_dsi.c      |   13 ++
 drivers/gpu/drm/i915/intel_dsi_cabc.c |  349 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_dsi_cabc.h |   45 +++++
 drivers/gpu/drm/i915/intel_panel.c    |   22 ++-
 include/video/mipi_display.h          |    8 +
 7 files changed, 436 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_dsi_cabc.c
 create mode 100644 drivers/gpu/drm/i915/intel_dsi_cabc.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index de21965..a73953c 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -75,6 +75,7 @@ i915-y += dvo_ch7017.o \
 	  intel_dp_mst.o \
 	  intel_dsi.o \
 	  intel_dsi_pll.o \
+	  intel_dsi_cabc.o \
 	  intel_dsi_panel_vbt.o \
 	  intel_dvo.o \
 	  intel_hdmi.o \
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3f0a890..9f806dd5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1319,7 +1319,8 @@ extern struct drm_display_mode *intel_find_panel_downclock(
 				struct drm_connector *connector);
 void intel_backlight_register(struct drm_device *dev);
 void intel_backlight_unregister(struct drm_device *dev);
-
+extern int cabc_backlight_device_register(struct intel_connector *connector);
+extern void cabc_backlight_device_unregister(struct intel_connector *connector);
 
 /* intel_psr.c */
 void intel_psr_enable(struct intel_dp *intel_dp);
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 98998e9..8f006f2 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -34,6 +34,7 @@
 #include "i915_drv.h"
 #include "intel_drv.h"
 #include "intel_dsi.h"
+#include "intel_dsi_cabc.h"
 
 static const struct {
 	u16 panel_id;
@@ -376,6 +377,7 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	struct intel_connector *connector = intel_dsi->attached_connector;
 	enum port port;
 
 	DRM_DEBUG_KMS("\n");
@@ -396,6 +398,9 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
 
 		intel_dsi_port_enable(encoder);
 	}
+
+	if (dev_priv->vbt.dsi.config->cabc_supported)
+		cabc_enable_backlight(connector);
 }
 
 static void intel_dsi_pre_enable(struct intel_encoder *encoder)
@@ -469,11 +474,15 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	struct intel_connector *connector = intel_dsi->attached_connector;
 	enum port port;
 	u32 temp;
 
 	DRM_DEBUG_KMS("\n");
 
+	if (dev_priv->vbt.dsi.config->cabc_supported)
+		cabc_disable_backlight(connector);
+
 	if (is_vid_mode(intel_dsi)) {
 		for_each_dsi_port(port, intel_dsi->ports)
 			wait_for_dsi_fifo_empty(intel_dsi, port);
@@ -1099,6 +1108,10 @@ void intel_dsi_init(struct drm_device *dev)
 
 	intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
 
+	if (dev_priv->vbt.dsi.config->cabc_supported)
+		cabc_setup_backlight(connector,
+			intel_encoder->crtc_mask ==
+				(1 << PIPE_A) ? PIPE_A : PIPE_B);
 	return;
 
 err:
diff --git a/drivers/gpu/drm/i915/intel_dsi_cabc.c b/drivers/gpu/drm/i915/intel_dsi_cabc.c
new file mode 100644
index 0000000..2a78326
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dsi_cabc.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright © 2006-2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include "intel_drv.h"
+#include "intel_dsi.h"
+#include "i915_drv.h"
+#include "intel_dsi_cabc.h"
+#include <video/mipi_display.h>
+#include <drm/drm_mipi_dsi.h>
+
+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 = CABC_MAX_VALUE;
+	panel->backlight.level = CABC_MAX_VALUE;
+	level = CABC_MAX_VALUE;
+	panel->backlight.enabled = true;
+	return 0;
+}
+
+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;
+	struct intel_panel *panel = &connector->panel;
+	u8 data[2] = {0};
+	enum port port = PORT_A;
+	u32 ret;
+
+	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);
+
+	ret = (data[1] * panel->backlight.max) / 255;
+	return ret;
+}
+
+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;
+	struct intel_panel *panel = &connector->panel;
+	u8 count = 1;
+	u32 hw_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);
+		}
+	}
+
+	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;
+
+
+	hw_level = level % (panel->backlight.max + 1);
+	hw_level = (hw_level * 255) / panel->backlight.max;
+	panel->backlight.level = hw_level;
+
+	do {
+		dsi_device = intel_dsi->dsi_hosts[port]->device;
+		data[1] = hw_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);
+}
+
+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);
+
+	cabc_set_backlight(connector, panel->backlight.level);
+}
+
+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;
+
+		cabc_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 int cabc_backlight_device_update_status(struct backlight_device *bd)
+{
+	struct intel_connector *connector = bl_get_data(bd);
+	struct intel_panel *panel = &connector->panel;
+	struct drm_device *dev = connector->base.dev;
+
+	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+	DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
+			bd->props.brightness, bd->props.max_brightness);
+	cabc_set_backlight(connector, bd->props.brightness);
+
+	/*
+	 * Allow flipping bl_power as a sub-state of enabled. Sadly the
+	 * backlight class device does not make it easy to to differentiate
+	 * between callbacks for brightness and bl_power, so our backlight_power
+	 * callback needs to take this into account.
+	 */
+	if (panel->backlight.enabled) {
+		if (panel->backlight_power) {
+			bool enable = bd->props.power == FB_BLANK_UNBLANK &&
+				bd->props.brightness != 0;
+			panel->backlight_power(connector, enable);
+		}
+	} else {
+		bd->props.power = FB_BLANK_POWERDOWN;
+	}
+
+	drm_modeset_unlock(&dev->mode_config.connection_mutex);
+	return 0;
+}
+
+static int cabc_backlight_device_get_brightness(struct backlight_device *bd)
+{
+	struct intel_connector *connector = bl_get_data(bd);
+	struct drm_device *dev = connector->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	intel_runtime_pm_get(dev_priv);
+	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+
+	ret = cabc_get_backlight(connector);
+
+	drm_modeset_unlock(&dev->mode_config.connection_mutex);
+	intel_runtime_pm_put(dev_priv);
+
+	return ret;
+}
+
+static const struct backlight_ops cabc_backlight_device_ops = {
+	.update_status = cabc_backlight_device_update_status,
+	.get_brightness = cabc_backlight_device_get_brightness,
+};
+
+int cabc_backlight_device_register(struct intel_connector *connector)
+{
+	struct intel_panel *panel = &connector->panel;
+	struct backlight_properties props;
+
+	if (WARN_ON(panel->backlight.device))
+		return -ENODEV;
+
+	if (!panel->backlight.present)
+		return 0;
+
+	WARN_ON(panel->backlight.max == 0);
+
+	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_FIRMWARE;
+
+	/*
+	 * Note: Everything should work even if the backlight device max
+	 * presented to the userspace is arbitrarily chosen.
+	 */
+	props.max_brightness = panel->backlight.max;
+	props.brightness = props.max_brightness;
+
+	if (panel->backlight.enabled)
+		props.power = FB_BLANK_UNBLANK;
+	else
+		props.power = FB_BLANK_POWERDOWN;
+
+	/*
+	 * Note: using the same name independent of the connector prevents
+	 * registration of multiple backlight devices in the driver.
+	 */
+	panel->backlight.device =
+		backlight_device_register("intel_backlight",
+				connector->base.kdev,
+				connector,
+				&cabc_backlight_device_ops, &props);
+
+	if (IS_ERR(panel->backlight.device)) {
+		DRM_ERROR("Failed to register backlight: %ld\n",
+				PTR_ERR(panel->backlight.device));
+		panel->backlight.device = NULL;
+		return -ENODEV;
+	}
+
+	DRM_DEBUG_KMS("Connector %s backlight sysfs interface registered\n",
+			connector->base.name);
+
+	return 0;
+}
+
+void cabc_backlight_device_unregister(struct intel_connector *connector)
+{
+	struct intel_panel *panel = &connector->panel;
+
+	if (panel->backlight.device) {
+		backlight_device_unregister(panel->backlight.device);
+		panel->backlight.device = NULL;
+	}
+}
diff --git a/drivers/gpu/drm/i915/intel_dsi_cabc.h b/drivers/gpu/drm/i915/intel_dsi_cabc.h
new file mode 100644
index 0000000..5d134f5
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dsi_cabc.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+extern int cabc_backlight_device_register(struct intel_connector *connector);
+extern void cabc_backlight_device_unregister(struct intel_connector *connector);
+void cabc_set_backlight(struct intel_connector *connector, u32 level);
+u32 cabc_get_backlight(struct intel_connector *connector);
+void cabc_enable_backlight(struct intel_connector *connector);
+void cabc_disable_backlight(struct intel_connector *connector);
+int cabc_setup_backlight(struct intel_connector *connector, enum pipe unused);
+
+#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
+#define CABC_MAX_VALUE		       0xff
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 55aad23..c73449b 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -1502,15 +1502,29 @@ void intel_panel_fini(struct intel_panel *panel)
 void intel_backlight_register(struct drm_device *dev)
 {
 	struct intel_connector *connector;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
-		intel_backlight_device_register(connector);
+	list_for_each_entry(connector, &dev->mode_config.connector_list,
+					base.head) {
+		if (connector->encoder->type == INTEL_OUTPUT_DSI &&
+			dev_priv->vbt.dsi.config->cabc_supported)
+			cabc_backlight_device_register(connector);
+		else
+			intel_backlight_device_register(connector);
+	}
 }
 
 void intel_backlight_unregister(struct drm_device *dev)
 {
 	struct intel_connector *connector;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
-		intel_backlight_device_unregister(connector);
+	list_for_each_entry(connector, &dev->mode_config.connector_list,
+					base.head) {
+		if (connector->encoder->type == INTEL_OUTPUT_DSI &&
+			dev_priv->vbt.dsi.config->cabc_supported)
+			cabc_backlight_device_unregister(connector);
+		else
+			intel_backlight_device_unregister(connector);
+	}
 }
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 */
-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [RFC CABC PATCH v2 3/3] drm/i915: CABC support for backlight control
  2015-07-24 12:24     ` [RFC CABC PATCH v2 3/3] " Deepak M
@ 2015-07-30 10:48       ` Singh, Gaurav K
  2015-08-05  7:50         ` Singh, Gaurav K
  0 siblings, 1 reply; 8+ messages in thread
From: Singh, Gaurav K @ 2015-07-30 10:48 UTC (permalink / raw)
  To: Deepak M, intel-gfx



On 7/24/2015 5:54 PM, Deepak M wrote:
> In CABC (Content Adaptive Brightness Control) content grey level
> scale can be increased while simultaneously decreasing
> brightness of the backlight to achieve same perceived brightness.
>
> The CABC is not standardized and panel vendors are free to follow
> their implementation. The CABC implementaion here assumes that the
> panels use standard SW register for control.
>
> In this design there will be no PWM signal from the SoC and DCS
> commands are sent to enable and control the backlight brightness.
>
> v2:
> - Created a new backlight driver for cabc, which will be registered
>    only when it cabc is supported by panel.
>    (Addressed comment from Daniel Vetter)
>
> Signed-off-by: Deepak M <m.deepak@intel.com>
> ---
>   drivers/gpu/drm/i915/Makefile         |    1 +
>   drivers/gpu/drm/i915/intel_drv.h      |    3 +-
>   drivers/gpu/drm/i915/intel_dsi.c      |   13 ++
>   drivers/gpu/drm/i915/intel_dsi_cabc.c |  349 +++++++++++++++++++++++++++++++++
>   drivers/gpu/drm/i915/intel_dsi_cabc.h |   45 +++++
>   drivers/gpu/drm/i915/intel_panel.c    |   22 ++-
>   include/video/mipi_display.h          |    8 +
>   7 files changed, 436 insertions(+), 5 deletions(-)
>   create mode 100644 drivers/gpu/drm/i915/intel_dsi_cabc.c
>   create mode 100644 drivers/gpu/drm/i915/intel_dsi_cabc.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index de21965..a73953c 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -75,6 +75,7 @@ i915-y += dvo_ch7017.o \
>   	  intel_dp_mst.o \
>   	  intel_dsi.o \
>   	  intel_dsi_pll.o \
> +	  intel_dsi_cabc.o \
>   	  intel_dsi_panel_vbt.o \
>   	  intel_dvo.o \
>   	  intel_hdmi.o \
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 3f0a890..9f806dd5 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1319,7 +1319,8 @@ extern struct drm_display_mode *intel_find_panel_downclock(
>   				struct drm_connector *connector);
>   void intel_backlight_register(struct drm_device *dev);
>   void intel_backlight_unregister(struct drm_device *dev);
> -
> +extern int cabc_backlight_device_register(struct intel_connector *connector);
> +extern void cabc_backlight_device_unregister(struct intel_connector *connector);
>   
>   /* intel_psr.c */
>   void intel_psr_enable(struct intel_dp *intel_dp);
> diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
> index 98998e9..8f006f2 100644
> --- a/drivers/gpu/drm/i915/intel_dsi.c
> +++ b/drivers/gpu/drm/i915/intel_dsi.c
> @@ -34,6 +34,7 @@
>   #include "i915_drv.h"
>   #include "intel_drv.h"
>   #include "intel_dsi.h"
> +#include "intel_dsi_cabc.h"
>   
>   static const struct {
>   	u16 panel_id;
> @@ -376,6 +377,7 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
>   	struct drm_device *dev = encoder->base.dev;
>   	struct drm_i915_private *dev_priv = dev->dev_private;
>   	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
> +	struct intel_connector *connector = intel_dsi->attached_connector;
>   	enum port port;
>   
>   	DRM_DEBUG_KMS("\n");
> @@ -396,6 +398,9 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
>   
>   		intel_dsi_port_enable(encoder);
>   	}
> +
> +	if (dev_priv->vbt.dsi.config->cabc_supported)
> +		cabc_enable_backlight(connector);
>   }
>   
>   static void intel_dsi_pre_enable(struct intel_encoder *encoder)
> @@ -469,11 +474,15 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
>   	struct drm_device *dev = encoder->base.dev;
>   	struct drm_i915_private *dev_priv = dev->dev_private;
>   	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
> +	struct intel_connector *connector = intel_dsi->attached_connector;
>   	enum port port;
>   	u32 temp;
>   
>   	DRM_DEBUG_KMS("\n");
>   
> +	if (dev_priv->vbt.dsi.config->cabc_supported)
> +		cabc_disable_backlight(connector);
> +
>   	if (is_vid_mode(intel_dsi)) {
>   		for_each_dsi_port(port, intel_dsi->ports)
>   			wait_for_dsi_fifo_empty(intel_dsi, port);
> @@ -1099,6 +1108,10 @@ void intel_dsi_init(struct drm_device *dev)
>   
>   	intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
>   
> +	if (dev_priv->vbt.dsi.config->cabc_supported)
> +		cabc_setup_backlight(connector,
> +			intel_encoder->crtc_mask ==
> +				(1 << PIPE_A) ? PIPE_A : PIPE_B);
>   	return;
>   
>   err:
> diff --git a/drivers/gpu/drm/i915/intel_dsi_cabc.c b/drivers/gpu/drm/i915/intel_dsi_cabc.c
> new file mode 100644
> index 0000000..2a78326
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_dsi_cabc.c
> @@ -0,0 +1,349 @@
> +/*
> + * Copyright © 2006-2010 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/moduleparam.h>
> +#include "intel_drv.h"
> +#include "intel_dsi.h"
> +#include "i915_drv.h"
> +#include "intel_dsi_cabc.h"
> +#include <video/mipi_display.h>
> +#include <drm/drm_mipi_dsi.h>
> +
> +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;
This will work only for MIPI Port A not for MIPI Port C. Use 
for_each_dsi_port macro and intel_dsi->dsi_hosts[port] to correctly 
reach to mipi_dsi_device for both ports. If it is dual link, break after 
the completion of the first iteration.
> +	panel->backlight.max = CABC_MAX_VALUE;
> +	panel->backlight.level = CABC_MAX_VALUE;
> +	level = CABC_MAX_VALUE;
> +	panel->backlight.enabled = true;
> +	return 0;
> +}
> +
> +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;
> +	struct intel_panel *panel = &connector->panel;
> +	u8 data[2] = {0};
> +	enum port port = PORT_A;
will fail for single link MIPI Port C.
> +	u32 ret;
> +
> +	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) {
Put the below or required logic into static inline function returning 
enum port .
> +		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;
> +	}
Use for_each_dsi_port macro here . call the  inline function within 
for_each_dsi_port macro to get the required enum port for dual link.
> +
> +	dsi_device = intel_dsi->dsi_hosts[port]->device;
> +	mipi_dsi_dcs_read(dsi_device, MIPI_DCS_CABC_LEVEL_RD, data, 2);
> +
> +	ret = (data[1] * panel->backlight.max) / 255;
> +	return ret;
> +}
> +
> +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;
> +	struct intel_panel *panel = &connector->panel;
> +	u8 count = 1;
> +	u32 hw_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);
> +		}
> +	}
> +
> +	if (intel_dsi->dual_link) {
Put the below logic into static inline function returning enum port .
> +		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;
> +	}
> +
Below part not required. use for_each_dsi_port macro.
> +	if (intel_dsi->dual_link && intel_dsi->dl_cabc_port ==
> +			CABC_PORT_A_AND_C)
> +		count = 2;
> +
> +
> +	hw_level = level % (panel->backlight.max + 1);
> +	hw_level = (hw_level * 255) / panel->backlight.max;
> +	panel->backlight.level = hw_level;
> +
Use for_each_dsi_port macro as explained above.
> +	do {
> +		dsi_device = intel_dsi->dsi_hosts[port]->device;
> +		data[1] = hw_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);
> +}
> +
> +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;
Will fail for single link Port C
> +	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) {
Same comment .Put the below logic into static inline function returning 
enum port .
> +		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;
Also below condition need not be taken into the inline function. Since 
it is dual link and with other conditions are met, then 
CABC_PORT_A_AND_C will be automatically taken care for both ports by the 
for_each_dsi_port macro.
Within for_each_dsi_port, just check for intel_dsi->dl_cabc_port != 
CABC_PORT_A_AND_C, if yes call the inline function to get the port no 
and if no, all other conditions will be taken care for both ports by 
for_each_dsi_port.
Before the end of for_each_dsi_port ,you may require to check the 
intel_dsi->dl_cabc_port != CABC_PORT_A_AND_C , so that you can return 
from the macro.
> +		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 {
same comment as above. Use for_each_dsi_port
> +		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);
> +
> +	cabc_set_backlight(connector, panel->backlight.level);
> +}
> +
> +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;
Will fail for single link Port C
> +	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) {
Same comment as above. Use static inline function for this.
> +		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 {
Use for_each_dsi_port macro
> +		dsi_device = intel_dsi->dsi_hosts[port]->device;
> +
> +		cabc_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 int cabc_backlight_device_update_status(struct backlight_device *bd)
> +{
> +	struct intel_connector *connector = bl_get_data(bd);
> +	struct intel_panel *panel = &connector->panel;
> +	struct drm_device *dev = connector->base.dev;
> +
> +	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> +	DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
> +			bd->props.brightness, bd->props.max_brightness);
> +	cabc_set_backlight(connector, bd->props.brightness);
> +
> +	/*
> +	 * Allow flipping bl_power as a sub-state of enabled. Sadly the
> +	 * backlight class device does not make it easy to to differentiate
> +	 * between callbacks for brightness and bl_power, so our backlight_power
> +	 * callback needs to take this into account.
> +	 */
> +	if (panel->backlight.enabled) {
> +		if (panel->backlight_power) {
> +			bool enable = bd->props.power == FB_BLANK_UNBLANK &&
> +				bd->props.brightness != 0;
> +			panel->backlight_power(connector, enable);
> +		}
> +	} else {
> +		bd->props.power = FB_BLANK_POWERDOWN;
> +	}
> +
> +	drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +	return 0;
> +}
> +
> +static int cabc_backlight_device_get_brightness(struct backlight_device *bd)
> +{
> +	struct intel_connector *connector = bl_get_data(bd);
> +	struct drm_device *dev = connector->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	int ret;
> +
> +	intel_runtime_pm_get(dev_priv);
> +	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> +
> +	ret = cabc_get_backlight(connector);
> +
> +	drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +	intel_runtime_pm_put(dev_priv);
> +
> +	return ret;
> +}
> +
> +static const struct backlight_ops cabc_backlight_device_ops = {
> +	.update_status = cabc_backlight_device_update_status,
> +	.get_brightness = cabc_backlight_device_get_brightness,
> +};
> +
> +int cabc_backlight_device_register(struct intel_connector *connector)
> +{
> +	struct intel_panel *panel = &connector->panel;
> +	struct backlight_properties props;
> +
> +	if (WARN_ON(panel->backlight.device))
> +		return -ENODEV;
> +
> +	if (!panel->backlight.present)
> +		return 0;
> +
> +	WARN_ON(panel->backlight.max == 0);
> +
> +	memset(&props, 0, sizeof(props));
> +	props.type = BACKLIGHT_FIRMWARE;
> +
> +	/*
> +	 * Note: Everything should work even if the backlight device max
> +	 * presented to the userspace is arbitrarily chosen.
> +	 */
> +	props.max_brightness = panel->backlight.max;
> +	props.brightness = props.max_brightness;
> +
> +	if (panel->backlight.enabled)
> +		props.power = FB_BLANK_UNBLANK;
> +	else
> +		props.power = FB_BLANK_POWERDOWN;
> +
> +	/*
> +	 * Note: using the same name independent of the connector prevents
> +	 * registration of multiple backlight devices in the driver.
> +	 */
> +	panel->backlight.device =
> +		backlight_device_register("intel_backlight",
> +				connector->base.kdev,
> +				connector,
> +				&cabc_backlight_device_ops, &props);
> +
> +	if (IS_ERR(panel->backlight.device)) {
> +		DRM_ERROR("Failed to register backlight: %ld\n",
> +				PTR_ERR(panel->backlight.device));
> +		panel->backlight.device = NULL;
> +		return -ENODEV;
> +	}
> +
> +	DRM_DEBUG_KMS("Connector %s backlight sysfs interface registered\n",
> +			connector->base.name);
> +
> +	return 0;
> +}
> +
> +void cabc_backlight_device_unregister(struct intel_connector *connector)
> +{
> +	struct intel_panel *panel = &connector->panel;
> +
> +	if (panel->backlight.device) {
> +		backlight_device_unregister(panel->backlight.device);
> +		panel->backlight.device = NULL;
> +	}
> +}
> diff --git a/drivers/gpu/drm/i915/intel_dsi_cabc.h b/drivers/gpu/drm/i915/intel_dsi_cabc.h
> new file mode 100644
> index 0000000..5d134f5
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_dsi_cabc.h
> @@ -0,0 +1,45 @@
> +/*
> + * Copyright © 2013 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +extern int cabc_backlight_device_register(struct intel_connector *connector);
> +extern void cabc_backlight_device_unregister(struct intel_connector *connector);
> +void cabc_set_backlight(struct intel_connector *connector, u32 level);
> +u32 cabc_get_backlight(struct intel_connector *connector);
> +void cabc_enable_backlight(struct intel_connector *connector);
> +void cabc_disable_backlight(struct intel_connector *connector);
> +int cabc_setup_backlight(struct intel_connector *connector, enum pipe unused);
> +
> +#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
> +#define CABC_MAX_VALUE		       0xff
> diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
> index 55aad23..c73449b 100644
> --- a/drivers/gpu/drm/i915/intel_panel.c
> +++ b/drivers/gpu/drm/i915/intel_panel.c
> @@ -1502,15 +1502,29 @@ void intel_panel_fini(struct intel_panel *panel)
>   void intel_backlight_register(struct drm_device *dev)
>   {
>   	struct intel_connector *connector;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
>   
> -	list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
> -		intel_backlight_device_register(connector);
> +	list_for_each_entry(connector, &dev->mode_config.connector_list,
> +					base.head) {
> +		if (connector->encoder->type == INTEL_OUTPUT_DSI &&
> +			dev_priv->vbt.dsi.config->cabc_supported)
> +			cabc_backlight_device_register(connector);
> +		else
> +			intel_backlight_device_register(connector);
> +	}
>   }
>   
>   void intel_backlight_unregister(struct drm_device *dev)
>   {
>   	struct intel_connector *connector;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
>   
> -	list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
> -		intel_backlight_device_unregister(connector);
> +	list_for_each_entry(connector, &dev->mode_config.connector_list,
> +					base.head) {
> +		if (connector->encoder->type == INTEL_OUTPUT_DSI &&
> +			dev_priv->vbt.dsi.config->cabc_supported)
> +			cabc_backlight_device_unregister(connector);
> +		else
> +			intel_backlight_device_unregister(connector);
> +	}
>   }
> 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 */

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC CABC PATCH v2 3/3] drm/i915: CABC support for backlight control
  2015-07-30 10:48       ` Singh, Gaurav K
@ 2015-08-05  7:50         ` Singh, Gaurav K
  0 siblings, 0 replies; 8+ messages in thread
From: Singh, Gaurav K @ 2015-08-05  7:50 UTC (permalink / raw)
  To: Deepak M, intel-gfx



On 7/30/2015 4:18 PM, Singh, Gaurav K wrote:
>
>
> On 7/24/2015 5:54 PM, Deepak M wrote:
>> In CABC (Content Adaptive Brightness Control) content grey level
>> scale can be increased while simultaneously decreasing
>> brightness of the backlight to achieve same perceived brightness.
>>
>> The CABC is not standardized and panel vendors are free to follow
>> their implementation. The CABC implementaion here assumes that the
>> panels use standard SW register for control.
>>
>> In this design there will be no PWM signal from the SoC and DCS
>> commands are sent to enable and control the backlight brightness.
>>
>> v2:
>> - Created a new backlight driver for cabc, which will be registered
>>    only when it cabc is supported by panel.
>>    (Addressed comment from Daniel Vetter)
>>
>> Signed-off-by: Deepak M <m.deepak@intel.com>
>> ---
>>   drivers/gpu/drm/i915/Makefile         |    1 +
>>   drivers/gpu/drm/i915/intel_drv.h      |    3 +-
>>   drivers/gpu/drm/i915/intel_dsi.c      |   13 ++
>>   drivers/gpu/drm/i915/intel_dsi_cabc.c |  349 
>> +++++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/i915/intel_dsi_cabc.h |   45 +++++
>>   drivers/gpu/drm/i915/intel_panel.c    |   22 ++-
>>   include/video/mipi_display.h          |    8 +
>>   7 files changed, 436 insertions(+), 5 deletions(-)
>>   create mode 100644 drivers/gpu/drm/i915/intel_dsi_cabc.c
>>   create mode 100644 drivers/gpu/drm/i915/intel_dsi_cabc.h
>>
>> diff --git a/drivers/gpu/drm/i915/Makefile 
>> b/drivers/gpu/drm/i915/Makefile
>> index de21965..a73953c 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -75,6 +75,7 @@ i915-y += dvo_ch7017.o \
>>         intel_dp_mst.o \
>>         intel_dsi.o \
>>         intel_dsi_pll.o \
>> +      intel_dsi_cabc.o \
>>         intel_dsi_panel_vbt.o \
>>         intel_dvo.o \
>>         intel_hdmi.o \
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h 
>> b/drivers/gpu/drm/i915/intel_drv.h
>> index 3f0a890..9f806dd5 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -1319,7 +1319,8 @@ extern struct drm_display_mode 
>> *intel_find_panel_downclock(
>>                   struct drm_connector *connector);
>>   void intel_backlight_register(struct drm_device *dev);
>>   void intel_backlight_unregister(struct drm_device *dev);
>> -
>> +extern int cabc_backlight_device_register(struct intel_connector 
>> *connector);
>> +extern void cabc_backlight_device_unregister(struct intel_connector 
>> *connector);
>>     /* intel_psr.c */
>>   void intel_psr_enable(struct intel_dp *intel_dp);
>> diff --git a/drivers/gpu/drm/i915/intel_dsi.c 
>> b/drivers/gpu/drm/i915/intel_dsi.c
>> index 98998e9..8f006f2 100644
>> --- a/drivers/gpu/drm/i915/intel_dsi.c
>> +++ b/drivers/gpu/drm/i915/intel_dsi.c
>> @@ -34,6 +34,7 @@
>>   #include "i915_drv.h"
>>   #include "intel_drv.h"
>>   #include "intel_dsi.h"
>> +#include "intel_dsi_cabc.h"
>>     static const struct {
>>       u16 panel_id;
>> @@ -376,6 +377,7 @@ static void intel_dsi_enable(struct intel_encoder 
>> *encoder)
>>       struct drm_device *dev = encoder->base.dev;
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +    struct intel_connector *connector = intel_dsi->attached_connector;
>>       enum port port;
>>         DRM_DEBUG_KMS("\n");
>> @@ -396,6 +398,9 @@ static void intel_dsi_enable(struct intel_encoder 
>> *encoder)
>>             intel_dsi_port_enable(encoder);
>>       }
>> +
>> +    if (dev_priv->vbt.dsi.config->cabc_supported)
>> +        cabc_enable_backlight(connector);
>>   }
>>     static void intel_dsi_pre_enable(struct intel_encoder *encoder)
>> @@ -469,11 +474,15 @@ static void intel_dsi_disable(struct 
>> intel_encoder *encoder)
>>       struct drm_device *dev = encoder->base.dev;
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +    struct intel_connector *connector = intel_dsi->attached_connector;
>>       enum port port;
>>       u32 temp;
>>         DRM_DEBUG_KMS("\n");
>>   +    if (dev_priv->vbt.dsi.config->cabc_supported)
>> +        cabc_disable_backlight(connector);
>> +
>>       if (is_vid_mode(intel_dsi)) {
>>           for_each_dsi_port(port, intel_dsi->ports)
>>               wait_for_dsi_fifo_empty(intel_dsi, port);
>> @@ -1099,6 +1108,10 @@ void intel_dsi_init(struct drm_device *dev)
>>         intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
>>   +    if (dev_priv->vbt.dsi.config->cabc_supported)
>> +        cabc_setup_backlight(connector,
>> +            intel_encoder->crtc_mask ==
>> +                (1 << PIPE_A) ? PIPE_A : PIPE_B);
>>       return;
>>     err:
>> diff --git a/drivers/gpu/drm/i915/intel_dsi_cabc.c 
>> b/drivers/gpu/drm/i915/intel_dsi_cabc.c
>> new file mode 100644
>> index 0000000..2a78326
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/intel_dsi_cabc.c
>> @@ -0,0 +1,349 @@
>> +/*
>> + * Copyright © 2006-2010 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person 
>> obtaining a
>> + * copy of this software and associated documentation files (the 
>> "Software"),
>> + * to deal in the Software without restriction, including without 
>> limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, 
>> sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom 
>> the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including 
>> the next
>> + * paragraph) shall be included in all copies or substantial 
>> portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO 
>> EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 
>> OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>> ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> + * DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/moduleparam.h>
>> +#include "intel_drv.h"
>> +#include "intel_dsi.h"
>> +#include "i915_drv.h"
>> +#include "intel_dsi_cabc.h"
>> +#include <video/mipi_display.h>
>> +#include <drm/drm_mipi_dsi.h>
>> +
>> +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;
> This will work only for MIPI Port A not for MIPI Port C. Use 
> for_each_dsi_port macro and intel_dsi->dsi_hosts[port] to correctly 
> reach to mipi_dsi_device for both ports. If it is dual link, break 
> after the completion of the first iteration.
>> +    panel->backlight.max = CABC_MAX_VALUE;
>> +    panel->backlight.level = CABC_MAX_VALUE;
>> +    level = CABC_MAX_VALUE;
>> +    panel->backlight.enabled = true;
>> +    return 0;
>> +}
>> +
>> +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;
>> +    struct intel_panel *panel = &connector->panel;
>> +    u8 data[2] = {0};
>> +    enum port port = PORT_A;
> will fail for single link MIPI Port C.
>> +    u32 ret;
>> +
>> +    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) {
> Put the below or required logic into static inline function returning 
> enum port .
>> +        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;
>> +    }
> Use for_each_dsi_port macro here . call the  inline function within 
> for_each_dsi_port macro to get the required enum port for dual link.
>> +
>> +    dsi_device = intel_dsi->dsi_hosts[port]->device;
>> +    mipi_dsi_dcs_read(dsi_device, MIPI_DCS_CABC_LEVEL_RD, data, 2);
>> +
>> +    ret = (data[1] * panel->backlight.max) / 255;
>> +    return ret;
>> +}
>> +
>> +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;
>> +    struct intel_panel *panel = &connector->panel;
>> +    u8 count = 1;
>> +    u32 hw_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);
>> +        }
>> +    }
>> +
>> +    if (intel_dsi->dual_link) {
> Put the below logic into static inline function returning enum port .
>> +        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;
>> +    }
>> +
> Below part not required. use for_each_dsi_port macro.
>> +    if (intel_dsi->dual_link && intel_dsi->dl_cabc_port ==
>> +            CABC_PORT_A_AND_C)
>> +        count = 2;
>> +
>> +
>> +    hw_level = level % (panel->backlight.max + 1);
>> +    hw_level = (hw_level * 255) / panel->backlight.max;
>> +    panel->backlight.level = hw_level;
>> +
> Use for_each_dsi_port macro as explained above.
>> +    do {
>> +        dsi_device = intel_dsi->dsi_hosts[port]->device;
>> +        data[1] = hw_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);
>> +}
>> +
>> +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;
> Will fail for single link Port C
>> +    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) {
> Same comment .Put the below logic into static inline function 
> returning enum port .
>> +        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;
> Also below condition need not be taken into the inline function. Since 
> it is dual link and with other conditions are met, then 
> CABC_PORT_A_AND_C will be automatically taken care for both ports by 
> the for_each_dsi_port macro.
> Within for_each_dsi_port, just check for intel_dsi->dl_cabc_port != 
> CABC_PORT_A_AND_C, if yes call the inline function to get the port no 
> and if no, all other conditions will be taken care for both ports by 
> for_each_dsi_port.
> Before the end of for_each_dsi_port ,you may require to check the 
> intel_dsi->dl_cabc_port != CABC_PORT_A_AND_C , so that you can return 
> from the macro.
>> +        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 {
> same comment as above. Use for_each_dsi_port
>> +        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);
>> +
>> +    cabc_set_backlight(connector, panel->backlight.level);
>> +}
>> +
>> +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;
> Will fail for single link Port C
>> +    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) {
> Same comment as above. Use static inline function for this.
>> +        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 {
> Use for_each_dsi_port macro
>> +        dsi_device = intel_dsi->dsi_hosts[port]->device;
>> +
>> +        cabc_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 int cabc_backlight_device_update_status(struct 
>> backlight_device *bd)
>> +{
>> +    struct intel_connector *connector = bl_get_data(bd);
>> +    struct intel_panel *panel = &connector->panel;
>> +    struct drm_device *dev = connector->base.dev;
>> +
>> +    drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>> +    DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
>> +            bd->props.brightness, bd->props.max_brightness);
>> +    cabc_set_backlight(connector, bd->props.brightness);
>> +
>> +    /*
>> +     * Allow flipping bl_power as a sub-state of enabled. Sadly the
>> +     * backlight class device does not make it easy to to differentiate
>> +     * between callbacks for brightness and bl_power, so our 
>> backlight_power
>> +     * callback needs to take this into account.
>> +     */
>> +    if (panel->backlight.enabled) {
>> +        if (panel->backlight_power) {
>> +            bool enable = bd->props.power == FB_BLANK_UNBLANK &&
>> +                bd->props.brightness != 0;
>> +            panel->backlight_power(connector, enable);
>> +        }
>> +    } else {
>> +        bd->props.power = FB_BLANK_POWERDOWN;
>> +    }
>> +
>> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
>> +    return 0;
>> +}
>> +
>> +static int cabc_backlight_device_get_brightness(struct 
>> backlight_device *bd)
>> +{
>> +    struct intel_connector *connector = bl_get_data(bd);
>> +    struct drm_device *dev = connector->base.dev;
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>> +    int ret;
>> +
>> +    intel_runtime_pm_get(dev_priv);
>> +    drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>> +
>> +    ret = cabc_get_backlight(connector);
>> +
>> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
>> +    intel_runtime_pm_put(dev_priv);
>> +
>> +    return ret;
>> +}
>> +
>> +static const struct backlight_ops cabc_backlight_device_ops = {
>> +    .update_status = cabc_backlight_device_update_status,
>> +    .get_brightness = cabc_backlight_device_get_brightness,
>> +};
>> +
>> +int cabc_backlight_device_register(struct intel_connector *connector)
>> +{
>> +    struct intel_panel *panel = &connector->panel;
>> +    struct backlight_properties props;
>> +
>> +    if (WARN_ON(panel->backlight.device))
>> +        return -ENODEV;
>> +
>> +    if (!panel->backlight.present)
>> +        return 0;
>> +
>> +    WARN_ON(panel->backlight.max == 0);
>> +
>> +    memset(&props, 0, sizeof(props));
>> +    props.type = BACKLIGHT_FIRMWARE;
>> +
>> +    /*
>> +     * Note: Everything should work even if the backlight device max
>> +     * presented to the userspace is arbitrarily chosen.
>> +     */
>> +    props.max_brightness = panel->backlight.max;
>> +    props.brightness = props.max_brightness;
>> +
>> +    if (panel->backlight.enabled)
>> +        props.power = FB_BLANK_UNBLANK;
>> +    else
>> +        props.power = FB_BLANK_POWERDOWN;
>> +
>> +    /*
>> +     * Note: using the same name independent of the connector prevents
>> +     * registration of multiple backlight devices in the driver.
>> +     */
>> +    panel->backlight.device =
>> +        backlight_device_register("intel_backlight",
>> +                connector->base.kdev,
>> +                connector,
>> +                &cabc_backlight_device_ops, &props);
>> +
>> +    if (IS_ERR(panel->backlight.device)) {
>> +        DRM_ERROR("Failed to register backlight: %ld\n",
>> +                PTR_ERR(panel->backlight.device));
>> +        panel->backlight.device = NULL;
>> +        return -ENODEV;
>> +    }
>> +
>> +    DRM_DEBUG_KMS("Connector %s backlight sysfs interface 
>> registered\n",
>> +            connector->base.name);
>> +
>> +    return 0;
>> +}
>> +
>> +void cabc_backlight_device_unregister(struct intel_connector 
>> *connector)
>> +{
>> +    struct intel_panel *panel = &connector->panel;
>> +
>> +    if (panel->backlight.device) {
>> + backlight_device_unregister(panel->backlight.device);
>> +        panel->backlight.device = NULL;
>> +    }
>> +}
>> diff --git a/drivers/gpu/drm/i915/intel_dsi_cabc.h 
>> b/drivers/gpu/drm/i915/intel_dsi_cabc.h
>> new file mode 100644
>> index 0000000..5d134f5
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/intel_dsi_cabc.h
>> @@ -0,0 +1,45 @@
>> +/*
>> + * Copyright © 2013 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person 
>> obtaining a
>> + * copy of this software and associated documentation files (the 
>> "Software"),
>> + * to deal in the Software without restriction, including without 
>> limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, 
>> sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom 
>> the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including 
>> the next
>> + * paragraph) shall be included in all copies or substantial 
>> portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO 
>> EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 
>> OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>> ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> + * DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +
>> +extern int cabc_backlight_device_register(struct intel_connector 
>> *connector);
>> +extern void cabc_backlight_device_unregister(struct intel_connector 
>> *connector);
>> +void cabc_set_backlight(struct intel_connector *connector, u32 level);
>> +u32 cabc_get_backlight(struct intel_connector *connector);
>> +void cabc_enable_backlight(struct intel_connector *connector);
>> +void cabc_disable_backlight(struct intel_connector *connector);
>> +int cabc_setup_backlight(struct intel_connector *connector, enum 
>> pipe unused);
>> +
>> +#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
>> +#define CABC_MAX_VALUE               0xff
>> diff --git a/drivers/gpu/drm/i915/intel_panel.c 
>> b/drivers/gpu/drm/i915/intel_panel.c
>> index 55aad23..c73449b 100644
>> --- a/drivers/gpu/drm/i915/intel_panel.c
>> +++ b/drivers/gpu/drm/i915/intel_panel.c
>> @@ -1502,15 +1502,29 @@ void intel_panel_fini(struct intel_panel *panel)
>>   void intel_backlight_register(struct drm_device *dev)
>>   {
>>       struct intel_connector *connector;
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>   -    list_for_each_entry(connector, 
>> &dev->mode_config.connector_list, base.head)
>> -        intel_backlight_device_register(connector);
>> +    list_for_each_entry(connector, &dev->mode_config.connector_list,
>> +                    base.head) {
>> +        if (connector->encoder->type == INTEL_OUTPUT_DSI &&
>> +            dev_priv->vbt.dsi.config->cabc_supported)
>> +            cabc_backlight_device_register(connector);
>> +        else
>> +            intel_backlight_device_register(connector);
>> +    }
>>   }
>>     void intel_backlight_unregister(struct drm_device *dev)
>>   {
>>       struct intel_connector *connector;
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>   -    list_for_each_entry(connector, 
>> &dev->mode_config.connector_list, base.head)
>> -        intel_backlight_device_unregister(connector);
>> +    list_for_each_entry(connector, &dev->mode_config.connector_list,
>> +                    base.head) {
>> +        if (connector->encoder->type == INTEL_OUTPUT_DSI &&
>> +            dev_priv->vbt.dsi.config->cabc_supported)
>> +            cabc_backlight_device_unregister(connector);
>> +        else
>> +            intel_backlight_device_unregister(connector);
>> +    }
>>   }
>> 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,
Please add them in increment order. Also, in HLD it is mentioned that 
offset for MIPI_DCS_CABC_LEVEL_RD is 0x51. Correct either of them 
accordingly.
>> +    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 */
>

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2015-08-05  7:50 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-06  4:16 [CABC PATCH v1 0/3][RFC] CABC patch list Deepak M
2015-07-06  4:16 ` [CABC PATCH v1 1/3][RFC] drm/i915: Store the CABC enabled field parsed from VBT to dev_priv structure Deepak M
2015-07-06  4:16 ` [CABC PATCH v1 2/3][RFC] drm/i915: Parsing the PWM cntrl and CABC ON/OFF fileds in VBT Deepak M
2015-07-06  4:16 ` [CABC PATCH v1 3/3][RFC] drm/i915: CABC support for backlight control Deepak M
2015-07-06 12:51   ` Daniel Vetter
2015-07-24 12:24     ` [RFC CABC PATCH v2 3/3] " Deepak M
2015-07-30 10:48       ` Singh, Gaurav K
2015-08-05  7:50         ` Singh, Gaurav K

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).