All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP
@ 2013-06-12 20:55 Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 02/13] drm/i915: Read the EDP DPCD and PSR Capability Rodrigo Vivi
                   ` (12 more replies)
  0 siblings, 13 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx; +Cc: Sateesh Kavuri, Paulo Zanoni

From: Shobhit Kumar <shobhit.kumar@intel.com>

v2: Modified and corrected the structures to be more in line for
kernel coding guidelines and rebased the code on Paulo's DP patchset
v3: removing unecessary identation at DP_RECEIVER_CAP_SIZE
v4: moving them to include/drm/drm_dp_helper.h and also already
    icluding EDP_PSR_RECEIVER_CAP_SIZE to add everything needed
    for PSR at once at drm_dp_helper.h
v5: Fix SDP VSC header and identation by (Paulo Zanoni) and
    remove i915 from title (Daniel Vetter)

CC: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Sateesh Kavuri <sateesh.kavuri@intel.com>
Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 include/drm/drm_dp_helper.h | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index e8e1417..4062c9e 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -342,13 +342,44 @@ u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
 u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
 					  int lane);
 
-#define DP_RECEIVER_CAP_SIZE	0xf
+#define DP_RECEIVER_CAP_SIZE		0xf
+#define EDP_PSR_RECEIVER_CAP_SIZE	2
+
 void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 
 u8 drm_dp_link_rate_to_bw_code(int link_rate);
 int drm_dp_bw_code_to_link_rate(u8 link_bw);
 
+/* SDP header as per eDP 1.3 spec, section 3.6 */
+struct edp_sdp_header {
+	u8 HB0; /* Secondary Data Packet ID */
+	u8 HB1; /* Secondary Data Packet Type */
+	u8 HB2; /* 7:5 reserved, 4:0 revision number */
+	u8 HB3; /* 7:5 reserved, 4:0 number of valid data bytes */
+} __packed;
+
+#define EDP_SDP_HEADER_REVISION_MASK		0x1F
+#define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES	0x1F
+
+/* SDP VSC header as per eDP 1.3 spec, section 3.6 */
+struct edp_vsc_psr {
+	struct edp_sdp_header sdp_header;
+	u8 DB0; /* Stereo Interface */
+	u8 DB1; /* 0 - PSR State; 1 - Update RFB; 2 - CRC Valid */
+	u8 DB2; /* CRC value bits 7:0 of the R or Cr component */
+	u8 DB3; /* CRC value bits 15:8 of the R or Cr component */
+	u8 DB4; /* CRC value bits 7:0 of the G or Y component */
+	u8 DB5; /* CRC value bits 15:8 of the G or Y component */
+	u8 DB6; /* CRC value bits 7:0 of the B or Cb component */
+	u8 DB7; /* CRC value bits 15:8 of the B or Cb component */
+	u8 DB8_31[24]; /* Reserved */
+} __packed;
+
+#define EDP_VSC_PSR_STATE_ACTIVE	(1<<0)
+#define EDP_VSC_PSR_UPDATE_RFB		(1<<1)
+#define EDP_VSC_PSR_CRC_VALUES_VALID	(1<<2)
+
 static inline int
 drm_dp_max_link_rate(u8 dpcd[DP_RECEIVER_CAP_SIZE])
 {
-- 
1.7.11.7

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

* [PATCH 02/13] drm/i915: Read the EDP DPCD and PSR Capability
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-14 16:42   ` Paulo Zanoni
  2013-06-12 20:55 ` [PATCH 03/13] drm/i915: VBT Parsing for the PSR Feature Block for HSW Rodrigo Vivi
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

From: Shobhit Kumar <shobhit.kumar@intel.com>

v2: reuse of just created is_edp_psr and put it at right place.
v3: move is_edp_psr above intel_edp_disable

Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c  | 13 +++++++++++++
 drivers/gpu/drm/i915/intel_drv.h |  1 +
 2 files changed, 14 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 759a1c5..5332186 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1342,6 +1342,12 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
 	pipe_config->adjusted_mode.flags |= flags;
 }
 
+static bool is_edp_psr(struct intel_dp *intel_dp)
+{
+	return (is_edp(intel_dp) &&
+		(intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED));
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -2255,6 +2261,13 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
 	if (intel_dp->dpcd[DP_DPCD_REV] == 0)
 		return false; /* DPCD not present */
 
+	/* Check if the panel supports PSR */
+	memset(intel_dp->psr_dpcd, 0, sizeof(intel_dp->psr_dpcd));
+	intel_dp_aux_native_read_retry(intel_dp, DP_PSR_SUPPORT,
+				       intel_dp->psr_dpcd,
+				       sizeof(intel_dp->psr_dpcd));
+	if (is_edp_psr(intel_dp))
+		DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
 	if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
 	      DP_DWN_STRM_PORT_PRESENT))
 		return true; /* native DP sink */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0445d8c..18d9dea 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -470,6 +470,7 @@ struct intel_dp {
 	uint8_t link_bw;
 	uint8_t lane_count;
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
+	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
 	struct i2c_adapter adapter;
 	struct i2c_algo_dp_aux_data algo;
-- 
1.7.11.7

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

* [PATCH 03/13] drm/i915: VBT Parsing for the PSR Feature Block for HSW
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 02/13] drm/i915: Read the EDP DPCD and PSR Capability Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-13 13:41   ` Chris Wilson
  2013-06-14 17:02   ` Paulo Zanoni
  2013-06-12 20:55 ` [PATCH 04/13] drm/i915: split aux_clock_divider logic in a separated function for reuse Rodrigo Vivi
                   ` (10 subsequent siblings)
  12 siblings, 2 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

From: Shobhit Kumar <shobhit.kumar@intel.com>

Parse and store useful information in i915_dev_private

v2: Add to new vbt struct and call them psr_*
v3: Fix comment and variable name

Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_drv.h   |  7 +++++++
 drivers/gpu/drm/i915/intel_bios.c | 30 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_bios.h | 20 +++++++++++++++++++-
 3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 87f7f88..dd459a5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -951,6 +951,13 @@ struct intel_vbt_data {
 	int edp_bpp;
 	struct edp_power_seq edp_pps;
 
+	/* eDP PSR*/
+	u8 psr_full_link_state;
+	u8 psr_wait_lines;
+	u8 psr_idle_frames;
+	u16 psr_wakeup_tp1;
+	u16 psr_wakeup_tp2_tp3;
+
 	int crt_ddc_pin;
 
 	int child_dev_num;
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 53f2bed..99c6788 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -383,6 +383,35 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
 	}
 }
 
+
+static void
+parse_edp_psr(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+	struct bdb_psr_features *psr;
+	struct bdb_lvds_options *lvds_opts;
+	int index = 0;
+	lvds_opts = find_section(bdb, BDB_LVDS_OPTIONS);
+	if (!lvds_opts) {
+		DRM_DEBUG_KMS("No LVDS Options block found.\n");
+		return;
+	}
+
+	index = lvds_opts->panel_type;
+
+	psr = find_section(bdb, BDB_PSR_FEATURES);
+	if (!psr) {
+		DRM_DEBUG_KMS("No PSR feature block found.\n");
+		return;
+	}
+
+	dev_priv->vbt.psr_full_link_state = psr[index].link_disable;
+	dev_priv->vbt.psr_wait_lines = psr[index].wait_lines;
+	dev_priv->vbt.psr_idle_frames = psr[index].idle_frames;
+	dev_priv->vbt.psr_wakeup_tp1 = psr[index].wakeup_tp1;
+	dev_priv->vbt.psr_wakeup_tp2_tp3 = psr[index].wakeup_tp2_tp3;
+}
+
+
 static void
 parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
 			  struct bdb_header *bdb)
@@ -745,6 +774,7 @@ intel_parse_bios(struct drm_device *dev)
 	parse_device_mapping(dev_priv, bdb);
 	parse_driver_features(dev_priv, bdb);
 	parse_edp(dev_priv, bdb);
+	parse_edp_psr(dev_priv, bdb);
 
 	if (bios)
 		pci_unmap_rom(pdev, bios);
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index e088d6f..c883b87 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -80,7 +80,7 @@ struct vbios_data {
 #define BDB_EXT_MMIO_REGS	  6
 #define BDB_SWF_IO		  7
 #define BDB_SWF_MMIO		  8
-#define BDB_DOT_CLOCK_TABLE	  9
+#define BDB_PSR_FEATURES	  9
 #define BDB_MODE_REMOVAL_TABLE	 10
 #define BDB_CHILD_DEVICE_TABLE	 11
 #define BDB_DRIVER_FEATURES	 12
@@ -265,6 +265,24 @@ struct bdb_lvds_options {
 	u8 rsvd4;
 } __attribute__((packed));
 
+struct bdb_psr_features {
+	/* Feature bits */
+	u8 link_disable:1;
+	u8 require_aux:1;
+	u8 rsvd1:6;
+
+	/* Wait times */
+	u8 idle_frames:4;
+	u8 wait_lines:3;
+	u8 rsvd2:1;
+
+	/* TP1 wakeup time */
+	u16 wakeup_tp1;
+
+	/* TP2 TP3 wakeup time */
+	u16 wakeup_tp2_tp3;
+} __attribute__((packed));
+
 /* LFP pointer table contains entries to the struct below */
 struct bdb_lvds_lfp_data_ptr {
 	u16 fp_timing_offset; /* offsets are from start of bdb */
-- 
1.7.11.7

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

* [PATCH 04/13] drm/i915: split aux_clock_divider logic in a separated function for reuse.
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 02/13] drm/i915: Read the EDP DPCD and PSR Capability Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 03/13] drm/i915: VBT Parsing for the PSR Feature Block for HSW Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-14 17:18   ` Paulo Zanoni
  2013-06-12 20:55 ` [PATCH 05/13] drm/i915: Enable/Disable PSR Rodrigo Vivi
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

Prep patch for reuse aux_clock_divider with EDP_PSR_AUX_CTL setup.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/intel_dp.c | 58 +++++++++++++++++++++++------------------
 1 file changed, 33 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 5332186..02b2865 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -271,29 +271,12 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
 	return status;
 }
 
-static int
-intel_dp_aux_ch(struct intel_dp *intel_dp,
-		uint8_t *send, int send_bytes,
-		uint8_t *recv, int recv_size)
+static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
-	uint32_t ch_data = ch_ctl + 4;
-	int i, ret, recv_bytes;
-	uint32_t status;
-	uint32_t aux_clock_divider;
-	int try, precharge;
-	bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
 
-	/* dp aux is extremely sensitive to irq latency, hence request the
-	 * lowest possible wakeup latency and so prevent the cpu from going into
-	 * deep sleep states.
-	 */
-	pm_qos_update_request(&dev_priv->pm_qos, 0);
-
-	intel_dp_check_edp(intel_dp);
 	/* The clock divider is based off the hrawclk,
 	 * and would like to run at 2MHz. So, take the
 	 * hrawclk value and divide by 2 and use that
@@ -302,23 +285,48 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 	 * clock divider.
 	 */
 	if (IS_VALLEYVIEW(dev)) {
-		aux_clock_divider = 100;
+		return 100;
 	} else if (intel_dig_port->port == PORT_A) {
 		if (HAS_DDI(dev))
-			aux_clock_divider = DIV_ROUND_CLOSEST(
+			return DIV_ROUND_CLOSEST(
 				intel_ddi_get_cdclk_freq(dev_priv), 2000);
 		else if (IS_GEN6(dev) || IS_GEN7(dev))
-			aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
+			return 200; /* SNB & IVB eDP input clock at 400Mhz */
 		else
-			aux_clock_divider = 225; /* eDP input clock at 450Mhz */
+			return 225; /* eDP input clock at 450Mhz */
 	} else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
 		/* Workaround for non-ULT HSW */
-		aux_clock_divider = 74;
+		return 74;
 	} else if (HAS_PCH_SPLIT(dev)) {
-		aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
+		return DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
 	} else {
-		aux_clock_divider = intel_hrawclk(dev) / 2;
+		return intel_hrawclk(dev) / 2;
 	}
+}
+
+static int
+intel_dp_aux_ch(struct intel_dp *intel_dp,
+		uint8_t *send, int send_bytes,
+		uint8_t *recv, int recv_size)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
+	uint32_t ch_data = ch_ctl + 4;
+	int i, ret, recv_bytes;
+	uint32_t status;
+	uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp);
+	int try, precharge;
+	bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
+
+	/* dp aux is extremely sensitive to irq latency, hence request the
+	 * lowest possible wakeup latency and so prevent the cpu from going into
+	 * deep sleep states.
+	 */
+	pm_qos_update_request(&dev_priv->pm_qos, 0);
+
+	intel_dp_check_edp(intel_dp);
 
 	if (IS_GEN6(dev))
 		precharge = 3;
-- 
1.7.11.7

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

* [PATCH 05/13] drm/i915: Enable/Disable PSR
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (2 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 04/13] drm/i915: split aux_clock_divider logic in a separated function for reuse Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 06/13] drm/i915: Added debugfs support for PSR Status Rodrigo Vivi
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

Adding Enable and Disable PSR functionalities. This includes setting the
PSR configuration over AUX, sending SDP VSC DIP over the eDP PIPE config,
enabling PSR in the sink via DPCD register and finally enabling PSR on
the host.

This patch is heavily based on initial PSR code by Sateesh Kavuri and
Kumar Shobhit but in a different implementation.

v2: * moved functions around and changed its names.
    * removed VSC DIP unset from disable.
    * remove FBC wa.
    * don't mask LSPS anymore.
    * incorporate new crtc usage after a rebase.

Credits-by: Sateesh Kavuri <sateesh.kavuri@intel.com>
Credits-by: Shobhit Kumar <shobhit.kumar@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_reg.h  |  42 ++++++++++
 drivers/gpu/drm/i915/intel_dp.c  | 172 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h |   3 +
 3 files changed, 217 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index b1fdca9..4df97b4 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1775,6 +1775,47 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* HSW eDP PSR registers */
+#define EDP_PSR_CTL				0x64800
+#define   EDP_PSR_ENABLE			(1<<31)
+#define   EDP_PSR_LINK_DISABLE			(0<<27)
+#define   EDP_PSR_LINK_STANDBY			(1<<27)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_MASK	(3<<25)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES	(0<<25)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_4_LINES	(1<<25)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_2_LINES	(2<<25)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES	(3<<25)
+#define   EDP_PSR_MAX_SLEEP_TIME_SHIFT		20
+#define   EDP_PSR_SKIP_AUX_EXIT			(1<<12)
+#define   EDP_PSR_TP1_TP2_SEL			(0<<11)
+#define   EDP_PSR_TP1_TP3_SEL			(1<<11)
+#define   EDP_PSR_TP2_TP3_TIME_500us		(0<<8)
+#define   EDP_PSR_TP2_TP3_TIME_100us		(1<<8)
+#define   EDP_PSR_TP2_TP3_TIME_2500us		(2<<8)
+#define   EDP_PSR_TP2_TP3_TIME_0us		(3<<8)
+#define   EDP_PSR_TP1_TIME_500us		(0<<4)
+#define   EDP_PSR_TP1_TIME_100us		(1<<4)
+#define   EDP_PSR_TP1_TIME_2500us		(2<<4)
+#define   EDP_PSR_TP1_TIME_0us			(3<<4)
+#define   EDP_PSR_IDLE_FRAME_SHIFT		0
+
+#define EDP_PSR_AUX_CTL			0x64810
+#define EDP_PSR_AUX_DATA1		0x64814
+#define   EDP_PSR_DPCD_COMMAND		0x80060000
+#define EDP_PSR_AUX_DATA2		0x64818
+#define   EDP_PSR_DPCD_NORMAL_OPERATION	(1<<24)
+#define EDP_PSR_AUX_DATA3		0x6481c
+#define EDP_PSR_AUX_DATA4		0x64820
+#define EDP_PSR_AUX_DATA5		0x64824
+
+#define EDP_PSR_STATUS_CTL			0x64840
+#define   EDP_PSR_STATUS_STATE_MASK		(7<<29)
+
+#define EDP_PSR_DEBUG_CTL		0x64860
+#define   EDP_PSR_DEBUG_MASK_LPSP	(1<<27)
+#define   EDP_PSR_DEBUG_MASK_MEMUP	(1<<26)
+#define   EDP_PSR_DEBUG_MASK_HPD	(1<<25)
+
 /* VGA port control */
 #define ADPA			0x61100
 #define PCH_ADPA                0xe1100
@@ -2045,6 +2086,7 @@
  * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
  * of the infoframe structure specified by CEA-861. */
 #define   VIDEO_DIP_DATA_SIZE	32
+#define   VIDEO_DIP_VSC_DATA_SIZE	36
 #define VIDEO_DIP_CTL		0x61170
 /* Pre HSW: */
 #define   VIDEO_DIP_ENABLE		(1 << 31)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 02b2865..e9c18bd 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1356,6 +1356,178 @@ static bool is_edp_psr(struct intel_dp *intel_dp)
 		(intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED));
 }
 
+static bool intel_edp_is_psr_enabled(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
+}
+
+static void intel_edp_psr_enable_src(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t max_sleep_time = 0x1f;
+	uint32_t val = 0x0;
+
+	if (dev_priv->vbt.psr_idle_frames)
+	    val |= dev_priv->vbt.psr_idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+	else
+	    val |= 1 << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) {
+		val |= EDP_PSR_LINK_STANDBY;
+		val |= EDP_PSR_TP2_TP3_TIME_0us;
+		val |= EDP_PSR_TP1_TIME_0us;
+		val |= EDP_PSR_SKIP_AUX_EXIT;
+	} else {
+		val |= EDP_PSR_LINK_DISABLE;
+		/* Use these Values from VBT
+		 * Case values are timings for HSW as of now
+		 * in multiple of 100us
+		 */
+		switch(dev_priv->vbt.psr_wakeup_tp1) {
+			case 1:
+				val |= EDP_PSR_TP1_TIME_100us;
+				break;
+			case 5:
+				val |= EDP_PSR_TP1_TIME_500us;
+				break;
+			case 25:
+				val |= EDP_PSR_TP1_TIME_2500us;
+				break;
+			default:
+				val |= EDP_PSR_TP1_TIME_500us;
+				break;
+		};
+		switch(dev_priv->vbt.psr_wakeup_tp2_tp3) {
+			case 1:
+				val |= EDP_PSR_TP2_TP3_TIME_100us;
+				break;
+			case 5:
+				val |= EDP_PSR_TP2_TP3_TIME_500us;
+				break;
+			case 25:
+				val |= EDP_PSR_TP2_TP3_TIME_2500us;
+				break;
+			default:
+				val |= EDP_PSR_TP2_TP3_TIME_500us;
+				break;
+		};
+	}
+
+	I915_WRITE(EDP_PSR_CTL, val |
+		   EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES |
+		   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
+		   EDP_PSR_ENABLE);
+}
+
+void intel_edp_psr_write_vsc(struct intel_dp* intel_dp,
+			     struct edp_vsc_psr *vsc_psr)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
+
+	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
+	u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
+	uint32_t *data = (uint32_t *) vsc_psr;
+	unsigned int i;
+	u32 val = I915_READ(ctl_reg);
+
+	/* As per eDP spec, wait for vblank to send SDP VSC packet */
+	intel_wait_for_vblank(dev, crtc->pipe);
+
+	/* As per BSPec (Pipe Video Data Island Packet), besides wait for
+	   vsync we need to disable the video DIP being updated before program
+	   video DIP data buffer registers for DIP being updated.*/
+	I915_WRITE(ctl_reg, val & ~VIDEO_DIP_ENABLE_VSC_HSW);
+	POSTING_READ(ctl_reg);
+
+	for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
+                if (i < sizeof(struct edp_vsc_psr))
+                        I915_WRITE(data_reg + i, *data++);
+                else
+                        I915_WRITE(data_reg + i, 0);
+        }
+
+	I915_WRITE(ctl_reg, val | VIDEO_DIP_ENABLE_VSC_HSW);
+	POSTING_READ(ctl_reg);
+}
+
+void intel_edp_psr_enable(struct intel_dp* intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct edp_vsc_psr psr_vsc;
+	uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp);
+	int precharge = 0x3;
+	int msg_size = 5;       /* Header(4) + Message(1) */
+
+	if (!is_edp_psr(intel_dp) || intel_edp_is_psr_enabled(dev))
+		return;
+
+	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+	memset(&psr_vsc, 0, sizeof(psr_vsc));
+	psr_vsc.sdp_header.HB0 = 0;
+	psr_vsc.sdp_header.HB1 = 0x7;
+	psr_vsc.sdp_header.HB2 = 0x2;
+	psr_vsc.sdp_header.HB3 = 0x8;
+	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+
+	/* Enable PSR in sink */
+	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
+		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+					    DP_PSR_ENABLE &
+					    ~DP_PSR_MAIN_LINK_ACTIVE);
+	else
+		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+					    DP_PSR_ENABLE |
+					    DP_PSR_MAIN_LINK_ACTIVE);
+
+	/* Setup AUX registers */
+	I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND);
+	I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION);
+	I915_WRITE(EDP_PSR_AUX_CTL,
+		   DP_AUX_CH_CTL_TIME_OUT_400us |
+		   (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+		   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
+
+	/* Avoid continuous PSR exit by masking memup and hpd */
+	I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
+		   EDP_PSR_DEBUG_MASK_HPD);
+
+	/* Disable unused interrupts */
+	I915_WRITE(GEN6_PMINTRMSK, GEN6_PM_RP_UP_EI_EXPIRED |
+		   GEN6_PM_RP_DOWN_EI_EXPIRED);
+
+	/* Enable PSR on the host */
+	intel_edp_psr_enable_src(intel_dp);
+}
+
+void intel_edp_psr_disable(struct intel_dp* intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
+	uint32_t val;
+
+	if (!intel_edp_is_psr_enabled(dev))
+		return;
+
+	val = I915_READ(EDP_PSR_CTL);
+	I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
+
+	/* Wait till PSR is idle */
+	if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) &
+		       EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
+		DRM_ERROR("Timed out waiting for PSR Idle State\n");
+
+	intel_wait_for_vblank(dev, intel_crtc->pipe);
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 18d9dea..5113572 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -809,4 +809,7 @@ extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
 						 enum transcoder pch_transcoder,
 						 bool enable);
 
+extern void intel_edp_psr_enable(struct intel_dp* intel_dp);
+extern void intel_edp_psr_disable(struct intel_dp* intel_dp);
+
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.11.7

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

* [PATCH 06/13] drm/i915: Added debugfs support for PSR Status
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (3 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 05/13] drm/i915: Enable/Disable PSR Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 07/13] drm/i915: Match all PSR mode entry conditions before enabling it Rodrigo Vivi
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

Adding support for PSR Status, PSR entry counter and performance counters.
Heavily based on initial work from Shobhit.

v2: Fix PSR Status Link bits by Paulo Zanoni.

CC: Paulo Zanoni <paulo.r.zanoni@intel.com>
Credits-by: Shobhit Kumar <shobhit.kumar@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c | 90 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_reg.h     | 24 ++++++++++
 2 files changed, 114 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index d4e78b6..19192af 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1875,6 +1875,95 @@ static int i915_dpio_info(struct seq_file *m, void *data)
 	return 0;
 }
 
+static int i915_edp_psr_status(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 psrctl, psrstat, psrperf;
+
+	psrctl = I915_READ(EDP_PSR_CTL);
+	seq_printf(m, "PSR Enabled: %s\n",
+		   yesno(psrctl & EDP_PSR_ENABLE));
+
+	psrstat = I915_READ(EDP_PSR_STATUS_CTL);
+
+	seq_printf(m, "PSR Current State: ");
+	switch (psrstat & EDP_PSR_STATUS_STATE_MASK) {
+	case EDP_PSR_STATUS_STATE_IDLE:
+		seq_printf(m, "Reset state\n");
+		break;
+	case EDP_PSR_STATUS_STATE_SRDONACK:
+		seq_printf(m, "Wait for TG/Stream to send on frame of data after SRD conditions are met\n");
+		break;
+	case EDP_PSR_STATUS_STATE_SRDENT:
+		seq_printf(m, "SRD entry\n");
+		break;
+	case EDP_PSR_STATUS_STATE_BUFOFF:
+		seq_printf(m, "Wait for buffer turn off\n");
+		break;
+	case EDP_PSR_STATUS_STATE_BUFON:
+			seq_printf(m, "Wait for buffer turn on\n");
+		break;
+	case EDP_PSR_STATUS_STATE_AUXACK:
+			seq_printf(m, "Wait for AUX to acknowledge on SRD exit\n");
+		break;
+	case EDP_PSR_STATUS_STATE_SRDOFFACK:
+			seq_printf(m, "Wait for TG/Stream to acknowledge the SRD VDM exit\n");
+		break;
+	default:
+		seq_printf(m, "Unknown\n");
+		break;
+	}
+
+	seq_printf(m, "Link Status: ");
+	switch (psrstat & EDP_PSR_STATUS_LINK_MASK) {
+	case EDP_PSR_STATUS_LINK_FULL_OFF:
+		seq_printf(m, "Link is fully off\n");
+		break;
+	case EDP_PSR_STATUS_LINK_FULL_ON:
+		seq_printf(m, "Link is fully on\n");
+		break;
+	case EDP_PSR_STATUS_LINK_STANDBY:
+		seq_printf(m, "Link is in standby\n");
+		break;
+	default:
+		seq_printf(m, "Unknown\n");
+		break;
+	}
+
+	seq_printf(m, "PSR Entry Count: %u\n",
+		   psrstat >> EDP_PSR_STATUS_COUNT_SHIFT &
+		   EDP_PSR_STATUS_COUNT_MASK);
+
+	seq_printf(m, "Max Sleep Timer Counter: %u\n",
+		   psrstat >> EDP_PSR_STATUS_MAX_SLEEP_TIMER_SHIFT &
+		   EDP_PSR_STATUS_MAX_SLEEP_TIMER_MASK);
+
+	seq_printf(m, "Had AUX error: %s\n",
+		   yesno(psrstat & EDP_PSR_STATUS_AUX_ERROR));
+
+	seq_printf(m, "Sending AUX: %s\n",
+		   yesno(psrstat & EDP_PSR_STATUS_AUX_SENDING));
+
+	seq_printf(m, "Sending Idle: %s\n",
+		   yesno(psrstat & EDP_PSR_STATUS_SENDING_IDLE));
+
+	seq_printf(m, "Sending TP2 TP3: %s\n",
+		   yesno(psrstat & EDP_PSR_STATUS_SENDING_TP2_TP3));
+
+	seq_printf(m, "Sending TP1: %s\n",
+		   yesno(psrstat & EDP_PSR_STATUS_SENDING_TP1));
+
+	seq_printf(m, "Idle Count: %u\n",
+		   psrstat & EDP_PSR_STATUS_IDLE_MASK);
+
+	psrperf = (I915_READ(EDP_PSR_PERF_CNT)) & EDP_PSR_PERF_CNT_MASK;
+	seq_printf(m, "Performance Counter: %u\n", psrperf);
+
+	return 0;
+}
+
 static int
 i915_wedged_get(void *data, u64 *val)
 {
@@ -2304,6 +2393,7 @@ static struct drm_info_list i915_debugfs_list[] = {
 	{"i915_swizzle_info", i915_swizzle_info, 0},
 	{"i915_ppgtt_info", i915_ppgtt_info, 0},
 	{"i915_dpio", i915_dpio_info, 0},
+	{"i915_edp_psr_status", i915_edp_psr_status, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 4df97b4..16ab839 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1810,6 +1810,30 @@
 
 #define EDP_PSR_STATUS_CTL			0x64840
 #define   EDP_PSR_STATUS_STATE_MASK		(7<<29)
+#define   EDP_PSR_STATUS_STATE_IDLE		(0<<29)
+#define   EDP_PSR_STATUS_STATE_SRDONACK		(1<<29)
+#define   EDP_PSR_STATUS_STATE_SRDENT		(2<<29)
+#define   EDP_PSR_STATUS_STATE_BUFOFF		(3<<29)
+#define   EDP_PSR_STATUS_STATE_BUFON		(4<<29)
+#define   EDP_PSR_STATUS_STATE_AUXACK		(5<<29)
+#define   EDP_PSR_STATUS_STATE_SRDOFFACK	(6<<29)
+#define   EDP_PSR_STATUS_LINK_MASK		(3<<26)
+#define   EDP_PSR_STATUS_LINK_FULL_OFF		(0<<26)
+#define   EDP_PSR_STATUS_LINK_FULL_ON		(1<<26)
+#define   EDP_PSR_STATUS_LINK_STANDBY		(2<<26)
+#define   EDP_PSR_STATUS_MAX_SLEEP_TIMER_SHIFT 	20
+#define   EDP_PSR_STATUS_MAX_SLEEP_TIMER_MASK 	0x1f
+#define   EDP_PSR_STATUS_COUNT_SHIFT		16
+#define   EDP_PSR_STATUS_COUNT_MASK		0xf
+#define   EDP_PSR_STATUS_AUX_ERROR		(1<<15)
+#define   EDP_PSR_STATUS_AUX_SENDING		(1<<12)
+#define   EDP_PSR_STATUS_SENDING_IDLE		(1<<9)
+#define   EDP_PSR_STATUS_SENDING_TP2_TP3	(1<<8)
+#define   EDP_PSR_STATUS_SENDING_TP1		(1<<4)
+#define   EDP_PSR_STATUS_IDLE_MASK		0xf
+
+#define EDP_PSR_PERF_CNT		0x64844
+#define   EDP_PSR_PERF_CNT_MASK		0xffffff
 
 #define EDP_PSR_DEBUG_CTL		0x64860
 #define   EDP_PSR_DEBUG_MASK_LPSP	(1<<27)
-- 
1.7.11.7

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

* [PATCH 07/13] drm/i915: Match all PSR mode entry conditions before enabling it.
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (4 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 06/13] drm/i915: Added debugfs support for PSR Status Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 08/13] drm/i915: Hook PSR functionality Rodrigo Vivi
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c | 39 ++++++++++++++++++---
 drivers/gpu/drm/i915/i915_drv.h     | 12 +++++++
 drivers/gpu/drm/i915/intel_dp.c     | 68 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 114 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 19192af..f4e9147 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1880,11 +1880,42 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_info_node *node = m->private;
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 psrctl, psrstat, psrperf;
+	u32 psrstat, psrperf;
 
-	psrctl = I915_READ(EDP_PSR_CTL);
-	seq_printf(m, "PSR Enabled: %s\n",
-		   yesno(psrctl & EDP_PSR_ENABLE));
+	if (I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE) {
+		seq_printf(m, "PSR enabled\n");
+	} else {
+		seq_printf(m, "PSR disabled: ");
+		switch (dev_priv->no_psr_reason) {
+		case PSR_NO_SOURCE:
+			seq_printf(m, "not supported on this platform");
+			break;
+		case PSR_NO_SINK:
+			seq_printf(m, "not supported by panel");
+			break;
+		case PSR_CRTC_NOT_ACTIVE:
+			seq_printf(m, "crtc not active");
+			break;
+		case PSR_PWR_WELL_ENABLED:
+			seq_printf(m, "power well enabled");
+			break;
+		case PSR_NOT_TILED:
+			seq_printf(m, "not tiled");
+			break;
+		case PSR_SPRITE_ENABLED:
+			seq_printf(m, "sprite enabled");
+			break;
+		case PSR_INTERLACED_ENABLED:
+			seq_printf(m, "interlaced enabled");
+			break;
+		case PSR_HSW_NOT_DDIA:
+			seq_printf(m, "HSW ties PSR to DDI A (eDP)");
+			break;
+		default:
+			seq_printf(m, "unknown reason");
+		}
+		seq_printf(m, "\n");
+	}
 
 	psrstat = I915_READ(EDP_PSR_STATUS_CTL);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index dd459a5..cbe842b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -509,6 +509,17 @@ enum no_fbc_reason {
 	FBC_MODULE_PARAM,
 };
 
+enum no_psr_reason {
+	PSR_NO_SOURCE, /* Not supported on platform */
+	PSR_NO_SINK, /* Not supported by panel */
+	PSR_CRTC_NOT_ACTIVE,
+	PSR_PWR_WELL_ENABLED,
+	PSR_NOT_TILED,
+	PSR_SPRITE_ENABLED,
+	PSR_INTERLACED_ENABLED,
+	PSR_HSW_NOT_DDIA,
+};
+
 enum intel_pch {
 	PCH_NONE = 0,	/* No PCH present */
 	PCH_IBX,	/* Ibexpeak PCH */
@@ -1119,6 +1130,7 @@ typedef struct drm_i915_private {
 	struct i915_power_well power_well;
 
 	enum no_fbc_reason no_fbc_reason;
+	enum no_psr_reason no_psr_reason;
 
 	struct drm_mm_node *compressed_fb;
 	struct drm_mm_node *compressed_llb;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e9c18bd..c105236 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1455,6 +1455,71 @@ void intel_edp_psr_write_vsc(struct intel_dp* intel_dp,
 	POSTING_READ(ctl_reg);
 }
 
+static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_crtc *crtc = dig_port->base.base.crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj;
+	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
+
+	if (!IS_HASWELL(dev)) {
+		DRM_DEBUG_KMS("PSR not supported on this platform\n");
+		dev_priv->no_psr_reason = PSR_NO_SOURCE;
+		return false;
+	}
+
+	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+	    (enc_to_dig_port(&intel_encoder->base)->port != PORT_A)) {
+		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
+		dev_priv->no_psr_reason = PSR_HSW_NOT_DDIA;
+		return false;
+	}
+
+	if (!is_edp_psr(intel_dp)) {
+		DRM_DEBUG_KMS("PSR not supported by this panel\n");
+		dev_priv->no_psr_reason = PSR_NO_SINK;
+		return false;
+	}
+
+	if (!intel_crtc->active || !crtc->fb || !crtc->mode.clock) {
+		DRM_DEBUG_KMS("crtc not active for PSR\n");
+		dev_priv->no_psr_reason = PSR_CRTC_NOT_ACTIVE;
+		return false;
+	}
+
+	if ((I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE) |
+	    (I915_READ(HSW_PWR_WELL_KVMR) & HSW_PWR_WELL_ENABLE)) {
+		DRM_DEBUG_KMS("PSR condition failed: Power Well is Enabled\n");
+		dev_priv->no_psr_reason = PSR_PWR_WELL_ENABLED;
+		return false;
+	}
+
+	if (obj->tiling_mode != I915_TILING_X ||
+	    obj->fence_reg == I915_FENCE_REG_NONE) {
+		DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n");
+		dev_priv->no_psr_reason = PSR_NOT_TILED;
+		return false;
+	}
+
+	if (I915_READ(SPRCTL(intel_crtc->pipe)) & SPRITE_ENABLE) {
+		DRM_DEBUG_KMS("PSR condition failed: Sprite is Enabled\n");
+		dev_priv->no_psr_reason = PSR_SPRITE_ENABLED;
+		return false;
+	}
+
+	if ((I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) &
+	     PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK) {
+		DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
+		dev_priv->no_psr_reason = PSR_INTERLACED_ENABLED;
+		return false;
+	}
+
+	return true;
+}
+
 void intel_edp_psr_enable(struct intel_dp* intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1464,7 +1529,8 @@ void intel_edp_psr_enable(struct intel_dp* intel_dp)
 	int precharge = 0x3;
 	int msg_size = 5;       /* Header(4) + Message(1) */
 
-	if (!is_edp_psr(intel_dp) || intel_edp_is_psr_enabled(dev))
+	if (!intel_edp_psr_match_conditions(intel_dp) ||
+	    intel_edp_is_psr_enabled(dev))
 		return;
 
 	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-- 
1.7.11.7

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

* [PATCH 08/13] drm/i915: Hook PSR functionality
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (5 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 07/13] drm/i915: Match all PSR mode entry conditions before enabling it Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 09/13] drm/i915: add update function to disable/enable-back PSR Rodrigo Vivi
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

PSR must be enabled after transcoder and port are running.
And it is only available for HSW.

v2: move enable/disable to intel_ddi
v3: The spec suggests PSR should be disabled even before backlight (by pzanoni)
v4: also disabling and enabling whenever panel is disabled/enabled.

CC: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/intel_ddi.c | 2 ++
 drivers/gpu/drm/i915/intel_dp.c  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 224ce25..45042c0 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1117,6 +1117,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 			intel_dp_stop_link_train(intel_dp);
 
 		ironlake_edp_backlight_on(intel_dp);
+		intel_edp_psr_enable(intel_dp);
 	}
 
 	if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) {
@@ -1147,6 +1148,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
 	if (type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
+		intel_edp_psr_disable(intel_dp);
 		ironlake_edp_backlight_off(intel_dp);
 	}
 }
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c105236..e7cd6e0 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1603,6 +1603,7 @@ static void intel_disable_dp(struct intel_encoder *encoder)
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	ironlake_edp_panel_vdd_on(intel_dp);
+	intel_edp_psr_disable(intel_dp);
 	ironlake_edp_backlight_off(intel_dp);
 	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
 	ironlake_edp_panel_off(intel_dp);
@@ -1643,6 +1644,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
 	intel_dp_complete_link_train(intel_dp);
 	intel_dp_stop_link_train(intel_dp);
 	ironlake_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 
 	if (IS_VALLEYVIEW(dev)) {
 		struct intel_digital_port *dport =
-- 
1.7.11.7

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

* [PATCH 09/13] drm/i915: add update function to disable/enable-back PSR
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (6 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 08/13] drm/i915: Hook PSR functionality Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 10/13] drm/intel: add enable_psr module option Rodrigo Vivi
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

Required function to disable PSR when going to console mode.
But also can be used whenever PSR mode entry conditions changed.
---
 drivers/gpu/drm/i915/intel_display.c |  1 +
 drivers/gpu/drm/i915/intel_dp.c      | 32 +++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_drv.h     |  1 +
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ccd28f4..c62fe39 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2233,6 +2233,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 	}
 
 	intel_update_fbc(dev);
+	intel_edp_psr_update(dev);
 	mutex_unlock(&dev->struct_mutex);
 
 	intel_crtc_update_sarea_pos(crtc, x, y);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e7cd6e0..ea88207 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1520,7 +1520,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 	return true;
 }
 
-void intel_edp_psr_enable(struct intel_dp* intel_dp)
+void intel_edp_psr_do_enable(struct intel_dp* intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1572,6 +1572,15 @@ void intel_edp_psr_enable(struct intel_dp* intel_dp)
 	intel_edp_psr_enable_src(intel_dp);
 }
 
+void intel_edp_psr_enable(struct intel_dp* intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+
+	if (intel_edp_psr_match_conditions(intel_dp) &&
+	    !intel_edp_is_psr_enabled(dev))
+		intel_edp_psr_do_enable(intel_dp);
+}
+
 void intel_edp_psr_disable(struct intel_dp* intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1594,6 +1603,26 @@ void intel_edp_psr_disable(struct intel_dp* intel_dp)
 	intel_wait_for_vblank(dev, intel_crtc->pipe);
 }
 
+void intel_edp_psr_update(struct drm_device *dev)
+{
+	struct intel_encoder *encoder;
+	struct intel_dp *intel_dp = NULL;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			intel_dp = enc_to_intel_dp(&encoder->base);
+
+			if (!is_edp_psr(intel_dp))
+				return;
+
+			if (!intel_edp_psr_match_conditions(intel_dp))
+				intel_edp_psr_disable(intel_dp);
+			else
+				if (!intel_edp_is_psr_enabled(dev))
+					intel_edp_psr_do_enable(intel_dp);
+		}
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -1626,6 +1655,7 @@ static void intel_post_disable_dp(struct intel_encoder *encoder)
 	}
 }
 
+
 static void intel_enable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5113572..c6c8076 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -811,5 +811,6 @@ extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
 
 extern void intel_edp_psr_enable(struct intel_dp* intel_dp);
 extern void intel_edp_psr_disable(struct intel_dp* intel_dp);
+extern void intel_edp_psr_update(struct drm_device *dev);
 
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.11.7

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

* [PATCH 10/13] drm/intel: add enable_psr module option
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (7 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 09/13] drm/i915: add update function to disable/enable-back PSR Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 11/13] drm/i915: PSR: Make a clear separation between Sink (Panel) and Source (HW) enabling Rodrigo Vivi
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

PSR is enabled by default but can be disabled.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c | 3 +++
 drivers/gpu/drm/i915/i915_drv.c     | 4 ++++
 drivers/gpu/drm/i915/i915_drv.h     | 2 ++
 drivers/gpu/drm/i915/intel_dp.c     | 6 ++++++
 4 files changed, 15 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index f4e9147..f3e83a6 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1893,6 +1893,9 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 		case PSR_NO_SINK:
 			seq_printf(m, "not supported by panel");
 			break;
+		case PSR_MODULE_PARAM:
+			seq_printf(m, "disabled by flag");
+			break;
 		case PSR_CRTC_NOT_ACTIVE:
 			seq_printf(m, "crtc not active");
 			break;
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index b23cd63..020f416 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -118,6 +118,10 @@ module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600);
 MODULE_PARM_DESC(i915_enable_ppgtt,
 		"Enable PPGTT (default: true)");
 
+int i915_enable_psr __read_mostly = 1;
+module_param_named(enable_psr, i915_enable_psr, int, 0600);
+MODULE_PARM_DESC(enable_psr, "Enable PSR (default: true)");
+
 unsigned int i915_preliminary_hw_support __read_mostly = 0;
 module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600);
 MODULE_PARM_DESC(preliminary_hw_support,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index cbe842b..cbf85aa 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -512,6 +512,7 @@ enum no_fbc_reason {
 enum no_psr_reason {
 	PSR_NO_SOURCE, /* Not supported on platform */
 	PSR_NO_SINK, /* Not supported by panel */
+	PSR_MODULE_PARAM,
 	PSR_CRTC_NOT_ACTIVE,
 	PSR_PWR_WELL_ENABLED,
 	PSR_NOT_TILED,
@@ -1518,6 +1519,7 @@ extern int i915_enable_rc6 __read_mostly;
 extern int i915_enable_fbc __read_mostly;
 extern bool i915_enable_hangcheck __read_mostly;
 extern int i915_enable_ppgtt __read_mostly;
+extern int i915_enable_psr __read_mostly;
 extern unsigned int i915_preliminary_hw_support __read_mostly;
 extern int i915_disable_power_well __read_mostly;
 extern int i915_enable_ips __read_mostly;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index ea88207..a7f3bd1 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1484,6 +1484,12 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
+	if (!i915_enable_psr) {
+		DRM_DEBUG_KMS("PSR disable by flag\n");
+		dev_priv->no_psr_reason = PSR_MODULE_PARAM;
+		return false;
+	}
+
 	if (!intel_crtc->active || !crtc->fb || !crtc->mode.clock) {
 		DRM_DEBUG_KMS("crtc not active for PSR\n");
 		dev_priv->no_psr_reason = PSR_CRTC_NOT_ACTIVE;
-- 
1.7.11.7

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

* [PATCH 11/13] drm/i915: PSR: Make a clear separation between Sink (Panel) and Source (HW) enabling.
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (8 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 10/13] drm/intel: add enable_psr module option Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-13 13:01   ` Daniel Vetter
  2013-06-12 20:55 ` [PATCH 12/13] drm/i915: Adding global I915_PARAM for PSR ACTIVE Rodrigo Vivi
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/intel_dp.c | 169 +++++++++++++++++++++-------------------
 1 file changed, 87 insertions(+), 82 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index a7f3bd1..c5ea419 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1362,7 +1362,79 @@ static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 	return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
 }
 
-static void intel_edp_psr_enable_src(struct intel_dp *intel_dp)
+
+void intel_edp_psr_write_vsc(struct intel_dp* intel_dp,
+			     struct edp_vsc_psr *vsc_psr)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
+
+	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
+	u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
+	uint32_t *data = (uint32_t *) vsc_psr;
+	unsigned int i;
+	u32 val = I915_READ(ctl_reg);
+
+	/* As per eDP spec, wait for vblank to send SDP VSC packet */
+	intel_wait_for_vblank(dev, crtc->pipe);
+
+	/* As per BSPec (Pipe Video Data Island Packet), besides wait for
+	   vsync we need to disable the video DIP being updated before program
+	   video DIP data buffer registers for DIP being updated.*/
+	I915_WRITE(ctl_reg, val & ~VIDEO_DIP_ENABLE_VSC_HSW);
+	POSTING_READ(ctl_reg);
+
+	for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
+                if (i < sizeof(struct edp_vsc_psr))
+                        I915_WRITE(data_reg + i, *data++);
+                else
+                        I915_WRITE(data_reg + i, 0);
+        }
+
+	I915_WRITE(ctl_reg, val | VIDEO_DIP_ENABLE_VSC_HSW);
+	POSTING_READ(ctl_reg);
+}
+
+static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct edp_vsc_psr psr_vsc;
+	uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp);
+	int precharge = 0x3;
+	int msg_size = 5;       /* Header(4) + Message(1) */
+
+	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+	memset(&psr_vsc, 0, sizeof(psr_vsc));
+	psr_vsc.sdp_header.HB0 = 0;
+	psr_vsc.sdp_header.HB1 = 0x7;
+	psr_vsc.sdp_header.HB2 = 0x2;
+	psr_vsc.sdp_header.HB3 = 0x8;
+	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+
+	/* Enable PSR in sink */
+	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
+		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+					    DP_PSR_ENABLE &
+					    ~DP_PSR_MAIN_LINK_ACTIVE);
+	else
+		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+					    DP_PSR_ENABLE |
+					    DP_PSR_MAIN_LINK_ACTIVE);
+
+	/* Setup AUX registers */
+	I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND);
+	I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION);
+	I915_WRITE(EDP_PSR_AUX_CTL,
+		   DP_AUX_CH_CTL_TIME_OUT_400us |
+		   (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+		   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
+}
+
+static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1415,44 +1487,29 @@ static void intel_edp_psr_enable_src(struct intel_dp *intel_dp)
 		};
 	}
 
+	/* Avoid continuous PSR exit by masking memup and hpd */
+	I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
+		   EDP_PSR_DEBUG_MASK_HPD);
+
+	/* Disable unused interrupts */
+	I915_WRITE(GEN6_PMINTRMSK, GEN6_PM_RP_UP_EI_EXPIRED |
+		   GEN6_PM_RP_DOWN_EI_EXPIRED);
+
+
 	I915_WRITE(EDP_PSR_CTL, val |
 		   EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES |
 		   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
 		   EDP_PSR_ENABLE);
 }
 
-void intel_edp_psr_write_vsc(struct intel_dp* intel_dp,
-			     struct edp_vsc_psr *vsc_psr)
+static void intel_edp_psr_do_enable(struct intel_dp* intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
-
-	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
-	u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
-	uint32_t *data = (uint32_t *) vsc_psr;
-	unsigned int i;
-	u32 val = I915_READ(ctl_reg);
-
-	/* As per eDP spec, wait for vblank to send SDP VSC packet */
-	intel_wait_for_vblank(dev, crtc->pipe);
-
-	/* As per BSPec (Pipe Video Data Island Packet), besides wait for
-	   vsync we need to disable the video DIP being updated before program
-	   video DIP data buffer registers for DIP being updated.*/
-	I915_WRITE(ctl_reg, val & ~VIDEO_DIP_ENABLE_VSC_HSW);
-	POSTING_READ(ctl_reg);
 
-	for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
-                if (i < sizeof(struct edp_vsc_psr))
-                        I915_WRITE(data_reg + i, *data++);
-                else
-                        I915_WRITE(data_reg + i, 0);
-        }
+	/* Enable PSR on the panel */
+	intel_edp_psr_enable_sink(intel_dp);
 
-	I915_WRITE(ctl_reg, val | VIDEO_DIP_ENABLE_VSC_HSW);
-	POSTING_READ(ctl_reg);
+	/* Enable PSR on the host */
+	intel_edp_psr_enable_source(intel_dp);
 }
 
 static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
@@ -1526,58 +1583,6 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 	return true;
 }
 
-void intel_edp_psr_do_enable(struct intel_dp* intel_dp)
-{
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct edp_vsc_psr psr_vsc;
-	uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp);
-	int precharge = 0x3;
-	int msg_size = 5;       /* Header(4) + Message(1) */
-
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
-		return;
-
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
-
-	/* Enable PSR in sink */
-	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
-		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
-					    DP_PSR_ENABLE &
-					    ~DP_PSR_MAIN_LINK_ACTIVE);
-	else
-		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
-					    DP_PSR_ENABLE |
-					    DP_PSR_MAIN_LINK_ACTIVE);
-
-	/* Setup AUX registers */
-	I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND);
-	I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION);
-	I915_WRITE(EDP_PSR_AUX_CTL,
-		   DP_AUX_CH_CTL_TIME_OUT_400us |
-		   (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
-		   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
-		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
-
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD);
-
-	/* Disable unused interrupts */
-	I915_WRITE(GEN6_PMINTRMSK, GEN6_PM_RP_UP_EI_EXPIRED |
-		   GEN6_PM_RP_DOWN_EI_EXPIRED);
-
-	/* Enable PSR on the host */
-	intel_edp_psr_enable_src(intel_dp);
-}
-
 void intel_edp_psr_enable(struct intel_dp* intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
-- 
1.7.11.7

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

* [PATCH 12/13] drm/i915: Adding global I915_PARAM for PSR ACTIVE.
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (9 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 11/13] drm/i915: PSR: Make a clear separation between Sink (Panel) and Source (HW) enabling Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-12 20:55 ` [PATCH 13/13] drm/i915: force psr exit when busy Rodrigo Vivi
  2013-06-14 16:21 ` [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Paulo Zanoni
  12 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

This global value allows userspace know when PSR is enabled and active,
i.e. in SRD entry state.
This will allow userspace emit more busy_ioctl when doing directly copy_area
operations through scanout allowing forced psr exit.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_dma.c | 3 +++
 include/uapi/drm/i915_drm.h     | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index fd8898c..d21b9a0 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1001,6 +1001,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
 	case I915_PARAM_HAS_EXEC_HANDLE_LUT:
 		value = 1;
 		break;
+	case I915_PARAM_PSR_ACTIVE:
+		value = I915_READ(EDP_PSR_STATUS_CTL) & EDP_PSR_STATUS_STATE_SRDENT;
+		break;
 	default:
 		DRM_DEBUG("Unknown parameter %d\n", param->param);
 		return -EINVAL;
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 923ed7f..191a7fc 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -310,6 +310,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_PINNED_BATCHES	 24
 #define I915_PARAM_HAS_EXEC_NO_RELOC	 25
 #define I915_PARAM_HAS_EXEC_HANDLE_LUT   26
+#define I915_PARAM_PSR_ACTIVE		 27
 
 typedef struct drm_i915_getparam {
 	int param;
-- 
1.7.11.7

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

* [PATCH 13/13] drm/i915: force psr exit when busy
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (10 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 12/13] drm/i915: Adding global I915_PARAM for PSR ACTIVE Rodrigo Vivi
@ 2013-06-12 20:55 ` Rodrigo Vivi
  2013-06-14 16:21 ` [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Paulo Zanoni
  12 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-12 20:55 UTC (permalink / raw)
  To: intel-gfx

PSR tracking engine in HSW doesn't detect automagically some directly copy area
operations through scanout so we have to kick it manually and reschedule it to
come back to normal operation as soon as possible.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_gem.c  |  2 ++
 drivers/gpu/drm/i915/i915_reg.h  |  1 +
 drivers/gpu/drm/i915/intel_dp.c  | 61 ++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h |  4 +++
 4 files changed, 68 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 58048d4..fc640fc 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3684,6 +3684,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 		goto unlock;
 	}
 
+	intel_edp_psr_force_exit(dev);
+
 	/* Count all active objects as busy, even if they are currently not used
 	 * by the gpu. Users of this interface expect objects to eventually
 	 * become non-busy without any further actions, therefore emit any
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 16ab839..9ad699e 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1836,6 +1836,7 @@
 #define   EDP_PSR_PERF_CNT_MASK		0xffffff
 
 #define EDP_PSR_DEBUG_CTL		0x64860
+#define   EDP_PSR_DEBUG_FORCE_EXIT	(3<<30)
 #define   EDP_PSR_DEBUG_MASK_LPSP	(1<<27)
 #define   EDP_PSR_DEBUG_MASK_MEMUP	(1<<26)
 #define   EDP_PSR_DEBUG_MASK_HPD	(1<<25)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c5ea419..4ab9aa9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1359,9 +1359,54 @@ static bool is_edp_psr(struct intel_dp *intel_dp)
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (!IS_HASWELL(dev))
+		return false;
+
 	return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
 }
 
+static void intel_edp_psr_delayed_normal_work(struct work_struct *__work)
+{
+	struct intel_dp *intel_dp = container_of(to_delayed_work(__work),
+						 struct intel_dp,
+						 edp_psr_delayed_normal_work);
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	mutex_lock(&intel_dp->psr_exit_mutex);
+	I915_WRITE(EDP_PSR_DEBUG_CTL, I915_READ(EDP_PSR_DEBUG_CTL) &
+		   ~EDP_PSR_DEBUG_FORCE_EXIT);
+	mutex_unlock(&intel_dp->psr_exit_mutex);
+}
+
+void intel_edp_psr_force_exit(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+	struct intel_dp *intel_dp = NULL;
+
+	if (!intel_edp_is_psr_enabled(dev))
+		return;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP)
+			intel_dp = enc_to_intel_dp(&encoder->base);
+
+	if (!intel_dp)
+		return;
+
+	if (WARN_ON(!intel_dp->psr_setup_done))
+		return;
+
+	mutex_lock(&intel_dp->psr_exit_mutex);
+	I915_WRITE(EDP_PSR_DEBUG_CTL, I915_READ(EDP_PSR_DEBUG_CTL) |
+		   EDP_PSR_DEBUG_FORCE_EXIT);
+	mutex_unlock(&intel_dp->psr_exit_mutex);
+
+	schedule_delayed_work(&intel_dp->edp_psr_delayed_normal_work,
+			      msecs_to_jiffies(100));
+}
 
 void intel_edp_psr_write_vsc(struct intel_dp* intel_dp,
 			     struct edp_vsc_psr *vsc_psr)
@@ -1397,6 +1442,18 @@ void intel_edp_psr_write_vsc(struct intel_dp* intel_dp,
 	POSTING_READ(ctl_reg);
 }
 
+static void intel_edp_psr_setup(struct intel_dp *intel_dp)
+{
+	if (intel_dp->psr_setup_done)
+		return;
+
+	INIT_DELAYED_WORK(&intel_dp->edp_psr_delayed_normal_work,
+			  intel_edp_psr_delayed_normal_work);
+	mutex_init(&intel_dp->psr_exit_mutex);
+
+	intel_dp->psr_setup_done = true;
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1504,6 +1561,8 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 
 static void intel_edp_psr_do_enable(struct intel_dp* intel_dp)
 {
+	/* Setup PSR once */
+	intel_edp_psr_setup(intel_dp);
 
 	/* Enable PSR on the panel */
 	intel_edp_psr_enable_sink(intel_dp);
@@ -3370,6 +3429,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	if (is_edp(intel_dp))
 		intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
 
+	intel_dp->psr_setup_done = false;
+
 	intel_dp_i2c_init(intel_dp, intel_connector, name);
 
 	/* Cache DPCD and EDID for edp. */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c6c8076..15e8023 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -481,6 +481,9 @@ struct intel_dp {
 	int backlight_on_delay;
 	int backlight_off_delay;
 	struct delayed_work panel_vdd_work;
+	struct delayed_work edp_psr_delayed_normal_work;
+	struct mutex psr_exit_mutex;
+	bool psr_setup_done;
 	bool want_panel_vdd;
 	struct intel_connector *attached_connector;
 };
@@ -812,5 +815,6 @@ extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
 extern void intel_edp_psr_enable(struct intel_dp* intel_dp);
 extern void intel_edp_psr_disable(struct intel_dp* intel_dp);
 extern void intel_edp_psr_update(struct drm_device *dev);
+extern void intel_edp_psr_force_exit(struct drm_device *dev);
 
 #endif /* __INTEL_DRV_H__ */
-- 
1.7.11.7

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

* Re: [PATCH 11/13] drm/i915: PSR: Make a clear separation between Sink (Panel) and Source (HW) enabling.
  2013-06-12 20:55 ` [PATCH 11/13] drm/i915: PSR: Make a clear separation between Sink (Panel) and Source (HW) enabling Rodrigo Vivi
@ 2013-06-13 13:01   ` Daniel Vetter
  0 siblings, 0 replies; 21+ messages in thread
From: Daniel Vetter @ 2013-06-13 13:01 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jun 12, 2013 at 05:55:52PM -0300, Rodrigo Vivi wrote:
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>

Shouldn't that be folded into an earlier patch?
-Daniel

> ---
>  drivers/gpu/drm/i915/intel_dp.c | 169 +++++++++++++++++++++-------------------
>  1 file changed, 87 insertions(+), 82 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index a7f3bd1..c5ea419 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1362,7 +1362,79 @@ static bool intel_edp_is_psr_enabled(struct drm_device *dev)
>  	return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
>  }
>  
> -static void intel_edp_psr_enable_src(struct intel_dp *intel_dp)
> +
> +void intel_edp_psr_write_vsc(struct intel_dp* intel_dp,
> +			     struct edp_vsc_psr *vsc_psr)
> +{
> +	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
> +
> +	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
> +	u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
> +	uint32_t *data = (uint32_t *) vsc_psr;
> +	unsigned int i;
> +	u32 val = I915_READ(ctl_reg);
> +
> +	/* As per eDP spec, wait for vblank to send SDP VSC packet */
> +	intel_wait_for_vblank(dev, crtc->pipe);
> +
> +	/* As per BSPec (Pipe Video Data Island Packet), besides wait for
> +	   vsync we need to disable the video DIP being updated before program
> +	   video DIP data buffer registers for DIP being updated.*/
> +	I915_WRITE(ctl_reg, val & ~VIDEO_DIP_ENABLE_VSC_HSW);
> +	POSTING_READ(ctl_reg);
> +
> +	for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
> +                if (i < sizeof(struct edp_vsc_psr))
> +                        I915_WRITE(data_reg + i, *data++);
> +                else
> +                        I915_WRITE(data_reg + i, 0);
> +        }
> +
> +	I915_WRITE(ctl_reg, val | VIDEO_DIP_ENABLE_VSC_HSW);
> +	POSTING_READ(ctl_reg);
> +}
> +
> +static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
> +{
> +	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct edp_vsc_psr psr_vsc;
> +	uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp);
> +	int precharge = 0x3;
> +	int msg_size = 5;       /* Header(4) + Message(1) */
> +
> +	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> +	memset(&psr_vsc, 0, sizeof(psr_vsc));
> +	psr_vsc.sdp_header.HB0 = 0;
> +	psr_vsc.sdp_header.HB1 = 0x7;
> +	psr_vsc.sdp_header.HB2 = 0x2;
> +	psr_vsc.sdp_header.HB3 = 0x8;
> +	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> +
> +	/* Enable PSR in sink */
> +	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
> +		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> +					    DP_PSR_ENABLE &
> +					    ~DP_PSR_MAIN_LINK_ACTIVE);
> +	else
> +		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> +					    DP_PSR_ENABLE |
> +					    DP_PSR_MAIN_LINK_ACTIVE);
> +
> +	/* Setup AUX registers */
> +	I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND);
> +	I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION);
> +	I915_WRITE(EDP_PSR_AUX_CTL,
> +		   DP_AUX_CH_CTL_TIME_OUT_400us |
> +		   (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
> +		   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
> +		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
> +}
> +
> +static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>  {
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -1415,44 +1487,29 @@ static void intel_edp_psr_enable_src(struct intel_dp *intel_dp)
>  		};
>  	}
>  
> +	/* Avoid continuous PSR exit by masking memup and hpd */
> +	I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
> +		   EDP_PSR_DEBUG_MASK_HPD);
> +
> +	/* Disable unused interrupts */
> +	I915_WRITE(GEN6_PMINTRMSK, GEN6_PM_RP_UP_EI_EXPIRED |
> +		   GEN6_PM_RP_DOWN_EI_EXPIRED);
> +
> +
>  	I915_WRITE(EDP_PSR_CTL, val |
>  		   EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES |
>  		   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
>  		   EDP_PSR_ENABLE);
>  }
>  
> -void intel_edp_psr_write_vsc(struct intel_dp* intel_dp,
> -			     struct edp_vsc_psr *vsc_psr)
> +static void intel_edp_psr_do_enable(struct intel_dp* intel_dp)
>  {
> -	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
> -
> -	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
> -	u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
> -	uint32_t *data = (uint32_t *) vsc_psr;
> -	unsigned int i;
> -	u32 val = I915_READ(ctl_reg);
> -
> -	/* As per eDP spec, wait for vblank to send SDP VSC packet */
> -	intel_wait_for_vblank(dev, crtc->pipe);
> -
> -	/* As per BSPec (Pipe Video Data Island Packet), besides wait for
> -	   vsync we need to disable the video DIP being updated before program
> -	   video DIP data buffer registers for DIP being updated.*/
> -	I915_WRITE(ctl_reg, val & ~VIDEO_DIP_ENABLE_VSC_HSW);
> -	POSTING_READ(ctl_reg);
>  
> -	for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
> -                if (i < sizeof(struct edp_vsc_psr))
> -                        I915_WRITE(data_reg + i, *data++);
> -                else
> -                        I915_WRITE(data_reg + i, 0);
> -        }
> +	/* Enable PSR on the panel */
> +	intel_edp_psr_enable_sink(intel_dp);
>  
> -	I915_WRITE(ctl_reg, val | VIDEO_DIP_ENABLE_VSC_HSW);
> -	POSTING_READ(ctl_reg);
> +	/* Enable PSR on the host */
> +	intel_edp_psr_enable_source(intel_dp);
>  }
>  
>  static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> @@ -1526,58 +1583,6 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>  	return true;
>  }
>  
> -void intel_edp_psr_do_enable(struct intel_dp* intel_dp)
> -{
> -	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct edp_vsc_psr psr_vsc;
> -	uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp);
> -	int precharge = 0x3;
> -	int msg_size = 5;       /* Header(4) + Message(1) */
> -
> -	if (!intel_edp_psr_match_conditions(intel_dp) ||
> -	    intel_edp_is_psr_enabled(dev))
> -		return;
> -
> -	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> -	memset(&psr_vsc, 0, sizeof(psr_vsc));
> -	psr_vsc.sdp_header.HB0 = 0;
> -	psr_vsc.sdp_header.HB1 = 0x7;
> -	psr_vsc.sdp_header.HB2 = 0x2;
> -	psr_vsc.sdp_header.HB3 = 0x8;
> -	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> -
> -	/* Enable PSR in sink */
> -	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
> -		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> -					    DP_PSR_ENABLE &
> -					    ~DP_PSR_MAIN_LINK_ACTIVE);
> -	else
> -		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> -					    DP_PSR_ENABLE |
> -					    DP_PSR_MAIN_LINK_ACTIVE);
> -
> -	/* Setup AUX registers */
> -	I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND);
> -	I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION);
> -	I915_WRITE(EDP_PSR_AUX_CTL,
> -		   DP_AUX_CH_CTL_TIME_OUT_400us |
> -		   (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
> -		   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
> -		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
> -
> -	/* Avoid continuous PSR exit by masking memup and hpd */
> -	I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
> -		   EDP_PSR_DEBUG_MASK_HPD);
> -
> -	/* Disable unused interrupts */
> -	I915_WRITE(GEN6_PMINTRMSK, GEN6_PM_RP_UP_EI_EXPIRED |
> -		   GEN6_PM_RP_DOWN_EI_EXPIRED);
> -
> -	/* Enable PSR on the host */
> -	intel_edp_psr_enable_src(intel_dp);
> -}
> -
>  void intel_edp_psr_enable(struct intel_dp* intel_dp)
>  {
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> -- 
> 1.7.11.7
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH 03/13] drm/i915: VBT Parsing for the PSR Feature Block for HSW
  2013-06-12 20:55 ` [PATCH 03/13] drm/i915: VBT Parsing for the PSR Feature Block for HSW Rodrigo Vivi
@ 2013-06-13 13:41   ` Chris Wilson
  2013-06-14 17:02   ` Paulo Zanoni
  1 sibling, 0 replies; 21+ messages in thread
From: Chris Wilson @ 2013-06-13 13:41 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jun 12, 2013 at 05:55:44PM -0300, Rodrigo Vivi wrote:
> From: Shobhit Kumar <shobhit.kumar@intel.com>
> 
> Parse and store useful information in i915_dev_private
> 
> v2: Add to new vbt struct and call them psr_*
> v3: Fix comment and variable name
> 
> Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h   |  7 +++++++
>  drivers/gpu/drm/i915/intel_bios.c | 30 ++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_bios.h | 20 +++++++++++++++++++-
>  3 files changed, 56 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 87f7f88..dd459a5 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -951,6 +951,13 @@ struct intel_vbt_data {
>  	int edp_bpp;
>  	struct edp_power_seq edp_pps;
>  
> +	/* eDP PSR*/
> +	u8 psr_full_link_state;
> +	u8 psr_wait_lines;
> +	u8 psr_idle_frames;
> +	u16 psr_wakeup_tp1;
> +	u16 psr_wakeup_tp2_tp3;

Let's be neat and tidy and move these into their own psr struct. Do we
want a valid flag here?

>+
>  	int crt_ddc_pin;
>  
>  	int child_dev_num;
> diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
> index 53f2bed..99c6788 100644
> --- a/drivers/gpu/drm/i915/intel_bios.c
> +++ b/drivers/gpu/drm/i915/intel_bios.c
> @@ -383,6 +383,35 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
>  	}
>  }
>  
> +
> +static void
> +parse_edp_psr(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
> +{
> +	struct bdb_psr_features *psr;
> +	struct bdb_lvds_options *lvds_opts;
> +	int index = 0;
> +	lvds_opts = find_section(bdb, BDB_LVDS_OPTIONS);
> +	if (!lvds_opts) {
> +		DRM_DEBUG_KMS("No LVDS Options block found.\n");
> +		return;
> +	}
> +
> +	index = lvds_opts->panel_type;
> +
> +	psr = find_section(bdb, BDB_PSR_FEATURES);
> +	if (!psr) {
> +		DRM_DEBUG_KMS("No PSR feature block found.\n");
> +		return;
> +	}

You trust the bios that much to read a random index into an array?
Everything from the BIOS is tainted and must be validated.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

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

* Re: [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP
  2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
                   ` (11 preceding siblings ...)
  2013-06-12 20:55 ` [PATCH 13/13] drm/i915: force psr exit when busy Rodrigo Vivi
@ 2013-06-14 16:21 ` Paulo Zanoni
  2013-06-25  1:56   ` [PATCH] " Rodrigo Vivi
  12 siblings, 1 reply; 21+ messages in thread
From: Paulo Zanoni @ 2013-06-14 16:21 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx, Sateesh Kavuri, Paulo Zanoni

2013/6/12 Rodrigo Vivi <rodrigo.vivi@gmail.com>:
> From: Shobhit Kumar <shobhit.kumar@intel.com>
>
> v2: Modified and corrected the structures to be more in line for
> kernel coding guidelines and rebased the code on Paulo's DP patchset
> v3: removing unecessary identation at DP_RECEIVER_CAP_SIZE
> v4: moving them to include/drm/drm_dp_helper.h and also already
>     icluding EDP_PSR_RECEIVER_CAP_SIZE to add everything needed
>     for PSR at once at drm_dp_helper.h
> v5: Fix SDP VSC header and identation by (Paulo Zanoni) and
>     remove i915 from title (Daniel Vetter)
>
> CC: Paulo Zanoni <paulo.r.zanoni@intel.com>
> Signed-off-by: Sateesh Kavuri <sateesh.kavuri@intel.com>
> Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> ---
>  include/drm/drm_dp_helper.h | 33 ++++++++++++++++++++++++++++++++-
>  1 file changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> index e8e1417..4062c9e 100644
> --- a/include/drm/drm_dp_helper.h
> +++ b/include/drm/drm_dp_helper.h
> @@ -342,13 +342,44 @@ u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
>  u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
>                                           int lane);
>
> -#define DP_RECEIVER_CAP_SIZE   0xf
> +#define DP_RECEIVER_CAP_SIZE           0xf
> +#define EDP_PSR_RECEIVER_CAP_SIZE      2
> +
>  void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
>  void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
>
>  u8 drm_dp_link_rate_to_bw_code(int link_rate);
>  int drm_dp_bw_code_to_link_rate(u8 link_bw);
>
> +/* SDP header as per eDP 1.3 spec, section 3.6 */

On my version of the spec, it's section 3.5, same for the comment
below. Maybe we should just include the chapter name ("PSR Secondary
Data Packet Support") or just don't add anything. These numbers might
change in the future.

Everything else looks correct, so with or without the comment fixed:
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

> +struct edp_sdp_header {
> +       u8 HB0; /* Secondary Data Packet ID */
> +       u8 HB1; /* Secondary Data Packet Type */
> +       u8 HB2; /* 7:5 reserved, 4:0 revision number */
> +       u8 HB3; /* 7:5 reserved, 4:0 number of valid data bytes */
> +} __packed;
> +
> +#define EDP_SDP_HEADER_REVISION_MASK           0x1F
> +#define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES     0x1F
> +
> +/* SDP VSC header as per eDP 1.3 spec, section 3.6 */
> +struct edp_vsc_psr {
> +       struct edp_sdp_header sdp_header;
> +       u8 DB0; /* Stereo Interface */
> +       u8 DB1; /* 0 - PSR State; 1 - Update RFB; 2 - CRC Valid */
> +       u8 DB2; /* CRC value bits 7:0 of the R or Cr component */
> +       u8 DB3; /* CRC value bits 15:8 of the R or Cr component */
> +       u8 DB4; /* CRC value bits 7:0 of the G or Y component */
> +       u8 DB5; /* CRC value bits 15:8 of the G or Y component */
> +       u8 DB6; /* CRC value bits 7:0 of the B or Cb component */
> +       u8 DB7; /* CRC value bits 15:8 of the B or Cb component */
> +       u8 DB8_31[24]; /* Reserved */
> +} __packed;
> +
> +#define EDP_VSC_PSR_STATE_ACTIVE       (1<<0)
> +#define EDP_VSC_PSR_UPDATE_RFB         (1<<1)
> +#define EDP_VSC_PSR_CRC_VALUES_VALID   (1<<2)
> +
>  static inline int
>  drm_dp_max_link_rate(u8 dpcd[DP_RECEIVER_CAP_SIZE])
>  {
> --
> 1.7.11.7
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

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

* Re: [PATCH 02/13] drm/i915: Read the EDP DPCD and PSR Capability
  2013-06-12 20:55 ` [PATCH 02/13] drm/i915: Read the EDP DPCD and PSR Capability Rodrigo Vivi
@ 2013-06-14 16:42   ` Paulo Zanoni
  2013-06-25  1:58     ` [PATCH] " Rodrigo Vivi
  0 siblings, 1 reply; 21+ messages in thread
From: Paulo Zanoni @ 2013-06-14 16:42 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

2013/6/12 Rodrigo Vivi <rodrigo.vivi@gmail.com>:
> From: Shobhit Kumar <shobhit.kumar@intel.com>
>
> v2: reuse of just created is_edp_psr and put it at right place.
> v3: move is_edp_psr above intel_edp_disable
>
> Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> Reviewed-by: Jani Nikula <jani.nikula@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp.c  | 13 +++++++++++++
>  drivers/gpu/drm/i915/intel_drv.h |  1 +
>  2 files changed, 14 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 759a1c5..5332186 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1342,6 +1342,12 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>         pipe_config->adjusted_mode.flags |= flags;
>  }
>
> +static bool is_edp_psr(struct intel_dp *intel_dp)
> +{
> +       return (is_edp(intel_dp) &&
> +               (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED));
> +}

My only concern about this is: what will happen when they define PSR
version 02? Will that DP_PSR_IS_SUPPORTED bit still be 1? Anyway, if
things change in the future we should fix the DP_PSR_IS_SUPPORTED
definition and all its users, so for now I think the code is fine.

The patch looks good and I think that we could try to merge patches 1
and 2 now because they allow us to at least properly detect which
panels support PSR and which panels don't.

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

> +
>  static void intel_disable_dp(struct intel_encoder *encoder)
>  {
>         struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> @@ -2255,6 +2261,13 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
>         if (intel_dp->dpcd[DP_DPCD_REV] == 0)
>                 return false; /* DPCD not present */
>
> +       /* Check if the panel supports PSR */
> +       memset(intel_dp->psr_dpcd, 0, sizeof(intel_dp->psr_dpcd));
> +       intel_dp_aux_native_read_retry(intel_dp, DP_PSR_SUPPORT,
> +                                      intel_dp->psr_dpcd,
> +                                      sizeof(intel_dp->psr_dpcd));
> +       if (is_edp_psr(intel_dp))
> +               DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
>         if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
>               DP_DWN_STRM_PORT_PRESENT))
>                 return true; /* native DP sink */
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 0445d8c..18d9dea 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -470,6 +470,7 @@ struct intel_dp {
>         uint8_t link_bw;
>         uint8_t lane_count;
>         uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
> +       uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
>         uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
>         struct i2c_adapter adapter;
>         struct i2c_algo_dp_aux_data algo;
> --
> 1.7.11.7
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

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

* Re: [PATCH 03/13] drm/i915: VBT Parsing for the PSR Feature Block for HSW
  2013-06-12 20:55 ` [PATCH 03/13] drm/i915: VBT Parsing for the PSR Feature Block for HSW Rodrigo Vivi
  2013-06-13 13:41   ` Chris Wilson
@ 2013-06-14 17:02   ` Paulo Zanoni
  1 sibling, 0 replies; 21+ messages in thread
From: Paulo Zanoni @ 2013-06-14 17:02 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

2013/6/12 Rodrigo Vivi <rodrigo.vivi@gmail.com>:
> From: Shobhit Kumar <shobhit.kumar@intel.com>
>
> Parse and store useful information in i915_dev_private
>
> v2: Add to new vbt struct and call them psr_*
> v3: Fix comment and variable name
>
> Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h   |  7 +++++++
>  drivers/gpu/drm/i915/intel_bios.c | 30 ++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_bios.h | 20 +++++++++++++++++++-
>  3 files changed, 56 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 87f7f88..dd459a5 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -951,6 +951,13 @@ struct intel_vbt_data {
>         int edp_bpp;
>         struct edp_power_seq edp_pps;
>
> +       /* eDP PSR*/
> +       u8 psr_full_link_state;
> +       u8 psr_wait_lines;
> +       u8 psr_idle_frames;
> +       u16 psr_wakeup_tp1;
> +       u16 psr_wakeup_tp2_tp3;
> +
>         int crt_ddc_pin;
>
>         int child_dev_num;
> diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
> index 53f2bed..99c6788 100644
> --- a/drivers/gpu/drm/i915/intel_bios.c
> +++ b/drivers/gpu/drm/i915/intel_bios.c
> @@ -383,6 +383,35 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
>         }
>  }
>
> +
> +static void
> +parse_edp_psr(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
> +{
> +       struct bdb_psr_features *psr;
> +       struct bdb_lvds_options *lvds_opts;
> +       int index = 0;
> +       lvds_opts = find_section(bdb, BDB_LVDS_OPTIONS);
> +       if (!lvds_opts) {
> +               DRM_DEBUG_KMS("No LVDS Options block found.\n");
> +               return;

We already parse BDB_LVDS_OPTIONS inside parse_lfp_panel_data(). I
wonder if we can reuse that parse somehow.


> +       }
> +
> +       index = lvds_opts->panel_type;
> +
> +       psr = find_section(bdb, BDB_PSR_FEATURES);

Don't we need to check for VBT version >= 155 here before proceeding?
Actually the docs are confusing, they say this block comes from
version 155, but all the bits inside it come from version 165... Which
one is the correct one? It seems 165 is the "safer" option at least...


> +       if (!psr) {
> +               DRM_DEBUG_KMS("No PSR feature block found.\n");
> +               return;
> +       }
> +
> +       dev_priv->vbt.psr_full_link_state = psr[index].link_disable;
> +       dev_priv->vbt.psr_wait_lines = psr[index].wait_lines;
> +       dev_priv->vbt.psr_idle_frames = psr[index].idle_frames;
> +       dev_priv->vbt.psr_wakeup_tp1 = psr[index].wakeup_tp1;
> +       dev_priv->vbt.psr_wakeup_tp2_tp3 = psr[index].wakeup_tp2_tp3;
> +}
> +
> +
>  static void
>  parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
>                           struct bdb_header *bdb)
> @@ -745,6 +774,7 @@ intel_parse_bios(struct drm_device *dev)
>         parse_device_mapping(dev_priv, bdb);
>         parse_driver_features(dev_priv, bdb);
>         parse_edp(dev_priv, bdb);
> +       parse_edp_psr(dev_priv, bdb);
>
>         if (bios)
>                 pci_unmap_rom(pdev, bios);
> diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
> index e088d6f..c883b87 100644
> --- a/drivers/gpu/drm/i915/intel_bios.h
> +++ b/drivers/gpu/drm/i915/intel_bios.h
> @@ -80,7 +80,7 @@ struct vbios_data {
>  #define BDB_EXT_MMIO_REGS        6
>  #define BDB_SWF_IO               7
>  #define BDB_SWF_MMIO             8
> -#define BDB_DOT_CLOCK_TABLE      9

This is probably from some older VBT version. That's why I suggested
checking the version above. I guess we shouldn't remove the old one,
but we should add some comments explaining this.


> +#define BDB_PSR_FEATURES         9
>  #define BDB_MODE_REMOVAL_TABLE  10
>  #define BDB_CHILD_DEVICE_TABLE  11
>  #define BDB_DRIVER_FEATURES     12
> @@ -265,6 +265,24 @@ struct bdb_lvds_options {
>         u8 rsvd4;
>  } __attribute__((packed));
>
> +struct bdb_psr_features {
> +       /* Feature bits */
> +       u8 link_disable:1;

Considering that 1 means "Enable", I'd rename this to "full_link_enable".


> +       u8 require_aux:1;
> +       u8 rsvd1:6;
> +
> +       /* Wait times */
> +       u8 idle_frames:4;
> +       u8 wait_lines:3;
> +       u8 rsvd2:1;
> +
> +       /* TP1 wakeup time */
> +       u16 wakeup_tp1;
> +
> +       /* TP2 TP3 wakeup time */
> +       u16 wakeup_tp2_tp3;
> +} __attribute__((packed));
> +
>  /* LFP pointer table contains entries to the struct below */
>  struct bdb_lvds_lfp_data_ptr {
>         u16 fp_timing_offset; /* offsets are from start of bdb */
> --
> 1.7.11.7
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

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

* Re: [PATCH 04/13] drm/i915: split aux_clock_divider logic in a separated function for reuse.
  2013-06-12 20:55 ` [PATCH 04/13] drm/i915: split aux_clock_divider logic in a separated function for reuse Rodrigo Vivi
@ 2013-06-14 17:18   ` Paulo Zanoni
  0 siblings, 0 replies; 21+ messages in thread
From: Paulo Zanoni @ 2013-06-14 17:18 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

2013/6/12 Rodrigo Vivi <rodrigo.vivi@gmail.com>:
> Prep patch for reuse aux_clock_divider with EDP_PSR_AUX_CTL setup.
>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>

I've seen this patch on this mailing list a few times already, and
it's just a prep-work for PSR, so I guess we could merge it now so we
spare Rodrigo the pain of rebasing it again and again. And I like tiny
functions like these, even if they have just 1 caller.

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_dp.c | 58 +++++++++++++++++++++++------------------
>  1 file changed, 33 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 5332186..02b2865 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -271,29 +271,12 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
>         return status;
>  }
>
> -static int
> -intel_dp_aux_ch(struct intel_dp *intel_dp,
> -               uint8_t *send, int send_bytes,
> -               uint8_t *recv, int recv_size)
> +static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp)
>  {
>         struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>         struct drm_device *dev = intel_dig_port->base.base.dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
> -       uint32_t ch_data = ch_ctl + 4;
> -       int i, ret, recv_bytes;
> -       uint32_t status;
> -       uint32_t aux_clock_divider;
> -       int try, precharge;
> -       bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
>
> -       /* dp aux is extremely sensitive to irq latency, hence request the
> -        * lowest possible wakeup latency and so prevent the cpu from going into
> -        * deep sleep states.
> -        */
> -       pm_qos_update_request(&dev_priv->pm_qos, 0);
> -
> -       intel_dp_check_edp(intel_dp);
>         /* The clock divider is based off the hrawclk,
>          * and would like to run at 2MHz. So, take the
>          * hrawclk value and divide by 2 and use that
> @@ -302,23 +285,48 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
>          * clock divider.
>          */
>         if (IS_VALLEYVIEW(dev)) {
> -               aux_clock_divider = 100;
> +               return 100;
>         } else if (intel_dig_port->port == PORT_A) {
>                 if (HAS_DDI(dev))
> -                       aux_clock_divider = DIV_ROUND_CLOSEST(
> +                       return DIV_ROUND_CLOSEST(
>                                 intel_ddi_get_cdclk_freq(dev_priv), 2000);
>                 else if (IS_GEN6(dev) || IS_GEN7(dev))
> -                       aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
> +                       return 200; /* SNB & IVB eDP input clock at 400Mhz */
>                 else
> -                       aux_clock_divider = 225; /* eDP input clock at 450Mhz */
> +                       return 225; /* eDP input clock at 450Mhz */
>         } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
>                 /* Workaround for non-ULT HSW */
> -               aux_clock_divider = 74;
> +               return 74;
>         } else if (HAS_PCH_SPLIT(dev)) {
> -               aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
> +               return DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
>         } else {
> -               aux_clock_divider = intel_hrawclk(dev) / 2;
> +               return intel_hrawclk(dev) / 2;
>         }
> +}
> +
> +static int
> +intel_dp_aux_ch(struct intel_dp *intel_dp,
> +               uint8_t *send, int send_bytes,
> +               uint8_t *recv, int recv_size)
> +{
> +       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +       struct drm_device *dev = intel_dig_port->base.base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
> +       uint32_t ch_data = ch_ctl + 4;
> +       int i, ret, recv_bytes;
> +       uint32_t status;
> +       uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp);
> +       int try, precharge;
> +       bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
> +
> +       /* dp aux is extremely sensitive to irq latency, hence request the
> +        * lowest possible wakeup latency and so prevent the cpu from going into
> +        * deep sleep states.
> +        */
> +       pm_qos_update_request(&dev_priv->pm_qos, 0);
> +
> +       intel_dp_check_edp(intel_dp);
>
>         if (IS_GEN6(dev))
>                 precharge = 3;
> --
> 1.7.11.7
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

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

* [PATCH] drm: Added SDP and VSC structures for handling PSR for eDP
  2013-06-14 16:21 ` [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Paulo Zanoni
@ 2013-06-25  1:56   ` Rodrigo Vivi
  0 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-25  1:56 UTC (permalink / raw)
  To: intel-gfx; +Cc: Shobhit Kumar, Sateesh Kavuri, Paulo Zanoni, dri-devel

From: Shobhit Kumar <shobhit.kumar@intel.com>

SDP header and SDP VSC header as per eDP 1.3 spec, section 3.5,
chapter "PSR Secondary Data Package Support".

v2: Modified and corrected the structures to be more in line for
kernel coding guidelines and rebased the code on Paulo's DP patchset
v3: removing unecessary identation at DP_RECEIVER_CAP_SIZE
v4: moving them to include/drm/drm_dp_helper.h and also already
    icluding EDP_PSR_RECEIVER_CAP_SIZE to add everything needed
    for PSR at once at drm_dp_helper.h
v5: Fix SDP VSC header and identation by (Paulo Zanoni) and
    remove i915 from title (Daniel Vetter)
v6: Fix spec version and move comments from code to commit message
    since numbers might change in the future (by Paulo Zanoni).

CC: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Sateesh Kavuri <sateesh.kavuri@intel.com>
Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 include/drm/drm_dp_helper.h | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index e8e1417..ae8dbfb 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -342,13 +342,42 @@ u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
 u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
 					  int lane);
 
-#define DP_RECEIVER_CAP_SIZE	0xf
+#define DP_RECEIVER_CAP_SIZE		0xf
+#define EDP_PSR_RECEIVER_CAP_SIZE	2
+
 void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 
 u8 drm_dp_link_rate_to_bw_code(int link_rate);
 int drm_dp_bw_code_to_link_rate(u8 link_bw);
 
+struct edp_sdp_header {
+	u8 HB0; /* Secondary Data Packet ID */
+	u8 HB1; /* Secondary Data Packet Type */
+	u8 HB2; /* 7:5 reserved, 4:0 revision number */
+	u8 HB3; /* 7:5 reserved, 4:0 number of valid data bytes */
+} __packed;
+
+#define EDP_SDP_HEADER_REVISION_MASK		0x1F
+#define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES	0x1F
+
+struct edp_vsc_psr {
+	struct edp_sdp_header sdp_header;
+	u8 DB0; /* Stereo Interface */
+	u8 DB1; /* 0 - PSR State; 1 - Update RFB; 2 - CRC Valid */
+	u8 DB2; /* CRC value bits 7:0 of the R or Cr component */
+	u8 DB3; /* CRC value bits 15:8 of the R or Cr component */
+	u8 DB4; /* CRC value bits 7:0 of the G or Y component */
+	u8 DB5; /* CRC value bits 15:8 of the G or Y component */
+	u8 DB6; /* CRC value bits 7:0 of the B or Cb component */
+	u8 DB7; /* CRC value bits 15:8 of the B or Cb component */
+	u8 DB8_31[24]; /* Reserved */
+} __packed;
+
+#define EDP_VSC_PSR_STATE_ACTIVE	(1<<0)
+#define EDP_VSC_PSR_UPDATE_RFB		(1<<1)
+#define EDP_VSC_PSR_CRC_VALUES_VALID	(1<<2)
+
 static inline int
 drm_dp_max_link_rate(u8 dpcd[DP_RECEIVER_CAP_SIZE])
 {
-- 
1.8.1.4

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

* [PATCH] drm/i915: Read the EDP DPCD and PSR Capability
  2013-06-14 16:42   ` Paulo Zanoni
@ 2013-06-25  1:58     ` Rodrigo Vivi
  0 siblings, 0 replies; 21+ messages in thread
From: Rodrigo Vivi @ 2013-06-25  1:58 UTC (permalink / raw)
  To: intel-gfx

From: Shobhit Kumar <shobhit.kumar@intel.com>

v2: reuse of just created is_edp_psr and put it at right place.
v3: move is_edp_psr above intel_edp_disable

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/intel_dp.c  | 13 +++++++++++++
 drivers/gpu/drm/i915/intel_drv.h |  1 +
 2 files changed, 14 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 759a1c5..5332186 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1342,6 +1342,12 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
 	pipe_config->adjusted_mode.flags |= flags;
 }
 
+static bool is_edp_psr(struct intel_dp *intel_dp)
+{
+	return (is_edp(intel_dp) &&
+		(intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED));
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -2255,6 +2261,13 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
 	if (intel_dp->dpcd[DP_DPCD_REV] == 0)
 		return false; /* DPCD not present */
 
+	/* Check if the panel supports PSR */
+	memset(intel_dp->psr_dpcd, 0, sizeof(intel_dp->psr_dpcd));
+	intel_dp_aux_native_read_retry(intel_dp, DP_PSR_SUPPORT,
+				       intel_dp->psr_dpcd,
+				       sizeof(intel_dp->psr_dpcd));
+	if (is_edp_psr(intel_dp))
+		DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
 	if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
 	      DP_DWN_STRM_PORT_PRESENT))
 		return true; /* native DP sink */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0445d8c..18d9dea 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -470,6 +470,7 @@ struct intel_dp {
 	uint8_t link_bw;
 	uint8_t lane_count;
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
+	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
 	struct i2c_adapter adapter;
 	struct i2c_algo_dp_aux_data algo;
-- 
1.8.1.4

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

end of thread, other threads:[~2013-06-25  1:58 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-12 20:55 [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 02/13] drm/i915: Read the EDP DPCD and PSR Capability Rodrigo Vivi
2013-06-14 16:42   ` Paulo Zanoni
2013-06-25  1:58     ` [PATCH] " Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 03/13] drm/i915: VBT Parsing for the PSR Feature Block for HSW Rodrigo Vivi
2013-06-13 13:41   ` Chris Wilson
2013-06-14 17:02   ` Paulo Zanoni
2013-06-12 20:55 ` [PATCH 04/13] drm/i915: split aux_clock_divider logic in a separated function for reuse Rodrigo Vivi
2013-06-14 17:18   ` Paulo Zanoni
2013-06-12 20:55 ` [PATCH 05/13] drm/i915: Enable/Disable PSR Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 06/13] drm/i915: Added debugfs support for PSR Status Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 07/13] drm/i915: Match all PSR mode entry conditions before enabling it Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 08/13] drm/i915: Hook PSR functionality Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 09/13] drm/i915: add update function to disable/enable-back PSR Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 10/13] drm/intel: add enable_psr module option Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 11/13] drm/i915: PSR: Make a clear separation between Sink (Panel) and Source (HW) enabling Rodrigo Vivi
2013-06-13 13:01   ` Daniel Vetter
2013-06-12 20:55 ` [PATCH 12/13] drm/i915: Adding global I915_PARAM for PSR ACTIVE Rodrigo Vivi
2013-06-12 20:55 ` [PATCH 13/13] drm/i915: force psr exit when busy Rodrigo Vivi
2013-06-14 16:21 ` [PATCH 01/13] drm: Added SDP and VSC structures for handling PSR for eDP Paulo Zanoni
2013-06-25  1:56   ` [PATCH] " Rodrigo Vivi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.