blob: d6758d9fecfd42bfd8ec3423af8523b4744f1f27 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_REGISTERS_DDI_PHY_TIGER_LAKE_H_
#define SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_REGISTERS_DDI_PHY_TIGER_LAKE_H_
// Most fields in the PHY (Physical Layer) configuration registers are not
// sufficiently documented to be configured by driver authors. Plausible
// explanations are that the fields are only intended for DMC (display
// microcontroller) usage, or that their default values are the only supported
// values for correct hardware operation. The register definitions below expand
// abbreviations in register and field names when we have guesses that we are
// reasonably confident in.
//
// The "spare" fields are considered reserved, as opposed to free for driver
// use. This assumption is supported by the PORT_TX_DW5 descriptions, where the
// "Disable 2tap" field (referenced in the initialization sequence) is marked as
// "ospare2".
//
// Some reserved fields are documented as MBZ (must be zero) on Tiger Lake and
// DG1, but PBC (preserve bit content) on Ice Lake. These fields are currently
// described as MBZ.
#include <lib/ddk/debug.h>
#include <zircon/assert.h>
#include <cstdint>
#include <hwreg/bitfields.h>
#include "src/graphics/display/drivers/intel-i915/hardware-common.h"
namespace registers {
// PHY_MISC (Miscellaneous Physical layer settings?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 page 664
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 663-664
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 page 361
class PhyMisc : public hwreg::RegisterBase<PhyMisc, uint32_t> {
public:
// Undocumented semantics.
//
// This is likely a communication channel from the display engine driver to
// the PHY logic.
DEF_FIELD(31, 28, display_engine_to_io);
// Undocumented semantics.
//
// This is likely a communication channel from the PHY logic to the display
// engine driver.
DEF_FIELD(27, 24, io_to_display_engine);
// If true, the compensation resistors are powered down.
//
// The display engine driver sets this field, and the PHY logic acts on it.
// This must be set to false before the DDI is enabled.
DEF_BIT(23, compensation_resistors_powered_down);
DEF_RSVDZ_FIELD(19, 0);
static auto GetForDdi(i915::DdiId ddi_id) {
ZX_ASSERT(ddi_id >= i915::DdiId::DDI_A);
ZX_ASSERT(ddi_id <= i915::DdiId::DDI_C);
const int ddi_index = ddi_id - i915::DdiId::DDI_A;
return hwreg::RegisterAddr<PhyMisc>(0x64c00 + 4 * ddi_index);
}
};
// Undocumented register PORT_CL_DW0 / PHY Common Lane config double-word 0?
//
// This definition is currently only used as a host for MmioAddressForDdi().
class PortCommonLane0 : public hwreg::RegisterBase<PortCommonLane0, uint32_t> {
public:
// Returns the base address of the PORT_CL_ configuration registers for a i915::DdiId.
static constexpr uint32_t MmioAddressForDdi(i915::DdiId ddi_id) {
ZX_ASSERT(ddi_id >= i915::DdiId::DDI_A);
ZX_ASSERT(ddi_id <= i915::DdiId::DDI_C);
const int ddi_index = ddi_id - i915::DdiId::DDI_A;
// `kMmioAddress` can be static in C++20.
constexpr uint32_t kMmioAddress[] = {0x162000, 0x6c000, 0x160000};
return kMmioAddress[ddi_index];
}
};
// PORT_CL_DW5 (PHY Common Lane config double-word 5?)
//
// "Common Lane" functionality is centralized across all lanes in a PHY, and
// placed in a single power gate.
//
// All the bits in this register are documented, so it is safe to update this
// register without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 885-886
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 897-898
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 553-554
class PortCommonLane5 : public hwreg::RegisterBase<PortCommonLane5, uint32_t> {
public:
// Undocumented semantics.
DEF_FIELD(31, 24, force);
DEF_RSVDZ_BIT(23);
DEF_BIT(22, fuse_valid_reset);
DEF_BIT(21, fuse_valid_override);
DEF_BIT(20, fuse_repull);
DEF_FIELD(19, 16, common_register_interface_clock_count_max);
DEF_RSVDZ_BIT(15);
// IOSF PD (Intel On-chip System Fabric Presence Detection) count.
DEF_FIELD(14, 13, onchip_system_fabric_presence_detection_count);
DEF_RSVDZ_BIT(12);
DEF_FIELD(11, 9, onchip_system_fabric_clock_divider_select);
// If true, all transmitters are programmed by writes to group addresses.
DEF_BIT(8, downlink_broadcast_enable);
DEF_RSVDZ_BIT(7);
DEF_BIT(6, port_staggering_enabled);
DEF_BIT(5, power_gate_staggering_control_disabled);
DEF_BIT(4, common_lane_power_down_enabled);
DEF_BIT(3, common_register_interface_clock_select);
DEF_BIT(2, phy_power_ack_override);
DEF_FIELD(1, 0, suspend_clock_config);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCommonLane5>(PortCommonLane0::MmioAddressForDdi(ddi_id) + 5 * 4);
}
};
// PORT_CL_DW10 (PHY Common Lane config double-word 10?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 887-889
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 899-901
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 555-556
class PortCommonLaneMainLinkPower
: public hwreg::RegisterBase<PortCommonLaneMainLinkPower, uint32_t> {
public:
// Possible values for the `terminating_resistor_override` field.
enum class TerminatingResistorOverride {
k150Ohms = 0,
k100Ohms = 1,
};
DEF_RSVDZ_FIELD(31, 27);
DEF_FIELD(26, 25, power_gate_sequential_delay_override);
// If false, `power_gate_sequential_delay_override` is ignored.
DEF_BIT(24, power_gate_sequential_delay_override_valid);
// HPVG (High Voltage Power Gate) for the MIPI DSI operating mode.
//
// On Ice Lake display engines with one common lane for all IOs, this bit
// controls the HVPG (High-Voltage Power Gate) for DSI0 (MIPI A).
//
// On display engines without MIPI DSI support, this bit is ignored.
DEF_BIT(23, high_voltage_power_gate_control);
// Unused (Common Register Interface spare bit) on most display engines.
//
// On Ice Lake display engines with one common lane for all IOs, this bit
// controls the HVPG (High-Voltage Power Gate) for DSI1 (MIPI C).
DEF_BIT(22, high_voltage_power_gate_control_dsi_c);
// CRI (Common Register Interface) spare bits.
DEF_FIELD(21, 16, common_register_interface_ret);
DEF_RSVDZ_FIELD(15, 12);
// If true, the DDI's main link lane 3 is powered down.
//
// Some `power_down_lane*` field combinations are not supported. The
// `set_powered_up_lanes()` helper is guaranteed to set valid combinations.
DEF_BIT(7, power_down_lane3);
// If true, the DDI's main link lane 2 is powered down.
//
// Some `power_down_lane*` field combinations are not supported. The
// `set_powered_up_lanes()` helper is guaranteed to set valid combinations.
DEF_BIT(6, power_down_lane2);
// If true, the DDI's main link lane 1 is powered down.
//
// Some `power_down_lane*` field combinations are not supported. The
// `set_powered_up_lanes()` helper is guaranteed to set valid combinations.
DEF_BIT(5, power_down_lane1);
// If true, the DDI's main link lane 0 is powered down.
//
// Some `power_down_lane*` field combinations are not supported. The
// `set_powered_up_lanes()` helper is guaranteed to set valid combinations.
DEF_BIT(4, power_down_lane0);
// If false, `edp_power_optimized_mode_enabled` is ignored.
//
// Some `power_down_lane*` field combinations are not supported. The
// `set_powered_up_lanes()` helper is guaranteed to set valid combinations.
DEF_BIT(3, edp_power_optimized_mode_valid);
// If true, enables a eDP (embedded DisplayPort) power-optimized mode.
//
// This field is ignored if `edp_power_optimized_mode_valid` is false. Setting
// this to true must be accompanied by a specific voltage swing configuration.
DEF_BIT(2, edp_power_optimized_mode_enabled);
// If false, `terminating_resistor_override` is ignored.
DEF_BIT(1, terminating_resistor_override_valid);
// Overrides the terminating resisor value.
DEF_ENUM_FIELD(TerminatingResistorOverride, 0, 0, terminating_resistor_override);
// Powers up/down DDI main link lanes.
//
// `active_lane_count` must be a 1/2/4 for DisplayPort connections, and 4 for
// HDMI connections. DSI connections are not currently supported.
PortCommonLaneMainLinkPower& set_powered_up_lanes(int active_lane_count) {
ZX_ASSERT(active_lane_count >= 1);
ZX_ASSERT(active_lane_count <= 4);
return set_power_down_lane0(false)
.set_power_down_lane1(active_lane_count <= 1)
.set_power_down_lane2(active_lane_count <= 2)
.set_power_down_lane3(active_lane_count <= 3);
}
// Powers up/down DDI main link lanes for a reverse connection.
//
// `active_lane_count` must be a 1/2/4 for DisplayPort connections, and 4 for
// HDMI connections. DSI connections are not currently supported.
PortCommonLaneMainLinkPower& set_powered_up_lanes_reversed(int active_lane_count) {
ZX_ASSERT(active_lane_count >= 1);
ZX_ASSERT(active_lane_count <= 4);
return set_power_down_lane3(false)
.set_power_down_lane2(active_lane_count <= 1)
.set_power_down_lane1(active_lane_count <= 2)
.set_power_down_lane0(active_lane_count <= 3);
}
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCommonLaneMainLinkPower>(
PortCommonLane0::MmioAddressForDdi(ddi_id) + 10 * 4);
}
};
// PORT_CL_DW12 (PHY Common Lane config double-word 12?)
//
// All the bits in this register are documented, so it is safe to update this
// register without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 890-891
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 902-903
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 557-559
class PortCommonLaneMiscPower : public hwreg::RegisterBase<PortCommonLaneMiscPower, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 30);
DEF_BIT(29, mipi_lane_enabled);
DEF_RSVDZ_BIT(28);
// If false, `mipi_mode_override` is ignored.
DEF_BIT(27, mipi_mode_override_valid);
DEF_BIT(26, mipi_mode_override);
DEF_RSVDZ_FIELD(25, 12);
// Overrides the power request signal for the AUX channel.
//
// Ignored if `aux_power_request_override_valid` is false.
DEF_BIT(11, aux_power_request_override);
// If false, `aux_power_request_override` is ignored.
DEF_BIT(10, aux_power_request_override_valid);
DEF_RSVDZ_FIELD(9, 7);
DEF_BIT(6, aux_phy_status); // Read-only.
DEF_RSVDZ_BIT(5);
DEF_BIT(4, aux_power_acknowledged); // Read-only.
DEF_RSVDZ_FIELD(3, 1);
// If true, the AUX lane will eventually be powered up.
DEF_BIT(0, aux_lane_enabled);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCommonLaneMiscPower>(PortCommonLane0::MmioAddressForDdi(ddi_id) +
12 * 4);
}
};
// PORT_CL_DW15 (PHY Common Lane config double-word 15?)
//
// This register reports the state of powering various domains inside the PHY.
// All fields are read-only.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 892-893
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 904-905
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 560-561
class PortCommonLanePowerStatus : public hwreg::RegisterBase<PortCommonLanePowerStatus, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 30);
DEF_BIT(29, high_voltage_power_gate_power_acknowledged);
DEF_BIT(28, high_voltage_power_gate_enabled);
DEF_BIT(27, mipi_power_acknowledged);
DEF_RSVDZ_FIELD(26, 22);
DEF_BIT(21, aux_power_requested);
DEF_RSVDZ_FIELD(20, 18);
DEF_BIT(17, aux_power_acknowledged);
DEF_RSVDZ_FIELD(16, 0);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCommonLanePowerStatus>(
PortCommonLane0::MmioAddressForDdi(ddi_id) + 15 * 4);
}
};
// PORT_CL_DW16 (PHY Common Lane config double-word 16?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 894-895
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 906-907
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 562-563
class PortCommonLane16 : public hwreg::RegisterBase<PortCommonLane16, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 16);
DEF_BIT(15, ddi_b_hd_port_select_override_valid);
DEF_BIT(14, ddi_b_hd_port_select_override);
DEF_BIT(13, ddi_c_hd_port_select_override_valid);
DEF_BIT(12, ddi_c_hd_port_select_override);
DEF_BIT(11, ddi_d_hd_port_select_override_valid);
DEF_BIT(10, ddi_d_hd_port_select_override);
DEF_RSVDZ_FIELD(9, 8);
// If true, forces powering down the compensation source in the PHY.
DEF_BIT(3, compensators_power_down_override);
// If false, `compensators_power_down_override` is ignored.
DEF_BIT(2, compensators_power_down_override_valid);
// If true, force-wakes the CRI (Common Register Interface) domain.
DEF_BIT(1, common_register_interface_wake_override);
// If false, `common_register_interface_wake_override` is ignored.
DEF_BIT(0, common_register_interface_wake_override_valid);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCommonLane16>(PortCommonLane0::MmioAddressForDdi(ddi_id) +
16 * 4);
}
};
// PORT_COMP_DW0 (PHY process variation Compensation config double-word 0?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 page 896
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 page 908
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 page 564
class PortCompensation0 : public hwreg::RegisterBase<PortCompensation0, uint32_t> {
public:
// If true, the PHY's compensation resistors are initialized.
DEF_BIT(31, initialized);
DEF_FIELD(30, 29, transmitter_slew_control);
DEF_FIELD(28, 27, transmitter_drive_switch_on);
DEF_BIT(26, transmitter_drive_switch_control);
DEF_BIT(23, process_monitor_clock_select);
DEF_RSVDZ_FIELD(22, 20);
// Programmable counter driving the frequency of compensation updates.
DEF_FIELD(19, 8, periodic_counter);
DEF_RSVDZ_FIELD(7, 0);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCompensation0>(MmioAddressForDdi(ddi_id) + 0 * 4);
}
// Returns the base address of the PORT_COMP configuration registers.
static constexpr uint32_t MmioAddressForDdi(i915::DdiId ddi_id) {
ZX_ASSERT(ddi_id >= i915::DdiId::DDI_A);
ZX_ASSERT(ddi_id <= i915::DdiId::DDI_C);
const int ddi_index = ddi_id - i915::DdiId::DDI_A;
// `kMmioAddress` can be static in C++20.
constexpr uint32_t kMmioAddress[] = {0x162100, 0x6c100, 0x160100};
return kMmioAddress[ddi_index];
}
};
// PORT_COMP_DW1 (PHY process variation Compensation config double-word 1?)
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 897-898
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 909-910
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 565-566
class PortCompensation1 : public hwreg::RegisterBase<PortCompensation1, uint32_t> {
public:
DEF_BIT(31, low_dropout_regulator_bypass);
DEF_BIT(30, frequency_compensation_override_valid);
DEF_BIT(29, frequency_compensation_capacity_ratio);
DEF_BIT(28, frequency_compensation_bias_select);
DEF_FIELD(27, 26, frequency_compensation_input_select_overload);
DEF_BIT(25, frequency_compensation_polarity_select);
DEF_BIT(24, resistance_compensation_enabled);
// TODO(https://fxbug.dev/42065922): Add helpers for reading and writing the fields
// below, which are spread across PortCompensation1,
// PortCompensationNominalVoltageReferences, and
// PortCompensationLowVoltageReferences.
DEF_FIELD(23, 22, positive_nominal_voltage_reference_high_value_bits98);
DEF_FIELD(21, 20, positive_nominal_voltage_reference_low_value_bits98);
DEF_FIELD(19, 18, negative_nominal_voltage_reference_high_value_bits98);
DEF_FIELD(17, 16, negative_nominal_voltage_reference_low_value_bits98);
DEF_FIELD(15, 14, positive_high_voltage_reference_high_value_bits98);
DEF_FIELD(13, 12, positive_high_voltage_reference_low_value_bits98);
DEF_FIELD(11, 10, negative_high_voltage_reference_high_value_bits98);
DEF_FIELD(9, 8, negative_high_voltage_reference_low_value_bits98);
DEF_FIELD(7, 6, positive_low_voltage_reference_high_value_bits98);
DEF_FIELD(5, 4, positive_low_voltage_reference_low_value_bits98);
DEF_FIELD(3, 2, negative_low_voltage_reference_high_value_bits98);
DEF_FIELD(1, 0, negative_low_voltage_reference_low_value_bits98);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCompensation1>(PortCompensation0::MmioAddressForDdi(ddi_id) +
1 * 4);
}
};
// PORT_COMP_DW3 (PHY process variation Compensation config double-word 3?)
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 899-900
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 909-910
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 567-568
class PortCompensationStatus : public hwreg::RegisterBase<PortCompensationStatus, uint32_t> {
public:
// Documented values for the `process_select` field.
enum class ProcessSelect {
kDot0 = 0b000,
kDot1 = 0b001,
kDot4 = 0b010,
};
// Documented values for the `voltage_select` field.
enum class VoltageSelect {
k850mv = 0b00,
k950mv = 0b01,
k1050mv = 0b10,
};
DEF_RSVDZ_FIELD(31, 29);
// Process variation reported by the procmon (process monitor).
//
// The process monitor is a circuit that detects process skew (effects of
// manufacturing variation) for the chip area that hosts the display engine.
// The skew is characterized as slow, nominal, or fast.
//
// Sources:
// * "Synergies Between Delay Test and Post-silicon Speed Path Validation:
// A Tutorial Introduction," 2021 IEEE European Test Symposium (ETS)
// * "Use of Process monitors in Post silicon validation to reduce TTM,"
// 2017 IEEE 35th VLSI Test Symposium (VTS)
DEF_ENUM_FIELD(ProcessSelect, 28, 26, process_select);
// The port's operating voltage.
DEF_ENUM_FIELD(VoltageSelect, 25, 24, voltage_select);
DEF_BIT(23, pll_ddi_power_acknowledged);
DEF_BIT(22, first_compensation_done);
DEF_BIT(21, process_monitor_done);
DEF_BIT(20, current_compensation_code_maxout);
DEF_BIT(19, current_compensation_code_minout);
DEF_RSVDZ_FIELD(18, 15);
DEF_FIELD(14, 8, current_compensation_code);
DEF_BIT(7, mipi_low_power_data_negative_code_maxout);
DEF_BIT(6, mipi_low_power_data_negative_code_minout);
// LPDn (negative Data pin in Low-Power mode) compensation value.
DEF_FIELD(5, 0, mipi_low_power_data_negative_code);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCompensationStatus>(
PortCompensation0::MmioAddressForDdi(ddi_id) + 3 * 4);
}
};
// PORT_COMP_DW8 (PHY process variation Compensation config double-word 8?)
//
// All the bits in this register are documented, so it is safe to update this
// register without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 page 901
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 page 914
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 569-570
class PortCompensationSource : public hwreg::RegisterBase<PortCompensationSource, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 25);
// Must be true for PHYs that serve as compensation sources.
DEF_BIT(24, generate_internal_references);
DEF_RSVDZ_FIELD(23, 15);
// If true, periodic ICOMP (current compensation) value updates are disabled.
DEF_BIT(14, periodic_current_compensation_disabled);
DEF_RSVDZ_FIELD(13, 0);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCompensationSource>(
PortCompensation0::MmioAddressForDdi(ddi_id) + 8 * 4);
}
};
// PORT_COMP_DW9 (PHY process variation Compensation config double-word 9?)
//
// This register stores the low bits of {negative, positive} {low, high}
// reference values for nominal voltage transistors. The high bits are in
// PORT_COMP_DW1.
//
// All the bits in this register are documented, so it is safe to update this
// register without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 page 902
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 page 915
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 page 571
class PortCompensationNominalVoltageReferences
: public hwreg::RegisterBase<PortCompensationNominalVoltageReferences, uint32_t> {
public:
// The high bits for all these values are in PORT_COMP_DW1.
DEF_FIELD(31, 24, negative_nominal_voltage_reference_low_value_bits70);
DEF_FIELD(23, 16, negative_nominal_voltage_reference_high_value_bits70);
DEF_FIELD(15, 8, positive_nominal_voltage_reference_low_value_bits70);
DEF_FIELD(7, 0, positive_nominal_voltage_reference_high_value_bits70);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCompensationNominalVoltageReferences>(
PortCompensation0::MmioAddressForDdi(ddi_id) + 9 * 4);
}
};
// PORT_COMP_DW10 (PHY process variation Compensation config double-word 10?)
//
// This register stores the low bits of {negative, positive} {low, high}
// reference values for LVT (low voltage transistors). The high bits are in
// PORT_COMP_DW1.
//
// All the bits in this register are documented, so it is safe to update this
// register without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 page 903
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 page 916
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 page 572
class PortCompensationLowVoltageReferences
: public hwreg::RegisterBase<PortCompensationLowVoltageReferences, uint32_t> {
public:
// The high bits for all these values are in PORT_COMP_DW1.
DEF_FIELD(31, 24, negative_low_voltage_reference_low_value_bits70);
DEF_FIELD(23, 16, negative_low_voltage_reference_high_value_bits70);
DEF_FIELD(15, 8, positive_low_voltage_reference_low_value_bits70);
DEF_FIELD(7, 0, positive_low_voltage_reference_high_value_bits70);
static auto GetForDdi(i915::DdiId ddi_id) {
return hwreg::RegisterAddr<PortCompensationLowVoltageReferences>(
PortCompensation0::MmioAddressForDdi(ddi_id) + 10 * 4);
}
};
// Identifies a pair of pins used in voltage differential transmission.
//
// The lane usage is documented in the "Mode Set" > "Sequences for MIPI DSI" >
// "DSI Transcoder Enable Sequence" section of the display engine PRMs.
// Tiger Lake: IHD-OS-TGL-Vol 12-1.22-Rev2.0 page 127
// Ice Lake: IHD-OS-ICLLP-Vol 12-1.22-Rev2.0 page 129
enum class PortLane {
kAux = 0x3, // DisplayPort AUX channel. DSI Data lane 0.
kAll = 0x6, // Virtual pair that routes writes to all non-AUX lanes.
kMainLinkLane0 = 0x8, // 1st DisplayPort main link lane. DSI Data lane 1.
kMainLinkLane1 = 0x9, // 2nd DisplayPort main link lane. DSI Data lane 2.
kMainLinkLane2 = 0xa, // 3rd DisplayPort main link lane. DSI Clock lane.
kMainLinkLane3 = 0xb, // 4th DisplayPort main link lane. DSI Data lane 3.
};
// PORT_PCS_DW1 (Physical Coding Sublayer config double-word 1?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 903-907
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 917-921
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 573-575
class PortPhysicalCoding1 : public hwreg::RegisterBase<PortPhysicalCoding1, uint32_t> {
public:
// Possible values for the `duty_cycle_correction_schedule_select` field.
enum class DutyCycleCorrectionScheduleSelect {
kOnce = 0b00,
kEvery100Microseconds = 0b01,
kEvery1000Microseconds = 0b10,
kContinuously = 0b11,
};
DEF_RSVDZ_FIELD(31, 29);
DEF_BIT(28, common_mode_keeper_enabled_while_power_gated);
// If true, the pins are power-gated (powered off).
DEF_BIT(27, power_gate_powered_down);
// Enables the common mode voltage keeper circuit.
//
// The common keeper preserves the common-mode voltage between the pair of
// pins during low power modes.
DEF_BIT(26, common_mode_keeper_enabled);
DEF_FIELD(25, 24, common_mode_keeper_bias_control);
DEF_RSVDZ_FIELD(23, 22);
// Selects how often DCC (Duty Cycle Correction) is performed.
DEF_ENUM_FIELD(DutyCycleCorrectionScheduleSelect, 21, 20, duty_cycle_correction_schedule_select);
// If true, the DCC (Duty Cycle Correction) calibration is bypassed.
//
// Setting this to true also bypasses DFx (design for debug/test) receiver
// calibration. The two bypasses share a signal in the PCS (Physical Coding
// Sublayer).
DEF_BIT(19, duty_cycle_correction_calibration_bypassed);
// If true, DCC calibration will be performed on the next power up.
//
// Setting this to true forces a DCC (Duty Cycle Correction) calibration the
// next time the DL (downlink) is woken up after a power down event.
DEF_BIT(18, duty_cycle_correction_calibration_on_wake);
// If true, forces a transmitter DCC (Duty Cycle Correction) calibration.
//
// This field should only be used (set to true) after the boot-time
// initialization completes.
DEF_BIT(17, force_transmitter_duty_cycle_correction_calibration);
DEF_RSVDZ_FIELD(15, 14);
DEF_FIELD(13, 12, transmitter_high);
DEF_RSVDZ_FIELD(11, 10);
DEF_FIELD(9, 8, clock_request);
// If true, the lane's symbol clock is the TBC (Transmitter Buffer Clock).
DEF_BIT(7, use_transmitter_buffer_clock_as_symbol_clock);
// If false, `transmitter_fifo_reset_main_override` is ignored.
DEF_BIT(6, transmitter_fifo_reset_main_override_valid);
// Reset Main override for the transmitter's FIFO.
//
// Ignored if `transmitter_fifo_reset_main_override_valid` is false
DEF_BIT(5, transmitter_fifo_reset_main_override);
DEF_BIT(4, transmitter_deemphasis_value);
DEF_FIELD(3, 2, latency_optimization_value);
// If true, `soft_lane_reset` is read by the circuitry.
DEF_BIT(1, soft_lane_reset_valid);
// If false, requests that the lanes controlled by this register are reset.
//
// This field is only used if `soft_lane_reset_valid` is true.
DEF_BIT(0, soft_lane_reset);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortPhysicalCoding1>(MmioAddressForDdiLane(ddi_id, lane) + 1 * 4);
}
// Returns the base address of lane's PORT_PCS_ configuration registers.
static constexpr uint32_t MmioAddressForDdiLane(i915::DdiId ddi_id, PortLane lane) {
ZX_ASSERT(ddi_id >= i915::DdiId::DDI_A);
ZX_ASSERT(ddi_id <= i915::DdiId::DDI_C);
const int ddi_index = ddi_id - i915::DdiId::DDI_A;
// `kMmioAddress` can be static in C++20.
constexpr uint32_t kMmioAddress[] = {0x162000, 0x6c000, 0x160000};
return kMmioAddress[ddi_index] | (static_cast<uint32_t>(lane) << 8);
}
};
// PORT_PCS_DW9 (Physical Coding Sublayer config double-word 9?)
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 908-910
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 922-925
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 576-579
class PortPhysicalCoding9 : public hwreg::RegisterBase<PortPhysicalCoding9, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 28);
DEF_FIELD(27, 16, strong_cm_count_overload);
DEF_RSVDZ_FIELD(15, 11);
DEF_FIELD(10, 8, stagger_multiplier);
DEF_RSVDZ_FIELD(7, 6);
DEF_BIT(5, stagger_override_valid);
DEF_FIELD(4, 0, stagger_override);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortPhysicalCoding9>(
PortPhysicalCoding1::MmioAddressForDdiLane(ddi_id, lane) + 9 * 4);
}
};
// PORT_TX_DW0 (Transmitter analog front-end config double-word 0?)
//
// This register controls transmitter equalization in the Combo PHY's AFE
// (Analog Front-End).
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 929-931
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 945-948
class PortTransmitterMipiEqualization
: public hwreg::RegisterBase<PortTransmitterMipiEqualization, uint32_t> {
public:
// Selects the equalization level for MIPI DSI transmission.
//
// This bit is ignored unless `mipi_equalization_override` is true.
//
// Low level equalization is 3.5 dB. High level equalization is 7 dB.
DEF_BIT(31, mipi_equalization_is_high);
// If true, lane equalization for MIPI DSI transmission is enabled.
//
// This bit is ignored unless `mipi_equalization_override` is true.
DEF_BIT(30, mipi_equalization_enabled);
// Transmitter equalization tap C+1 (post-cursor) coefficient.
//
// The PRM advises against changing this field. The default value is 0xb.
DEF_FIELD(29, 24, post_cursor_coefficient);
// If true, the equalization logic is driven by fields in this register.
//
// If this field is false, the equalization logic is driven by PPI (PHY
// Protocol Interface, in the MIPI D-PHY specification) Transmitter
// Equalization pins (TxEqActiveHS, TxEqLevelHS).
DEF_BIT(23, mipi_equalization_override);
DEF_RSVDZ_FIELD(22, 6);
// Transmitter equalization tap C (cursor) coefficient.
//
// The PRM advises against changing this field. The default value is 0x34.
DEF_FIELD(5, 0, cursor_coefficient);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortTransmitterMipiEqualization>(
MmioAddressForDdiLane(ddi_id, lane) + 0 * 4);
}
// Returns the base address of lane's PORT_TX_ configuration registers.
static constexpr uint32_t MmioAddressForDdiLane(i915::DdiId ddi_id, PortLane lane) {
ZX_ASSERT(ddi_id >= i915::DdiId::DDI_A);
ZX_ASSERT(ddi_id <= i915::DdiId::DDI_C);
const int ddi_index = ddi_id - i915::DdiId::DDI_A;
// `kMmioAddress` can be static in C++20.
constexpr uint32_t kMmioAddress[] = {0x162080, 0x6c080, 0x160080};
return kMmioAddress[ddi_index] | (static_cast<uint32_t>(lane) << 8);
}
};
using PortTransmitter0 = PortTransmitterMipiEqualization;
// PORT_TX_DW1 (Transmitter analog front-end config double-word 1?)
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 932-934
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 949-952
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 page 614
class PortTransmitter1 : public hwreg::RegisterBase<PortTransmitter1, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 8);
// ICOMP (current configuration) reference configuration.
//
// This configuration bit is routed from the COMP (compensation) registers to
// the TX (Transmitter analog front-end) registers.
DEF_BIT(7, output_current_compensation_reference_config);
// Sets the transmitter's current intensity boost ratio.
DEF_FIELD(6, 5, output_current_reference_control);
// Configures the MIPI DSI HSTX (high-speed transmission mode) slew.
DEF_FIELD(4, 3, mipi_high_speed_transmission_slew_rate_control);
// Enables the LDO feedback path for low reference voltage.
DEF_BIT(2, low_reference_voltage_low_dropout_regulator_feedback_enabled);
// Enables the LDO feedback path for high reference voltage.
DEF_BIT(1, high_reference_voltage_low_dropout_regulator_feedback_enabled);
// Enables the LDO feedback path for nominal reference voltage.
DEF_BIT(0, nominal_reference_voltage_low_dropout_regulator_feedback_enabled);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortTransmitter1>(
PortTransmitter0::MmioAddressForDdiLane(ddi_id, lane) + 1 * 4);
}
};
// PORT_TX_DW2 (Transmitter analog front-end config double-word 2?)
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 935-937
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 953-956
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 615-617
class PortTransmitterVoltageSwing
: public hwreg::RegisterBase<PortTransmitterVoltageSwing, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 16);
// This field must be combined with `voltage_swing_select_bits20`. The helpers
// `voltage_swing_select()` and `set_voltage_swing_select()` handle that.
DEF_BIT(15, voltage_swing_select_bit3);
DEF_BIT(14, weak_common_mode_select);
// This field must be combined with `voltage_swing_select_bits3`. The helpers
// `voltage_swing_select()` and `set_voltage_swing_select()` handle that.
DEF_FIELD(13, 11, voltage_swing_select_bits20);
DEF_FIELD(10, 8, force_latency_optimized_fifo);
// Applied to RCOMP (resistance compensation) code.
//
// This field adjusts the RCOMP code to get the desired output termination
// resistance. This field is also named the (voltage) swing scalar.
DEF_FIELD(7, 0, resistance_compensation_code_scalar);
// Configures the signal's peak-to-peak voltage differences.
//
// There is an undocumented mapping between (transition and non-transition)
// peak-to-peak voltage differences and values in this field. Intel's
// documentation has tables mapping voltage swing and pre-emphasis levels to
// field values.
int8_t voltage_swing_select() const {
return static_cast<int8_t>((static_cast<int8_t>(voltage_swing_select_bit3()) << 3) |
static_cast<int8_t>(voltage_swing_select_bits20()));
}
// See `voltage_swing_select()` for details.
PortTransmitterVoltageSwing& set_voltage_swing_select(int voltage_swing_select) {
ZX_DEBUG_ASSERT(voltage_swing_select >= 0);
ZX_DEBUG_ASSERT(voltage_swing_select <= 0b1111);
return set_voltage_swing_select_bits20(static_cast<uint32_t>(voltage_swing_select & 7))
.set_voltage_swing_select_bit3(static_cast<uint32_t>((voltage_swing_select >> 3) & 1));
}
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortTransmitterVoltageSwing>(
PortTransmitter0::MmioAddressForDdiLane(ddi_id, lane) + 2 * 4);
}
};
// PORT_TX_DW4 (Transmitter analog front-end config double-word 4?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 938-940
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 957-960
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 618-620
class PortTransmitterEqualization
: public hwreg::RegisterBase<PortTransmitterEqualization, uint32_t> {
public:
DEF_BIT(31, load_generation_select);
DEF_BIT(23, bs_comp_override);
DEF_FIELD(22, 18, termination_resistance_limit);
// Equalization tap C+1 (post-cursor) coefficient.
DEF_FIELD(17, 12, post_cursor_coefficient1);
// Equalization tap C+2 (post-cursor) coefficient.
DEF_FIELD(11, 6, post_cursor_coefficient2);
// Equalization tap C (cursor) coefficient.
DEF_FIELD(5, 0, cursor_coefficient);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortTransmitterEqualization>(
PortTransmitter0::MmioAddressForDdiLane(ddi_id, lane) + 4 * 4);
}
};
// PORT_TX_DW5 (Transmitter analog front-end config double-word 5?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 941-944
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 961-964
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 621-624
class PortTransmitterVoltage : public hwreg::RegisterBase<PortTransmitterVoltage, uint32_t> {
public:
// While true, the lane's voltage parameters cannot be reconfigured.
//
// This field must be set to false briefly for the parameters in the PORT_TX*
// registers to be picked up, then set back to true.
DEF_BIT(31, training_enabled);
DEF_BIT(30, two_tap_equalization_disabled);
DEF_BIT(29, three_tap_equalization_disabled);
DEF_BIT(26, cursor_programming_disabled);
DEF_BIT(25, coefficient_polarity_disabled);
DEF_RSVDZ_FIELD(23, 21);
DEF_FIELD(20, 18, scaling_mode_select);
DEF_FIELD(17, 16, decode_timer_select);
DEF_FIELD(15, 11, cr_scaling_coefficient);
DEF_FIELD(5, 3, terminating_resistor_select);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortTransmitterVoltage>(
PortTransmitter0::MmioAddressForDdiLane(ddi_id, lane) + 5 * 4);
}
};
// PORT_TX_DW6 (Transmitter analog front-end config double-word 6?)
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 945-947
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 965-968
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 page 625
class PortTransmitterLowDropoutRegulator
: public hwreg::RegisterBase<PortTransmitterLowDropoutRegulator, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 8);
DEF_BIT(7, function_override_enabled);
// This field should be replicated from CRI (Common Register Interface).
DEF_FIELD(6, 1, low_dropout_reference_select);
// This field should be replicated from CRI (Common Register Interface).
DEF_BIT(0, low_dropout_bypass);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortTransmitterLowDropoutRegulator>(
PortTransmitter0::MmioAddressForDdiLane(ddi_id, lane) + 6 * 4);
}
};
// PORT_TX_DW7 (Transmitter analog front-end config double-word 7?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 948-950
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 969-971
// Ice Lake: IHD-OS-ICLLP-Vol 2c-1.22-Rev2.0 Part 2 pages 626-628
class PortTransmitterNScalar : public hwreg::RegisterBase<PortTransmitterNScalar, uint32_t> {
public:
DEF_FIELD(30, 24, n_scalar);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortTransmitterNScalar>(
PortTransmitter0::MmioAddressForDdiLane(ddi_id, lane) + 7 * 4);
}
};
// PORT_TX_DW8 (Transmitter analog front-end config double-word 8?)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 951-953
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 972-975
class PortTransmitterDutyCycleCorrection
: public hwreg::RegisterBase<PortTransmitterDutyCycleCorrection, uint32_t> {
public:
// Possible values for `duty_cycle_correction_clock_divider_select`.
enum class ClockDividerSelect {
k2 = 0b01,
k4 = 0b10,
k8 = 0b11,
};
DEF_BIT(31, output_duty_cycle_correction_clock_select);
DEF_ENUM_FIELD(ClockDividerSelect, 30, 29, output_duty_cycle_correction_clock_divider_select);
// Ignored if `output_duty_cycle_correction_code_override_valid` is false.
DEF_FIELD(28, 24, output_duty_cycle_correction_code_override);
// If false, `output_duty_cycle_correction_code_override` is ignored.
DEF_BIT(23, output_duty_cycle_correction_code_override_valid);
DEF_BIT(22, output_duty_cycle_correction_fuse_enabled);
DEF_FIELD(20, 16, output_duty_cycle_correction_lower_limit);
DEF_FIELD(14, 13, input_duty_cycle_correction_thermal_bits43);
DEF_FIELD(12, 8, input_duty_cycle_correction_code);
DEF_FIELD(7, 5, input_duty_cycle_correction_thermal_bits20);
DEF_FIELD(4, 0, output_duty_cycle_correction_upper_limit);
static auto GetForDdiLane(i915::DdiId ddi_id, PortLane lane) {
return hwreg::RegisterAddr<PortTransmitterDutyCycleCorrection>(
PortTransmitter0::MmioAddressForDdiLane(ddi_id, lane) + 8 * 4);
}
};
} // namespace registers
#endif // SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_REGISTERS_DDI_PHY_TIGER_LAKE_H_