blob: 9556684b18f47c924d951e826cdc435f1b634dc0 [file] [log] [blame]
// 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_