| // Copyright 2024 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_LIB_DESIGNWARE_DSI_DPHY_INTERFACE_CONFIG_H_ |
| #define SRC_GRAPHICS_DISPLAY_LIB_DESIGNWARE_DSI_DPHY_INTERFACE_CONFIG_H_ |
| |
| #include <chrono> |
| |
| namespace designware_dsi { |
| |
| // The Designware DSI Host Controller supports the D-PHY transmission rate |
| // of up to 2.5 Gbps per lane, so the minimum possible unit interval is |
| // 1 / 2.5 Gbps = 0.4 nanoseconds. Thus, we use picoseconds as the minimum |
| // time unit for all the durations used by this driver. |
| using Picoseconds = std::chrono::duration<int64_t, std::pico>; |
| |
| inline constexpr int kMinSupportedDphyDataLaneCount = 1; |
| |
| // Specified in DSI Host Databook, Section 1.1.2 "Supported Features": |
| // When in D-PHY, supports ... up to four data lanes. |
| inline constexpr int kMaxSupportedDphyDataLaneCount = 4; |
| |
| // Constrained by the `tx_esc_clk_division` field in the `CLKMGR_CFG` register. |
| // DSI Host Databook, Section 5.1.3 "CLKMGR_CFG", page 192. |
| inline constexpr int32_t kMaxHighSpeedByteClockToEscapeClockFrequencyRatio = 255; |
| |
| // Constrained by the `phy_hs2lp_time` field in the `PHY_TMR_CFG` register. |
| // DSI Host Databook, Section 5.1.40 "PHY_TMR_CFG", page 243. |
| inline constexpr int32_t kMinPossibleMaxDataLaneHsToLpTransitionDurationLaneByteClockCycles = 0; |
| inline constexpr int32_t kMaxPossibleMaxDataLaneHsToLpTransitionDurationLaneByteClockCycles = 1023; |
| |
| // Constrained by the `phy_lp2hs_time` field in the `PHY_TMR_CFG` register. |
| // DSI Host Databook, Section 5.1.40 "PHY_TMR_CFG", page 243. |
| inline constexpr int32_t kMinPossibleMaxDataLaneLpToHsTransitionDurationLaneByteClockCycles = 0; |
| inline constexpr int32_t kMaxPossibleMaxDataLaneLpToHsTransitionDurationLaneByteClockCycles = 1023; |
| |
| // Constrained by the `phy_hs2lp_time` field in the `PHY_TMR_LPCLK_CFG` register. |
| // DSI Host Databook, Section 5.1.39 "PHY_TMR_LPCLK_CFG", page 242. |
| inline constexpr int32_t kMinPossibleMaxClockLaneHsToLpTransitionDurationLaneByteClockCycles = 0; |
| inline constexpr int32_t kMaxPossibleMaxClockLaneHsToLpTransitionDurationLaneByteClockCycles = 1023; |
| |
| // Constrained by the `phy_lp2hs_time` field in the `PHY_TMR_LPCLK_CFG` register. |
| // DSI Host Databook, Section 5.1.39 "PHY_TMR_LPCLK_CFG", page 242. |
| inline constexpr int32_t kMinPossibleMaxClockLaneLpToHsTransitionDurationLaneByteClockCycles = 0; |
| inline constexpr int32_t kMaxPossibleMaxClockLaneLpToHsTransitionDurationLaneByteClockCycles = 1023; |
| |
| // The DesignWare MIPI DSI Host Controller connects to the MIPI D-PHY physical |
| // layer over the PHY-Protocol Interface (PPI) for signal output. |
| // |
| // Configures the output interface and timers so that the output signal format |
| // and timings matches the D-PHY transmitter. |
| struct DphyInterfaceConfig { |
| // Number of data lanes used for data transmission to the peripheral. |
| // |
| // Must be >= kMinSupportedDphyDataLaneCount and <= kMaxSupportedDphyDataLaneCount. |
| // Must be <= the number of physical lanes of the host processor. |
| // Must be <= the number of physical lanes of the peripheral. |
| int data_lane_count; |
| |
| // If true, the DSI Host Controller automatically controls the mode of the |
| // D-PHY clock lane. |
| bool clock_lane_mode_automatic_control_enabled = true; |
| |
| // The frequency of the external clock signal provided for the D-PHY clock |
| // lane in High Speed (HS) mode. |
| // |
| // Must be positive. |
| int64_t high_speed_mode_clock_lane_frequency_hz; |
| |
| // The frequency of the output clock signal generated by the DSI Host |
| // Controller for the D-PHY clock lane in escape mode. |
| // |
| // Must be positive. |
| // Must be a divisor of `high_speed_mode_data_lane_bytes_per_second()`. |
| // |
| // The ratio of `high_speed_mode_data_lane_bytes_per_second()` to |
| // `escape_mode_clock_lane_frequency_hz` must be >= 1 and |
| // <= kMaxHighSpeedByteClockToEscapeClockFrequencyRatio. |
| int64_t escape_mode_clock_lane_frequency_hz; |
| |
| // The maximum time that the D-PHY data lanes take to go from High Speed |
| // (HS) to Low Power (LP) transmission. |
| // |
| // The result is expressed in D-PHY lane byte clock cycles, which is the |
| // number of bytes that can be transmitted on a D-PHY data lane in High Speed |
| // mode. |
| // |
| // Must match the D-PHY hardware timing configuration. |
| // |
| // Must be >= kMinPossibleMaxDataLaneHsToLpTransitionDurationLaneByteClockCycles |
| // and <= kMaxPossibleMaxDataLaneHsToLpTransitionDurationLaneByteClockCycles. |
| int32_t max_data_lane_hs_to_lp_transition_duration_lane_byte_clock_cycles; |
| |
| // The maximum time that the D-PHY data lanes take to go from Low Power (LP) |
| // to High Speed (HS) transmission. |
| // |
| // The result is expressed in D-PHY lane byte clock cycles, which is the |
| // number of bytes that can be transmitted on a D-PHY data lane in High Speed |
| // mode. |
| // |
| // Must match the D-PHY hardware timing configuration. |
| // |
| // Must be >= kMinPossibleMaxDataLaneLpToHsTransitionDurationLaneByteClockCycles |
| // and <= kMaxPossibleMaxDataLaneLpToHsTransitionDurationLaneByteClockCycles. |
| int32_t max_data_lane_lp_to_hs_transition_duration_lane_byte_clock_cycles; |
| |
| // The maximum time that the D-PHY clock lane takes to go from High Speed |
| // (HS) to Low Power (LP) transmission. |
| // |
| // The result is expressed in D-PHY lane byte clock cycles, which is the |
| // number of bytes that can be transmitted on a D-PHY data lane in High Speed |
| // mode. |
| // |
| // Must match the D-PHY hardware timing configuration. |
| // |
| // Must be >= kMinPossibleMaxClockLaneHsToLpTransitionDurationLaneByteClockCycles |
| // and <= kMaxPossibleMaxClockLaneHsToLpTransitionDurationLaneByteClockCycles. |
| int32_t max_clock_lane_hs_to_lp_transition_duration_lane_byte_clock_cycles; |
| |
| // The maximum time that the D-PHY clock lane takes to go from Low Power (LP) |
| // to High Speed (HS) transmission. |
| // |
| // The result is expressed in D-PHY lane byte clock cycles, which is the |
| // number of bytes that can be transmitted on a D-PHY data lane in High Speed |
| // mode. |
| // |
| // Must match the D-PHY hardware timing configuration. |
| // |
| // Must be >= kMinPossibleMaxClockLaneLpToHsTransitionDurationLaneByteClockCycles |
| // and <= kMaxPossibleMaxClockLaneLpToHsTransitionDurationLaneByteClockCycles. |
| int32_t max_clock_lane_lp_to_hs_transition_duration_lane_byte_clock_cycles; |
| |
| constexpr int64_t high_speed_mode_data_lane_bits_per_second() const { |
| // The MIPI D-PHY Clock lane uses a DDR (Double Data Rate) clock signal. |
| // Thus, the per lane data rate is 2 times of the clock signal frequency. |
| return high_speed_mode_clock_lane_frequency_hz * 2; |
| } |
| constexpr int64_t escape_mode_data_lane_bits_per_second() const { |
| // The MIPI D-PHY Clock lane uses a DDR (Double Data Rate) clock signal. |
| // Thus, the per lane data rate is 2 times of the clock signal frequency. |
| return escape_mode_clock_lane_frequency_hz * 2; |
| } |
| constexpr int64_t high_speed_mode_data_lane_bytes_per_second() const { |
| constexpr int kBitsPerByte = 8; |
| return high_speed_mode_data_lane_bits_per_second() / kBitsPerByte; |
| } |
| constexpr int64_t escape_mode_data_lane_bytes_per_second() const { |
| constexpr int kBitsPerByte = 8; |
| return escape_mode_data_lane_bits_per_second() / kBitsPerByte; |
| } |
| |
| // The Unit Interval (UI) is defined as the time equal to the duration of any |
| // High Speed (HS) state on the Clock Lane. It equals to the duration to |
| // transmit a bit on the data line on High Speed mode. |
| // |
| // D-PHY spec, Section 2.4 "Acronyms", page 6. |
| // D-PHY spec, Section 10.1 "High-Speed Clock Timing", Figure 86 "DDR Clock |
| // Definition", page 143. |
| constexpr Picoseconds unit_interval() const { |
| return Picoseconds{std::chrono::seconds(1)} / high_speed_mode_data_lane_bits_per_second(); |
| } |
| |
| // The duration to transmit a byte (8 bits) on the data line on High Speed |
| // mode. |
| // |
| // Also known as "lanebyteclk" in the DSI Host Databook and User Guide. |
| constexpr Picoseconds lane_byte_clock_period() const { |
| constexpr int kBitsPerByte = 8; |
| return unit_interval() * kBitsPerByte; |
| } |
| |
| constexpr Picoseconds max_data_lane_hs_to_lp_transition_duration() const { |
| return max_data_lane_hs_to_lp_transition_duration_lane_byte_clock_cycles * |
| lane_byte_clock_period(); |
| } |
| constexpr Picoseconds max_data_lane_lp_to_hs_transition_duration() const { |
| return max_data_lane_lp_to_hs_transition_duration_lane_byte_clock_cycles * |
| lane_byte_clock_period(); |
| } |
| constexpr Picoseconds max_clock_lane_hs_to_lp_transition_duration() const { |
| return max_clock_lane_hs_to_lp_transition_duration_lane_byte_clock_cycles * |
| lane_byte_clock_period(); |
| } |
| constexpr Picoseconds max_clock_lane_lp_to_hs_transition_duration() const { |
| return max_clock_lane_lp_to_hs_transition_duration_lane_byte_clock_cycles * |
| lane_byte_clock_period(); |
| } |
| |
| constexpr bool IsValid() const; |
| }; |
| |
| constexpr bool DphyInterfaceConfig::IsValid() const { |
| if (data_lane_count < kMinSupportedDphyDataLaneCount) { |
| return false; |
| } |
| if (data_lane_count > kMaxSupportedDphyDataLaneCount) { |
| return false; |
| } |
| |
| if (high_speed_mode_clock_lane_frequency_hz <= 0) { |
| return false; |
| } |
| if (escape_mode_clock_lane_frequency_hz <= 0) { |
| return false; |
| } |
| |
| // `high_speed_mode_data_lane_bytes_per_second` and `escape_mode_clock_lane_frequency_hz` |
| // calculation may introduce rounding errors, so the clock frequency ratio |
| // might not be integer and we need to round it to its nearest integral |
| // value. We add a small threshold (1 / 10000) for the ratio ensure that |
| // the error is not too large. |
| constexpr double kHighSpeedByteClockToEscapeLockFrequencyRatioErrorThreshold = 1.0 / 10000; |
| |
| const double actual_high_speed_byte_clock_to_escape_clock_frequency_ratio = |
| static_cast<double>(high_speed_mode_data_lane_bytes_per_second()) / |
| static_cast<double>(escape_mode_clock_lane_frequency_hz); |
| |
| // round(a / b) = (a + b div 2) div b |
| const int64_t high_speed_byte_clock_to_escape_clock_frequency_ratio = |
| (high_speed_mode_data_lane_bytes_per_second() + escape_mode_clock_lane_frequency_hz / 2) / |
| escape_mode_clock_lane_frequency_hz; |
| |
| if (fabs(static_cast<double>(high_speed_byte_clock_to_escape_clock_frequency_ratio) - |
| actual_high_speed_byte_clock_to_escape_clock_frequency_ratio) > |
| kHighSpeedByteClockToEscapeLockFrequencyRatioErrorThreshold) { |
| return false; |
| } |
| |
| if (high_speed_byte_clock_to_escape_clock_frequency_ratio > |
| kMaxHighSpeedByteClockToEscapeClockFrequencyRatio) { |
| return false; |
| } |
| |
| if (max_data_lane_hs_to_lp_transition_duration_lane_byte_clock_cycles < |
| kMinPossibleMaxDataLaneHsToLpTransitionDurationLaneByteClockCycles) { |
| return false; |
| } |
| if (max_data_lane_hs_to_lp_transition_duration_lane_byte_clock_cycles > |
| kMaxPossibleMaxDataLaneHsToLpTransitionDurationLaneByteClockCycles) { |
| return false; |
| } |
| |
| if (max_data_lane_lp_to_hs_transition_duration_lane_byte_clock_cycles < |
| kMinPossibleMaxDataLaneLpToHsTransitionDurationLaneByteClockCycles) { |
| return false; |
| } |
| if (max_data_lane_lp_to_hs_transition_duration_lane_byte_clock_cycles > |
| kMaxPossibleMaxDataLaneLpToHsTransitionDurationLaneByteClockCycles) { |
| return false; |
| } |
| |
| if (max_clock_lane_hs_to_lp_transition_duration_lane_byte_clock_cycles < |
| kMinPossibleMaxClockLaneHsToLpTransitionDurationLaneByteClockCycles) { |
| return false; |
| } |
| if (max_clock_lane_hs_to_lp_transition_duration_lane_byte_clock_cycles > |
| kMaxPossibleMaxClockLaneHsToLpTransitionDurationLaneByteClockCycles) { |
| return false; |
| } |
| |
| if (max_clock_lane_lp_to_hs_transition_duration_lane_byte_clock_cycles < |
| kMinPossibleMaxClockLaneLpToHsTransitionDurationLaneByteClockCycles) { |
| return false; |
| } |
| if (max_clock_lane_lp_to_hs_transition_duration_lane_byte_clock_cycles > |
| kMaxPossibleMaxClockLaneLpToHsTransitionDurationLaneByteClockCycles) { |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace designware_dsi |
| |
| #endif // SRC_GRAPHICS_DISPLAY_LIB_DESIGNWARE_DSI_DPHY_INTERFACE_CONFIG_H_ |