diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 161 |
1 files changed, 105 insertions, 56 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d4e3f9d9370..7a4fd2ed128 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -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, |