119c468b4SFrançois Tigeot /* 219c468b4SFrançois Tigeot * Copyright (c) 2014 Samsung Electronics Co., Ltd 319c468b4SFrançois Tigeot * 419c468b4SFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 519c468b4SFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 619c468b4SFrançois Tigeot * to deal in the Software without restriction, including without limitation 719c468b4SFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sub license, 819c468b4SFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 919c468b4SFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 1019c468b4SFrançois Tigeot * 1119c468b4SFrançois Tigeot * The above copyright notice and this permission notice (including the 1219c468b4SFrançois Tigeot * next paragraph) shall be included in all copies or substantial portions 1319c468b4SFrançois Tigeot * of the Software. 1419c468b4SFrançois Tigeot * 1519c468b4SFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1619c468b4SFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1719c468b4SFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1819c468b4SFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1919c468b4SFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2019c468b4SFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2119c468b4SFrançois Tigeot * DEALINGS IN THE SOFTWARE. 2219c468b4SFrançois Tigeot */ 2319c468b4SFrançois Tigeot 2419c468b4SFrançois Tigeot #include <linux/err.h> 2519c468b4SFrançois Tigeot #include <linux/module.h> 2619c468b4SFrançois Tigeot 2719c468b4SFrançois Tigeot 2819c468b4SFrançois Tigeot #include "drm/drmP.h" 2919c468b4SFrançois Tigeot 3019c468b4SFrançois Tigeot /** 3119c468b4SFrançois Tigeot * DOC: overview 3219c468b4SFrançois Tigeot * 33*aee94f86SFrançois Tigeot * struct &drm_bridge represents a device that hangs on to an encoder. These are 34*aee94f86SFrançois Tigeot * handy when a regular &drm_encoder entity isn't enough to represent the entire 3519c468b4SFrançois Tigeot * encoder chain. 3619c468b4SFrançois Tigeot * 37*aee94f86SFrançois Tigeot * A bridge is always attached to a single &drm_encoder at a time, but can be 3819c468b4SFrançois Tigeot * either connected to it directly, or through an intermediate bridge: 3919c468b4SFrançois Tigeot * 4019c468b4SFrançois Tigeot * encoder ---> bridge B ---> bridge A 4119c468b4SFrançois Tigeot * 4219c468b4SFrançois Tigeot * Here, the output of the encoder feeds to bridge B, and that furthers feeds to 4319c468b4SFrançois Tigeot * bridge A. 4419c468b4SFrançois Tigeot * 4519c468b4SFrançois Tigeot * The driver using the bridge is responsible to make the associations between 4619c468b4SFrançois Tigeot * the encoder and bridges. Once these links are made, the bridges will 4719c468b4SFrançois Tigeot * participate along with encoder functions to perform mode_set/enable/disable 48*aee94f86SFrançois Tigeot * through the ops provided in &drm_bridge_funcs. 4919c468b4SFrançois Tigeot * 5019c468b4SFrançois Tigeot * drm_bridge, like drm_panel, aren't drm_mode_object entities like planes, 51*aee94f86SFrançois Tigeot * CRTCs, encoders or connectors and hence are not visible to userspace. They 52*aee94f86SFrançois Tigeot * just provide additional hooks to get the desired output at the end of the 53*aee94f86SFrançois Tigeot * encoder chain. 54*aee94f86SFrançois Tigeot * 55*aee94f86SFrançois Tigeot * Bridges can also be chained up using the next pointer in struct &drm_bridge. 56*aee94f86SFrançois Tigeot * 57*aee94f86SFrançois Tigeot * Both legacy CRTC helpers and the new atomic modeset helpers support bridges. 5819c468b4SFrançois Tigeot */ 5919c468b4SFrançois Tigeot 6019c468b4SFrançois Tigeot static DEFINE_MUTEX(bridge_lock); 6119c468b4SFrançois Tigeot static LINUX_LIST_HEAD(bridge_list); 6219c468b4SFrançois Tigeot 6319c468b4SFrançois Tigeot /** 6419c468b4SFrançois Tigeot * drm_bridge_add - add the given bridge to the global bridge list 6519c468b4SFrançois Tigeot * 6619c468b4SFrançois Tigeot * @bridge: bridge control structure 6719c468b4SFrançois Tigeot * 6819c468b4SFrançois Tigeot * RETURNS: 6919c468b4SFrançois Tigeot * Unconditionally returns Zero. 7019c468b4SFrançois Tigeot */ 7119c468b4SFrançois Tigeot int drm_bridge_add(struct drm_bridge *bridge) 7219c468b4SFrançois Tigeot { 7319c468b4SFrançois Tigeot mutex_lock(&bridge_lock); 7419c468b4SFrançois Tigeot list_add_tail(&bridge->list, &bridge_list); 7519c468b4SFrançois Tigeot mutex_unlock(&bridge_lock); 7619c468b4SFrançois Tigeot 7719c468b4SFrançois Tigeot return 0; 7819c468b4SFrançois Tigeot } 7919c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_add); 8019c468b4SFrançois Tigeot 8119c468b4SFrançois Tigeot /** 8219c468b4SFrançois Tigeot * drm_bridge_remove - remove the given bridge from the global bridge list 8319c468b4SFrançois Tigeot * 8419c468b4SFrançois Tigeot * @bridge: bridge control structure 8519c468b4SFrançois Tigeot */ 8619c468b4SFrançois Tigeot void drm_bridge_remove(struct drm_bridge *bridge) 8719c468b4SFrançois Tigeot { 8819c468b4SFrançois Tigeot mutex_lock(&bridge_lock); 8919c468b4SFrançois Tigeot list_del_init(&bridge->list); 9019c468b4SFrançois Tigeot mutex_unlock(&bridge_lock); 9119c468b4SFrançois Tigeot } 9219c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_remove); 9319c468b4SFrançois Tigeot 9419c468b4SFrançois Tigeot /** 9519c468b4SFrançois Tigeot * drm_bridge_attach - associate given bridge to our DRM device 9619c468b4SFrançois Tigeot * 9719c468b4SFrançois Tigeot * @dev: DRM device 9819c468b4SFrançois Tigeot * @bridge: bridge control structure 9919c468b4SFrançois Tigeot * 10019c468b4SFrançois Tigeot * called by a kms driver to link one of our encoder/bridge to the given 10119c468b4SFrançois Tigeot * bridge. 10219c468b4SFrançois Tigeot * 10319c468b4SFrançois Tigeot * Note that setting up links between the bridge and our encoder/bridge 10419c468b4SFrançois Tigeot * objects needs to be handled by the kms driver itself 10519c468b4SFrançois Tigeot * 10619c468b4SFrançois Tigeot * RETURNS: 10719c468b4SFrançois Tigeot * Zero on success, error code on failure 10819c468b4SFrançois Tigeot */ 10919c468b4SFrançois Tigeot int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge) 11019c468b4SFrançois Tigeot { 11119c468b4SFrançois Tigeot if (!dev || !bridge) 11219c468b4SFrançois Tigeot return -EINVAL; 11319c468b4SFrançois Tigeot 11419c468b4SFrançois Tigeot if (bridge->dev) 11519c468b4SFrançois Tigeot return -EBUSY; 11619c468b4SFrançois Tigeot 11719c468b4SFrançois Tigeot bridge->dev = dev; 11819c468b4SFrançois Tigeot 11919c468b4SFrançois Tigeot if (bridge->funcs->attach) 12019c468b4SFrançois Tigeot return bridge->funcs->attach(bridge); 12119c468b4SFrançois Tigeot 12219c468b4SFrançois Tigeot return 0; 12319c468b4SFrançois Tigeot } 12419c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_attach); 12519c468b4SFrançois Tigeot 12619c468b4SFrançois Tigeot /** 12719c468b4SFrançois Tigeot * DOC: bridge callbacks 12819c468b4SFrançois Tigeot * 129*aee94f86SFrançois Tigeot * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM 130*aee94f86SFrançois Tigeot * internals (atomic and CRTC helpers) use the helpers defined in drm_bridge.c 131*aee94f86SFrançois Tigeot * These helpers call a specific &drm_bridge_funcs op for all the bridges 13219c468b4SFrançois Tigeot * during encoder configuration. 13319c468b4SFrançois Tigeot * 134*aee94f86SFrançois Tigeot * For detailed specification of the bridge callbacks see &drm_bridge_funcs. 13519c468b4SFrançois Tigeot */ 13619c468b4SFrançois Tigeot 13719c468b4SFrançois Tigeot /** 13819c468b4SFrançois Tigeot * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the 13919c468b4SFrançois Tigeot * encoder chain 14019c468b4SFrançois Tigeot * @bridge: bridge control structure 14119c468b4SFrançois Tigeot * @mode: desired mode to be set for the bridge 14219c468b4SFrançois Tigeot * @adjusted_mode: updated mode that works for this bridge 14319c468b4SFrançois Tigeot * 144*aee94f86SFrançois Tigeot * Calls ->mode_fixup() &drm_bridge_funcs op for all the bridges in the 14519c468b4SFrançois Tigeot * encoder chain, starting from the first bridge to the last. 14619c468b4SFrançois Tigeot * 14719c468b4SFrançois Tigeot * Note: the bridge passed should be the one closest to the encoder 14819c468b4SFrançois Tigeot * 14919c468b4SFrançois Tigeot * RETURNS: 15019c468b4SFrançois Tigeot * true on success, false on failure 15119c468b4SFrançois Tigeot */ 15219c468b4SFrançois Tigeot bool drm_bridge_mode_fixup(struct drm_bridge *bridge, 15319c468b4SFrançois Tigeot const struct drm_display_mode *mode, 15419c468b4SFrançois Tigeot struct drm_display_mode *adjusted_mode) 15519c468b4SFrançois Tigeot { 15619c468b4SFrançois Tigeot bool ret = true; 15719c468b4SFrançois Tigeot 15819c468b4SFrançois Tigeot if (!bridge) 15919c468b4SFrançois Tigeot return true; 16019c468b4SFrançois Tigeot 16119c468b4SFrançois Tigeot if (bridge->funcs->mode_fixup) 16219c468b4SFrançois Tigeot ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode); 16319c468b4SFrançois Tigeot 16419c468b4SFrançois Tigeot ret = ret && drm_bridge_mode_fixup(bridge->next, mode, adjusted_mode); 16519c468b4SFrançois Tigeot 16619c468b4SFrançois Tigeot return ret; 16719c468b4SFrançois Tigeot } 16819c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_mode_fixup); 16919c468b4SFrançois Tigeot 17019c468b4SFrançois Tigeot /** 171*aee94f86SFrançois Tigeot * drm_bridge_disable - calls ->disable() &drm_bridge_funcs op for all 17219c468b4SFrançois Tigeot * bridges in the encoder chain. 17319c468b4SFrançois Tigeot * @bridge: bridge control structure 17419c468b4SFrançois Tigeot * 175*aee94f86SFrançois Tigeot * Calls ->disable() &drm_bridge_funcs op for all the bridges in the encoder 17619c468b4SFrançois Tigeot * chain, starting from the last bridge to the first. These are called before 17719c468b4SFrançois Tigeot * calling the encoder's prepare op. 17819c468b4SFrançois Tigeot * 17919c468b4SFrançois Tigeot * Note: the bridge passed should be the one closest to the encoder 18019c468b4SFrançois Tigeot */ 18119c468b4SFrançois Tigeot void drm_bridge_disable(struct drm_bridge *bridge) 18219c468b4SFrançois Tigeot { 18319c468b4SFrançois Tigeot if (!bridge) 18419c468b4SFrançois Tigeot return; 18519c468b4SFrançois Tigeot 18619c468b4SFrançois Tigeot drm_bridge_disable(bridge->next); 18719c468b4SFrançois Tigeot 18819c468b4SFrançois Tigeot bridge->funcs->disable(bridge); 18919c468b4SFrançois Tigeot } 19019c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_disable); 19119c468b4SFrançois Tigeot 19219c468b4SFrançois Tigeot /** 193*aee94f86SFrançois Tigeot * drm_bridge_post_disable - calls ->post_disable() &drm_bridge_funcs op for 19419c468b4SFrançois Tigeot * all bridges in the encoder chain. 19519c468b4SFrançois Tigeot * @bridge: bridge control structure 19619c468b4SFrançois Tigeot * 197*aee94f86SFrançois Tigeot * Calls ->post_disable() &drm_bridge_funcs op for all the bridges in the 19819c468b4SFrançois Tigeot * encoder chain, starting from the first bridge to the last. These are called 19919c468b4SFrançois Tigeot * after completing the encoder's prepare op. 20019c468b4SFrançois Tigeot * 20119c468b4SFrançois Tigeot * Note: the bridge passed should be the one closest to the encoder 20219c468b4SFrançois Tigeot */ 20319c468b4SFrançois Tigeot void drm_bridge_post_disable(struct drm_bridge *bridge) 20419c468b4SFrançois Tigeot { 20519c468b4SFrançois Tigeot if (!bridge) 20619c468b4SFrançois Tigeot return; 20719c468b4SFrançois Tigeot 20819c468b4SFrançois Tigeot bridge->funcs->post_disable(bridge); 20919c468b4SFrançois Tigeot 21019c468b4SFrançois Tigeot drm_bridge_post_disable(bridge->next); 21119c468b4SFrançois Tigeot } 21219c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_post_disable); 21319c468b4SFrançois Tigeot 21419c468b4SFrançois Tigeot /** 21519c468b4SFrançois Tigeot * drm_bridge_mode_set - set proposed mode for all bridges in the 21619c468b4SFrançois Tigeot * encoder chain 21719c468b4SFrançois Tigeot * @bridge: bridge control structure 21819c468b4SFrançois Tigeot * @mode: desired mode to be set for the bridge 21919c468b4SFrançois Tigeot * @adjusted_mode: updated mode that works for this bridge 22019c468b4SFrançois Tigeot * 221*aee94f86SFrançois Tigeot * Calls ->mode_set() &drm_bridge_funcs op for all the bridges in the 22219c468b4SFrançois Tigeot * encoder chain, starting from the first bridge to the last. 22319c468b4SFrançois Tigeot * 22419c468b4SFrançois Tigeot * Note: the bridge passed should be the one closest to the encoder 22519c468b4SFrançois Tigeot */ 22619c468b4SFrançois Tigeot void drm_bridge_mode_set(struct drm_bridge *bridge, 22719c468b4SFrançois Tigeot struct drm_display_mode *mode, 22819c468b4SFrançois Tigeot struct drm_display_mode *adjusted_mode) 22919c468b4SFrançois Tigeot { 23019c468b4SFrançois Tigeot if (!bridge) 23119c468b4SFrançois Tigeot return; 23219c468b4SFrançois Tigeot 23319c468b4SFrançois Tigeot if (bridge->funcs->mode_set) 23419c468b4SFrançois Tigeot bridge->funcs->mode_set(bridge, mode, adjusted_mode); 23519c468b4SFrançois Tigeot 23619c468b4SFrançois Tigeot drm_bridge_mode_set(bridge->next, mode, adjusted_mode); 23719c468b4SFrançois Tigeot } 23819c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_mode_set); 23919c468b4SFrançois Tigeot 24019c468b4SFrançois Tigeot /** 241*aee94f86SFrançois Tigeot * drm_bridge_pre_enable - calls ->pre_enable() &drm_bridge_funcs op for all 24219c468b4SFrançois Tigeot * bridges in the encoder chain. 24319c468b4SFrançois Tigeot * @bridge: bridge control structure 24419c468b4SFrançois Tigeot * 245*aee94f86SFrançois Tigeot * Calls ->pre_enable() &drm_bridge_funcs op for all the bridges in the encoder 24619c468b4SFrançois Tigeot * chain, starting from the last bridge to the first. These are called 24719c468b4SFrançois Tigeot * before calling the encoder's commit op. 24819c468b4SFrançois Tigeot * 24919c468b4SFrançois Tigeot * Note: the bridge passed should be the one closest to the encoder 25019c468b4SFrançois Tigeot */ 25119c468b4SFrançois Tigeot void drm_bridge_pre_enable(struct drm_bridge *bridge) 25219c468b4SFrançois Tigeot { 25319c468b4SFrançois Tigeot if (!bridge) 25419c468b4SFrançois Tigeot return; 25519c468b4SFrançois Tigeot 25619c468b4SFrançois Tigeot drm_bridge_pre_enable(bridge->next); 25719c468b4SFrançois Tigeot 25819c468b4SFrançois Tigeot bridge->funcs->pre_enable(bridge); 25919c468b4SFrançois Tigeot } 26019c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_pre_enable); 26119c468b4SFrançois Tigeot 26219c468b4SFrançois Tigeot /** 263*aee94f86SFrançois Tigeot * drm_bridge_enable - calls ->enable() &drm_bridge_funcs op for all bridges 26419c468b4SFrançois Tigeot * in the encoder chain. 26519c468b4SFrançois Tigeot * @bridge: bridge control structure 26619c468b4SFrançois Tigeot * 267*aee94f86SFrançois Tigeot * Calls ->enable() &drm_bridge_funcs op for all the bridges in the encoder 26819c468b4SFrançois Tigeot * chain, starting from the first bridge to the last. These are called 26919c468b4SFrançois Tigeot * after completing the encoder's commit op. 27019c468b4SFrançois Tigeot * 27119c468b4SFrançois Tigeot * Note that the bridge passed should be the one closest to the encoder 27219c468b4SFrançois Tigeot */ 27319c468b4SFrançois Tigeot void drm_bridge_enable(struct drm_bridge *bridge) 27419c468b4SFrançois Tigeot { 27519c468b4SFrançois Tigeot if (!bridge) 27619c468b4SFrançois Tigeot return; 27719c468b4SFrançois Tigeot 27819c468b4SFrançois Tigeot bridge->funcs->enable(bridge); 27919c468b4SFrançois Tigeot 28019c468b4SFrançois Tigeot drm_bridge_enable(bridge->next); 28119c468b4SFrançois Tigeot } 28219c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_enable); 28319c468b4SFrançois Tigeot 28419c468b4SFrançois Tigeot #ifdef CONFIG_OF 28519c468b4SFrançois Tigeot /** 28619c468b4SFrançois Tigeot * of_drm_find_bridge - find the bridge corresponding to the device node in 28719c468b4SFrançois Tigeot * the global bridge list 28819c468b4SFrançois Tigeot * 28919c468b4SFrançois Tigeot * @np: device node 29019c468b4SFrançois Tigeot * 29119c468b4SFrançois Tigeot * RETURNS: 29219c468b4SFrançois Tigeot * drm_bridge control struct on success, NULL on failure 29319c468b4SFrançois Tigeot */ 29419c468b4SFrançois Tigeot struct drm_bridge *of_drm_find_bridge(struct device_node *np) 29519c468b4SFrançois Tigeot { 29619c468b4SFrançois Tigeot struct drm_bridge *bridge; 29719c468b4SFrançois Tigeot 29819c468b4SFrançois Tigeot mutex_lock(&bridge_lock); 29919c468b4SFrançois Tigeot 30019c468b4SFrançois Tigeot list_for_each_entry(bridge, &bridge_list, list) { 30119c468b4SFrançois Tigeot if (bridge->of_node == np) { 30219c468b4SFrançois Tigeot mutex_unlock(&bridge_lock); 30319c468b4SFrançois Tigeot return bridge; 30419c468b4SFrançois Tigeot } 30519c468b4SFrançois Tigeot } 30619c468b4SFrançois Tigeot 30719c468b4SFrançois Tigeot mutex_unlock(&bridge_lock); 30819c468b4SFrançois Tigeot return NULL; 30919c468b4SFrançois Tigeot } 31019c468b4SFrançois Tigeot EXPORT_SYMBOL(of_drm_find_bridge); 31119c468b4SFrançois Tigeot #endif 31219c468b4SFrançois Tigeot 31319c468b4SFrançois Tigeot MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>"); 31419c468b4SFrançois Tigeot MODULE_DESCRIPTION("DRM bridge infrastructure"); 315