[PATCH 6/8] c10 msgbus fixes
Mika Kahola
mika.kahola at intel.com
Tue Apr 4 10:32:35 UTC 2023
Signed-off-by: Mika Kahola <mika.kahola at intel.com>
---
drivers/gpu/drm/i915/display/intel_cx0_phy.c | 198 ++++++++++--------
drivers/gpu/drm/i915/display/intel_cx0_phy.h | 11 +-
.../gpu/drm/i915/display/intel_cx0_phy_regs.h | 7 +-
3 files changed, 120 insertions(+), 96 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..c2ffa4797ca2 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;
+
+ 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;
+ int i, status;
+ /* 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;
+ return 0;
}
-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;
+ int lane = lane_mask_to_lane(lane_mask);
- /* Check for write ack. */
- ack = intel_cx0_wait_for_ack(i915, port, lane, &val);
- if (ack < 0)
- return ack;
-
- 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, "Incorrect lane for PHY %c\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_mask, lane)
__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, 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_mask, lane)
__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;
}
@@ -558,9 +580,9 @@ void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder,
cmn = intel_cx0_read(i915, encoder->port, lane, PHY_C10_VDR_CMN(0));
tx0 = intel_cx0_read(i915, encoder->port, lane, PHY_C10_VDR_TX(0));
- if (tx0 != C10_TX0_VAL || cmn != C10_CMN0_DP_VAL)
- drm_warn(&i915->drm, "Unexpected tx: %x or cmn: %x for phy: %c.\n",
- tx0, cmn, phy_name(phy));
+ if (tx0 != C10_TX0_VAL || cmn != (C10_CMN0_REF_RANGE | C10_CMN0_REF_CLK_MPLLB_DIV))
+ drm_dbg_kms(&i915->drm, "Unexpected tx: %x or cmn: %x for phy: %c.\n",
+ tx0, cmn, phy_name(phy));
}
static void intel_c10_pll_program(struct drm_i915_private *i915,
@@ -570,8 +592,6 @@ static void intel_c10_pll_program(struct drm_i915_private *i915,
const struct intel_c10mpllb_state *pll_state = &crtc_state->c10mpllb_state;
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
- u8 master_lane = lane_reversal ? INTEL_CX0_LANE1 :
- INTEL_CX0_LANE0;
u8 follower_lane = lane_reversal ? INTEL_CX0_LANE0 :
INTEL_CX0_LANE1;
@@ -588,7 +608,9 @@ static void intel_c10_pll_program(struct drm_i915_private *i915,
if (!intel_panel_use_ssc(i915))
use_ssc = false;
- cmn0 = C10_CMN0_DP_VAL;
+ /* Using 38.4 MHz reference */
+ cmn0 = C10_CMN0_REF_RANGE |
+ C10_CMN0_REF_CLK_MPLLB_DIV;
}
intel_cx0_write(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1),
@@ -603,13 +625,13 @@ static void intel_c10_pll_program(struct drm_i915_private *i915,
/* Program the pll values only for the master lane */
for (i = 0; i < ARRAY_SIZE(pll_state->pll); i++)
/* If not using ssc pll[4] through pll[8] must be 0*/
- intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_PLL(i),
+ intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C10_VDR_PLL(i),
(!use_ssc && (i > 3 && i < 9)) ? 0 : pll_state->pll[i],
(i % 4) ? MB_WRITE_UNCOMMITTED : MB_WRITE_COMMITTED);
- intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_CMN(0), cmn0, MB_WRITE_COMMITTED);
- intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_TX(0), C10_TX0_VAL, MB_WRITE_COMMITTED);
- intel_cx0_rmw(i915, encoder->port, master_lane, PHY_C10_VDR_CONTROL(1),
+ intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C10_VDR_CMN(0), cmn0, MB_WRITE_COMMITTED);
+ intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C10_VDR_TX(0), C10_TX0_VAL, MB_WRITE_COMMITTED);
+ intel_cx0_rmw(i915, encoder->port, INTEL_CX0_LANE0, PHY_C10_VDR_CONTROL(1),
C10_VDR_CTRL_MSGBUS_ACCESS, C10_VDR_CTRL_MASTER_LANE |
C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED);
}
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
index 8cf340509097..385263ef40e2 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_mask, __lane) \
+ 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,
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
index 15e249f46a64..8b22e90c99d1 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
@@ -134,7 +134,8 @@
#define C10_PLL3_MULTIPLIERH_MASK REG_GENMASK8(3, 0)
#define C10_PLL15_TXCLKDIV_MASK REG_GENMASK8(2, 0)
#define PHY_C10_VDR_CMN(idx) (0xC20 + (idx))
-#define C10_CMN0_DP_VAL 0x21
+#define C10_CMN0_REF_RANGE REG_FIELD_PREP(REG_GENMASK(4, 0), 1)
+#define C10_CMN0_REF_CLK_MPLLB_DIV REG_FIELD_PREP(REG_GENMASK(7, 5), 1)
#define C10_CMN3_TXVBOOST_MASK REG_GENMASK8(7, 5)
#define C10_CMN3_TXVBOOST(val) REG_FIELD_PREP8(C10_CMN3_TXVBOOST_MASK, val)
#define PHY_C10_VDR_TX(idx) (0xC30 + (idx))
@@ -155,7 +156,7 @@
#define PLL_C10_MPLL_SSC_EN REG_BIT8(0)
/* PIPE SPEC Defined Registers */
-#define PHY_CX0_TX_CONTROL(tx, control) (0x400 + ((tx) - 1) * 0x200 + (control))
-#define CONTROL2_DISABLE_SINGLE_TX REG_BIT(6)
+#define PHY_CX0_TX_CONTROL(tx, control) (0x400 + ((tx) - 1) * 0x200 + (control))
+#define CONTROL2_DISABLE_SINGLE_TX REG_BIT(6)
#endif /* __INTEL_CX0_REG_DEFS_H__ */
--
2.34.1
More information about the Intel-gfx-trybot
mailing list