2009-04-07 23:16:42 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2008 Keith Packard
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
|
|
* that the name of the copyright holders not be used in advertising or
|
|
|
|
* publicity pertaining to distribution of the software without specific,
|
|
|
|
* written prior permission. The copyright holders make no representations
|
|
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
|
|
* is" without express or implied warranty.
|
|
|
|
*
|
|
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
|
|
* OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2009-12-04 00:55:24 +00:00
|
|
|
#ifndef _DRM_DP_HELPER_H_
|
|
|
|
#define _DRM_DP_HELPER_H_
|
2009-04-07 23:16:42 +00:00
|
|
|
|
2012-10-18 13:32:40 +00:00
|
|
|
#include <linux/delay.h>
|
2019-10-21 14:34:25 +00:00
|
|
|
#include <linux/i2c.h>
|
2022-04-21 07:31:04 +00:00
|
|
|
|
|
|
|
#include <drm/display/drm_dp.h>
|
2020-04-24 12:50:51 +00:00
|
|
|
#include <drm/drm_connector.h>
|
2010-10-07 23:01:14 +00:00
|
|
|
|
2020-09-04 11:53:49 +00:00
|
|
|
struct drm_device;
|
2021-04-23 18:42:57 +00:00
|
|
|
struct drm_dp_aux;
|
2021-07-12 15:00:44 +00:00
|
|
|
struct drm_panel;
|
2020-09-04 11:53:49 +00:00
|
|
|
|
2013-09-27 16:01:01 +00:00
|
|
|
bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
|
2012-10-18 08:15:24 +00:00
|
|
|
int lane_count);
|
2013-09-27 16:01:01 +00:00
|
|
|
bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
|
2012-10-18 08:15:25 +00:00
|
|
|
int lane_count);
|
2013-09-27 16:01:01 +00:00
|
|
|
u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE],
|
2012-10-18 08:15:27 +00:00
|
|
|
int lane);
|
2013-09-27 16:01:01 +00:00
|
|
|
u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE],
|
2012-10-18 08:15:27 +00:00
|
|
|
int lane);
|
2021-09-09 12:51:56 +00:00
|
|
|
u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE],
|
|
|
|
int lane);
|
2012-10-18 08:15:24 +00:00
|
|
|
|
2021-10-14 15:00:57 +00:00
|
|
|
int drm_dp_read_clock_recovery_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
enum drm_dp_phy dp_phy, bool uhbr);
|
|
|
|
int drm_dp_read_channel_eq_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
enum drm_dp_phy dp_phy, bool uhbr);
|
|
|
|
|
2021-04-23 18:42:57 +00:00
|
|
|
void drm_dp_link_train_clock_recovery_delay(const struct drm_dp_aux *aux,
|
|
|
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
|
2020-10-07 17:09:15 +00:00
|
|
|
void drm_dp_lttpr_link_train_clock_recovery_delay(void);
|
2021-04-23 18:42:58 +00:00
|
|
|
void drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux,
|
|
|
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
|
|
|
|
void drm_dp_lttpr_link_train_channel_eq_delay(const struct drm_dp_aux *aux,
|
|
|
|
const u8 caps[DP_LTTPR_PHY_CAP_SIZE]);
|
2012-10-18 13:32:40 +00:00
|
|
|
|
2022-02-03 09:03:50 +00:00
|
|
|
int drm_dp_128b132b_read_aux_rd_interval(struct drm_dp_aux *aux);
|
2022-02-03 09:03:51 +00:00
|
|
|
bool drm_dp_128b132b_lane_channel_eq_done(const u8 link_status[DP_LINK_STATUS_SIZE],
|
|
|
|
int lane_count);
|
|
|
|
bool drm_dp_128b132b_lane_symbol_locked(const u8 link_status[DP_LINK_STATUS_SIZE],
|
|
|
|
int lane_count);
|
|
|
|
bool drm_dp_128b132b_eq_interlane_align_done(const u8 link_status[DP_LINK_STATUS_SIZE]);
|
|
|
|
bool drm_dp_128b132b_cds_interlane_align_done(const u8 link_status[DP_LINK_STATUS_SIZE]);
|
|
|
|
bool drm_dp_128b132b_link_training_failed(const u8 link_status[DP_LINK_STATUS_SIZE]);
|
2022-02-03 09:03:50 +00:00
|
|
|
|
2012-10-18 08:15:31 +00:00
|
|
|
u8 drm_dp_link_rate_to_bw_code(int link_rate);
|
|
|
|
int drm_dp_bw_code_to_link_rate(u8 link_bw);
|
|
|
|
|
2022-08-15 08:58:34 +00:00
|
|
|
const char *drm_dp_phy_name(enum drm_dp_phy dp_phy);
|
|
|
|
|
2020-02-11 07:46:40 +00:00
|
|
|
/**
|
|
|
|
* struct drm_dp_vsc_sdp - drm DP VSC SDP
|
|
|
|
*
|
|
|
|
* This structure represents a DP VSC SDP of drm
|
|
|
|
* It is based on DP 1.4 spec [Table 2-116: VSC SDP Header Bytes] and
|
|
|
|
* [Table 2-117: VSC SDP Payload for DB16 through DB18]
|
|
|
|
*
|
|
|
|
* @sdp_type: secondary-data packet type
|
|
|
|
* @revision: revision number
|
|
|
|
* @length: number of valid data bytes
|
|
|
|
* @pixelformat: pixel encoding format
|
|
|
|
* @colorimetry: colorimetry format
|
|
|
|
* @bpc: bit per color
|
|
|
|
* @dynamic_range: dynamic range information
|
|
|
|
* @content_type: CTA-861-G defines content types and expected processing by a sink device
|
|
|
|
*/
|
|
|
|
struct drm_dp_vsc_sdp {
|
|
|
|
unsigned char sdp_type;
|
|
|
|
unsigned char revision;
|
|
|
|
unsigned char length;
|
|
|
|
enum dp_pixelformat pixelformat;
|
|
|
|
enum dp_colorimetry colorimetry;
|
|
|
|
int bpc;
|
|
|
|
enum dp_dynamic_range dynamic_range;
|
|
|
|
enum dp_content_type content_type;
|
|
|
|
};
|
|
|
|
|
2020-05-14 06:07:21 +00:00
|
|
|
void drm_dp_vsc_sdp_log(const char *level, struct device *dev,
|
|
|
|
const struct drm_dp_vsc_sdp *vsc);
|
|
|
|
|
2016-05-18 08:57:29 +00:00
|
|
|
int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]);
|
|
|
|
|
2012-10-18 08:15:31 +00:00
|
|
|
static inline int
|
2013-09-27 16:01:01 +00:00
|
|
|
drm_dp_max_link_rate(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
2012-10-18 08:15:31 +00:00
|
|
|
{
|
|
|
|
return drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]);
|
|
|
|
}
|
2012-10-22 20:56:43 +00:00
|
|
|
|
|
|
|
static inline u8
|
2013-09-27 16:01:01 +00:00
|
|
|
drm_dp_max_lane_count(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
2012-10-22 20:56:43 +00:00
|
|
|
{
|
|
|
|
return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
|
|
|
|
}
|
|
|
|
|
2013-10-04 12:08:08 +00:00
|
|
|
static inline bool
|
|
|
|
drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_DPCD_REV] >= 0x11 &&
|
|
|
|
(dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP);
|
|
|
|
}
|
|
|
|
|
2019-10-21 14:34:27 +00:00
|
|
|
static inline bool
|
|
|
|
drm_dp_fast_training_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_DPCD_REV] >= 0x11 &&
|
|
|
|
(dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING);
|
|
|
|
}
|
|
|
|
|
2015-08-26 11:33:31 +00:00
|
|
|
static inline bool
|
|
|
|
drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_DPCD_REV] >= 0x12 &&
|
|
|
|
dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2021-11-02 07:48:43 +00:00
|
|
|
static inline bool
|
|
|
|
drm_dp_max_downspread(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_DPCD_REV] >= 0x11 ||
|
|
|
|
dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5;
|
|
|
|
}
|
|
|
|
|
2018-01-22 22:43:11 +00:00
|
|
|
static inline bool
|
|
|
|
drm_dp_tps4_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_DPCD_REV] >= 0x14 &&
|
|
|
|
dpcd[DP_MAX_DOWNSPREAD] & DP_TPS4_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8
|
|
|
|
drm_dp_training_pattern_mask(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return (dpcd[DP_DPCD_REV] >= 0x14) ? DP_TRAINING_PATTERN_MASK_1_4 :
|
|
|
|
DP_TRAINING_PATTERN_MASK;
|
|
|
|
}
|
|
|
|
|
2016-10-24 16:33:24 +00:00
|
|
|
static inline bool
|
|
|
|
drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT;
|
|
|
|
}
|
|
|
|
|
2018-10-31 00:19:20 +00:00
|
|
|
/* DP/eDP DSC support */
|
|
|
|
u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
|
|
|
|
bool is_edp);
|
|
|
|
u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]);
|
2018-11-27 21:41:03 +00:00
|
|
|
int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpc[DP_DSC_RECEIVER_CAP_SIZE],
|
|
|
|
u8 dsc_bpc[3]);
|
2018-10-31 00:19:20 +00:00
|
|
|
|
|
|
|
static inline bool
|
|
|
|
drm_dp_sink_supports_dsc(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dsc_dpcd[DP_DSC_SUPPORT - DP_DSC_SUPPORT] &
|
|
|
|
DP_DSC_DECOMPRESSION_IS_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u16
|
|
|
|
drm_edp_dsc_sink_output_bpp(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_LOW - DP_DSC_SUPPORT] |
|
2023-04-06 13:46:14 +00:00
|
|
|
((dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_HI - DP_DSC_SUPPORT] &
|
|
|
|
DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK) << 8);
|
2018-10-31 00:19:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32
|
|
|
|
drm_dp_dsc_sink_max_slice_width(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
/* Max Slicewidth = Number of Pixels * 320 */
|
|
|
|
return dsc_dpcd[DP_DSC_MAX_SLICE_WIDTH - DP_DSC_SUPPORT] *
|
|
|
|
DP_DSC_SLICE_WIDTH_MULTIPLIER;
|
|
|
|
}
|
|
|
|
|
2023-03-09 06:28:49 +00:00
|
|
|
/**
|
|
|
|
* drm_dp_dsc_sink_supports_format() - check if sink supports DSC with given output format
|
|
|
|
* @dsc_dpcd : DSC-capability DPCDs of the sink
|
|
|
|
* @output_format: output_format which is to be checked
|
|
|
|
*
|
|
|
|
* Returns true if the sink supports DSC with the given output_format, false otherwise.
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
drm_dp_dsc_sink_supports_format(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], u8 output_format)
|
|
|
|
{
|
|
|
|
return dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT] & output_format;
|
|
|
|
}
|
|
|
|
|
2018-11-02 04:14:55 +00:00
|
|
|
/* Forward Error Correction Support on DP 1.4 */
|
|
|
|
static inline bool
|
|
|
|
drm_dp_sink_supports_fec(const u8 fec_capable)
|
|
|
|
{
|
|
|
|
return fec_capable & DP_FEC_CAPABLE;
|
|
|
|
}
|
|
|
|
|
2019-10-21 14:34:28 +00:00
|
|
|
static inline bool
|
|
|
|
drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B;
|
|
|
|
}
|
|
|
|
|
2019-10-21 14:34:29 +00:00
|
|
|
static inline bool
|
|
|
|
drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_EDP_CONFIGURATION_CAP] &
|
|
|
|
DP_ALTERNATE_SCRAMBLER_RESET_CAP;
|
|
|
|
}
|
|
|
|
|
2020-06-19 21:23:54 +00:00
|
|
|
/* Ignore MSA timing for Adaptive Sync support on DP 1.4 */
|
|
|
|
static inline bool
|
|
|
|
drm_dp_sink_can_do_video_without_timing_msa(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
|
|
|
{
|
|
|
|
return dpcd[DP_DOWN_STREAM_PORT_COUNT] &
|
|
|
|
DP_MSA_TIMING_PAR_IGNORED;
|
|
|
|
}
|
|
|
|
|
2021-05-14 18:15:02 +00:00
|
|
|
/**
|
|
|
|
* drm_edp_backlight_supported() - Check an eDP DPCD for VESA backlight support
|
|
|
|
* @edp_dpcd: The DPCD to check
|
|
|
|
*
|
|
|
|
* Note that currently this function will return %false for panels which support various DPCD
|
|
|
|
* backlight features but which require the brightness be set through PWM, and don't support setting
|
2021-11-05 18:33:41 +00:00
|
|
|
* the brightness level via the DPCD.
|
2021-05-14 18:15:02 +00:00
|
|
|
*
|
|
|
|
* Returns: %True if @edp_dpcd indicates that VESA backlight controls are supported, %false
|
|
|
|
* otherwise
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
drm_edp_backlight_supported(const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE])
|
|
|
|
{
|
2021-11-05 18:33:41 +00:00
|
|
|
return !!(edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP);
|
2021-05-14 18:15:02 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:31:00 +00:00
|
|
|
/*
|
|
|
|
* DisplayPort AUX channel
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct drm_dp_aux_msg - DisplayPort AUX channel transaction
|
|
|
|
* @address: address of the (first) register to access
|
|
|
|
* @request: contains the type of transaction (see DP_AUX_* macros)
|
|
|
|
* @reply: upon completion, contains the reply type of the transaction
|
|
|
|
* @buffer: pointer to a transmission or reception buffer
|
|
|
|
* @size: size of @buffer
|
|
|
|
*/
|
|
|
|
struct drm_dp_aux_msg {
|
|
|
|
unsigned int address;
|
|
|
|
u8 request;
|
|
|
|
u8 reply;
|
|
|
|
void *buffer;
|
|
|
|
size_t size;
|
|
|
|
};
|
|
|
|
|
2018-07-11 13:29:07 +00:00
|
|
|
struct cec_adapter;
|
2019-08-14 10:44:59 +00:00
|
|
|
struct drm_connector;
|
2023-10-04 16:21:49 +00:00
|
|
|
struct drm_edid;
|
2018-07-11 13:29:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* struct drm_dp_aux_cec - DisplayPort CEC-Tunneling-over-AUX
|
|
|
|
* @lock: mutex protecting this struct
|
|
|
|
* @adap: the CEC adapter for CEC-Tunneling-over-AUX support.
|
2019-08-14 10:44:59 +00:00
|
|
|
* @connector: the connector this CEC adapter is associated with
|
2018-07-11 13:29:07 +00:00
|
|
|
* @unregister_work: unregister the CEC adapter
|
|
|
|
*/
|
|
|
|
struct drm_dp_aux_cec {
|
|
|
|
struct mutex lock;
|
|
|
|
struct cec_adapter *adap;
|
2019-08-14 10:44:59 +00:00
|
|
|
struct drm_connector *connector;
|
2018-07-11 13:29:07 +00:00
|
|
|
struct delayed_work unregister_work;
|
|
|
|
};
|
|
|
|
|
2013-11-28 10:31:00 +00:00
|
|
|
/**
|
|
|
|
* struct drm_dp_aux - DisplayPort AUX channel
|
2013-12-12 08:57:53 +00:00
|
|
|
*
|
|
|
|
* An AUX channel can also be used to transport I2C messages to a sink. A
|
2021-03-26 20:37:48 +00:00
|
|
|
* typical application of that is to access an EDID that's present in the sink
|
|
|
|
* device. The @transfer() function can also be used to execute such
|
|
|
|
* transactions. The drm_dp_aux_register() function registers an I2C adapter
|
|
|
|
* that can be passed to drm_probe_ddc(). Upon removal, drivers should call
|
|
|
|
* drm_dp_aux_unregister() to remove the I2C adapter. The I2C adapter uses long
|
|
|
|
* transfers by default; if a partial response is received, the adapter will
|
|
|
|
* drop down to the size given by the partial response for this transaction
|
|
|
|
* only.
|
2013-11-28 10:31:00 +00:00
|
|
|
*/
|
|
|
|
struct drm_dp_aux {
|
2021-06-16 14:15:27 +00:00
|
|
|
/**
|
|
|
|
* @name: user-visible name of this AUX channel and the
|
|
|
|
* I2C-over-AUX adapter.
|
|
|
|
*
|
|
|
|
* It's also used to specify the name of the I2C adapter. If set
|
|
|
|
* to %NULL, dev_name() of @dev will be used.
|
|
|
|
*/
|
2014-03-14 14:51:12 +00:00
|
|
|
const char *name;
|
2021-06-16 14:15:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @ddc: I2C adapter that can be used for I2C-over-AUX
|
|
|
|
* communication
|
|
|
|
*/
|
2013-12-12 08:57:53 +00:00
|
|
|
struct i2c_adapter ddc;
|
2021-06-16 14:15:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev: pointer to struct device that is the parent for this
|
|
|
|
* AUX channel.
|
|
|
|
*/
|
2013-11-28 10:31:00 +00:00
|
|
|
struct device *dev;
|
2021-06-16 14:15:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @drm_dev: pointer to the &drm_device that owns this AUX channel.
|
|
|
|
* Beware, this may be %NULL before drm_dp_aux_register() has been
|
|
|
|
* called.
|
|
|
|
*
|
|
|
|
* It should be set to the &drm_device that will be using this AUX
|
|
|
|
* channel as early as possible. For many graphics drivers this should
|
|
|
|
* happen before drm_dp_aux_init(), however it's perfectly fine to set
|
|
|
|
* this field later so long as it's assigned before calling
|
|
|
|
* drm_dp_aux_register().
|
|
|
|
*/
|
2021-04-23 18:42:55 +00:00
|
|
|
struct drm_device *drm_dev;
|
2021-06-16 14:15:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @crtc: backpointer to the crtc that is currently using this
|
|
|
|
* AUX channel
|
|
|
|
*/
|
2017-03-03 13:39:33 +00:00
|
|
|
struct drm_crtc *crtc;
|
2021-06-16 14:15:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @hw_mutex: internal mutex used for locking transfers.
|
2021-06-16 14:15:28 +00:00
|
|
|
*
|
|
|
|
* Note that if the underlying hardware is shared among multiple
|
|
|
|
* channels, the driver needs to do additional locking to
|
|
|
|
* prevent concurrent access.
|
2021-06-16 14:15:27 +00:00
|
|
|
*/
|
2014-06-04 06:02:28 +00:00
|
|
|
struct mutex hw_mutex;
|
2021-06-16 14:15:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @crc_work: worker that captures CRCs for each frame
|
|
|
|
*/
|
2017-03-03 13:39:34 +00:00
|
|
|
struct work_struct crc_work;
|
2021-06-16 14:15:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @crc_count: counter of captured frame CRCs
|
|
|
|
*/
|
2017-03-03 13:39:34 +00:00
|
|
|
u8 crc_count;
|
2021-06-16 14:15:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @transfer: transfers a message representing a single AUX
|
|
|
|
* transaction.
|
|
|
|
*
|
|
|
|
* This is a hardware-specific implementation of how
|
|
|
|
* transactions are executed that the drivers must provide.
|
|
|
|
*
|
|
|
|
* A pointer to a &drm_dp_aux_msg structure describing the
|
|
|
|
* transaction is passed into this function. Upon success, the
|
|
|
|
* implementation should return the number of payload bytes that
|
|
|
|
* were transferred, or a negative error-code on failure.
|
|
|
|
*
|
|
|
|
* Helpers will propagate these errors, with the exception of
|
|
|
|
* the %-EBUSY error, which causes a transaction to be retried.
|
|
|
|
* On a short, helpers will return %-EPROTO to make it simpler
|
|
|
|
* to check for failure.
|
|
|
|
*
|
|
|
|
* The @transfer() function must only modify the reply field of
|
|
|
|
* the &drm_dp_aux_msg structure. The retry logic and i2c
|
|
|
|
* helpers assume this is the case.
|
2021-06-16 14:15:29 +00:00
|
|
|
*
|
|
|
|
* Also note that this callback can be called no matter the
|
2022-05-09 23:18:09 +00:00
|
|
|
* state @dev is in and also no matter what state the panel is
|
|
|
|
* in. It's expected:
|
2022-06-11 16:55:04 +00:00
|
|
|
*
|
2022-05-09 23:18:09 +00:00
|
|
|
* - If the @dev providing the AUX bus is currently unpowered then
|
|
|
|
* it will power itself up for the transfer.
|
2022-06-11 16:55:04 +00:00
|
|
|
*
|
2022-05-09 23:18:09 +00:00
|
|
|
* - If we're on eDP (using a drm_panel) and the panel is not in a
|
|
|
|
* state where it can respond (it's not powered or it's in a
|
|
|
|
* low power state) then this function may return an error, but
|
|
|
|
* not crash. It's up to the caller of this code to make sure that
|
|
|
|
* the panel is powered on if getting an error back is not OK. If a
|
|
|
|
* drm_panel driver is initiating a DP AUX transfer it may power
|
|
|
|
* itself up however it wants. All other code should ensure that
|
|
|
|
* the pre_enable() bridge chain (which eventually calls the
|
|
|
|
* drm_panel prepare function) has powered the panel.
|
2021-06-16 14:15:27 +00:00
|
|
|
*/
|
2013-11-28 10:31:00 +00:00
|
|
|
ssize_t (*transfer)(struct drm_dp_aux *aux,
|
|
|
|
struct drm_dp_aux_msg *msg);
|
2021-06-16 14:15:27 +00:00
|
|
|
|
2022-06-14 21:54:15 +00:00
|
|
|
/**
|
|
|
|
* @wait_hpd_asserted: wait for HPD to be asserted
|
|
|
|
*
|
|
|
|
* This is mainly useful for eDP panels drivers to wait for an eDP
|
|
|
|
* panel to finish powering on. This is an optional function.
|
|
|
|
*
|
|
|
|
* This function will efficiently wait for the HPD signal to be
|
|
|
|
* asserted. The `wait_us` parameter that is passed in says that we
|
|
|
|
* know that the HPD signal is expected to be asserted within `wait_us`
|
|
|
|
* microseconds. This function could wait for longer than `wait_us` if
|
|
|
|
* the logic in the DP controller has a long debouncing time. The
|
|
|
|
* important thing is that if this function returns success that the
|
|
|
|
* DP controller is ready to send AUX transactions.
|
|
|
|
*
|
|
|
|
* This function returns 0 if HPD was asserted or -ETIMEDOUT if time
|
|
|
|
* expired and HPD wasn't asserted. This function should not print
|
|
|
|
* timeout errors to the log.
|
|
|
|
*
|
|
|
|
* The semantics of this function are designed to match the
|
|
|
|
* readx_poll_timeout() function. That means a `wait_us` of 0 means
|
|
|
|
* to wait forever. Like readx_poll_timeout(), this function may sleep.
|
|
|
|
*
|
|
|
|
* NOTE: this function specifically reports the state of the HPD pin
|
|
|
|
* that's associated with the DP AUX channel. This is different from
|
|
|
|
* the HPD concept in much of the rest of DRM which is more about
|
|
|
|
* physical presence of a display. For eDP, for instance, a display is
|
|
|
|
* assumed always present even if the HPD pin is deasserted.
|
|
|
|
*/
|
|
|
|
int (*wait_hpd_asserted)(struct drm_dp_aux *aux, unsigned long wait_us);
|
|
|
|
|
2016-07-15 19:48:02 +00:00
|
|
|
/**
|
|
|
|
* @i2c_nack_count: Counts I2C NACKs, used for DP validation.
|
|
|
|
*/
|
|
|
|
unsigned i2c_nack_count;
|
|
|
|
/**
|
|
|
|
* @i2c_defer_count: Counts I2C DEFERs, used for DP validation.
|
|
|
|
*/
|
|
|
|
unsigned i2c_defer_count;
|
2018-07-11 13:29:07 +00:00
|
|
|
/**
|
|
|
|
* @cec: struct containing fields used for CEC-Tunneling-over-AUX.
|
|
|
|
*/
|
|
|
|
struct drm_dp_aux_cec cec;
|
drm/dp_mst: Enable registration of AUX devices for MST ports
All available downstream ports - physical and logical - are exposed for
each MST device. They are listed in /dev/, following the same naming
scheme as SST devices by appending an incremental ID.
Although all downstream ports are exposed, only some will work as
expected. Consider the following topology:
+---------+
| ASIC |
+---------+
Conn-0|
|
+----v----+
+----| MST HUB |----+
| +---------+ |
| |
|Port-1 Port-2|
+-----v-----+ +-----v-----+
| MST | | SST |
| Display | | Display |
+-----------+ +-----------+
|Port-1
x
MST Path | MST Device
----------+----------------------------------
sst:0 | MST Hub
mst:0-1 | MST Display
mst:0-1-1 | MST Display's disconnected DP out
mst:0-1-8 | MST Display's internal sink
mst:0-2 | SST Display
On certain MST displays, the upstream physical port will ACK DPCD reads.
However, reads on the local logical port to the internal sink will
*NAK*. i.e. reading mst:0-1 ACKs, but mst:0-1-8 NAKs.
There may also be duplicates. Some displays will return the same GUID
when reading DPCD from both mst:0-1 and mst:0-1-8.
There are some device-dependent behavior as well. The MST hub used
during testing will actually *ACK* read requests on a disconnected
physical port, whereas the MST displays will NAK.
In light of these discrepancies, it's simpler to expose all downstream
ports - both physical and logical - and let the user decide what to use.
v3 changes:
* Change WARN_ON_ONCE -> DRM_ERROR on dpcd read errors
* Docstring and cosmetic fixes
v2 changes:
Moved remote aux device (un)registration to new mst connector late
register and early unregister helpers. Drivers should call these from
their own mst connector function hooks.
This is to solve an issue during driver unload, where mst connector
devices are unregistered before the remote aux devices are. In a setup
where aux devices are created as children of connector devices, the aux
device would be removed too early, and uncleanly. Doing so in
early_unregister solves this issue, as that is called before connector
unregistration.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Leo Li <sunpeng.li@amd.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190723232808.28128-3-sunpeng.li@amd.com
2019-07-23 23:28:01 +00:00
|
|
|
/**
|
|
|
|
* @is_remote: Is this AUX CH actually using sideband messaging.
|
|
|
|
*/
|
|
|
|
bool is_remote;
|
2013-11-28 10:31:00 +00:00
|
|
|
};
|
|
|
|
|
2022-04-11 13:25:39 +00:00
|
|
|
int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset);
|
2013-11-28 10:31:00 +00:00
|
|
|
ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
|
|
|
|
void *buffer, size_t size);
|
|
|
|
ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
|
|
|
|
void *buffer, size_t size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* drm_dp_dpcd_readb() - read a single byte from the DPCD
|
|
|
|
* @aux: DisplayPort AUX channel
|
|
|
|
* @offset: address of the register to read
|
|
|
|
* @valuep: location where the value of the register will be stored
|
|
|
|
*
|
|
|
|
* Returns the number of bytes transferred (1) on success, or a negative
|
|
|
|
* error code on failure.
|
|
|
|
*/
|
|
|
|
static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux,
|
|
|
|
unsigned int offset, u8 *valuep)
|
|
|
|
{
|
|
|
|
return drm_dp_dpcd_read(aux, offset, valuep, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* drm_dp_dpcd_writeb() - write a single byte to the DPCD
|
|
|
|
* @aux: DisplayPort AUX channel
|
|
|
|
* @offset: address of the register to write
|
|
|
|
* @value: value to write to the register
|
|
|
|
*
|
|
|
|
* Returns the number of bytes transferred (1) on success, or a negative
|
|
|
|
* error code on failure.
|
|
|
|
*/
|
|
|
|
static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux,
|
|
|
|
unsigned int offset, u8 value)
|
|
|
|
{
|
|
|
|
return drm_dp_dpcd_write(aux, offset, &value, 1);
|
|
|
|
}
|
|
|
|
|
2020-08-26 18:24:55 +00:00
|
|
|
int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux,
|
|
|
|
u8 dpcd[DP_RECEIVER_CAP_SIZE]);
|
|
|
|
|
2013-11-22 15:37:57 +00:00
|
|
|
int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
|
|
|
|
u8 status[DP_LINK_STATUS_SIZE]);
|
|
|
|
|
2020-10-07 17:09:15 +00:00
|
|
|
int drm_dp_dpcd_read_phy_link_status(struct drm_dp_aux *aux,
|
|
|
|
enum drm_dp_phy dp_phy,
|
|
|
|
u8 link_status[DP_LINK_STATUS_SIZE]);
|
|
|
|
|
2020-02-11 16:08:32 +00:00
|
|
|
bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux,
|
|
|
|
u8 real_edid_checksum);
|
|
|
|
|
2020-08-26 18:24:49 +00:00
|
|
|
int drm_dp_read_downstream_info(struct drm_dp_aux *aux,
|
|
|
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]);
|
2020-09-04 11:53:42 +00:00
|
|
|
bool drm_dp_downstream_is_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4], u8 type);
|
|
|
|
bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4],
|
2023-10-04 16:21:49 +00:00
|
|
|
const struct drm_edid *drm_edid);
|
2020-09-04 11:53:44 +00:00
|
|
|
int drm_dp_downstream_max_dotclock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4]);
|
2020-09-04 11:53:46 +00:00
|
|
|
int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4],
|
2023-10-04 16:21:49 +00:00
|
|
|
const struct drm_edid *drm_edid);
|
2020-09-04 11:53:46 +00:00
|
|
|
int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4],
|
2023-10-04 16:21:49 +00:00
|
|
|
const struct drm_edid *drm_edid);
|
2016-09-09 11:10:50 +00:00
|
|
|
int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
2020-09-04 11:53:43 +00:00
|
|
|
const u8 port_cap[4],
|
2023-10-04 16:21:49 +00:00
|
|
|
const struct drm_edid *drm_edid);
|
2020-09-04 11:53:53 +00:00
|
|
|
bool drm_dp_downstream_420_passthrough(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4]);
|
|
|
|
bool drm_dp_downstream_444_to_420_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4]);
|
2020-09-04 11:53:49 +00:00
|
|
|
struct drm_display_mode *drm_dp_downstream_mode(struct drm_device *dev,
|
|
|
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4]);
|
2016-09-09 11:10:51 +00:00
|
|
|
int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]);
|
2020-09-04 11:53:43 +00:00
|
|
|
void drm_dp_downstream_debug(struct seq_file *m,
|
|
|
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4],
|
2023-10-04 16:21:49 +00:00
|
|
|
const struct drm_edid *drm_edid,
|
2020-09-04 11:53:43 +00:00
|
|
|
struct drm_dp_aux *aux);
|
2020-04-24 12:50:51 +00:00
|
|
|
enum drm_mode_subconnector
|
|
|
|
drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4]);
|
|
|
|
void drm_dp_set_subconnector_property(struct drm_connector *connector,
|
|
|
|
enum drm_connector_status status,
|
|
|
|
const u8 *dpcd,
|
|
|
|
const u8 port_cap[4]);
|
2013-12-09 10:47:55 +00:00
|
|
|
|
2020-08-26 18:24:51 +00:00
|
|
|
struct drm_dp_desc;
|
|
|
|
bool drm_dp_read_sink_count_cap(struct drm_connector *connector,
|
|
|
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const struct drm_dp_desc *desc);
|
2020-08-26 18:24:52 +00:00
|
|
|
int drm_dp_read_sink_count(struct drm_dp_aux *aux);
|
2013-12-09 10:47:55 +00:00
|
|
|
|
2020-10-07 17:09:15 +00:00
|
|
|
int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux,
|
2022-03-22 14:38:44 +00:00
|
|
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
2020-10-07 17:09:15 +00:00
|
|
|
u8 caps[DP_LTTPR_COMMON_CAP_SIZE]);
|
|
|
|
int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux,
|
2022-03-22 14:38:44 +00:00
|
|
|
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
2020-10-07 17:09:15 +00:00
|
|
|
enum drm_dp_phy dp_phy,
|
|
|
|
u8 caps[DP_LTTPR_PHY_CAP_SIZE]);
|
|
|
|
int drm_dp_lttpr_count(const u8 cap[DP_LTTPR_COMMON_CAP_SIZE]);
|
|
|
|
int drm_dp_lttpr_max_link_rate(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]);
|
|
|
|
int drm_dp_lttpr_max_lane_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]);
|
|
|
|
bool drm_dp_lttpr_voltage_swing_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]);
|
|
|
|
bool drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]);
|
|
|
|
|
2019-12-06 22:56:37 +00:00
|
|
|
void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
|
2016-06-17 08:33:18 +00:00
|
|
|
void drm_dp_aux_init(struct drm_dp_aux *aux);
|
2014-06-04 06:02:28 +00:00
|
|
|
int drm_dp_aux_register(struct drm_dp_aux *aux);
|
|
|
|
void drm_dp_aux_unregister(struct drm_dp_aux *aux);
|
2013-12-12 08:57:53 +00:00
|
|
|
|
2017-03-03 13:39:34 +00:00
|
|
|
int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc);
|
|
|
|
int drm_dp_stop_crc(struct drm_dp_aux *aux);
|
|
|
|
|
2017-05-18 11:10:22 +00:00
|
|
|
struct drm_dp_dpcd_ident {
|
|
|
|
u8 oui[3];
|
|
|
|
u8 device_id[6];
|
|
|
|
u8 hw_rev;
|
|
|
|
u8 sw_major_rev;
|
|
|
|
u8 sw_minor_rev;
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct drm_dp_desc - DP branch/sink device descriptor
|
|
|
|
* @ident: DP device identification from DPCD 0x400 (sink) or 0x500 (branch).
|
2017-05-18 11:10:24 +00:00
|
|
|
* @quirks: Quirks; use drm_dp_has_quirk() to query for the quirks.
|
2017-05-18 11:10:22 +00:00
|
|
|
*/
|
|
|
|
struct drm_dp_desc {
|
|
|
|
struct drm_dp_dpcd_ident ident;
|
2017-05-18 11:10:24 +00:00
|
|
|
u32 quirks;
|
2017-05-18 11:10:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc,
|
|
|
|
bool is_branch);
|
|
|
|
|
2017-05-18 11:10:24 +00:00
|
|
|
/**
|
|
|
|
* enum drm_dp_quirk - Display Port sink/branch device specific quirks
|
|
|
|
*
|
|
|
|
* Display Port sink and branch devices in the wild have a variety of bugs, try
|
|
|
|
* to collect them here. The quirks are shared, but it's up to the drivers to
|
2020-09-15 16:49:13 +00:00
|
|
|
* implement workarounds for them.
|
2017-05-18 11:10:24 +00:00
|
|
|
*/
|
|
|
|
enum drm_dp_quirk {
|
|
|
|
/**
|
2018-09-12 06:22:50 +00:00
|
|
|
* @DP_DPCD_QUIRK_CONSTANT_N:
|
2017-05-18 11:10:24 +00:00
|
|
|
*
|
|
|
|
* The device requires main link attributes Mvid and Nvid to be limited
|
2018-09-12 06:22:50 +00:00
|
|
|
* to 16 bits. So will give a constant value (0x8000) for compatability.
|
2017-05-18 11:10:24 +00:00
|
|
|
*/
|
2018-09-12 06:22:50 +00:00
|
|
|
DP_DPCD_QUIRK_CONSTANT_N,
|
2018-12-04 00:33:55 +00:00
|
|
|
/**
|
2018-12-05 18:48:50 +00:00
|
|
|
* @DP_DPCD_QUIRK_NO_PSR:
|
2018-12-04 00:33:55 +00:00
|
|
|
*
|
|
|
|
* The device does not support PSR even if reports that it supports or
|
|
|
|
* driver still need to implement proper handling for such device.
|
|
|
|
*/
|
|
|
|
DP_DPCD_QUIRK_NO_PSR,
|
2019-05-28 14:06:49 +00:00
|
|
|
/**
|
|
|
|
* @DP_DPCD_QUIRK_NO_SINK_COUNT:
|
|
|
|
*
|
|
|
|
* The device does not set SINK_COUNT to a non-zero value.
|
2020-08-26 18:24:51 +00:00
|
|
|
* The driver should ignore SINK_COUNT during detection. Note that
|
|
|
|
* drm_dp_read_sink_count_cap() automatically checks for this quirk.
|
2019-05-28 14:06:49 +00:00
|
|
|
*/
|
|
|
|
DP_DPCD_QUIRK_NO_SINK_COUNT,
|
2019-09-20 19:44:56 +00:00
|
|
|
/**
|
|
|
|
* @DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD:
|
|
|
|
*
|
|
|
|
* The device supports MST DSC despite not supporting Virtual DPCD.
|
|
|
|
* The DSC caps can be read from the physical aux instead.
|
|
|
|
*/
|
|
|
|
DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD,
|
2020-03-16 04:23:40 +00:00
|
|
|
/**
|
|
|
|
* @DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS:
|
|
|
|
*
|
|
|
|
* The device supports a link rate of 3.24 Gbps (multiplier 0xc) despite
|
|
|
|
* the DP_MAX_LINK_RATE register reporting a lower max multiplier.
|
|
|
|
*/
|
|
|
|
DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS,
|
2017-05-18 11:10:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* drm_dp_has_quirk() - does the DP device have a specific quirk
|
2020-06-09 12:46:01 +00:00
|
|
|
* @desc: Device descriptor filled by drm_dp_read_desc()
|
2017-05-18 11:10:24 +00:00
|
|
|
* @quirk: Quirk to query for
|
|
|
|
*
|
|
|
|
* Return true if DP device identified by @desc has @quirk.
|
|
|
|
*/
|
|
|
|
static inline bool
|
2020-09-15 16:49:13 +00:00
|
|
|
drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk)
|
2017-05-18 11:10:24 +00:00
|
|
|
{
|
2020-09-15 16:49:13 +00:00
|
|
|
return desc->quirks & BIT(quirk);
|
2017-05-18 11:10:24 +00:00
|
|
|
}
|
|
|
|
|
2021-05-14 18:15:02 +00:00
|
|
|
/**
|
|
|
|
* struct drm_edp_backlight_info - Probed eDP backlight info struct
|
|
|
|
* @pwmgen_bit_count: The pwmgen bit count
|
|
|
|
* @pwm_freq_pre_divider: The PWM frequency pre-divider value being used for this backlight, if any
|
|
|
|
* @max: The maximum backlight level that may be set
|
|
|
|
* @lsb_reg_used: Do we also write values to the DP_EDP_BACKLIGHT_BRIGHTNESS_LSB register?
|
|
|
|
* @aux_enable: Does the panel support the AUX enable cap?
|
2021-11-05 18:33:41 +00:00
|
|
|
* @aux_set: Does the panel support setting the brightness through AUX?
|
2021-05-14 18:15:02 +00:00
|
|
|
*
|
|
|
|
* This structure contains various data about an eDP backlight, which can be populated by using
|
|
|
|
* drm_edp_backlight_init().
|
|
|
|
*/
|
|
|
|
struct drm_edp_backlight_info {
|
|
|
|
u8 pwmgen_bit_count;
|
|
|
|
u8 pwm_freq_pre_divider;
|
|
|
|
u16 max;
|
|
|
|
|
|
|
|
bool lsb_reg_used : 1;
|
|
|
|
bool aux_enable : 1;
|
2021-11-05 18:33:41 +00:00
|
|
|
bool aux_set : 1;
|
2021-05-14 18:15:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl,
|
|
|
|
u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE],
|
|
|
|
u16 *current_level, u8 *current_mode);
|
|
|
|
int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
|
|
|
u16 level);
|
|
|
|
int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
|
|
|
u16 level);
|
|
|
|
int drm_edp_backlight_disable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl);
|
|
|
|
|
2021-07-12 15:00:44 +00:00
|
|
|
#if IS_ENABLED(CONFIG_DRM_KMS_HELPER) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
|
|
|
|
(IS_MODULE(CONFIG_DRM_KMS_HELPER) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE)))
|
|
|
|
|
|
|
|
int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static inline int drm_panel_dp_aux_backlight(struct drm_panel *panel,
|
|
|
|
struct drm_dp_aux *aux)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2018-07-11 13:29:07 +00:00
|
|
|
#ifdef CONFIG_DRM_DP_CEC
|
|
|
|
void drm_dp_cec_irq(struct drm_dp_aux *aux);
|
2019-08-14 10:44:59 +00:00
|
|
|
void drm_dp_cec_register_connector(struct drm_dp_aux *aux,
|
|
|
|
struct drm_connector *connector);
|
2018-07-11 13:29:07 +00:00
|
|
|
void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux);
|
2023-08-25 13:01:20 +00:00
|
|
|
void drm_dp_cec_attach(struct drm_dp_aux *aux, u16 source_physical_address);
|
2018-07-11 13:29:07 +00:00
|
|
|
void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid);
|
|
|
|
void drm_dp_cec_unset_edid(struct drm_dp_aux *aux);
|
|
|
|
#else
|
|
|
|
static inline void drm_dp_cec_irq(struct drm_dp_aux *aux)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-08-14 10:44:59 +00:00
|
|
|
static inline void
|
|
|
|
drm_dp_cec_register_connector(struct drm_dp_aux *aux,
|
|
|
|
struct drm_connector *connector)
|
2018-07-11 13:29:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-08-25 13:01:20 +00:00
|
|
|
static inline void drm_dp_cec_attach(struct drm_dp_aux *aux,
|
|
|
|
u16 source_physical_address)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-07-11 13:29:07 +00:00
|
|
|
static inline void drm_dp_cec_set_edid(struct drm_dp_aux *aux,
|
|
|
|
const struct edid *edid)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void drm_dp_cec_unset_edid(struct drm_dp_aux *aux)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2020-03-16 10:37:54 +00:00
|
|
|
/**
|
|
|
|
* struct drm_dp_phy_test_params - DP Phy Compliance parameters
|
|
|
|
* @link_rate: Requested Link rate from DPCD 0x219
|
|
|
|
* @num_lanes: Number of lanes requested by sing through DPCD 0x220
|
|
|
|
* @phy_pattern: DP Phy test pattern from DPCD 0x248
|
2020-10-27 09:51:31 +00:00
|
|
|
* @hbr2_reset: DP HBR2_COMPLIANCE_SCRAMBLER_RESET from DCPD 0x24A and 0x24B
|
2020-03-16 10:37:54 +00:00
|
|
|
* @custom80: DP Test_80BIT_CUSTOM_PATTERN from DPCDs 0x250 through 0x259
|
|
|
|
* @enhanced_frame_cap: flag for enhanced frame capability.
|
|
|
|
*/
|
|
|
|
struct drm_dp_phy_test_params {
|
|
|
|
int link_rate;
|
|
|
|
u8 num_lanes;
|
|
|
|
u8 phy_pattern;
|
|
|
|
u8 hbr2_reset[2];
|
|
|
|
u8 custom80[10];
|
|
|
|
bool enhanced_frame_cap;
|
|
|
|
};
|
|
|
|
|
|
|
|
int drm_dp_get_phy_test_pattern(struct drm_dp_aux *aux,
|
|
|
|
struct drm_dp_phy_test_params *data);
|
|
|
|
int drm_dp_set_phy_test_pattern(struct drm_dp_aux *aux,
|
|
|
|
struct drm_dp_phy_test_params *data, u8 dp_rev);
|
2020-12-18 10:37:12 +00:00
|
|
|
int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4]);
|
|
|
|
int drm_dp_pcon_frl_prepare(struct drm_dp_aux *aux, bool enable_frl_ready_hpd);
|
|
|
|
bool drm_dp_pcon_is_frl_ready(struct drm_dp_aux *aux);
|
|
|
|
int drm_dp_pcon_frl_configure_1(struct drm_dp_aux *aux, int max_frl_gbps,
|
2021-03-23 11:24:21 +00:00
|
|
|
u8 frl_mode);
|
2020-12-18 10:37:12 +00:00
|
|
|
int drm_dp_pcon_frl_configure_2(struct drm_dp_aux *aux, int max_frl_mask,
|
2021-03-23 11:24:21 +00:00
|
|
|
u8 frl_type);
|
2020-12-18 10:37:12 +00:00
|
|
|
int drm_dp_pcon_reset_frl_config(struct drm_dp_aux *aux);
|
|
|
|
int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux);
|
|
|
|
|
|
|
|
bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux);
|
|
|
|
int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask);
|
2020-12-18 10:37:13 +00:00
|
|
|
void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux,
|
|
|
|
struct drm_connector *connector);
|
2020-12-22 15:50:27 +00:00
|
|
|
bool drm_dp_pcon_enc_is_dsc_1_2(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]);
|
|
|
|
int drm_dp_pcon_dsc_max_slices(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]);
|
|
|
|
int drm_dp_pcon_dsc_max_slice_width(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]);
|
|
|
|
int drm_dp_pcon_dsc_bpp_incr(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]);
|
|
|
|
int drm_dp_pcon_pps_default(struct drm_dp_aux *aux);
|
|
|
|
int drm_dp_pcon_pps_override_buf(struct drm_dp_aux *aux, u8 pps_buf[128]);
|
|
|
|
int drm_dp_pcon_pps_override_param(struct drm_dp_aux *aux, u8 pps_param[6]);
|
2020-12-18 10:37:15 +00:00
|
|
|
bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|
|
|
const u8 port_cap[4], u8 color_spc);
|
|
|
|
int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc);
|
2020-12-18 10:37:12 +00:00
|
|
|
|
2009-12-04 00:55:24 +00:00
|
|
|
#endif /* _DRM_DP_HELPER_H_ */
|