On Thu, Sep 29, 2022 at 04:17:43PM +0300, Mika Kahola wrote:
From: Radhakrishna Sripada <radhakrishna.srip...@intel.com>

XELPDP has C10 and C20 phys from Synopsys to drive displays. Each phy
has a dedicated PIPE 5.2 Message bus for configuration. This message
bus is used to configure the phy internal registers.

Bspec: 64599, 65100, 65101, 67610, 67636

Cc: Mika Kahola <mika.kah...@intel.com>
Cc: Imre Deak <imre.d...@intel.com>
Cc: Uma Shankar <uma.shan...@intel.com>
Signed-off-by: Radhakrishna Sripada <radhakrishna.srip...@intel.com>
Signed-off-by: Mika Kahola <mika.kah...@intel.com> (v4)
---
drivers/gpu/drm/i915/display/intel_cx0_phy.c | 179 +++++++++++++++++++
1 file changed, 179 insertions(+)
create mode 100644 drivers/gpu/drm/i915/display/intel_cx0_phy.c

diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c 
b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
new file mode 100644
index 000000000000..7930b0255cfa
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#include "intel_de.h"
+#include "intel_uncore.h"
+
+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),
+                      XELPDP_PORT_M2P_TRANSACTION_RESET);
+
+       /* Wait for Idle Clear. */
+       if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, 
lane),
+                                   XELPDP_PORT_M2P_TRANSACTION_RESET,
+                                   XELPDP_MSGBUS_TIMEOUT_SLOW)) {
+               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), ~0);
+       return;
+}
+
+__maybe_unused 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);
+       u32 val = 0;
+       int attempts = 0;
+
+retry:
+       if (attempts == 3) {
+               drm_err_once(&i915->drm, "PHY %c Read %04x failed after %d retries. 
Status: 0x%x\n", phy_name(phy), addr, attempts, val ?: 0);
+               return 0;
+       }
+
+       /* 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(&i915->drm, "PHY %c Timeout waiting for previous transaction 
to complete. Reset the bus and retry.\n", phy_name(phy));
+               attempts++;
+               intel_cx0_bus_reset(i915, port, lane);
+               goto retry;
+       }
+
+       /* Issue the read command. */
+       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.*/
+       if (__intel_wait_for_register(&i915->uncore,
+                                     XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane),
+                                     XELPDP_PORT_P2M_RESPONSE_READY,
+                                     XELPDP_PORT_P2M_RESPONSE_READY,
+                                     XELPDP_MSGBUS_TIMEOUT_FAST_US,
+                                     XELPDP_MSGBUS_TIMEOUT_SLOW, &val)) {
+               drm_dbg(&i915->drm, "PHY %c Timeout waiting for Read response ACK. 
Status: 0x%x\n", phy_name(phy), val);
+               attempts++;
+               intel_cx0_bus_reset(i915, port, lane);
+               goto retry;
+       }
+
+       /* Check for error. */
+       if (val & XELPDP_PORT_P2M_ERROR_SET) {
+               drm_dbg(&i915->drm, "PHY %c Error occurred during read command. 
Status: 0x%x\n", phy_name(phy), val);
+               attempts++;
+               intel_cx0_bus_reset(i915, port, lane);
+               goto retry;
+       }
+
+       /* Check for Read Ack. */
+       if (REG_FIELD_GET(XELPDP_PORT_P2M_COMMAND_TYPE_MASK, val) !=
+           XELPDP_PORT_P2M_COMMAND_READ_ACK) {
+               drm_dbg(&i915->drm, "PHY %c Not a Read response. MSGBUS Status: 
0x%x.\n", phy_name(phy), val);
+               attempts++;
+               intel_cx0_bus_reset(i915, port, lane);
+               goto retry;
+       }
+
+       /* Clear Response Ready flag.*/
+       intel_de_write(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane), ~0);
+       return (u8)REG_FIELD_GET(XELPDP_PORT_P2M_DATA_MASK, val);
+}
+
+static int intel_cx0_wait_cwrite_ack(struct drm_i915_private *i915,
+                                     enum port port, int lane)
+{
+       enum phy phy = intel_port_to_phy(i915, port);
+       u32 val;
+
+       /* Check for write ack. */
+       if (__intel_wait_for_register(&i915->uncore,
+                                     XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane),
+                                     XELPDP_PORT_P2M_RESPONSE_READY,
+                                     XELPDP_PORT_P2M_RESPONSE_READY,
+                                     XELPDP_MSGBUS_TIMEOUT_FAST_US,
+                                     XELPDP_MSGBUS_TIMEOUT_SLOW, &val)) {
+               drm_dbg(&i915->drm, "PHY %c Timeout waiting for Committed message 
ACK. Status: 0x%x\n", phy_name(phy), val);
+               return -ETIMEDOUT;
+       }
+
+       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(&i915->drm, "PHY %c Unexpected ACK received. MSGBUS STATUS: 
0x%x.\n", phy_name(phy), val);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+__maybe_unused static void intel_cx0_write(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);
+       int attempts = 0;
+
+retry:
+       if (attempts == 3) {
+               drm_err_once(&i915->drm, "PHY %c Write %04x failed after %d 
retries.\n", phy_name(phy), addr, attempts);
+               return;
+       }
+
+       /* 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(&i915->drm, "PHY %c Timeout waiting for previous transaction 
to complete. Reset the bus and retry.\n", phy_name(phy));
+               attempts++;
+               intel_cx0_bus_reset(i915, port, lane);
+               goto retry;
+       }
+
+       /* Issue the write command. */
+       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));
+
+       /* Check for error. */
+       if (committed) {
+               if (intel_cx0_wait_cwrite_ack(i915, port, lane) < 0) {
+                       attempts++;
+                       intel_cx0_bus_reset(i915, port, lane);
+                       goto retry;
+               }
+       } else if ((intel_de_read(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(phy, lane)) 
&


wrong argument here to XELPDP_PORT_P2M_MSGBUS_STATUS(). It should be
port, not phy.

Lucas De Marchi

Reply via email to