i + 2, hw_state->pll[i + 2], i + 3, hw_state->pll[i + 3]);
}
-static int intel_c20_compute_hdmi_tmds_pll(struct intel_crtc_state *crtc_state)
+/*
+ * Some ARLs SoCs have the same drm PCI IDs, so need a helper to differentiate based
+ * on the host bridge device ID to get the correct txx_mics value.
+ */
+static bool is_arrowlake_s_by_host_bridge(void)
+{
+ struct pci_dev *pdev = NULL;
+ u16 host_bridge_pci_dev_id;
+
+ while ((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, pdev)))
+ host_bridge_pci_dev_id = pdev->device;
+
+ return pdev && IS_ARROWLAKE_S_BY_HOST_BRIDGE_ID(host_bridge_pci_dev_id);
+}
+
+static u16 intel_c20_hdmi_tmds_tx_cgf_1(struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
+ u16 tx_misc;
+ u16 tx_dcc_cal_dac_ctrl_range = 8;
+ u16 tx_term_ctrl = 2;
+
+ if (DISPLAY_VER(display) >= 20) {
+ tx_misc = 5;
+ tx_term_ctrl = 4;
+ } else if (display->platform.battlemage) {
+ tx_misc = 0;
+ } else if (display->platform.meteorlake_u ||
+ is_arrowlake_s_by_host_bridge()) {
+ tx_misc = 3;
+ } else {
+ tx_misc = 7;
+ }
+
+ return (C20_PHY_TX_MISC(tx_misc) |
+ C20_PHY_TX_DCC_CAL_RANGE(tx_dcc_cal_dac_ctrl_range) |
+ C20_PHY_TX_DCC_BYPASS | C20_PHY_TX_TERM_CTL(tx_term_ctrl));
+}
+
+static int intel_c20_compute_hdmi_tmds_pll(struct intel_crtc_state *crtc_state)
+{
struct intel_c20pll_state *pll_state = &crtc_state->dpll_hw_state.cx0pll.c20;
u64 datarate;
u64 mpll_tx_clk_div;
u64 mpll_multiplier;
u64 mpll_fracn_quot;
u64 mpll_fracn_rem;
- u16 tx_misc;
u8 mpllb_ana_freq_vco;
u8 mpll_div_multiplier;
mpll_div_multiplier = min_t(u8, div64_u64((vco_freq * 16 + (datarate >> 1)),
datarate), 255);
- if (DISPLAY_VER(display) >= 20)
- tx_misc = 0x5;
- else
- tx_misc = 0x0;
-
if (vco_freq <= DATARATE_3000000000)
mpllb_ana_freq_vco = MPLLB_ANA_FREQ_VCO_3;
else if (vco_freq <= DATARATE_3500000000)
pll_state->clock = crtc_state->port_clock;
pll_state->tx[0] = 0xbe88;
- pll_state->tx[1] = 0x9800 | C20_PHY_TX_MISC(tx_misc);
+ pll_state->tx[1] = intel_c20_hdmi_tmds_tx_cgf_1(crtc_state);
pll_state->tx[2] = 0x0000;
pll_state->cmn[0] = 0x0500;
pll_state->cmn[1] = 0x0005;
#define C20_PHY_TX_RATE REG_GENMASK(2, 0)
#define C20_PHY_TX_MISC_MASK REG_GENMASK16(7, 0)
#define C20_PHY_TX_MISC(val) REG_FIELD_PREP16(C20_PHY_TX_MISC_MASK, (val))
+#define C20_PHY_TX_DCC_CAL_RANGE_MASK REG_GENMASK16(11, 8)
+#define C20_PHY_TX_DCC_CAL_RANGE(val) \
+ REG_FIELD_PREP16(C20_PHY_TX_DCC_CAL_RANGE_MASK, (val))
+#define C20_PHY_TX_DCC_BYPASS REG_BIT(12)
+#define C20_PHY_TX_TERM_CTL_MASK REG_GENMASK16(15, 13)
+#define C20_PHY_TX_TERM_CTL(val) REG_FIELD_PREP16(C20_PHY_TX_TERM_CTL_MASK, (val))
#define PHY_C20_A_CMN_CNTX_CFG(i915, idx) \
((_IS_XE2HPD_C20(i915) ? _XE2HPD_C20_A_CMN_CNTX_CFG : _MTL_C20_A_CMN_CNTX_CFG) - (idx))
(drm_WARN_ON(__to_intel_display(__display)->drm, INTEL_DISPLAY_STEP(__display) == STEP_NONE), \
INTEL_DISPLAY_STEP(__display) >= (since) && INTEL_DISPLAY_STEP(__display) < (until))
+#define ARLS_HOST_BRIDGE_PCI_ID1 0x7D1C
+#define ARLS_HOST_BRIDGE_PCI_ID2 0x7D2D
+#define ARLS_HOST_BRIDGE_PCI_ID3 0x7D2E
+#define ARLS_HOST_BRIDGE_PCI_ID4 0x7D2F
+
+#define IS_ARROWLAKE_S_BY_HOST_BRIDGE_ID(id) \
+ (((id) == ARLS_HOST_BRIDGE_PCI_ID1) || \
+ ((id) == ARLS_HOST_BRIDGE_PCI_ID2) || \
+ ((id) == ARLS_HOST_BRIDGE_PCI_ID3) || \
+ ((id) == ARLS_HOST_BRIDGE_PCI_ID4))
+
struct intel_display_runtime_info {
struct intel_display_ip_ver {
u16 ver;