|
@@ -984,9 +984,13 @@ static const u8 edid_header[] = {
|
|
|
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
|
|
|
};
|
|
|
|
|
|
- /*
|
|
|
- * Sanity check the header of the base EDID block. Return 8 if the header
|
|
|
- * is perfect, down to 0 if it's totally wrong.
|
|
|
+/**
|
|
|
+ * drm_edid_header_is_valid - sanity check the header of the base EDID block
|
|
|
+ * @raw_edid: pointer to raw base EDID block
|
|
|
+ *
|
|
|
+ * Sanity check the header of the base EDID block.
|
|
|
+ *
|
|
|
+ * Return: 8 if the header is perfect, down to 0 if it's totally wrong.
|
|
|
*/
|
|
|
int drm_edid_header_is_valid(const u8 *raw_edid)
|
|
|
{
|
|
@@ -1005,9 +1009,16 @@ module_param_named(edid_fixup, edid_fixup, int, 0400);
|
|
|
MODULE_PARM_DESC(edid_fixup,
|
|
|
"Minimum number of valid EDID header bytes (0-8, default 6)");
|
|
|
|
|
|
-/*
|
|
|
- * Sanity check the EDID block (base or extension). Return 0 if the block
|
|
|
- * doesn't check out, or 1 if it's valid.
|
|
|
+/**
|
|
|
+ * drm_edid_block_valid - Sanity check the EDID block (base or extension)
|
|
|
+ * @raw_edid: pointer to raw EDID block
|
|
|
+ * @block: type of block to validate (0 for base, extension otherwise)
|
|
|
+ * @print_bad_edid: if true, dump bad EDID blocks to the console
|
|
|
+ *
|
|
|
+ * Validate a base or extension EDID block and optionally dump bad blocks to
|
|
|
+ * the console.
|
|
|
+ *
|
|
|
+ * Return: True if the block is valid, false otherwise.
|
|
|
*/
|
|
|
bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
|
|
|
{
|
|
@@ -1077,6 +1088,8 @@ EXPORT_SYMBOL(drm_edid_block_valid);
|
|
|
* @edid: EDID data
|
|
|
*
|
|
|
* Sanity-check an entire EDID record (including extensions)
|
|
|
+ *
|
|
|
+ * Return: True if the EDID data is valid, false otherwise.
|
|
|
*/
|
|
|
bool drm_edid_is_valid(struct edid *edid)
|
|
|
{
|
|
@@ -1096,18 +1109,15 @@ EXPORT_SYMBOL(drm_edid_is_valid);
|
|
|
|
|
|
#define DDC_SEGMENT_ADDR 0x30
|
|
|
/**
|
|
|
- * Get EDID information via I2C.
|
|
|
- *
|
|
|
- * @adapter : i2c device adaptor
|
|
|
+ * drm_do_probe_ddc_edid() - get EDID information via I2C
|
|
|
+ * @adapter: I2C device adaptor
|
|
|
* @buf: EDID data buffer to be filled
|
|
|
* @block: 128 byte EDID block to start fetching from
|
|
|
* @len: EDID data buffer length to fetch
|
|
|
*
|
|
|
- * Returns:
|
|
|
- *
|
|
|
- * 0 on success or -1 on failure.
|
|
|
+ * Try to fetch EDID information by calling I2C driver functions.
|
|
|
*
|
|
|
- * Try to fetch EDID information by calling i2c driver function.
|
|
|
+ * Return: 0 on success or -1 on failure.
|
|
|
*/
|
|
|
static int
|
|
|
drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
|
|
@@ -1118,7 +1128,8 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
|
|
|
unsigned char xfers = segment ? 3 : 2;
|
|
|
int ret, retries = 5;
|
|
|
|
|
|
- /* The core i2c driver will automatically retry the transfer if the
|
|
|
+ /*
|
|
|
+ * The core I2C driver will automatically retry the transfer if the
|
|
|
* adapter reports EAGAIN. However, we find that bit-banging transfers
|
|
|
* are susceptible to errors under a heavily loaded machine and
|
|
|
* generate spurious NAKs and timeouts. Retrying the transfer
|
|
@@ -1144,10 +1155,10 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- /*
|
|
|
- * Avoid sending the segment addr to not upset non-compliant ddc
|
|
|
- * monitors.
|
|
|
- */
|
|
|
+ /*
|
|
|
+ * Avoid sending the segment addr to not upset non-compliant
|
|
|
+ * DDC monitors.
|
|
|
+ */
|
|
|
ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers);
|
|
|
|
|
|
if (ret == -ENXIO) {
|
|
@@ -1246,12 +1257,10 @@ out:
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Probe DDC presence.
|
|
|
- * @adapter: i2c adapter to probe
|
|
|
+ * drm_probe_ddc() - probe DDC presence
|
|
|
+ * @adapter: I2C adapter to probe
|
|
|
*
|
|
|
- * Returns:
|
|
|
- *
|
|
|
- * 1 on success
|
|
|
+ * Return: True on success, false on failure.
|
|
|
*/
|
|
|
bool
|
|
|
drm_probe_ddc(struct i2c_adapter *adapter)
|
|
@@ -1265,12 +1274,12 @@ EXPORT_SYMBOL(drm_probe_ddc);
|
|
|
/**
|
|
|
* drm_get_edid - get EDID data, if available
|
|
|
* @connector: connector we're probing
|
|
|
- * @adapter: i2c adapter to use for DDC
|
|
|
+ * @adapter: I2C adapter to use for DDC
|
|
|
*
|
|
|
- * Poke the given i2c channel to grab EDID data if possible. If found,
|
|
|
+ * Poke the given I2C channel to grab EDID data if possible. If found,
|
|
|
* attach it to the connector.
|
|
|
*
|
|
|
- * Return edid data or NULL if we couldn't find any.
|
|
|
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
|
|
|
*/
|
|
|
struct edid *drm_get_edid(struct drm_connector *connector,
|
|
|
struct i2c_adapter *adapter)
|
|
@@ -1288,7 +1297,7 @@ EXPORT_SYMBOL(drm_get_edid);
|
|
|
* drm_edid_duplicate - duplicate an EDID and the extensions
|
|
|
* @edid: EDID to duplicate
|
|
|
*
|
|
|
- * Return duplicate edid or NULL on allocation failure.
|
|
|
+ * Return: Pointer to duplicated EDID or NULL on allocation failure.
|
|
|
*/
|
|
|
struct edid *drm_edid_duplicate(const struct edid *edid)
|
|
|
{
|
|
@@ -1411,7 +1420,8 @@ mode_is_rb(const struct drm_display_mode *mode)
|
|
|
* @rb: Mode reduced-blanking-ness
|
|
|
*
|
|
|
* Walk the DMT mode list looking for a match for the given parameters.
|
|
|
- * Return a newly allocated copy of the mode, or NULL if not found.
|
|
|
+ *
|
|
|
+ * Return: A newly allocated copy of the mode, or NULL if not found.
|
|
|
*/
|
|
|
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
|
|
int hsize, int vsize, int fresh,
|
|
@@ -1595,14 +1605,13 @@ bad_std_timing(u8 a, u8 b)
|
|
|
* @connector: connector of for the EDID block
|
|
|
* @edid: EDID block to scan
|
|
|
* @t: standard timing params
|
|
|
- * @revision: standard timing level
|
|
|
*
|
|
|
* Take the standard timing params (in this case width, aspect, and refresh)
|
|
|
* and convert them into a real mode using CVT/GTF/DMT.
|
|
|
*/
|
|
|
static struct drm_display_mode *
|
|
|
drm_mode_std(struct drm_connector *connector, struct edid *edid,
|
|
|
- struct std_timing *t, int revision)
|
|
|
+ struct std_timing *t)
|
|
|
{
|
|
|
struct drm_device *dev = connector->dev;
|
|
|
struct drm_display_mode *m, *mode = NULL;
|
|
@@ -1623,7 +1632,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
|
|
|
vrefresh_rate = vfreq + 60;
|
|
|
/* the vdisplay is calculated based on the aspect ratio */
|
|
|
if (aspect_ratio == 0) {
|
|
|
- if (revision < 3)
|
|
|
+ if (edid->revision < 3)
|
|
|
vsize = hsize;
|
|
|
else
|
|
|
vsize = (hsize * 10) / 16;
|
|
@@ -2140,7 +2149,7 @@ do_established_modes(struct detailed_timing *timing, void *c)
|
|
|
|
|
|
/**
|
|
|
* add_established_modes - get est. modes from EDID and add them
|
|
|
- * @connector: connector of for the EDID block
|
|
|
+ * @connector: connector to add mode(s) to
|
|
|
* @edid: EDID block to scan
|
|
|
*
|
|
|
* Each EDID block contains a bitmap of the supported "established modes" list
|
|
@@ -2191,8 +2200,7 @@ do_standard_modes(struct detailed_timing *timing, void *c)
|
|
|
struct drm_display_mode *newmode;
|
|
|
|
|
|
std = &data->data.timings[i];
|
|
|
- newmode = drm_mode_std(connector, edid, std,
|
|
|
- edid->revision);
|
|
|
+ newmode = drm_mode_std(connector, edid, std);
|
|
|
if (newmode) {
|
|
|
drm_mode_probed_add(connector, newmode);
|
|
|
closure->modes++;
|
|
@@ -2203,7 +2211,7 @@ do_standard_modes(struct detailed_timing *timing, void *c)
|
|
|
|
|
|
/**
|
|
|
* add_standard_modes - get std. modes from EDID and add them
|
|
|
- * @connector: connector of for the EDID block
|
|
|
+ * @connector: connector to add mode(s) to
|
|
|
* @edid: EDID block to scan
|
|
|
*
|
|
|
* Standard modes can be calculated using the appropriate standard (DMT,
|
|
@@ -2221,8 +2229,7 @@ add_standard_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
struct drm_display_mode *newmode;
|
|
|
|
|
|
newmode = drm_mode_std(connector, edid,
|
|
|
- &edid->standard_timings[i],
|
|
|
- edid->revision);
|
|
|
+ &edid->standard_timings[i]);
|
|
|
if (newmode) {
|
|
|
drm_mode_probed_add(connector, newmode);
|
|
|
modes++;
|
|
@@ -2425,7 +2432,7 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
|
|
|
* drm_match_cea_mode - look for a CEA mode matching given mode
|
|
|
* @to_match: display mode
|
|
|
*
|
|
|
- * Returns the CEA Video ID (VIC) of the mode or 0 if it isn't a CEA-861
|
|
|
+ * Return: The CEA Video ID (VIC) of the mode or 0 if it isn't a CEA-861
|
|
|
* mode.
|
|
|
*/
|
|
|
u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
|
|
@@ -2452,6 +2459,22 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
|
|
|
}
|
|
|
EXPORT_SYMBOL(drm_match_cea_mode);
|
|
|
|
|
|
+/**
|
|
|
+ * drm_get_cea_aspect_ratio - get the picture aspect ratio corresponding to
|
|
|
+ * the input VIC from the CEA mode list
|
|
|
+ * @video_code: ID given to each of the CEA modes
|
|
|
+ *
|
|
|
+ * Returns picture aspect ratio
|
|
|
+ */
|
|
|
+enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code)
|
|
|
+{
|
|
|
+ /* return picture aspect ratio for video_code - 1 to access the
|
|
|
+ * right array element
|
|
|
+ */
|
|
|
+ return edid_cea_modes[video_code-1].picture_aspect_ratio;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(drm_get_cea_aspect_ratio);
|
|
|
+
|
|
|
/*
|
|
|
* Calculate the alternate clock for HDMI modes (those from the HDMI vendor
|
|
|
* specific block).
|
|
@@ -3023,11 +3046,9 @@ monitor_name(struct detailed_timing *t, void *data)
|
|
|
* @connector: connector corresponding to the HDMI/DP sink
|
|
|
* @edid: EDID to parse
|
|
|
*
|
|
|
- * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver.
|
|
|
- * Some ELD fields are left to the graphics driver caller:
|
|
|
- * - Conn_Type
|
|
|
- * - HDCP
|
|
|
- * - Port_ID
|
|
|
+ * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The
|
|
|
+ * Conn_Type, HDCP and Port_ID ELD fields are left for the graphics driver to
|
|
|
+ * fill in.
|
|
|
*/
|
|
|
void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
|
|
|
{
|
|
@@ -3111,9 +3132,10 @@ EXPORT_SYMBOL(drm_edid_to_eld);
|
|
|
* @sads: pointer that will be set to the extracted SADs
|
|
|
*
|
|
|
* Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it.
|
|
|
- * Note: returned pointer needs to be kfreed
|
|
|
*
|
|
|
- * Return number of found SADs or negative number on error.
|
|
|
+ * Note: The returned pointer needs to be freed using kfree().
|
|
|
+ *
|
|
|
+ * Return: The number of found SADs or negative number on error.
|
|
|
*/
|
|
|
int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads)
|
|
|
{
|
|
@@ -3170,9 +3192,11 @@ EXPORT_SYMBOL(drm_edid_to_sad);
|
|
|
* @sadb: pointer to the speaker block
|
|
|
*
|
|
|
* Looks for CEA EDID block and extracts the Speaker Allocation Data Block from it.
|
|
|
- * Note: returned pointer needs to be kfreed
|
|
|
*
|
|
|
- * Return number of found Speaker Allocation Blocks or negative number on error.
|
|
|
+ * Note: The returned pointer needs to be freed using kfree().
|
|
|
+ *
|
|
|
+ * Return: The number of found Speaker Allocation Blocks or negative number on
|
|
|
+ * error.
|
|
|
*/
|
|
|
int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb)
|
|
|
{
|
|
@@ -3219,9 +3243,12 @@ int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb)
|
|
|
EXPORT_SYMBOL(drm_edid_to_speaker_allocation);
|
|
|
|
|
|
/**
|
|
|
- * drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond
|
|
|
+ * drm_av_sync_delay - compute the HDMI/DP sink audio-video sync delay
|
|
|
* @connector: connector associated with the HDMI/DP sink
|
|
|
* @mode: the display mode
|
|
|
+ *
|
|
|
+ * Return: The HDMI/DP sink's audio-video sync delay in milliseconds or 0 if
|
|
|
+ * the sink doesn't support audio or video.
|
|
|
*/
|
|
|
int drm_av_sync_delay(struct drm_connector *connector,
|
|
|
struct drm_display_mode *mode)
|
|
@@ -3263,6 +3290,9 @@ EXPORT_SYMBOL(drm_av_sync_delay);
|
|
|
*
|
|
|
* It's possible for one encoder to be associated with multiple HDMI/DP sinks.
|
|
|
* The policy is now hard coded to simply use the first HDMI/DP sink's ELD.
|
|
|
+ *
|
|
|
+ * Return: The connector associated with the first HDMI/DP sink that has ELD
|
|
|
+ * attached to it.
|
|
|
*/
|
|
|
struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
|
|
|
struct drm_display_mode *mode)
|
|
@@ -3279,11 +3309,12 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
|
|
|
EXPORT_SYMBOL(drm_select_eld);
|
|
|
|
|
|
/**
|
|
|
- * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
|
|
|
+ * drm_detect_hdmi_monitor - detect whether monitor is HDMI
|
|
|
* @edid: monitor EDID information
|
|
|
*
|
|
|
* Parse the CEA extension according to CEA-861-B.
|
|
|
- * Return true if HDMI, false if not or unknown.
|
|
|
+ *
|
|
|
+ * Return: True if the monitor is HDMI, false if not or unknown.
|
|
|
*/
|
|
|
bool drm_detect_hdmi_monitor(struct edid *edid)
|
|
|
{
|
|
@@ -3321,6 +3352,7 @@ EXPORT_SYMBOL(drm_detect_hdmi_monitor);
|
|
|
* audio format, assume at least 'basic audio' support, even if 'basic
|
|
|
* audio' is not defined in EDID.
|
|
|
*
|
|
|
+ * Return: True if the monitor supports audio, false otherwise.
|
|
|
*/
|
|
|
bool drm_detect_monitor_audio(struct edid *edid)
|
|
|
{
|
|
@@ -3364,6 +3396,8 @@ EXPORT_SYMBOL(drm_detect_monitor_audio);
|
|
|
* Check whether the monitor reports the RGB quantization range selection
|
|
|
* as supported. The AVI infoframe can then be used to inform the monitor
|
|
|
* which quantization range (full or limited) is used.
|
|
|
+ *
|
|
|
+ * Return: True if the RGB quantization range is selectable, false otherwise.
|
|
|
*/
|
|
|
bool drm_rgb_quant_range_selectable(struct edid *edid)
|
|
|
{
|
|
@@ -3468,11 +3502,11 @@ static void drm_add_display_info(struct edid *edid,
|
|
|
/**
|
|
|
* drm_add_edid_modes - add modes from EDID data, if available
|
|
|
* @connector: connector we're probing
|
|
|
- * @edid: edid data
|
|
|
+ * @edid: EDID data
|
|
|
*
|
|
|
* Add the specified modes to the connector's mode list.
|
|
|
*
|
|
|
- * Return number of modes added or 0 if we couldn't find any.
|
|
|
+ * Return: The number of modes added or 0 if we couldn't find any.
|
|
|
*/
|
|
|
int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
{
|
|
@@ -3534,7 +3568,7 @@ EXPORT_SYMBOL(drm_add_edid_modes);
|
|
|
* Add the specified modes to the connector's mode list. Only when the
|
|
|
* hdisplay/vdisplay is not beyond the given limit, it will be added.
|
|
|
*
|
|
|
- * Return number of modes added or 0 if we couldn't find any.
|
|
|
+ * Return: The number of modes added or 0 if we couldn't find any.
|
|
|
*/
|
|
|
int drm_add_modes_noedid(struct drm_connector *connector,
|
|
|
int hdisplay, int vdisplay)
|
|
@@ -3573,13 +3607,22 @@ int drm_add_modes_noedid(struct drm_connector *connector,
|
|
|
}
|
|
|
EXPORT_SYMBOL(drm_add_modes_noedid);
|
|
|
|
|
|
+/**
|
|
|
+ * drm_set_preferred_mode - Sets the preferred mode of a connector
|
|
|
+ * @connector: connector whose mode list should be processed
|
|
|
+ * @hpref: horizontal resolution of preferred mode
|
|
|
+ * @vpref: vertical resolution of preferred mode
|
|
|
+ *
|
|
|
+ * Marks a mode as preferred if it matches the resolution specified by @hpref
|
|
|
+ * and @vpref.
|
|
|
+ */
|
|
|
void drm_set_preferred_mode(struct drm_connector *connector,
|
|
|
int hpref, int vpref)
|
|
|
{
|
|
|
struct drm_display_mode *mode;
|
|
|
|
|
|
list_for_each_entry(mode, &connector->probed_modes, head) {
|
|
|
- if (mode->hdisplay == hpref &&
|
|
|
+ if (mode->hdisplay == hpref &&
|
|
|
mode->vdisplay == vpref)
|
|
|
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
|
|
}
|
|
@@ -3592,7 +3635,7 @@ EXPORT_SYMBOL(drm_set_preferred_mode);
|
|
|
* @frame: HDMI AVI infoframe
|
|
|
* @mode: DRM display mode
|
|
|
*
|
|
|
- * Returns 0 on success or a negative error code on failure.
|
|
|
+ * Return: 0 on success or a negative error code on failure.
|
|
|
*/
|
|
|
int
|
|
|
drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
|
@@ -3613,6 +3656,12 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
|
|
frame->video_code = drm_match_cea_mode(mode);
|
|
|
|
|
|
frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE;
|
|
|
+
|
|
|
+ /* Populate picture aspect ratio from CEA mode list */
|
|
|
+ if (frame->video_code > 0)
|
|
|
+ frame->picture_aspect = drm_get_cea_aspect_ratio(
|
|
|
+ frame->video_code);
|
|
|
+
|
|
|
frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
|
|
|
frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
|
|
|
|
|
@@ -3657,7 +3706,7 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode)
|
|
|
* 4k or stereoscopic 3D mode. So when giving any other mode as input this
|
|
|
* function will return -EINVAL, error that can be safely ignored.
|
|
|
*
|
|
|
- * Returns 0 on success or a negative error code on failure.
|
|
|
+ * Return: 0 on success or a negative error code on failure.
|
|
|
*/
|
|
|
int
|
|
|
drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
|