Data Structure
struct drm_connector {
struct drm_device *dev;
struct device *kdev;
struct device_attribute *attr;
struct fwnode_handle *fwnode;
struct list_head head;
struct list_head global_connector_list_entry;
struct drm_mode_object base;
char *name;
struct mutex mutex;
unsigned index;
int connector_type; /// DRM_MODE_CONNECTOR_<foo>
int connector_type_id; /// index into connector type enum
bool interlace_allowed;
bool doublescan_allowed;
bool stereo_allowed;
bool ycbcr_420_allowed;
enum drm_connector_registration_state registration_state;
struct list_head modes;
enum drm_connector_status status;
struct list_head probed_modes;
struct drm_display_info display_info;
const struct drm_connector_funcs *funcs;
struct drm_property_blob *edid_blob_ptr;
struct drm_object_properties properties;
struct drm_property *scaling_mode_property;
struct drm_property *vrr_capable_property;
struct drm_property *colorspace_property;
struct drm_property_blob *path_blob_ptr;
struct drm_property *max_bpc_property;
struct drm_privacy_screen *privacy_screen;
struct notifier_block privacy_screen_notifier;
struct drm_property *privacy_screen_sw_state_property;
struct drm_property *privacy_screen_hw_state_property;
uint8_t polled;
int dpms;
const struct drm_connector_helper_funcs *helper_private;
struct drm_cmdline_mode cmdline_mode;
enum drm_connector_force force;
const struct drm_edid *edid_override;
struct mutex edid_override_mutex;
u64 epoch_counter;
u32 possible_encoders;
struct drm_encoder *encoder;
#define MAX_ELD_BYTES 128
uint8_t eld[MAX_ELD_BYTES];
bool latency_present[2];
int video_latency[2];
int audio_latency[2];
struct i2c_adapter *ddc;
int null_edid_counter;
unsigned bad_edid_counter;
bool edid_corrupt;
u8 real_edid_checksum;
struct dentry *debugfs_entry;
struct drm_connector_state *state;
struct drm_property_blob *tile_blob_ptr;
bool has_tile;
struct drm_tile_group *tile_group;
bool tile_is_single_monitor;
uint8_t num_h_tile, num_v_tile;
uint8_t tile_h_loc, tile_v_loc;
uint16_t tile_h_size, tile_v_size;
struct llist_node free_node;
struct hdr_sink_metadata hdr_sink_metadata;
};
polled
: 有三个宏,DRM_CONNECTOR_POLL_HPD: connector 能主动 detect 到 hotplug 并发出 hotplug event。 DRM_CONNECTOR_POLL_CONNECT:需要 polling 是否发生了 connect。DRM_CONNECTOR_POLL_DISCONNECT:需要 polling 是否发生了 disconnect。如果 polled 设置为 0,表示不支持检测 connection status 变化。
struct drm_connector_funcs {
int (*dpms)(struct drm_connector *connector, int mode);
void (*reset)(struct drm_connector *connector);
enum drm_connector_status (*detect)(struct drm_connector *connector,
bool force);
void (*force)(struct drm_connector *connector);
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
uint64_t val);
int (*late_register)(struct drm_connector *connector);
void (*early_unregister)(struct drm_connector *connector);
void (*destroy)(struct drm_connector *connector);
struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
void (*atomic_destroy_state)(struct drm_connector *connector,
struct drm_connector_state *state);
int (*atomic_set_property)(struct drm_connector *connector,
struct drm_connector_state *state,
struct drm_property *property,
uint64_t val);
int (*atomic_get_property)(struct drm_connector *connector,
const struct drm_connector_state *state,
struct drm_property *property,
uint64_t *val);
void (*atomic_print_state)(struct drm_printer *p,
const struct drm_connector_state *state);
void (*oob_hotplug_event)(struct drm_connector *connector,
enum drm_connector_status status);
void (*debugfs_init)(struct drm_connector *connector, struct dentry *root);
};
dpms
: optional, legacy support
reset
: optional,reset connector。通用接口 drm_atomic_helper_connector_reset
detect
: optional, legacy support, 检测 connector 是否 attached,如果没提供该回调,那么默认 connector 一直是 attached 的。atomic driver 实现 helper function 中的.detect_ctx 即可
force
: optional, 当 connector 被 force 进入一个状态时,更新 encoder 的状态
fill_modes
: mandatory, 在 userspace getconnector ioctl 时会调用到,通用接口 drm_helper_probe_single_connector_modes
set_property
: optional, legacy support
late_register
: optional, 用来注册一些 userspace 自定义的 sysfs, debugfs 接口early_unregister
: optional, 注销 late_register 中的接口
destroy
: 通用接口 drm_connector_cleanup
atomic_duplicate_state
: mandatory, 通用接口 drm_atomic_helper_connector_duplicate_stateatomic_destroy_state
: mandatory, 通用接口 drm_atomic_helper_connector_destroy_state
atomic_set_property
: optional, 设置 driver 自定义的 property
atomic_get_property
: optional, 获取 driver 自定义的 property
atomic_print_state
: optional, 打印 driver 自定义的 state
oob_hotplug_event
: optional
debugfs_init
: 创建 connector 相关的 debugfs
struct drm_connector_helper_funcs {
int (*get_modes)(struct drm_connector *connector);
int (*detect_ctx)(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force);
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
int (*mode_valid_ctx)(struct drm_connector *connector,
struct drm_display_mode *mode,
struct drm_modeset_acquire_ctx *ctx,
enum drm_mode_status *status);
struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector,
struct drm_atomic_state *state);
int (*atomic_check)(struct drm_connector *connector,
struct drm_atomic_state *state);
void (*atomic_commit)(struct drm_connector *connector,
struct drm_atomic_state *state);
int (*prepare_writeback_job)(struct drm_writeback_connector *connector,
struct drm_writeback_job *job);
void (*cleanup_writeback_job)(struct drm_writeback_connector *connector,
struct drm_writeback_job *job);
void (*enable_hpd)(struct drm_connector *connector);
void (*disable_hpd)(struct drm_connector *connector);
};
get_modes
: mandatory, 获取 connector 支持的所有 display mode, 有两种方法,一种通过 edid, 另一种通过 fixed specific modes 来填充 drm_display_mode 结构体,通过 drm_add_edid_modes()或 drm_mode_probed_add()保存进 &drm_connector.probed_modes list.
detect_ctx
: optional, 判断 connector 状态,代替 drm_connector_funcs 中的.detect 回调
mode_valid
: optional, 检查 connector 对 userspace 传入的 drm_dispaly_mode 限制是否满足
mode_valid_ctx
: optional, mode_valid 的 atomic 版本
best_encoder
:
atomic_best_encoder
:
atomic_check
:
atomic_commit
:
prepare_writeback_job
:
cleanup_writeback_job
:
enable_hpd
:
disable_hpd
:
Hotplug
检查 connector 状态的方式有两种,第一种 polling,第二种为 hotplug。
首先需要 connector 初始化时, 指定 connector.polled, DRM_CONNECTOR_POLL_HPD 表示支持 hotplug,connector 可以生成 hotplug event。DRM_CONNECTOR_POLL_CONNECT 和 DRM_CONNECTOR_POLL_DISCONNECT 表示周期性 polling connector status。如果 polled 为 0,那么表示不支持检测 connector 状态。
方式 1 polling
在 driver init 中调用 drm_kms_helper_poll_init 即可。在 polling 中检测到 connector status 改变就会向 userspace 发送 uevent。
方式 2 Hotplug Interrupt
仍然需要首先调用 drm_kms_helper_poll_init,其中会调用到 connector_helper_funcs->enable_hpd 来 enable hpd。
后面需要在 hotplug 中断处理函数中调用 drm_helper_hpd_irq_event(处理多个 connector) 或 drm_connector_helper_hpd_irq_event(单个 connector) 来进行 hotplug processing,向 userspace 发送 uevent。