18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> 48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Broadcom 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 88c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h> 98c2ecf20Sopenharmony_ci#include <drm/drm_connector.h> 108c2ecf20Sopenharmony_ci#include <drm/drm_encoder.h> 118c2ecf20Sopenharmony_ci#include <drm/drm_modeset_helper_vtables.h> 128c2ecf20Sopenharmony_ci#include <drm/drm_panel.h> 138c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct panel_bridge { 178c2ecf20Sopenharmony_ci struct drm_bridge bridge; 188c2ecf20Sopenharmony_ci struct drm_connector connector; 198c2ecf20Sopenharmony_ci struct drm_panel *panel; 208c2ecf20Sopenharmony_ci u32 connector_type; 218c2ecf20Sopenharmony_ci}; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic inline struct panel_bridge * 248c2ecf20Sopenharmony_cidrm_bridge_to_panel_bridge(struct drm_bridge *bridge) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci return container_of(bridge, struct panel_bridge, bridge); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic inline struct panel_bridge * 308c2ecf20Sopenharmony_cidrm_connector_to_panel_bridge(struct drm_connector *connector) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci return container_of(connector, struct panel_bridge, connector); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int panel_bridge_connector_get_modes(struct drm_connector *connector) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge = 388c2ecf20Sopenharmony_ci drm_connector_to_panel_bridge(connector); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci return drm_panel_get_modes(panel_bridge->panel, connector); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs 448c2ecf20Sopenharmony_cipanel_bridge_connector_helper_funcs = { 458c2ecf20Sopenharmony_ci .get_modes = panel_bridge_connector_get_modes, 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs panel_bridge_connector_funcs = { 498c2ecf20Sopenharmony_ci .reset = drm_atomic_helper_connector_reset, 508c2ecf20Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 518c2ecf20Sopenharmony_ci .destroy = drm_connector_cleanup, 528c2ecf20Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 538c2ecf20Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int panel_bridge_attach(struct drm_bridge *bridge, 578c2ecf20Sopenharmony_ci enum drm_bridge_attach_flags flags) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); 608c2ecf20Sopenharmony_ci struct drm_connector *connector = &panel_bridge->connector; 618c2ecf20Sopenharmony_ci int ret; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (!bridge->encoder) { 678c2ecf20Sopenharmony_ci DRM_ERROR("Missing encoder\n"); 688c2ecf20Sopenharmony_ci return -ENODEV; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, 728c2ecf20Sopenharmony_ci &panel_bridge_connector_helper_funcs); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci ret = drm_connector_init(bridge->dev, connector, 758c2ecf20Sopenharmony_ci &panel_bridge_connector_funcs, 768c2ecf20Sopenharmony_ci panel_bridge->connector_type); 778c2ecf20Sopenharmony_ci if (ret) { 788c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize connector\n"); 798c2ecf20Sopenharmony_ci return ret; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci drm_connector_attach_encoder(&panel_bridge->connector, 838c2ecf20Sopenharmony_ci bridge->encoder); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void panel_bridge_detach(struct drm_bridge *bridge) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); 918c2ecf20Sopenharmony_ci struct drm_connector *connector = &panel_bridge->connector; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* 948c2ecf20Sopenharmony_ci * Cleanup the connector if we know it was initialized. 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * FIXME: This wouldn't be needed if the panel_bridge structure was 978c2ecf20Sopenharmony_ci * allocated with drmm_kzalloc(). This might be tricky since the 988c2ecf20Sopenharmony_ci * drm_device pointer can only be retrieved when the bridge is attached. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci if (connector->dev) 1018c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void panel_bridge_pre_enable(struct drm_bridge *bridge) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci drm_panel_prepare(panel_bridge->panel); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic void panel_bridge_enable(struct drm_bridge *bridge) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci drm_panel_enable(panel_bridge->panel); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void panel_bridge_disable(struct drm_bridge *bridge) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci drm_panel_disable(panel_bridge->panel); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void panel_bridge_post_disable(struct drm_bridge *bridge) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci drm_panel_unprepare(panel_bridge->panel); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int panel_bridge_get_modes(struct drm_bridge *bridge, 1338c2ecf20Sopenharmony_ci struct drm_connector *connector) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return drm_panel_get_modes(panel_bridge->panel, connector); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs panel_bridge_bridge_funcs = { 1418c2ecf20Sopenharmony_ci .attach = panel_bridge_attach, 1428c2ecf20Sopenharmony_ci .detach = panel_bridge_detach, 1438c2ecf20Sopenharmony_ci .pre_enable = panel_bridge_pre_enable, 1448c2ecf20Sopenharmony_ci .enable = panel_bridge_enable, 1458c2ecf20Sopenharmony_ci .disable = panel_bridge_disable, 1468c2ecf20Sopenharmony_ci .post_disable = panel_bridge_post_disable, 1478c2ecf20Sopenharmony_ci .get_modes = panel_bridge_get_modes, 1488c2ecf20Sopenharmony_ci .atomic_reset = drm_atomic_helper_bridge_reset, 1498c2ecf20Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 1508c2ecf20Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 1518c2ecf20Sopenharmony_ci .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt, 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/** 1558c2ecf20Sopenharmony_ci * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that 1568c2ecf20Sopenharmony_ci * just calls the appropriate functions from &drm_panel. 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * @panel: The drm_panel being wrapped. Must be non-NULL. 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * For drivers converting from directly using drm_panel: The expected 1618c2ecf20Sopenharmony_ci * usage pattern is that during either encoder module probe or DSI 1628c2ecf20Sopenharmony_ci * host attach, a drm_panel will be looked up through 1638c2ecf20Sopenharmony_ci * drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to 1648c2ecf20Sopenharmony_ci * wrap that panel in the new bridge, and the result can then be 1658c2ecf20Sopenharmony_ci * passed to drm_bridge_attach(). The drm_panel_prepare() and related 1668c2ecf20Sopenharmony_ci * functions can be dropped from the encoder driver (they're now 1678c2ecf20Sopenharmony_ci * called by the KMS helpers before calling into the encoder), along 1688c2ecf20Sopenharmony_ci * with connector creation. When done with the bridge (after 1698c2ecf20Sopenharmony_ci * drm_mode_config_cleanup() if the bridge has already been attached), then 1708c2ecf20Sopenharmony_ci * drm_panel_bridge_remove() to free it. 1718c2ecf20Sopenharmony_ci * 1728c2ecf20Sopenharmony_ci * The connector type is set to @panel->connector_type, which must be set to a 1738c2ecf20Sopenharmony_ci * known type. Calling this function with a panel whose connector type is 1748c2ecf20Sopenharmony_ci * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL). 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * See devm_drm_panel_bridge_add() for an automatically managed version of this 1778c2ecf20Sopenharmony_ci * function. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistruct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown)) 1828c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return drm_panel_bridge_add_typed(panel, panel->connector_type); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_bridge_add); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/** 1898c2ecf20Sopenharmony_ci * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with 1908c2ecf20Sopenharmony_ci * an explicit connector type. 1918c2ecf20Sopenharmony_ci * @panel: The drm_panel being wrapped. Must be non-NULL. 1928c2ecf20Sopenharmony_ci * @connector_type: The connector type (DRM_MODE_CONNECTOR_*) 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * This is just like drm_panel_bridge_add(), but forces the connector type to 1958c2ecf20Sopenharmony_ci * @connector_type instead of infering it from the panel. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * This function is deprecated and should not be used in new drivers. Use 1988c2ecf20Sopenharmony_ci * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they 1998c2ecf20Sopenharmony_ci * don't report a connector type. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_cistruct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, 2028c2ecf20Sopenharmony_ci u32 connector_type) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (!panel) 2078c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge), 2108c2ecf20Sopenharmony_ci GFP_KERNEL); 2118c2ecf20Sopenharmony_ci if (!panel_bridge) 2128c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci panel_bridge->connector_type = connector_type; 2158c2ecf20Sopenharmony_ci panel_bridge->panel = panel; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs; 2188c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 2198c2ecf20Sopenharmony_ci panel_bridge->bridge.of_node = panel->dev->of_node; 2208c2ecf20Sopenharmony_ci#endif 2218c2ecf20Sopenharmony_ci panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES; 2228c2ecf20Sopenharmony_ci panel_bridge->bridge.type = connector_type; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci drm_bridge_add(&panel_bridge->bridge); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return &panel_bridge->bridge; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_bridge_add_typed); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/** 2318c2ecf20Sopenharmony_ci * drm_panel_bridge_remove - Unregisters and frees a drm_bridge 2328c2ecf20Sopenharmony_ci * created by drm_panel_bridge_add(). 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * @bridge: The drm_bridge being freed. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_civoid drm_panel_bridge_remove(struct drm_bridge *bridge) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (!bridge) 2418c2ecf20Sopenharmony_ci return; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (bridge->funcs != &panel_bridge_bridge_funcs) 2448c2ecf20Sopenharmony_ci return; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci panel_bridge = drm_bridge_to_panel_bridge(bridge); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci drm_bridge_remove(bridge); 2498c2ecf20Sopenharmony_ci devm_kfree(panel_bridge->panel->dev, bridge); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_bridge_remove); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void devm_drm_panel_bridge_release(struct device *dev, void *res) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct drm_bridge **bridge = res; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci drm_panel_bridge_remove(*bridge); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/** 2618c2ecf20Sopenharmony_ci * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector 2628c2ecf20Sopenharmony_ci * that just calls the appropriate functions from &drm_panel. 2638c2ecf20Sopenharmony_ci * @dev: device to tie the bridge lifetime to 2648c2ecf20Sopenharmony_ci * @panel: The drm_panel being wrapped. Must be non-NULL. 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * This is the managed version of drm_panel_bridge_add() which automatically 2678c2ecf20Sopenharmony_ci * calls drm_panel_bridge_remove() when @dev is unbound. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_cistruct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, 2708c2ecf20Sopenharmony_ci struct drm_panel *panel) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown)) 2738c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return devm_drm_panel_bridge_add_typed(dev, panel, 2768c2ecf20Sopenharmony_ci panel->connector_type); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devm_drm_panel_bridge_add); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/** 2818c2ecf20Sopenharmony_ci * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and 2828c2ecf20Sopenharmony_ci * &drm_connector with an explicit connector type. 2838c2ecf20Sopenharmony_ci * @dev: device to tie the bridge lifetime to 2848c2ecf20Sopenharmony_ci * @panel: The drm_panel being wrapped. Must be non-NULL. 2858c2ecf20Sopenharmony_ci * @connector_type: The connector type (DRM_MODE_CONNECTOR_*) 2868c2ecf20Sopenharmony_ci * 2878c2ecf20Sopenharmony_ci * This is just like devm_drm_panel_bridge_add(), but forces the connector type 2888c2ecf20Sopenharmony_ci * to @connector_type instead of infering it from the panel. 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * This function is deprecated and should not be used in new drivers. Use 2918c2ecf20Sopenharmony_ci * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if 2928c2ecf20Sopenharmony_ci * they don't report a connector type. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_cistruct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, 2958c2ecf20Sopenharmony_ci struct drm_panel *panel, 2968c2ecf20Sopenharmony_ci u32 connector_type) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct drm_bridge **ptr, *bridge; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr), 3018c2ecf20Sopenharmony_ci GFP_KERNEL); 3028c2ecf20Sopenharmony_ci if (!ptr) 3038c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci bridge = drm_panel_bridge_add_typed(panel, connector_type); 3068c2ecf20Sopenharmony_ci if (!IS_ERR(bridge)) { 3078c2ecf20Sopenharmony_ci *ptr = bridge; 3088c2ecf20Sopenharmony_ci devres_add(dev, ptr); 3098c2ecf20Sopenharmony_ci } else { 3108c2ecf20Sopenharmony_ci devres_free(ptr); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return bridge; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devm_drm_panel_bridge_add_typed); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/** 3188c2ecf20Sopenharmony_ci * drm_panel_bridge_connector - return the connector for the panel bridge 3198c2ecf20Sopenharmony_ci * @bridge: The drm_bridge. 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * drm_panel_bridge creates the connector. 3228c2ecf20Sopenharmony_ci * This function gives external access to the connector. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * Returns: Pointer to drm_connector 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_cistruct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct panel_bridge *panel_bridge; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci panel_bridge = drm_bridge_to_panel_bridge(bridge); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return &panel_bridge->connector; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_bridge_connector); 335