/* * Copyright (c) 2006 Luc Verhaegen (quirks list) * Copyright (c) 2007-2008 Intel Corporation * Jesse Barnes <[email protected]> * Copyright 2010 Red Hat, Inc. * * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from * FB layer. * Copyright (C) 2006 Dennis Munsie <[email protected]> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include <linux/bitfield.h> #include <linux/byteorder/generic.h> #include <linux/cec.h> #include <linux/hdmi.h> #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/seq_buf.h> #include <linux/slab.h> #include <linux/vga_switcheroo.h> #include <drm/drm_drv.h> #include <drm/drm_edid.h> #include <drm/drm_eld.h> #include <drm/drm_encoder.h> #include <drm/drm_print.h> #include "drm_crtc_internal.h" #include "drm_displayid_internal.h" #include "drm_internal.h" static int oui(u8 first, u8 second, u8 third) { … } #define EDID_EST_TIMINGS … #define EDID_STD_TIMINGS … #define EDID_DETAILED_TIMINGS … /* * EDID blocks out in the wild have a variety of bugs, try to collect * them here (note that userspace may work around broken monitors first, * but fixes should make their way here so that the kernel "just works" * on as many displays as possible). */ /* First detailed mode wrong, use largest 60Hz mode */ #define EDID_QUIRK_PREFER_LARGE_60 … /* Reported 135MHz pixel clock is too high, needs adjustment */ #define EDID_QUIRK_135_CLOCK_TOO_HIGH … /* Prefer the largest mode at 75 Hz */ #define EDID_QUIRK_PREFER_LARGE_75 … /* Detail timing is in cm not mm */ #define EDID_QUIRK_DETAILED_IN_CM … /* Detailed timing descriptors have bogus size values, so just take the * maximum size and use that. */ #define EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE … /* use +hsync +vsync for detailed mode */ #define EDID_QUIRK_DETAILED_SYNC_PP … /* Force reduced-blanking timings for detailed modes */ #define EDID_QUIRK_FORCE_REDUCED_BLANKING … /* Force 8bpc */ #define EDID_QUIRK_FORCE_8BPC … /* Force 12bpc */ #define EDID_QUIRK_FORCE_12BPC … /* Force 6bpc */ #define EDID_QUIRK_FORCE_6BPC … /* Force 10bpc */ #define EDID_QUIRK_FORCE_10BPC … /* Non desktop display (i.e. HMD) */ #define EDID_QUIRK_NON_DESKTOP … /* Cap the DSC target bitrate to 15bpp */ #define EDID_QUIRK_CAP_DSC_15BPP … #define MICROSOFT_IEEE_OUI … struct detailed_mode_closure { … }; struct drm_edid_match_closure { … }; #define LEVEL_DMT … #define LEVEL_GTF … #define LEVEL_GTF2 … #define LEVEL_CVT … #define EDID_QUIRK(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _quirks) … static const struct edid_quirk { … } edid_quirk_list[] = …; /* * Autogenerated from the DMT spec. * This table is copied from xfree86/modes/xf86EdidModes.c. */ static const struct drm_display_mode drm_dmt_modes[] = …; /* * These more or less come from the DMT spec. The 720x400 modes are * inferred from historical 80x25 practice. The 640x480@67 and 832x624@75 * modes are old-school Mac modes. The EDID spec says the 1152x864@75 mode * should be 1152x870, again for the Mac, but instead we use the x864 DMT * mode. * * The DMT modes have been fact-checked; the rest are mild guesses. */ static const struct drm_display_mode edid_est_modes[] = …; struct minimode { … }; static const struct minimode est3_modes[] = …; static const struct minimode extra_modes[] = …; /* * From CEA/CTA-861 spec. * * Do not access directly, instead always use cea_mode_for_vic(). */ static const struct drm_display_mode edid_cea_modes_1[] = …; /* * From CEA/CTA-861 spec. * * Do not access directly, instead always use cea_mode_for_vic(). */ static const struct drm_display_mode edid_cea_modes_193[] = …; /* * HDMI 1.4 4k modes. Index using the VIC. */ static const struct drm_display_mode edid_4k_modes[] = …; /*** DDC fetch and block validation ***/ /* * The opaque EDID type, internal to drm_edid.c. */ struct drm_edid { … }; static int edid_hfeeodb_extension_block_count(const struct edid *edid); static int edid_hfeeodb_block_count(const struct edid *edid) { … } static int edid_extension_block_count(const struct edid *edid) { … } static int edid_block_count(const struct edid *edid) { … } static int edid_size_by_blocks(int num_blocks) { … } static int edid_size(const struct edid *edid) { … } static const void *edid_block_data(const struct edid *edid, int index) { … } static const void *edid_extension_block_data(const struct edid *edid, int index) { … } /* EDID block count indicated in EDID, may exceed allocated size */ static int __drm_edid_block_count(const struct drm_edid *drm_edid) { … } /* EDID block count, limited by allocated size */ static int drm_edid_block_count(const struct drm_edid *drm_edid) { … } /* EDID extension block count, limited by allocated size */ static int drm_edid_extension_block_count(const struct drm_edid *drm_edid) { … } static const void *drm_edid_block_data(const struct drm_edid *drm_edid, int index) { … } static const void *drm_edid_extension_block_data(const struct drm_edid *drm_edid, int index) { … } /* * Initializer helper for legacy interfaces, where we have no choice but to * trust edid size. Not for general purpose use. */ static const struct drm_edid *drm_edid_legacy_init(struct drm_edid *drm_edid, const struct edid *edid) { … } /* * EDID base and extension block iterator. * * struct drm_edid_iter iter; * const u8 *block; * * drm_edid_iter_begin(drm_edid, &iter); * drm_edid_iter_for_each(block, &iter) { * // do stuff with block * } * drm_edid_iter_end(&iter); */ struct drm_edid_iter { … }; static void drm_edid_iter_begin(const struct drm_edid *drm_edid, struct drm_edid_iter *iter) { … } static const void *__drm_edid_iter_next(struct drm_edid_iter *iter) { … } #define drm_edid_iter_for_each(__block, __iter) … static void drm_edid_iter_end(struct drm_edid_iter *iter) { … } static const u8 edid_header[] = …; static void edid_header_fix(void *edid) { … } /** * drm_edid_header_is_valid - sanity check the header of the base EDID block * @_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 void *_edid) { … } EXPORT_SYMBOL(…); static int edid_fixup __read_mostly = …; module_param_named(edid_fixup, edid_fixup, int, 0400); MODULE_PARM_DESC(…) …; static int edid_block_compute_checksum(const void *_block) { … } static int edid_block_get_checksum(const void *_block) { … } static int edid_block_tag(const void *_block) { … } static bool edid_block_is_zero(const void *edid) { … } static bool drm_edid_eq(const struct drm_edid *drm_edid, const void *raw_edid, size_t raw_edid_size) { … } enum edid_block_status { … }; static enum edid_block_status edid_block_check(const void *_block, bool is_base_block) { … } static bool edid_block_status_valid(enum edid_block_status status, int tag) { … } static bool edid_block_valid(const void *block, bool base) { … } static void edid_block_status_print(enum edid_block_status status, const struct edid *block, int block_num) { … } static void edid_block_dump(const char *level, const void *block, int block_num) { … } /* * Validate a base or extension EDID block and optionally dump bad blocks to * the console. */ static bool drm_edid_block_valid(void *_block, int block_num, bool print_bad_edid, bool *edid_corrupt) { … } /** * drm_edid_is_valid - sanity check EDID data * @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) { … } EXPORT_SYMBOL(…); /** * drm_edid_valid - sanity check EDID data * @drm_edid: EDID data * * Sanity check an EDID. Cross check block count against allocated size and * checksum the blocks. * * Return: True if the EDID data is valid, false otherwise. */ bool drm_edid_valid(const struct drm_edid *drm_edid) { … } EXPORT_SYMBOL(…); static struct edid *edid_filter_invalid_blocks(struct edid *edid, size_t *alloc_size) { … } #define DDC_SEGMENT_ADDR … /** * drm_do_probe_ddc_edid() - get EDID information via I2C * @data: I2C device adapter * @buf: EDID data buffer to be filled * @block: 128 byte EDID block to start fetching from * @len: EDID data buffer length to fetch * * Try to fetch EDID information by calling I2C driver functions. * * Return: 0 on success or -1 on failure. */ static int drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len) { … } static void connector_bad_edid(struct drm_connector *connector, const struct edid *edid, int num_blocks) { … } /* Get override or firmware EDID */ static const struct drm_edid *drm_edid_override_get(struct drm_connector *connector) { … } /* For debugfs edid_override implementation */ int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m) { … } /* For debugfs edid_override implementation */ int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size) { … } /* For debugfs edid_override implementation */ int drm_edid_override_reset(struct drm_connector *connector) { … } /** * drm_edid_override_connector_update - add modes from override/firmware EDID * @connector: connector we're probing * * Add modes from the override/firmware EDID, if available. Only to be used from * drm_helper_probe_single_connector_modes() as a fallback for when DDC probe * failed during drm_get_edid() and caused the override/firmware EDID to be * skipped. * * Return: The number of modes added or 0 if we couldn't find any. */ int drm_edid_override_connector_update(struct drm_connector *connector) { … } EXPORT_SYMBOL(…); read_block_fn; static enum edid_block_status edid_block_read(void *block, unsigned int block_num, read_block_fn read_block, void *context) { … } static struct edid *_drm_do_get_edid(struct drm_connector *connector, read_block_fn read_block, void *context, size_t *size) { … } /** * drm_edid_raw - Get a pointer to the raw EDID data. * @drm_edid: drm_edid container * * Get a pointer to the raw EDID data. * * This is for transition only. Avoid using this like the plague. * * Return: Pointer to raw EDID data. */ const struct edid *drm_edid_raw(const struct drm_edid *drm_edid) { … } EXPORT_SYMBOL(…); /* Allocate struct drm_edid container *without* duplicating the edid data */ static const struct drm_edid *_drm_edid_alloc(const void *edid, size_t size) { … } /** * drm_edid_alloc - Allocate a new drm_edid container * @edid: Pointer to raw EDID data * @size: Size of memory allocated for EDID * * Allocate a new drm_edid container. Do not calculate edid size from edid, pass * the actual size that has been allocated for the data. There is no validation * of the raw EDID data against the size, but at least the EDID base block must * fit in the buffer. * * The returned pointer must be freed using drm_edid_free(). * * Return: drm_edid container, or NULL on errors */ const struct drm_edid *drm_edid_alloc(const void *edid, size_t size) { … } EXPORT_SYMBOL(…); /** * drm_edid_dup - Duplicate a drm_edid container * @drm_edid: EDID to duplicate * * The returned pointer must be freed using drm_edid_free(). * * Returns: drm_edid container copy, or NULL on errors */ const struct drm_edid *drm_edid_dup(const struct drm_edid *drm_edid) { … } EXPORT_SYMBOL(…); /** * drm_edid_free - Free the drm_edid container * @drm_edid: EDID to free */ void drm_edid_free(const struct drm_edid *drm_edid) { … } EXPORT_SYMBOL(…); /** * drm_probe_ddc() - probe DDC presence * @adapter: I2C adapter to probe * * Return: True on success, false on failure. */ bool drm_probe_ddc(struct i2c_adapter *adapter) { … } EXPORT_SYMBOL(…); /** * drm_get_edid - get EDID data, if available * @connector: connector we're probing * @adapter: I2C adapter to use for DDC * * Poke the given I2C channel to grab EDID data if possible. If found, * attach it to the connector. * * 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) { … } EXPORT_SYMBOL(…); /** * drm_edid_read_custom - Read EDID data using given EDID block read function * @connector: Connector to use * @read_block: EDID block read function * @context: Private data passed to the block read function * * When the I2C adapter connected to the DDC bus is hidden behind a device that * exposes a different interface to read EDID blocks this function can be used * to get EDID data using a custom block read function. * * As in the general case the DDC bus is accessible by the kernel at the I2C * level, drivers must make all reasonable efforts to expose it as an I2C * adapter and use drm_edid_read() or drm_edid_read_ddc() instead of abusing * this function. * * The EDID may be overridden using debugfs override_edid or firmware EDID * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority * order. Having either of them bypasses actual EDID reads. * * The returned pointer must be freed using drm_edid_free(). * * Return: Pointer to EDID, or NULL if probe/read failed. */ const struct drm_edid *drm_edid_read_custom(struct drm_connector *connector, read_block_fn read_block, void *context) { … } EXPORT_SYMBOL(…); /** * drm_edid_read_ddc - Read EDID data using given I2C adapter * @connector: Connector to use * @adapter: I2C adapter to use for DDC * * Read EDID using the given I2C adapter. * * The EDID may be overridden using debugfs override_edid or firmware EDID * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority * order. Having either of them bypasses actual EDID reads. * * Prefer initializing connector->ddc with drm_connector_init_with_ddc() and * using drm_edid_read() instead of this function. * * The returned pointer must be freed using drm_edid_free(). * * Return: Pointer to EDID, or NULL if probe/read failed. */ const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector, struct i2c_adapter *adapter) { … } EXPORT_SYMBOL(…); /** * drm_edid_read - Read EDID data using connector's I2C adapter * @connector: Connector to use * * Read EDID using the connector's I2C adapter. * * The EDID may be overridden using debugfs override_edid or firmware EDID * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority * order. Having either of them bypasses actual EDID reads. * * The returned pointer must be freed using drm_edid_free(). * * Return: Pointer to EDID, or NULL if probe/read failed. */ const struct drm_edid *drm_edid_read(struct drm_connector *connector) { … } EXPORT_SYMBOL(…); /** * drm_edid_get_product_id - Get the vendor and product identification * @drm_edid: EDID * @id: Where to place the product id */ void drm_edid_get_product_id(const struct drm_edid *drm_edid, struct drm_edid_product_id *id) { … } EXPORT_SYMBOL(…); static void decode_date(struct seq_buf *s, const struct drm_edid_product_id *id) { … } /** * drm_edid_print_product_id - Print decoded product id to printer * @p: drm printer * @id: EDID product id * @raw: If true, also print the raw hex * * See VESA E-EDID 1.4 section 3.4. */ void drm_edid_print_product_id(struct drm_printer *p, const struct drm_edid_product_id *id, bool raw) { … } EXPORT_SYMBOL(…); /** * drm_edid_get_panel_id - Get a panel's ID from EDID * @drm_edid: EDID that contains panel ID. * * This function uses the first block of the EDID of a panel and (assuming * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's * supposed to be different for each different modem of panel. * * Return: A 32-bit ID that should be different for each make/model of panel. * See the functions drm_edid_encode_panel_id() and * drm_edid_decode_panel_id() for some details on the structure of this * ID. Return 0 if the EDID size is less than a base block. */ u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid) { … } EXPORT_SYMBOL(…); /** * drm_edid_read_base_block - Get a panel's EDID base block * @adapter: I2C adapter to use for DDC * * This function returns the drm_edid containing the first block of the EDID of * a panel. * * This function is intended to be used during early probing on devices where * more than one panel might be present. Because of its intended use it must * assume that the EDID of the panel is correct, at least as far as the base * block is concerned (in other words, we don't process any overrides here). * * Caller should call drm_edid_free() after use. * * NOTE: it's expected that this function and drm_do_get_edid() will both * be read the EDID, but there is no caching between them. Since we're only * reading the first block, hopefully this extra overhead won't be too big. * * WARNING: Only use this function when the connector is unknown. For example, * during the early probe of panel. The EDID read from the function is temporary * and should be replaced by the full EDID returned from other drm_edid_read. * * Return: Pointer to allocated EDID base block, or NULL on any failure. */ const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter) { … } EXPORT_SYMBOL(…); /** * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output * @connector: connector we're probing * @adapter: I2C adapter to use for DDC * * Wrapper around drm_get_edid() for laptops with dual GPUs using one set of * outputs. The wrapper adds the requisite vga_switcheroo calls to temporarily * switch DDC to the GPU which is retrieving EDID. * * Return: Pointer to valid EDID or %NULL if we couldn't find any. */ struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, struct i2c_adapter *adapter) { … } EXPORT_SYMBOL(…); /** * drm_edid_read_switcheroo - get EDID data for a vga_switcheroo output * @connector: connector we're probing * @adapter: I2C adapter to use for DDC * * Wrapper around drm_edid_read_ddc() for laptops with dual GPUs using one set * of outputs. The wrapper adds the requisite vga_switcheroo calls to * temporarily switch DDC to the GPU which is retrieving EDID. * * Return: Pointer to valid EDID or %NULL if we couldn't find any. */ const struct drm_edid *drm_edid_read_switcheroo(struct drm_connector *connector, struct i2c_adapter *adapter) { … } EXPORT_SYMBOL(…); /** * drm_edid_duplicate - duplicate an EDID and the extensions * @edid: EDID to duplicate * * Return: Pointer to duplicated EDID or NULL on allocation failure. */ struct edid *drm_edid_duplicate(const struct edid *edid) { … } EXPORT_SYMBOL(…); /*** EDID parsing ***/ /** * edid_get_quirks - return quirk flags for a given EDID * @drm_edid: EDID to process * * This tells subsequent routines what fixes they need to apply. * * Return: A u32 represents the quirks to apply. */ static u32 edid_get_quirks(const struct drm_edid *drm_edid) { … } #define MODE_SIZE(m) … #define MODE_REFRESH_DIFF(c,t) … /* * Walk the mode list for connector, clearing the preferred status on existing * modes and setting it anew for the right mode ala quirks. */ static void edid_fixup_preferred(struct drm_connector *connector) { … } static bool mode_is_rb(const struct drm_display_mode *mode) { … } /* * drm_mode_find_dmt - Create a copy of a mode if present in DMT * @dev: Device to duplicate against * @hsize: Mode width * @vsize: Mode height * @fresh: Mode refresh rate * @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. */ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb) { … } EXPORT_SYMBOL(…); static bool is_display_descriptor(const struct detailed_timing *descriptor, u8 type) { … } static bool is_detailed_timing_descriptor(const struct detailed_timing *descriptor) { … } detailed_cb; static void cea_for_each_detailed_block(const u8 *ext, detailed_cb *cb, void *closure) { … } static void vtb_for_each_detailed_block(const u8 *ext, detailed_cb *cb, void *closure) { … } static void drm_for_each_detailed_block(const struct drm_edid *drm_edid, detailed_cb *cb, void *closure) { … } static void is_rb(const struct detailed_timing *descriptor, void *data) { … } /* EDID 1.4 defines this explicitly. For EDID 1.3, we guess, badly. */ static bool drm_monitor_supports_rb(const struct drm_edid *drm_edid) { … } static void find_gtf2(const struct detailed_timing *descriptor, void *data) { … } /* Secondary GTF curve kicks in above some break frequency */ static int drm_gtf2_hbreak(const struct drm_edid *drm_edid) { … } static int drm_gtf2_2c(const struct drm_edid *drm_edid) { … } static int drm_gtf2_m(const struct drm_edid *drm_edid) { … } static int drm_gtf2_k(const struct drm_edid *drm_edid) { … } static int drm_gtf2_2j(const struct drm_edid *drm_edid) { … } static void get_timing_level(const struct detailed_timing *descriptor, void *data) { … } /* Get standard timing level (CVT/GTF/DMT). */ static int standard_timing_level(const struct drm_edid *drm_edid) { … } /* * 0 is reserved. The spec says 0x01 fill for unused timings. Some old * monitors fill with ascii space (0x20) instead. */ static int bad_std_timing(u8 a, u8 b) { … } static int drm_mode_hsync(const struct drm_display_mode *mode) { … } static struct drm_display_mode * drm_gtf2_mode(struct drm_device *dev, const struct drm_edid *drm_edid, int hsize, int vsize, int vrefresh_rate) { … } /* * 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, const struct drm_edid *drm_edid, const struct std_timing *t) { … } /* * EDID is delightfully ambiguous about how interlaced modes are to be * encoded. Our internal representation is of frame height, but some * HDTV detailed timings are encoded as field height. * * The format list here is from CEA, in frame size. Technically we * should be checking refresh rate too. Whatever. */ static void drm_mode_do_interlace_quirk(struct drm_display_mode *mode, const struct detailed_pixel_timing *pt) { … } /* * Create a new mode from an EDID detailed timing section. An EDID detailed * timing block contains enough info for us to create and return a new struct * drm_display_mode. */ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connector, const struct drm_edid *drm_edid, const struct detailed_timing *timing) { … } static bool mode_in_hsync_range(const struct drm_display_mode *mode, const struct edid *edid, const u8 *t) { … } static bool mode_in_vsync_range(const struct drm_display_mode *mode, const struct edid *edid, const u8 *t) { … } static u32 range_pixel_clock(const struct edid *edid, const u8 *t) { … } static bool mode_in_range(const struct drm_display_mode *mode, const struct drm_edid *drm_edid, const struct detailed_timing *timing) { … } static bool valid_inferred_mode(const struct drm_connector *connector, const struct drm_display_mode *mode) { … } static int drm_dmt_modes_for_range(struct drm_connector *connector, const struct drm_edid *drm_edid, const struct detailed_timing *timing) { … } /* fix up 1366x768 mode from 1368x768; * GFT/CVT can't express 1366 width which isn't dividable by 8 */ void drm_mode_fixup_1366x768(struct drm_display_mode *mode) { … } static int drm_gtf_modes_for_range(struct drm_connector *connector, const struct drm_edid *drm_edid, const struct detailed_timing *timing) { … } static int drm_gtf2_modes_for_range(struct drm_connector *connector, const struct drm_edid *drm_edid, const struct detailed_timing *timing) { … } static int drm_cvt_modes_for_range(struct drm_connector *connector, const struct drm_edid *drm_edid, const struct detailed_timing *timing) { … } static void do_inferred_modes(const struct detailed_timing *timing, void *c) { … } static int add_inferred_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static int drm_est3_modes(struct drm_connector *connector, const struct detailed_timing *timing) { … } static void do_established_modes(const struct detailed_timing *timing, void *c) { … } /* * Get established modes from EDID and add them. Each EDID block contains a * bitmap of the supported "established modes" list (defined above). Tease them * out and add them to the global modes list. */ static int add_established_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static void do_standard_modes(const struct detailed_timing *timing, void *c) { … } /* * Get standard modes from EDID and add them. Standard modes can be calculated * using the appropriate standard (DMT, GTF, or CVT). Grab them from EDID and * add them to the list. */ static int add_standard_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static int drm_cvt_modes(struct drm_connector *connector, const struct detailed_timing *timing) { … } static void do_cvt_mode(const struct detailed_timing *timing, void *c) { … } static int add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static void fixup_detailed_cea_mode_clock(struct drm_connector *connector, struct drm_display_mode *mode); static void do_detailed_mode(const struct detailed_timing *timing, void *c) { … } /* * add_detailed_modes - Add modes from detailed timings * @connector: attached connector * @drm_edid: EDID block to scan */ static int add_detailed_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } /* CTA-861-H Table 60 - CTA Tag Codes */ #define CTA_DB_AUDIO … #define CTA_DB_VIDEO … #define CTA_DB_VENDOR … #define CTA_DB_SPEAKER … #define CTA_DB_EXTENDED_TAG … /* CTA-861-H Table 62 - CTA Extended Tag Codes */ #define CTA_EXT_DB_VIDEO_CAP … #define CTA_EXT_DB_VENDOR … #define CTA_EXT_DB_HDR_STATIC_METADATA … #define CTA_EXT_DB_420_VIDEO_DATA … #define CTA_EXT_DB_420_VIDEO_CAP_MAP … #define CTA_EXT_DB_HF_EEODB … #define CTA_EXT_DB_HF_SCDB … #define EDID_BASIC_AUDIO … #define EDID_CEA_YCRCB444 … #define EDID_CEA_YCRCB422 … #define EDID_CEA_VCDB_QS … /* * Search EDID for CEA extension block. * * FIXME: Prefer not returning pointers to raw EDID data. */ const u8 *drm_edid_find_extension(const struct drm_edid *drm_edid, int ext_id, int *ext_index) { … } /* Return true if the EDID has a CTA extension or a DisplayID CTA data block */ static bool drm_edid_has_cta_extension(const struct drm_edid *drm_edid) { … } static __always_inline const struct drm_display_mode *cea_mode_for_vic(u8 vic) { … } static u8 cea_num_vics(void) { … } static u8 cea_next_vic(u8 vic) { … } /* * Calculate the alternate clock for the CEA mode * (60Hz vs. 59.94Hz etc.) */ static unsigned int cea_mode_alternate_clock(const struct drm_display_mode *cea_mode) { … } static bool cea_mode_alternate_timings(u8 vic, struct drm_display_mode *mode) { … } static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match, unsigned int clock_tolerance) { … } /** * drm_match_cea_mode - look for a CEA mode matching given mode * @to_match: display mode * * 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) { … } EXPORT_SYMBOL(…); static bool drm_valid_cea_vic(u8 vic) { … } static enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code) { … } static enum hdmi_picture_aspect drm_get_hdmi_aspect_ratio(const u8 video_code) { … } /* * Calculate the alternate clock for HDMI modes (those from the HDMI vendor * specific block). */ static unsigned int hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode) { … } static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_match, unsigned int clock_tolerance) { … } /* * drm_match_hdmi_mode - look for a HDMI mode matching given mode * @to_match: display mode * * An HDMI mode is one defined in the HDMI vendor specific block. * * Returns the HDMI Video ID (VIC) of the mode or 0 if it isn't one. */ static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match) { … } static bool drm_valid_hdmi_vic(u8 vic) { … } static int add_alternate_cea_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static u8 svd_to_vic(u8 svd) { … } /* * Return a display mode for the 0-based vic_index'th VIC across all CTA VDBs in * the EDID, or NULL on errors. */ static struct drm_display_mode * drm_display_mode_from_vic_index(struct drm_connector *connector, int vic_index) { … } /* * do_y420vdb_modes - Parse YCBCR 420 only modes * @connector: connector corresponding to the HDMI sink * @svds: start of the data block of CEA YCBCR 420 VDB * @len: length of the CEA YCBCR 420 VDB * * Parse the CEA-861-F YCBCR 420 Video Data Block (Y420VDB) * which contains modes which can be supported in YCBCR 420 * output format only. */ static int do_y420vdb_modes(struct drm_connector *connector, const u8 *svds, u8 svds_len) { … } /** * drm_display_mode_from_cea_vic() - return a mode for CEA VIC * @dev: DRM device * @video_code: CEA VIC of the mode * * Creates a new mode matching the specified CEA VIC. * * Returns: A new drm_display_mode on success or NULL on failure */ struct drm_display_mode * drm_display_mode_from_cea_vic(struct drm_device *dev, u8 video_code) { … } EXPORT_SYMBOL(…); /* Add modes based on VICs parsed in parse_cta_vdb() */ static int add_cta_vdb_modes(struct drm_connector *connector) { … } struct stereo_mandatory_mode { … }; static const struct stereo_mandatory_mode stereo_mandatory_modes[] = …; static bool stereo_match_mandatory(const struct drm_display_mode *mode, const struct stereo_mandatory_mode *stereo_mode) { … } static int add_hdmi_mandatory_stereo_modes(struct drm_connector *connector) { … } static int add_hdmi_mode(struct drm_connector *connector, u8 vic) { … } static int add_3d_struct_modes(struct drm_connector *connector, u16 structure, int vic_index) { … } static bool hdmi_vsdb_latency_present(const u8 *db) { … } static bool hdmi_vsdb_i_latency_present(const u8 *db) { … } static int hdmi_vsdb_latency_length(const u8 *db) { … } /* * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block * @connector: connector corresponding to the HDMI sink * @db: start of the CEA vendor specific block * @len: length of the CEA block payload, ie. one can access up to db[len] * * Parses the HDMI VSDB looking for modes to add to @connector. This function * also adds the stereo 3d modes when applicable. */ static int do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) { … } static int cea_revision(const u8 *cea) { … } /* * CTA Data Block iterator. * * Iterate through all CTA Data Blocks in both EDID CTA Extensions and DisplayID * CTA Data Blocks. * * struct cea_db *db: * struct cea_db_iter iter; * * cea_db_iter_edid_begin(edid, &iter); * cea_db_iter_for_each(db, &iter) { * // do stuff with db * } * cea_db_iter_end(&iter); */ struct cea_db_iter { … }; /* CTA-861-H section 7.4 CTA Data BLock Collection */ struct cea_db { … } __packed; static int cea_db_tag(const struct cea_db *db) { … } static int cea_db_payload_len(const void *_db) { … } static const void *cea_db_data(const struct cea_db *db) { … } static bool cea_db_is_extended_tag(const struct cea_db *db, int tag) { … } static bool cea_db_is_vendor(const struct cea_db *db, int vendor_oui) { … } static void cea_db_iter_edid_begin(const struct drm_edid *drm_edid, struct cea_db_iter *iter) { … } static const struct cea_db * __cea_db_iter_current_block(const struct cea_db_iter *iter) { … } /* * References: * - CTA-861-H section 7.3.3 CTA Extension Version 3 */ static int cea_db_collection_size(const u8 *cta) { … } /* * References: * - VESA E-EDID v1.4 * - CTA-861-H section 7.3.3 CTA Extension Version 3 */ static const void *__cea_db_iter_edid_next(struct cea_db_iter *iter) { … } /* * References: * - DisplayID v1.3 Appendix C: CEA Data Block within a DisplayID Data Block * - DisplayID v2.0 section 4.10 CTA DisplayID Data Block * * Note that the above do not specify any connection between DisplayID Data * Block revision and CTA Extension versions. */ static const void *__cea_db_iter_displayid_next(struct cea_db_iter *iter) { … } static const struct cea_db *__cea_db_iter_next(struct cea_db_iter *iter) { … } #define cea_db_iter_for_each(__db, __iter) … static void cea_db_iter_end(struct cea_db_iter *iter) { … } static bool cea_db_is_hdmi_vsdb(const struct cea_db *db) { … } static bool cea_db_is_hdmi_forum_vsdb(const struct cea_db *db) { … } static bool cea_db_is_hdmi_forum_eeodb(const void *db) { … } static bool cea_db_is_microsoft_vsdb(const struct cea_db *db) { … } static bool cea_db_is_vcdb(const struct cea_db *db) { … } static bool cea_db_is_hdmi_forum_scdb(const struct cea_db *db) { … } static bool cea_db_is_y420cmdb(const struct cea_db *db) { … } static bool cea_db_is_y420vdb(const struct cea_db *db) { … } static bool cea_db_is_hdmi_hdr_metadata_block(const struct cea_db *db) { … } /* * Get the HF-EEODB override extension block count from EDID. * * The passed in EDID may be partially read, as long as it has at least two * blocks (base block and one extension block) if EDID extension count is > 0. * * Note that this is *not* how you should parse CTA Data Blocks in general; this * is only to handle partially read EDIDs. Normally, use the CTA Data Block * iterators instead. * * References: * - HDMI 2.1 section 10.3.6 HDMI Forum EDID Extension Override Data Block */ static int edid_hfeeodb_extension_block_count(const struct edid *edid) { … } /* * CTA-861 YCbCr 4:2:0 Capability Map Data Block (CTA Y420CMDB) * * Y420CMDB contains a bitmap which gives the index of CTA modes from CTA VDB, * which can support YCBCR 420 sampling output also (apart from RGB/YCBCR444 * etc). For example, if the bit 0 in bitmap is set, first mode in VDB can * support YCBCR420 output too. */ static void parse_cta_y420cmdb(struct drm_connector *connector, const struct cea_db *db, u64 *y420cmdb_map) { … } static int add_cea_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static void fixup_detailed_cea_mode_clock(struct drm_connector *connector, struct drm_display_mode *mode) { … } static void drm_calculate_luminance_range(struct drm_connector *connector) { … } static uint8_t eotf_supported(const u8 *edid_ext) { … } static uint8_t hdr_metadata_type(const u8 *edid_ext) { … } static void drm_parse_hdr_metadata_block(struct drm_connector *connector, const u8 *db) { … } /* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */ static void drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) { … } static void match_identity(const struct detailed_timing *timing, void *data) { … } /** * drm_edid_match - match drm_edid with given identity * @drm_edid: EDID * @ident: the EDID identity to match with * * Check if the EDID matches with the given identity. * * Return: True if the given identity matched with EDID, false otherwise. */ bool drm_edid_match(const struct drm_edid *drm_edid, const struct drm_edid_ident *ident) { … } EXPORT_SYMBOL(…); static void monitor_name(const struct detailed_timing *timing, void *data) { … } static int get_monitor_name(const struct drm_edid *drm_edid, char name[13]) { … } /** * drm_edid_get_monitor_name - fetch the monitor name from the edid * @edid: monitor EDID information * @name: pointer to a character array to hold the name of the monitor * @bufsize: The size of the name buffer (should be at least 14 chars.) * */ void drm_edid_get_monitor_name(const struct edid *edid, char *name, int bufsize) { … } EXPORT_SYMBOL(…); static void clear_eld(struct drm_connector *connector) { … } /* * Get 3-byte SAD buffer from struct cea_sad. */ void drm_edid_cta_sad_get(const struct cea_sad *cta_sad, u8 *sad) { … } /* * Set struct cea_sad from 3-byte SAD buffer. */ void drm_edid_cta_sad_set(struct cea_sad *cta_sad, const u8 *sad) { … } /* * drm_edid_to_eld - build ELD from EDID * @connector: connector corresponding to the HDMI/DP sink * @drm_edid: EDID to parse * * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. */ static void drm_edid_to_eld(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static int _drm_edid_to_sad(const struct drm_edid *drm_edid, struct cea_sad **psads) { … } /** * drm_edid_to_sad - extracts SADs from EDID * @edid: EDID to parse * @sads: pointer that will be set to the extracted SADs * * Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it. * * 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(const struct edid *edid, struct cea_sad **sads) { … } EXPORT_SYMBOL(…); static int _drm_edid_to_speaker_allocation(const struct drm_edid *drm_edid, u8 **sadb) { … } /** * drm_edid_to_speaker_allocation - extracts Speaker Allocation Data Blocks from EDID * @edid: EDID to parse * @sadb: pointer to the speaker block * * Looks for CEA EDID block and extracts the Speaker Allocation Data Block from it. * * 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(const struct edid *edid, u8 **sadb) { … } EXPORT_SYMBOL(…); /** * 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, const struct drm_display_mode *mode) { … } EXPORT_SYMBOL(…); static bool _drm_detect_hdmi_monitor(const struct drm_edid *drm_edid) { … } /** * drm_detect_hdmi_monitor - detect whether monitor is HDMI * @edid: monitor EDID information * * Parse the CEA extension according to CEA-861-B. * * Drivers that have added the modes parsed from EDID to drm_display_info * should use &drm_display_info.is_hdmi instead of calling this function. * * Return: True if the monitor is HDMI, false if not or unknown. */ bool drm_detect_hdmi_monitor(const struct edid *edid) { … } EXPORT_SYMBOL(…); static bool _drm_detect_monitor_audio(const struct drm_edid *drm_edid) { … } /** * drm_detect_monitor_audio - check monitor audio capability * @edid: EDID block to scan * * Monitor should have CEA extension block. * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic * audio' only. If there is any audio extension block and supported * 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(const struct edid *edid) { … } EXPORT_SYMBOL(…); /** * drm_default_rgb_quant_range - default RGB quantization range * @mode: display mode * * Determine the default RGB quantization range for the mode, * as specified in CEA-861. * * Return: The default RGB quantization range for the mode */ enum hdmi_quantization_range drm_default_rgb_quant_range(const struct drm_display_mode *mode) { … } EXPORT_SYMBOL(…); /* CTA-861 Video Data Block (CTA VDB) */ static void parse_cta_vdb(struct drm_connector *connector, const struct cea_db *db) { … } /* * Update y420_cmdb_modes based on previously parsed CTA VDB and Y420CMDB. * * Translate the y420cmdb_map based on VIC indexes to y420_cmdb_modes indexed * using the VICs themselves. */ static void update_cta_y420cmdb(struct drm_connector *connector, u64 y420cmdb_map) { … } static bool cta_vdb_has_vic(const struct drm_connector *connector, u8 vic) { … } /* CTA-861-H YCbCr 4:2:0 Video Data Block (CTA Y420VDB) */ static void parse_cta_y420vdb(struct drm_connector *connector, const struct cea_db *db) { … } static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db) { … } static void drm_get_max_frl_rate(int max_frl_rate, u8 *max_lanes, u8 *max_rate_per_lane) { … } static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, const u8 *db) { … } static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc, const u8 *hf_scds) { … } /* Sink Capability Data Structure */ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, const u8 *hf_scds) { … } static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, const u8 *hdmi) { … } /* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */ static void drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db) { … } /* * See EDID extension for head-mounted and specialized monitors, specified at: * https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension */ static void drm_parse_microsoft_vsdb(struct drm_connector *connector, const u8 *db) { … } static void drm_parse_cea_ext(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static void get_monitor_range(const struct detailed_timing *timing, void *c) { … } static void drm_get_monitor_range(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static void drm_parse_vesa_mso_data(struct drm_connector *connector, const struct displayid_block *block) { … } static void drm_update_mso(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } /* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset * all of the values which would have been set from EDID */ static void drm_reset_display_info(struct drm_connector *connector) { … } static void update_displayid_info(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static void update_display_info(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev, struct displayid_detailed_timings_1 *timings, bool type_7) { … } static int add_displayid_detailed_1_modes(struct drm_connector *connector, const struct displayid_block *block) { … } static int add_displayid_detailed_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static int _drm_edid_connector_add_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } static void _drm_update_tile_info(struct drm_connector *connector, const struct drm_edid *drm_edid); static int _drm_edid_connector_property_update(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } /* For sysfs edid show implementation */ ssize_t drm_edid_connector_property_show(struct drm_connector *connector, char *buf, loff_t off, size_t count) { … } /** * drm_edid_connector_update - Update connector information from EDID * @connector: Connector * @drm_edid: EDID * * Update the connector display info, ELD, HDR metadata, relevant properties, * etc. from the passed in EDID. * * If EDID is NULL, reset the information. * * Must be called before calling drm_edid_connector_add_modes(). * * Return: 0 on success, negative error on errors. */ int drm_edid_connector_update(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } EXPORT_SYMBOL(…); /** * drm_edid_connector_add_modes - Update probed modes from the EDID property * @connector: Connector * * Add the modes from the previously updated EDID property to the connector * probed modes list. * * drm_edid_connector_update() must have been called before this to update the * EDID property. * * Return: The number of modes added, or 0 if we couldn't find any. */ int drm_edid_connector_add_modes(struct drm_connector *connector) { … } EXPORT_SYMBOL(…); /** * drm_connector_update_edid_property - update the edid property of a connector * @connector: drm connector * @edid: new value of the edid property * * This function creates a new blob modeset object and assigns its id to the * connector's edid property. * Since we also parse tile information from EDID's displayID block, we also * set the connector's tile property here. See drm_connector_set_tile_property() * for more details. * * This function is deprecated. Use drm_edid_connector_update() instead. * * Returns: * Zero on success, negative errno on failure. */ int drm_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid) { … } EXPORT_SYMBOL(…); /** * drm_add_edid_modes - add modes from EDID data, if available * @connector: connector we're probing * @edid: EDID data * * Add the specified modes to the connector's mode list. Also fills out the * &drm_display_info structure and ELD in @connector with any information which * can be derived from the edid. * * This function is deprecated. Use drm_edid_connector_add_modes() instead. * * 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) { … } EXPORT_SYMBOL(…); /** * drm_add_modes_noedid - add modes for the connectors without EDID * @connector: connector we're probing * @hdisplay: the horizontal display limit * @vdisplay: the vertical display limit * * 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: 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) { … } EXPORT_SYMBOL(…); static bool is_hdmi2_sink(const struct drm_connector *connector) { … } static u8 drm_mode_hdmi_vic(const struct drm_connector *connector, const struct drm_display_mode *mode) { … } static u8 drm_mode_cea_vic(const struct drm_connector *connector, const struct drm_display_mode *mode) { … } /* * Avoid sending VICs defined in HDMI 2.0 in AVI infoframes to sinks that * conform to HDMI 1.4. * * HDMI 1.4 (CTA-861-D) VIC range: [1..64] * HDMI 2.0 (CTA-861-F) VIC range: [1..107] * * If the sink lists the VIC in CTA VDB, assume it's fine, regardless of HDMI * version. */ static u8 vic_for_avi_infoframe(const struct drm_connector *connector, u8 vic) { … } /** * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with * data from a DRM display mode * @frame: HDMI AVI infoframe * @connector: the connector * @mode: DRM display mode * * Return: 0 on success or a negative error code on failure. */ int drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, const struct drm_connector *connector, const struct drm_display_mode *mode) { … } EXPORT_SYMBOL(…); /** * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe * quantization range information * @frame: HDMI AVI infoframe * @connector: the connector * @mode: DRM display mode * @rgb_quant_range: RGB quantization range (Q) */ void drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, const struct drm_connector *connector, const struct drm_display_mode *mode, enum hdmi_quantization_range rgb_quant_range) { … } EXPORT_SYMBOL(…); static enum hdmi_3d_structure s3d_structure_from_display_mode(const struct drm_display_mode *mode) { … } /** * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with * data from a DRM display mode * @frame: HDMI vendor infoframe * @connector: the connector * @mode: DRM display mode * * Note that there's is a need to send HDMI vendor infoframes only when using a * 4k or stereoscopic 3D mode. So when giving any other mode as input this * function will return -EINVAL, error that can be safely ignored. * * Return: 0 on success or a negative error code on failure. */ int drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, const struct drm_connector *connector, const struct drm_display_mode *mode) { … } EXPORT_SYMBOL(…); static void drm_parse_tiled_block(struct drm_connector *connector, const struct displayid_block *block) { … } static bool displayid_is_tiled_block(const struct displayid_iter *iter, const struct displayid_block *block) { … } static void _drm_update_tile_info(struct drm_connector *connector, const struct drm_edid *drm_edid) { … } /** * drm_edid_is_digital - is digital? * @drm_edid: The EDID * * Return true if input is digital. */ bool drm_edid_is_digital(const struct drm_edid *drm_edid) { … } EXPORT_SYMBOL(…);