// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2019 Laurent Pinchart <[email protected]> */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> #include <linux/property.h> #include <linux/slab.h> #include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_bridge_connector.h> #include <drm/drm_connector.h> #include <drm/drm_device.h> #include <drm/drm_edid.h> #include <drm/drm_managed.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_probe_helper.h> #include <drm/display/drm_hdmi_state_helper.h> /** * DOC: overview * * The DRM bridge connector helper object provides a DRM connector * implementation that wraps a chain of &struct drm_bridge. The connector * operations are fully implemented based on the operations of the bridges in * the chain, and don't require any intervention from the display controller * driver at runtime. * * To use the helper, display controller drivers create a bridge connector with * a call to drm_bridge_connector_init(). This associates the newly created * connector with the chain of bridges passed to the function and registers it * with the DRM device. At that point the connector becomes fully usable, no * further operation is needed. * * The DRM bridge connector operations are implemented based on the operations * provided by the bridges in the chain. Each connector operation is delegated * to the bridge closest to the connector (at the end of the chain) that * provides the relevant functionality. * * To make use of this helper, all bridges in the chain shall report bridge * operation flags (&drm_bridge->ops) and bridge output type * (&drm_bridge->type), as well as the DRM_BRIDGE_ATTACH_NO_CONNECTOR attach * flag (none of the bridges shall create a DRM connector directly). */ /** * struct drm_bridge_connector - A connector backed by a chain of bridges */ struct drm_bridge_connector { … }; #define to_drm_bridge_connector(x) … /* ----------------------------------------------------------------------------- * Bridge Connector Hot-Plug Handling */ static void drm_bridge_connector_hpd_notify(struct drm_connector *connector, enum drm_connector_status status) { … } static void drm_bridge_connector_handle_hpd(struct drm_bridge_connector *drm_bridge_connector, enum drm_connector_status status) { … } static void drm_bridge_connector_hpd_cb(void *cb_data, enum drm_connector_status status) { … } static void drm_bridge_connector_oob_hotplug_event(struct drm_connector *connector, enum drm_connector_status status) { … } static void drm_bridge_connector_enable_hpd(struct drm_connector *connector) { … } static void drm_bridge_connector_disable_hpd(struct drm_connector *connector) { … } /* ----------------------------------------------------------------------------- * Bridge Connector Functions */ static enum drm_connector_status drm_bridge_connector_detect(struct drm_connector *connector, bool force) { … } static void drm_bridge_connector_debugfs_init(struct drm_connector *connector, struct dentry *root) { … } static const struct drm_connector_funcs drm_bridge_connector_funcs = …; /* ----------------------------------------------------------------------------- * Bridge Connector Helper Functions */ static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector, struct drm_bridge *bridge) { … } static int drm_bridge_connector_get_modes(struct drm_connector *connector) { … } static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = …; static enum drm_mode_status drm_bridge_connector_tmds_char_rate_valid(const struct drm_connector *connector, const struct drm_display_mode *mode, unsigned long long tmds_rate) { … } static int drm_bridge_connector_clear_infoframe(struct drm_connector *connector, enum hdmi_infoframe_type type) { … } static int drm_bridge_connector_write_infoframe(struct drm_connector *connector, enum hdmi_infoframe_type type, const u8 *buffer, size_t len) { … } static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = …; /* ----------------------------------------------------------------------------- * Bridge Connector Initialisation */ /** * drm_bridge_connector_init - Initialise a connector for a chain of bridges * @drm: the DRM device * @encoder: the encoder where the bridge chain starts * * Allocate, initialise and register a &drm_bridge_connector with the @drm * device. The connector is associated with a chain of bridges that starts at * the @encoder. All bridges in the chain shall report bridge operation flags * (&drm_bridge->ops) and bridge output type (&drm_bridge->type), and none of * them may create a DRM connector directly. * * Returns a pointer to the new connector on success, or a negative error * pointer otherwise. */ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, struct drm_encoder *encoder) { … } EXPORT_SYMBOL_GPL(…);