Commit 51390cc0 authored by Radhakrishna Sripada's avatar Radhakrishna Sripada
Browse files

drm/i915/mtl: Add Support for C10 PHY message bus and pll programming



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.

XELPDP has C10 phys to drive output to the EDP and the native output
from the display engine. Add structures, programming hardware state
readout logic. Port clock calculations are similar to DG2. Use the DG2
formulae to calculate the port clock but use the relevant pll signals.
Note: PHY lane 0 is always used for PLL programming.

Add sequences for C10 phy enable/disable phy lane reset,
powerdown change sequence and phy lane programming.

Bspec: 64539, 64568, 64599, 65100, 65101, 65450, 65451, 67610, 67636

v2: Squash patches related to C10 phy message bus and pll
    programming support (Jani)
    Move register definitions to a new file i.e. intel_cx0_reg_defs.h (Jani)
    Move macro definitions (Jani)
    DP rates as separate patch (Jani)
    Spin out xelpdp register definitions into a separate file (Jani)
    Replace macro to select registers based on phy lane with
    function calls (Jani)
    Fix styling issues (Jani)
    Call XELPDP_PORT_P2M_MSGBUS_STATUS() with port instead of phy (Lucas)
v3: Move clear request flag into try-loop
v4: On PHY idle change drm_err_once() as drm_dbg_kms() (Jani)
    use __intel_de_wait_for_register() instead of __intel_wait_for_register
    and uncomment intel_uncore.h (Jani)
    Add DP-alt support for PHY lane programming (Khaled)
v4: Add tx and cmn on c10mpllb_state (Imre)
    Add missing waits for pending transactions between two message bus
    writes (Imre)
    General cleanups and simplifications (Imre)
v5: Few nit cleanups from rev4 (imre)
    s/dev_priv/i915/ , s/c10mpllb/c10pll/ (RK)
    Rebase
v6: Move the mtl code from intel_c10pll_calc_port_clock to mtl function
    Fix typo in comment for REG_FIELD_PREP8 definition(Imre)

Cc: Mika Kahola <mika.kahola@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Uma Shankar <uma.shankar@intel.com>
Cc: Gustavo Sousa <gustavo.sousa@intel.com>
Signed-off-by: default avatarRadhakrishna Sripada <radhakrishna.sripada@intel.com>
Signed-off-by: default avatarMika Kahola <mika.kahola@intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com> (v4)
Link: https://patchwork.freedesktop.org/patch/msgid/20230413212443.1504245-4-radhakrishna.sripada@intel.com
parent a42e65f3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -298,6 +298,7 @@ i915-y += \
	display/icl_dsi.o \
	display/intel_backlight.o \
	display/intel_crt.o \
	display/intel_cx0_phy.o \
	display/intel_ddi.o \
	display/intel_ddi_buf_trans.o \
	display/intel_display_trace.o \
+1207 −0

File added.

Preview size limit exceeded, changes collapsed.

+34 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: MIT
/*
 * Copyright © 2023 Intel Corporation
 */

#ifndef __INTEL_CX0_PHY_H__
#define __INTEL_CX0_PHY_H__

#include <linux/types.h>
#include <linux/bitfield.h>
#include <linux/bits.h>

#include "i915_drv.h"
#include "intel_display_types.h"

struct drm_i915_private;
struct intel_encoder;
struct intel_crtc_state;
enum phy;

bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy);
void intel_cx0pll_enable(struct intel_encoder *encoder,
			 const struct intel_crtc_state *crtc_state);
void intel_cx0pll_disable(struct intel_encoder *encoder);
void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, struct intel_c10pll_state *pll_state);
int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder);
void intel_c10pll_dump_hw_state(struct drm_i915_private *dev_priv,
				const struct intel_c10pll_state *hw_state);
int intel_c10pll_calc_port_clock(struct intel_encoder *encoder,
				 const struct intel_c10pll_state *pll_state);
void intel_c10pll_state_verify(struct intel_atomic_state *state,
			       struct intel_crtc_state *new_crtc_state);

#endif /* __INTEL_CX0_PHY_H__ */
+38 −9
Original line number Diff line number Diff line
@@ -96,6 +96,11 @@
#define   XELPDP_PLL_LANE_STAGGERING_DELAY(val)		REG_FIELD_PREP(XELPDP_PLL_LANE_STAGGERING_DELAY_MASK, val)
#define   XELPDP_POWER_STATE_ACTIVE_MASK		REG_GENMASK(3, 0)
#define   XELPDP_POWER_STATE_ACTIVE(val)		REG_FIELD_PREP(XELPDP_POWER_STATE_ACTIVE_MASK, val)
#define   CX0_P0_STATE_ACTIVE				0x0
#define   CX0_P2_STATE_READY				0x2
#define   CX0_P2PG_STATE_DISABLE			0x9
#define   CX0_P4PG_STATE_DISABLE			0xC
#define   CX0_P2_STATE_RESET				0x2

#define _XELPDP_PORT_CLOCK_CTL_A			0x640E0
#define _XELPDP_PORT_CLOCK_CTL_B			0x641E0
@@ -106,14 +111,11 @@
										 _XELPDP_PORT_CLOCK_CTL_B, \
										 _XELPDP_PORT_CLOCK_CTL_USBC1, \
										 _XELPDP_PORT_CLOCK_CTL_USBC2))
#define   XELPDP_LANE0_PCLK_PLL_REQUEST			REG_BIT(31)
#define   XELPDP_LANE0_PCLK_PLL_ACK			REG_BIT(30)
#define   XELPDP_LANE0_PCLK_REFCLK_REQUEST		REG_BIT(29)
#define   XELPDP_LANE0_PCLK_REFCLK_ACK			REG_BIT(28)
#define   XELPDP_LANE1_PCLK_PLL_REQUEST			REG_BIT(27)
#define   XELPDP_LANE1_PCLK_PLL_ACK			REG_BIT(26)
#define   XELPDP_LANE1_PCLK_REFCLK_REQUEST		REG_BIT(25)
#define   XELPDP_LANE1_PCLK_REFCLK_ACK			REG_BIT(24)
#define   XELPDP_LANE_PCLK_PLL_REQUEST(lane)		REG_BIT(31 - ((lane) * 4))
#define   XELPDP_LANE_PCLK_PLL_ACK(lane)		REG_BIT(30 - ((lane) * 4))
#define   XELPDP_LANE_PCLK_REFCLK_REQUEST(lane)		REG_BIT(29 - ((lane) * 4))
#define   XELPDP_LANE_PCLK_REFCLK_ACK(lane)		REG_BIT(28 - ((lane) * 4))

#define   XELPDP_TBT_CLOCK_REQUEST			REG_BIT(19)
#define   XELPDP_TBT_CLOCK_ACK				REG_BIT(18)
#define   XELPDP_DDI_CLOCK_SELECT_MASK			REG_GENMASK(15, 12)
@@ -130,4 +132,31 @@
#define   XELPDP_SSC_ENABLE_PLLA			REG_BIT(1)
#define   XELPDP_SSC_ENABLE_PLLB			REG_BIT(0)

#endif /* __INTEL_CX0_PHY_REGS_H__ */
/* C10 Vendor Registers */
#define PHY_C10_VDR_PLL(idx)		(0xC00 + (idx))
#define   C10_PLL0_FRACEN		REG_BIT8(4)
#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_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))
#define   C10_TX0_TX_MPLLB_SEL		REG_BIT(4)
#define PHY_C10_VDR_CONTROL(idx)	(0xC70 + (idx) - 1)
#define   C10_VDR_CTRL_MSGBUS_ACCESS	REG_BIT8(2)
#define   C10_VDR_CTRL_MASTER_LANE	REG_BIT8(1)
#define   C10_VDR_CTRL_UPDATE_CFG	REG_BIT8(0)
#define PHY_C10_VDR_CUSTOM_WIDTH	0xD02
#define   C10_VDR_CUSTOM_WIDTH_MASK    REG_GENMASK(1, 0)
#define   C10_VDR_CUSTOM_WIDTH_8_10    REG_FIELD_PREP(C10_VDR_CUSTOM_WIDTH_MASK, 0)

/* PHY_C10_VDR_PLL0 */
#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)

#endif /* __INTEL_CX0_REG_DEFS_H__ */
+21 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include "intel_combo_phy_regs.h"
#include "intel_connector.h"
#include "intel_crtc.h"
#include "intel_cx0_phy.h"
#include "intel_ddi.h"
#include "intel_ddi_buf_trans.h"
#include "intel_de.h"
@@ -3488,6 +3489,21 @@ void intel_ddi_get_clock(struct intel_encoder *encoder,
						     &crtc_state->dpll_hw_state);
}

static void mtl_ddi_get_config(struct intel_encoder *encoder,
			       struct intel_crtc_state *crtc_state)
{
	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
	enum phy phy = intel_port_to_phy(i915, encoder->port);

	drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy));

	intel_c10pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10);
	intel_c10pll_dump_hw_state(i915, &crtc_state->cx0pll_state.c10);
	crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10);

	intel_ddi_get_config(encoder, crtc_state);
}

static void dg2_ddi_get_config(struct intel_encoder *encoder,
				struct intel_crtc_state *crtc_state)
{
@@ -4396,7 +4412,11 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
	encoder->cloneable = 0;
	encoder->pipe_mask = ~0;

	if (IS_DG2(dev_priv)) {
	if (DISPLAY_VER(dev_priv) >= 14) {
		encoder->enable_clock = intel_cx0pll_enable;
		encoder->disable_clock = intel_cx0pll_disable;
		encoder->get_config = mtl_ddi_get_config;
	} else if (IS_DG2(dev_priv)) {
		encoder->enable_clock = intel_mpllb_enable;
		encoder->disable_clock = intel_mpllb_disable;
		encoder->get_config = dg2_ddi_get_config;
Loading