[PATCH 5/7] c10 msgbus fixes

Mika Kahola mika.kahola at intel.com
Tue Apr 4 07:30:53 UTC 2023


Signed-off-by: Mika Kahola <mika.kahola at intel.com>
---
 drivers/gpu/drm/i915/display/intel_cx0_phy.c | 174 +++++++++++--------
 drivers/gpu/drm/i915/display/intel_cx0_phy.h |  11 +-
 2 files changed, 104 insertions(+), 81 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
index ced8c8aa6c82..768fa07a8e69 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -12,6 +12,9 @@
 #include "intel_panel.h"
 #include "intel_tc.h"
 
+#define MB_WRITE_COMMITTED      1
+#define MB_WRITE_UNCOMMITTED    0
+
 bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy)
 {
 	if (IS_METEORLAKE(dev_priv) && (phy < PHY_C))
@@ -20,31 +23,51 @@ bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy)
 	return false;
 }
 
+static int lane_mask_to_lane(u8 lane_mask)
+{
+	if (lane_mask == INTEL_CX0_LANE0)
+		return 0;
+	else if (lane_mask == INTEL_CX0_LANE1)
+		return 1;
+	else
+		return -EINVAL;
+}
+
+static void intel_clear_response_ready_flag(struct drm_i915_private *i915,
+					    enum port port, int lane)
+{
+	intel_de_rmw(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane),
+		     XELPDP_PORT_P2M_RESPONSE_READY, 0);
+	intel_de_rmw(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane),
+		     XELPDP_PORT_P2M_ERROR_SET, 0);
+}
+
 static void intel_cx0_bus_reset(struct drm_i915_private *i915, enum port port, int lane)
 {
 	enum phy phy = intel_port_to_phy(i915, port);
 
 	/* Bring the phy to idle. */
-	intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane - 1),
+	intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
 		       XELPDP_PORT_M2P_TRANSACTION_RESET);
 
 	/* Wait for Idle Clear. */
-	if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane - 1),
+	if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
 				    XELPDP_PORT_M2P_TRANSACTION_RESET,
 				    XELPDP_MSGBUS_TIMEOUT_SLOW)) {
-		drm_dbg_kms(&i915->drm, "Failed to bring PHY %c to idle.\n", phy_name(phy));
+		drm_err_once(&i915->drm, "Failed to bring PHY %c to idle.\n", phy_name(phy));
 		return;
 	}
 
-	intel_de_write(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane - 1), ~0);
+	intel_clear_response_ready_flag(i915, port, lane);
 }
 
-static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port, int lane, u32 *val)
+static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port,
+				  int command, int lane, u32 *val)
 {
 	enum phy phy = intel_port_to_phy(i915, port);
 
 	if (__intel_de_wait_for_register(i915,
-					 XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane - 1),
+					 XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane),
 					 XELPDP_PORT_P2M_RESPONSE_READY,
 					 XELPDP_PORT_P2M_RESPONSE_READY,
 					 XELPDP_MSGBUS_TIMEOUT_FAST_US,
@@ -53,17 +76,34 @@ static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port,
 		return -ETIMEDOUT;
 	}
 
+	/* Check for error. */
+	if (*val & XELPDP_PORT_P2M_ERROR_SET) {
+		drm_dbg_kms(&i915->drm, "PHY %c Error occurred during %s command. Status: 0x%x\n",
+			    phy_name(phy), command == XELPDP_PORT_P2M_COMMAND_READ_ACK ? "read" : "write", *val);
+		intel_cx0_bus_reset(i915, port, lane);
+		return -EINVAL;
+	}
+
+	/* Check for Read/Write Ack. */
+	if (REG_FIELD_GET(XELPDP_PORT_P2M_COMMAND_TYPE_MASK, *val) != command) {
+		drm_dbg_kms(&i915->drm, "PHY %c Not a %s response. MSGBUS Status: 0x%x.\n",
+			    phy_name(phy), command == XELPDP_PORT_P2M_COMMAND_READ_ACK ? "read" : "write", *val);
+		intel_cx0_bus_reset(i915, port, lane);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
-static int __intel_cx0_read(struct drm_i915_private *i915, enum port port,
-			   int lane, u16 addr, u32 *val)
+static int __intel_cx0_read_once(struct drm_i915_private *i915, enum port port,
+			         int lane, u16 addr)
 {
 	enum phy phy = intel_port_to_phy(i915, port);
 	int ack;
+	u32 val;
 
 	/* Wait for pending transactions.*/
-	if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane - 1),
+	if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
 				    XELPDP_PORT_M2P_TRANSACTION_PENDING,
 				    XELPDP_MSGBUS_TIMEOUT_SLOW)) {
 		drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for previous transaction to complete. Reset the bus and retry.\n", phy_name(phy));
@@ -72,118 +112,105 @@ static int __intel_cx0_read(struct drm_i915_private *i915, enum port port,
 	}
 
 	/* Issue the read command. */
-	intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane - 1),
+	intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
 		       XELPDP_PORT_M2P_TRANSACTION_PENDING |
 		       XELPDP_PORT_M2P_COMMAND_READ |
 		       XELPDP_PORT_M2P_ADDRESS(addr));
 
 	/* Wait for response ready. And read response.*/
-	ack = intel_cx0_wait_for_ack(i915, port, lane, val);
+	ack = intel_cx0_wait_for_ack(i915, port, XELPDP_PORT_P2M_COMMAND_READ_ACK, lane, &val);
 	if (ack < 0) {
 		intel_cx0_bus_reset(i915, port, lane);
 		return ack;
 	}
 
-	/* Check for error. */
-	if (*val & XELPDP_PORT_P2M_ERROR_SET) {
-		drm_dbg_kms(&i915->drm, "PHY %c Error occurred during read command. Status: 0x%x\n", phy_name(phy), *val);
-		intel_cx0_bus_reset(i915, port, lane);
-		return -EINVAL;
-	}
-
-	/* Check for Read Ack. */
-	if (REG_FIELD_GET(XELPDP_PORT_P2M_COMMAND_TYPE_MASK, *val) !=
-			  XELPDP_PORT_P2M_COMMAND_READ_ACK) {
-		drm_dbg_kms(&i915->drm, "PHY %c Not a Read response. MSGBUS Status: 0x%x.\n", phy_name(phy), *val);
-		intel_cx0_bus_reset(i915, port, lane);
-		return -EINVAL;
-	}
-
 	/* Clear Response Ready flag.*/
-	intel_de_write(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane - 1), ~0);
+	intel_clear_response_ready_flag(i915, port, lane);
 
-	return REG_FIELD_GET(XELPDP_PORT_P2M_DATA_MASK, *val);
+	return REG_FIELD_GET(XELPDP_PORT_P2M_DATA_MASK, val);
 }
 
-static u8 intel_cx0_read(struct drm_i915_private *i915, enum port port,
-			 int lane, u16 addr)
+static u8 __intel_cx0_read(struct drm_i915_private *i915, enum port port,
+			   int lane, u16 addr)
 {
 	enum phy phy = intel_port_to_phy(i915, port);
 	int i, status = 0;
-	u32 val;
 
+	/* 3 tries is assumed to be enough to read successfully */
 	for (i = 0; i < 3; i++) {
-		status = __intel_cx0_read(i915, port, lane, addr, &val);
+		status = __intel_cx0_read_once(i915, port, lane, addr);
 
 		if (status >= 0)
-			break;
+			return status;
 	}
 
-	if (i == 3) {
+	if (i == 3)
 		drm_err_once(&i915->drm, "PHY %c Read %04x failed after %d retries.\n", phy_name(phy), addr, i);
-		return 0;
-	}
 
 	return status;
 }
 
-static int intel_cx0_wait_cwrite_ack(struct drm_i915_private *i915,
-				      enum port port, int lane)
+static u8 intel_cx0_read(struct drm_i915_private *i915, enum port port,
+			 u8 lane_mask, u16 addr)
 {
 	enum phy phy = intel_port_to_phy(i915, port);
-	int ack;
-	u32 val = 0;
-
-	/* Check for write ack. */
-	ack = intel_cx0_wait_for_ack(i915, port, lane, &val);
-	if (ack < 0)
-		return ack;
+	int lane = lane_mask_to_lane(lane_mask);
 
-	if ((REG_FIELD_GET(XELPDP_PORT_P2M_COMMAND_TYPE_MASK, val) !=
-	     XELPDP_PORT_P2M_COMMAND_WRITE_ACK) || val & XELPDP_PORT_P2M_ERROR_SET) {
-		drm_dbg_kms(&i915->drm, "PHY %c Unexpected ACK received. MSGBUS STATUS: 0x%x.\n", phy_name(phy), val);
-		return -EINVAL;
+	if (lane < 0) {
+		drm_err_once(&i915->drm, "PHY %c incorrect lane.\n", phy_name(phy));
+		return lane;
 	}
 
-	return 0;
+	return __intel_cx0_read(i915, port, lane, addr);
 }
 
 static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port,
 				  int lane, u16 addr, u8 data, bool committed)
 {
 	enum phy phy = intel_port_to_phy(i915, port);
+	u32 val;
 
-	/* Wait for pending transactions.*/
-	if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane - 1),
+	/* Wait for pending transactions */
+	if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
 				    XELPDP_PORT_M2P_TRANSACTION_PENDING,
 				    XELPDP_MSGBUS_TIMEOUT_SLOW)) {
-		drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for previous transaction to complete. Reset the bus and retry.\n", phy_name(phy));
+		drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for previous transaction to complete. Resetting the bus.\n", phy_name(phy));
 		intel_cx0_bus_reset(i915, port, lane);
 		return -ETIMEDOUT;
 	}
 
 	/* Issue the write command. */
-	intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane - 1),
+	intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
 		       XELPDP_PORT_M2P_TRANSACTION_PENDING |
 		       (committed ? XELPDP_PORT_M2P_COMMAND_WRITE_COMMITTED :
 		       XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED) |
 		       XELPDP_PORT_M2P_DATA(data) |
 		       XELPDP_PORT_M2P_ADDRESS(addr));
 
+	/* Wait for pending transactions.*/
+	if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane),
+				    XELPDP_PORT_M2P_TRANSACTION_PENDING,
+				    XELPDP_MSGBUS_TIMEOUT_SLOW)) {
+		drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for previous transaction to complete. Resetting the bus.\n", phy_name(phy));
+		intel_cx0_bus_reset(i915, port, lane);
+		return -ETIMEDOUT;
+	}
+
 	/* Check for error. */
 	if (committed) {
-		if (intel_cx0_wait_cwrite_ack(i915, port, lane) < 0) {
+		if (intel_cx0_wait_for_ack(i915, port, XELPDP_PORT_P2M_COMMAND_WRITE_ACK, lane, &val) < 0) {
 			intel_cx0_bus_reset(i915, port, lane);
 			return -EINVAL;
 		}
-	} else if ((intel_de_read(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane - 1)) &
+	} else if ((intel_de_read(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane)) &
 			    XELPDP_PORT_P2M_ERROR_SET)) {
 		drm_dbg_kms(&i915->drm, "PHY %c Error occurred during write command.\n", phy_name(phy));
 		intel_cx0_bus_reset(i915, port, lane);
 		return -EINVAL;
 	}
 
-	intel_de_write(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane - 1), ~0);
+	/* Clear Response Ready flag.*/
+	intel_clear_response_ready_flag(i915, port, lane);
 
 	return 0;
 }
@@ -194,28 +221,25 @@ static void __intel_cx0_write(struct drm_i915_private *i915, enum port port,
 	enum phy phy = intel_port_to_phy(i915, port);
 	int i, status;
 
+	/* 3 tries is assumed to be enough to write successfully */
 	for (i = 0; i < 3; i++) {
 		status = __intel_cx0_write_once(i915, port, lane, addr, data, committed);
 
 		if (status == 0)
-			break;
+			return;
 	}
 
-	if (i == 3) {
+	if (i == 3)
 		drm_err_once(&i915->drm, "PHY %c Write %04x failed after %d retries.\n", phy_name(phy), addr, i);
-		return;
-	}
 }
 
 static void intel_cx0_write(struct drm_i915_private *i915, enum port port,
-			    int lane, u16 addr, u8 data, bool committed)
+			    u8 lane_mask, u16 addr, u8 data, bool committed)
 {
-	if (lane == INTEL_CX0_BOTH_LANES) {
-		__intel_cx0_write(i915, port, INTEL_CX0_LANE0, addr, data, committed);
-		__intel_cx0_write(i915, port, INTEL_CX0_LANE1, addr, data, committed);
-	} else {
+	int lane;
+
+	for_each_cx0_lane_in_mask(lane, lane_mask)
 		__intel_cx0_write(i915, port, lane, addr, data, committed);
-	}
 }
 
 static void __intel_cx0_rmw(struct drm_i915_private *i915, enum port port,
@@ -223,22 +247,20 @@ static void __intel_cx0_rmw(struct drm_i915_private *i915, enum port port,
 {
 	u8 old, val;
 
-	old = intel_cx0_read(i915, port, lane, addr);
+	old = intel_cx0_read(i915, port, lane + 1, addr);
 	val = (old & ~clear) | set;
 
 	if (val != old)
-		intel_cx0_write(i915, port, lane, addr, val, committed);
+		__intel_cx0_write(i915, port, lane, addr, val, committed);
 }
 
 static void intel_cx0_rmw(struct drm_i915_private *i915, enum port port,
-			  int lane, u16 addr, u8 clear, u8 set, bool committed)
+			  u8 lane_mask, u16 addr, u8 clear, u8 set, bool committed)
 {
-	if (lane == INTEL_CX0_BOTH_LANES) {
-		__intel_cx0_rmw(i915, port, INTEL_CX0_LANE0, addr, clear, set, committed);
-		__intel_cx0_rmw(i915, port, INTEL_CX0_LANE1, addr, clear, set, committed);
-	} else {
+	u8 lane;
+
+	for_each_cx0_lane_in_mask(lane, lane_mask)
 		__intel_cx0_rmw(i915, port, lane, addr, clear, set, committed);
-	}
 }
 
 /*
@@ -512,7 +534,7 @@ static int intel_c10mpllb_calc_state(struct intel_crtc_state *crtc_state,
 		return -EINVAL;
 
 	for (i = 0; tables[i]; i++) {
-		if (crtc_state->port_clock <= tables[i]->clock) {
+		if (crtc_state->port_clock == tables[i]->clock) {
 			crtc_state->c10mpllb_state = *tables[i];
 			return 0;
 		}
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
index 8cf340509097..09f70df5c69f 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
@@ -18,12 +18,13 @@ struct intel_encoder;
 struct intel_crtc_state;
 enum phy;
 
-#define INTEL_CX0_LANE0		0x1
-#define INTEL_CX0_LANE1		0x2
-#define INTEL_CX0_BOTH_LANES	0x3
+#define for_each_cx0_lane_in_mask(__lane, __lane_mask) \
+        for ((__lane) = 0; (__lane) < 3; (__lane)++) \
+                for_each_if((__lane_mask) & BIT(__lane))
 
-#define MB_WRITE_COMMITTED		1
-#define MB_WRITE_UNCOMMITTED		0
+#define INTEL_CX0_LANE0		BIT(0)
+#define INTEL_CX0_LANE1		BIT(1)
+#define INTEL_CX0_BOTH_LANES	(INTEL_CX0_LANE1 | INTEL_CX0_LANE0)
 
 bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy);
 void intel_cx0pll_enable(struct intel_encoder *encoder,
-- 
2.34.1



More information about the Intel-gfx-trybot mailing list