DRM全解析 —— connector详解(1)

本文参考以下博文:

Linux内核4.14版本------drm框架分析(2)------connector分析

特此致谢!

1. 简介

connector是指encoder和panel之间交互的接口部分,更通俗地说就是连接物理设备的连接器,对应于物理连接器 (如VGA、DVI、FPD-Link、HDMI、DisplayPort、S-Video等) 。connector并不是指物理线,在DRM中,connector 是一个抽象的数据结构,代表连接的显示设备,从connector中可以得到当前物理连接的输出设备相关的信息。

connector通常和encoder驱动绑定在一起。

connector在系统中的位置和作用如下所示:

2. 核心结构

在Linux内核的DRM中,connector对应的核心结构体为:struct drm_connector。该结构体在include/drm/drm_connector.h中定义,代码如下(Linux内核版本:6.1):

cpp 复制代码
/**
 * struct drm_connector - central DRM connector control structure
 *
 * Each connector may be connected to one or more CRTCs, or may be clonable by
 * another connector if they can share a CRTC.  Each connector also has a specific
 * position in the broader display (referred to as a 'screen' though it could
 * span multiple monitors).
 */
struct drm_connector {
	/** @dev: parent DRM device */
	struct drm_device *dev;
	/** @kdev: kernel device for sysfs attributes */
	struct device *kdev;
	/** @attr: sysfs attributes */
	struct device_attribute *attr;
	/**
	 * @fwnode: associated fwnode supplied by platform firmware
	 *
	 * Drivers can set this to associate a fwnode with a connector, drivers
	 * are expected to get a reference on the fwnode when setting this.
	 * drm_connector_cleanup() will call fwnode_handle_put() on this.
	 */
	struct fwnode_handle *fwnode;

	/**
	 * @head:
	 *
	 * List of all connectors on a @dev, linked from
	 * &drm_mode_config.connector_list. Protected by
	 * &drm_mode_config.connector_list_lock, but please only use
	 * &drm_connector_list_iter to walk this list.
	 */
	struct list_head head;

	/**
	 * @global_connector_list_entry:
	 *
	 * Connector entry in the global connector-list, used by
	 * drm_connector_find_by_fwnode().
	 */
	struct list_head global_connector_list_entry;

	/** @base: base KMS object */
	struct drm_mode_object base;

	/** @name: human readable name, can be overwritten by the driver */
	char *name;

	/**
	 * @mutex: Lock for general connector state, but currently only protects
	 * @registered. Most of the connector state is still protected by
	 * &drm_mode_config.mutex.
	 */
	struct mutex mutex;

	/**
	 * @index: Compacted connector index, which matches the position inside
	 * the mode_config.list for drivers not supporting hot-add/removing. Can
	 * be used as an array index. It is invariant over the lifetime of the
	 * connector.
	 */
	unsigned index;

	/**
	 * @connector_type:
	 * one of the DRM_MODE_CONNECTOR_<foo> types from drm_mode.h
	 */
	int connector_type;
	/** @connector_type_id: index into connector type enum */
	int connector_type_id;
	/**
	 * @interlace_allowed:
	 * Can this connector handle interlaced modes? Only used by
	 * drm_helper_probe_single_connector_modes() for mode filtering.
	 */
	bool interlace_allowed;
	/**
	 * @doublescan_allowed:
	 * Can this connector handle doublescan? Only used by
	 * drm_helper_probe_single_connector_modes() for mode filtering.
	 */
	bool doublescan_allowed;
	/**
	 * @stereo_allowed:
	 * Can this connector handle stereo modes? Only used by
	 * drm_helper_probe_single_connector_modes() for mode filtering.
	 */
	bool stereo_allowed;

	/**
	 * @ycbcr_420_allowed : This bool indicates if this connector is
	 * capable of handling YCBCR 420 output. While parsing the EDID
	 * blocks it's very helpful to know if the source is capable of
	 * handling YCBCR 420 outputs.
	 */
	bool ycbcr_420_allowed;

	/**
	 * @registration_state: Is this connector initializing, exposed
	 * (registered) with userspace, or unregistered?
	 *
	 * Protected by @mutex.
	 */
	enum drm_connector_registration_state registration_state;

	/**
	 * @modes:
	 * Modes available on this connector (from fill_modes() + user).
	 * Protected by &drm_mode_config.mutex.
	 */
	struct list_head modes;

	/**
	 * @status:
	 * One of the drm_connector_status enums (connected, not, or unknown).
	 * Protected by &drm_mode_config.mutex.
	 */
	enum drm_connector_status status;

	/**
	 * @probed_modes:
	 * These are modes added by probing with DDC or the BIOS, before
	 * filtering is applied. Used by the probe helpers. Protected by
	 * &drm_mode_config.mutex.
	 */
	struct list_head probed_modes;

	/**
	 * @display_info: Display information is filled from EDID information
	 * when a display is detected. For non hot-pluggable displays such as
	 * flat panels in embedded systems, the driver should initialize the
	 * &drm_display_info.width_mm and &drm_display_info.height_mm fields
	 * with the physical size of the display.
	 *
	 * Protected by &drm_mode_config.mutex.
	 */
	struct drm_display_info display_info;

	/** @funcs: connector control functions */
	const struct drm_connector_funcs *funcs;

	/**
	 * @edid_blob_ptr: DRM property containing EDID if present. Protected by
	 * &drm_mode_config.mutex. This should be updated only by calling
	 * drm_connector_update_edid_property().
	 */
	struct drm_property_blob *edid_blob_ptr;

	/** @properties: property tracking for this connector */
	struct drm_object_properties properties;

	/**
	 * @scaling_mode_property: Optional atomic property to control the
	 * upscaling. See drm_connector_attach_content_protection_property().
	 */
	struct drm_property *scaling_mode_property;

	/**
	 * @vrr_capable_property: Optional property to help userspace
	 * query hardware support for variable refresh rate on a connector.
	 * connector. Drivers can add the property to a connector by
	 * calling drm_connector_attach_vrr_capable_property().
	 *
	 * This should be updated only by calling
	 * drm_connector_set_vrr_capable_property().
	 */
	struct drm_property *vrr_capable_property;

	/**
	 * @colorspace_property: Connector property to set the suitable
	 * colorspace supported by the sink.
	 */
	struct drm_property *colorspace_property;

	/**
	 * @path_blob_ptr:
	 *
	 * DRM blob property data for the DP MST path property. This should only
	 * be updated by calling drm_connector_set_path_property().
	 */
	struct drm_property_blob *path_blob_ptr;

	/**
	 * @max_bpc_property: Default connector property for the max bpc to be
	 * driven out of the connector.
	 */
	struct drm_property *max_bpc_property;

	/** @privacy_screen: drm_privacy_screen for this connector, or NULL. */
	struct drm_privacy_screen *privacy_screen;

	/** @privacy_screen_notifier: privacy-screen notifier_block */
	struct notifier_block privacy_screen_notifier;

	/**
	 * @privacy_screen_sw_state_property: Optional atomic property for the
	 * connector to control the integrated privacy screen.
	 */
	struct drm_property *privacy_screen_sw_state_property;

	/**
	 * @privacy_screen_hw_state_property: Optional atomic property for the
	 * connector to report the actual integrated privacy screen state.
	 */
	struct drm_property *privacy_screen_hw_state_property;

#define DRM_CONNECTOR_POLL_HPD (1 << 0)
#define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)

	/**
	 * @polled:
	 *
	 * Connector polling mode, a combination of
	 *
	 * DRM_CONNECTOR_POLL_HPD
	 *     The connector generates hotplug events and doesn't need to be
	 *     periodically polled. The CONNECT and DISCONNECT flags must not
	 *     be set together with the HPD flag.
	 *
	 * DRM_CONNECTOR_POLL_CONNECT
	 *     Periodically poll the connector for connection.
	 *
	 * DRM_CONNECTOR_POLL_DISCONNECT
	 *     Periodically poll the connector for disconnection, without
	 *     causing flickering even when the connector is in use. DACs should
	 *     rarely do this without a lot of testing.
	 *
	 * Set to 0 for connectors that don't support connection status
	 * discovery.
	 */
	uint8_t polled;

	/**
	 * @dpms: Current dpms state. For legacy drivers the
	 * &drm_connector_funcs.dpms callback must update this. For atomic
	 * drivers, this is handled by the core atomic code, and drivers must
	 * only take &drm_crtc_state.active into account.
	 */
	int dpms;

	/** @helper_private: mid-layer private data */
	const struct drm_connector_helper_funcs *helper_private;

	/** @cmdline_mode: mode line parsed from the kernel cmdline for this connector */
	struct drm_cmdline_mode cmdline_mode;
	/** @force: a DRM_FORCE_<foo> state for forced mode sets */
	enum drm_connector_force force;
	/**
	 * @override_edid: has the EDID been overwritten through debugfs for
	 * testing? Do not modify outside of drm_edid_override_set() and
	 * drm_edid_override_reset().
	 */
	bool override_edid;
	/** @epoch_counter: used to detect any other changes in connector, besides status */
	u64 epoch_counter;

	/**
	 * @possible_encoders: Bit mask of encoders that can drive this
	 * connector, drm_encoder_index() determines the index into the bitfield
	 * and the bits are set with drm_connector_attach_encoder().
	 */
	u32 possible_encoders;

	/**
	 * @encoder: Currently bound encoder driving this connector, if any.
	 * Only really meaningful for non-atomic drivers. Atomic drivers should
	 * instead look at &drm_connector_state.best_encoder, and in case they
	 * need the CRTC driving this output, &drm_connector_state.crtc.
	 */
	struct drm_encoder *encoder;

#define MAX_ELD_BYTES	128
	/** @eld: EDID-like data, if present */
	uint8_t eld[MAX_ELD_BYTES];
	/** @latency_present: AV delay info from ELD, if found */
	bool latency_present[2];
	/**
	 * @video_latency: Video latency info from ELD, if found.
	 * [0]: progressive, [1]: interlaced
	 */
	int video_latency[2];
	/**
	 * @audio_latency: audio latency info from ELD, if found
	 * [0]: progressive, [1]: interlaced
	 */
	int audio_latency[2];

	/**
	 * @ddc: associated ddc adapter.
	 * A connector usually has its associated ddc adapter. If a driver uses
	 * this field, then an appropriate symbolic link is created in connector
	 * sysfs directory to make it easy for the user to tell which i2c
	 * adapter is for a particular display.
	 *
	 * The field should be set by calling drm_connector_init_with_ddc().
	 */
	struct i2c_adapter *ddc;

	/**
	 * @null_edid_counter: track sinks that give us all zeros for the EDID.
	 * Needed to workaround some HW bugs where we get all 0s
	 */
	int null_edid_counter;

	/** @bad_edid_counter: track sinks that give us an EDID with invalid checksum */
	unsigned bad_edid_counter;

	/**
	 * @edid_corrupt: Indicates whether the last read EDID was corrupt. Used
	 * in Displayport compliance testing - Displayport Link CTS Core 1.2
	 * rev1.1 4.2.2.6
	 */
	bool edid_corrupt;
	/**
	 * @real_edid_checksum: real edid checksum for corrupted edid block.
	 * Required in Displayport 1.4 compliance testing
	 * rev1.1 4.2.2.6
	 */
	u8 real_edid_checksum;

	/** @debugfs_entry: debugfs directory for this connector */
	struct dentry *debugfs_entry;

	/**
	 * @state:
	 *
	 * Current atomic state for this connector.
	 *
	 * This is protected by &drm_mode_config.connection_mutex. Note that
	 * nonblocking atomic commits access the current connector state without
	 * taking locks. Either by going through the &struct drm_atomic_state
	 * pointers, see for_each_oldnew_connector_in_state(),
	 * for_each_old_connector_in_state() and
	 * for_each_new_connector_in_state(). Or through careful ordering of
	 * atomic commit operations as implemented in the atomic helpers, see
	 * &struct drm_crtc_commit.
	 */
	struct drm_connector_state *state;

	/* DisplayID bits. FIXME: Extract into a substruct? */

	/**
	 * @tile_blob_ptr:
	 *
	 * DRM blob property data for the tile property (used mostly by DP MST).
	 * This is meant for screens which are driven through separate display
	 * pipelines represented by &drm_crtc, which might not be running with
	 * genlocked clocks. For tiled panels which are genlocked, like
	 * dual-link LVDS or dual-link DSI, the driver should try to not expose
	 * the tiling and virtualize both &drm_crtc and &drm_plane if needed.
	 *
	 * This should only be updated by calling
	 * drm_connector_set_tile_property().
	 */
	struct drm_property_blob *tile_blob_ptr;

	/** @has_tile: is this connector connected to a tiled monitor */
	bool has_tile;
	/** @tile_group: tile group for the connected monitor */
	struct drm_tile_group *tile_group;
	/** @tile_is_single_monitor: whether the tile is one monitor housing */
	bool tile_is_single_monitor;

	/** @num_h_tile: number of horizontal tiles in the tile group */
	/** @num_v_tile: number of vertical tiles in the tile group */
	uint8_t num_h_tile, num_v_tile;
	/** @tile_h_loc: horizontal location of this tile */
	/** @tile_v_loc: vertical location of this tile */
	uint8_t tile_h_loc, tile_v_loc;
	/** @tile_h_size: horizontal size of this tile. */
	/** @tile_v_size: vertical size of this tile. */
	uint16_t tile_h_size, tile_v_size;

	/**
	 * @free_node:
	 *
	 * List used only by &drm_connector_list_iter to be able to clean up a
	 * connector from any context, in conjunction with
	 * &drm_mode_config.connector_free_work.
	 */
	struct llist_node free_node;

	/** @hdr_sink_metadata: HDR Metadata Information read from sink */
	struct hdr_sink_metadata hdr_sink_metadata;
};

可以看到,这个结构比plane、CRTC和encoder大得多。

3. drm_connector结构释义

(0)总述

cpp 复制代码
/**
 * struct drm_connector - central DRM connector control structure
 *
 * Each connector may be connected to one or more CRTCs, or may be clonable by
 * another connector if they can share a CRTC.  Each connector also has a specific
 * position in the broader display (referred to as a 'screen' though it could
 * span multiple monitors).
 */

struct drm_connector ------ 核心的DRM connector控制结构。

每个connector可以连接到一个或多个CRTC,或者如果它们可以共享CRTC,则可以由另一个connector克隆。每个connector在更宽的显示中也有一个特定的位置(称为"屏幕",尽管它可以跨越多个监视器)。

(1)struct drm_device *dev

cpp 复制代码
    /** @dev: parent DRM device */
	struct drm_device *dev;

父DRM设备。

(2)struct device *kdev

cpp 复制代码
    /** @kdev: kernel device for sysfs attributes */
	struct device *kdev;

sysfs属性的内核设备。

(3)struct device_attribute *attr

cpp 复制代码
    /** @attr: sysfs attributes */
	struct device_attribute *attr;

sysfs属性。

(4)struct fwnode_handle *fwnode

cpp 复制代码
    /**
	 * @fwnode: associated fwnode supplied by platform firmware
	 *
	 * Drivers can set this to associate a fwnode with a connector, drivers
	 * are expected to get a reference on the fwnode when setting this.
	 * drm_connector_cleanup() will call fwnode_handle_put() on this.
	 */
	struct fwnode_handle *fwnode;

由平台固件提供的关联fwnode。

驱动程序可以将此项设置为将fwnode与一个connector相关联,在设置此项时,驱动程序需要在fwnode上获得引用。在如此设置后,drm_connector_cleanup()将调用fwnode_handle_put()。

(5)struct list_head head

cpp 复制代码
    /**
	 * @head:
	 *
	 * List of all connectors on a @dev, linked from
	 * &drm_mode_config.connector_list. Protected by
	 * &drm_mode_config.connector_list_lock, but please only use
	 * &drm_connector_list_iter to walk this list.
	 */
	struct list_head head;

从&drm_mode_config.connecter_List链接的@dev上所有连接器的列表。受&drm_mode_config.connector_list_lock保护,但请仅使用&drm_conconnector_list_iter遍历此链表。

(6)struct list_head global_connector_list_entry

cpp 复制代码
    /**
	 * @global_connector_list_entry:
	 *
	 * Connector entry in the global connector-list, used by
	 * drm_connector_find_by_fwnode().
	 */
	struct list_head global_connector_list_entry;

全局connector-list中的connector条目,由drm_connector_find_by_fwnode()使用。

(7)struct drm_mode_object base

cpp 复制代码
    /** @base: base KMS object */
	struct drm_mode_object base;

基本KMS对象。

(8)char *name

cpp 复制代码
    /** @name: human readable name, can be overwritten by the driver */
	char *name;

人类可读的名称(名字),可以被驱动程序覆盖。

drm_connector结构的其余成员将在下一篇文章中继续深入释义。

相关推荐
芒果黑4 个月前
Qt WebEngine播放DRM音视频
drm·qt webengine
炭烤毛蛋1 年前
modetest
drm·framebuffer
wenshizhang1 年前
AMD显卡休眠唤醒流程分析
linux·内核·drm·amdgpu
Android系统攻城狮1 年前
Android12之DRM架构(一)
drm
蓝天居士1 年前
DRM全解析 —— encoder详解(3)
drm
蓝天居士1 年前
DRM全解析 —— encoder详解(1)
drm
山东布谷科技官方1 年前
直播系统源码平台内容安全与版权维护技术:DRM
网络安全·drm·直播系统源码·数字版权管理·版权
风雨兼程80231 年前
Linux内核4.14版本——drm框架分析(14)——Atomic KMS 架构(struct drm_atomic_state)
drm
蓝天居士1 年前
DRM全解析 —— CREATE_DUMB(4)
linux内核·libdrm·drm