[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