LCOV - code coverage report
Current view: top level - drivers/gpu/drm/bridge - panel.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 115 0.0 %
Date: 2023-04-06 08:38:28 Functions: 0 20 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
       4             :  * Copyright (C) 2017 Broadcom
       5             :  */
       6             : 
       7             : #include <drm/drm_atomic_helper.h>
       8             : #include <drm/drm_bridge.h>
       9             : #include <drm/drm_connector.h>
      10             : #include <drm/drm_encoder.h>
      11             : #include <drm/drm_managed.h>
      12             : #include <drm/drm_modeset_helper_vtables.h>
      13             : #include <drm/drm_of.h>
      14             : #include <drm/drm_panel.h>
      15             : #include <drm/drm_print.h>
      16             : #include <drm/drm_probe_helper.h>
      17             : 
      18             : struct panel_bridge {
      19             :         struct drm_bridge bridge;
      20             :         struct drm_connector connector;
      21             :         struct drm_panel *panel;
      22             :         u32 connector_type;
      23             : };
      24             : 
      25             : static inline struct panel_bridge *
      26             : drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
      27             : {
      28           0 :         return container_of(bridge, struct panel_bridge, bridge);
      29             : }
      30             : 
      31             : static inline struct panel_bridge *
      32             : drm_connector_to_panel_bridge(struct drm_connector *connector)
      33             : {
      34           0 :         return container_of(connector, struct panel_bridge, connector);
      35             : }
      36             : 
      37           0 : static int panel_bridge_connector_get_modes(struct drm_connector *connector)
      38             : {
      39           0 :         struct panel_bridge *panel_bridge =
      40             :                 drm_connector_to_panel_bridge(connector);
      41             : 
      42           0 :         return drm_panel_get_modes(panel_bridge->panel, connector);
      43             : }
      44             : 
      45             : static const struct drm_connector_helper_funcs
      46             : panel_bridge_connector_helper_funcs = {
      47             :         .get_modes = panel_bridge_connector_get_modes,
      48             : };
      49             : 
      50             : static const struct drm_connector_funcs panel_bridge_connector_funcs = {
      51             :         .reset = drm_atomic_helper_connector_reset,
      52             :         .fill_modes = drm_helper_probe_single_connector_modes,
      53             :         .destroy = drm_connector_cleanup,
      54             :         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
      55             :         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
      56             : };
      57             : 
      58           0 : static int panel_bridge_attach(struct drm_bridge *bridge,
      59             :                                enum drm_bridge_attach_flags flags)
      60             : {
      61           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
      62           0 :         struct drm_connector *connector = &panel_bridge->connector;
      63             :         int ret;
      64             : 
      65           0 :         if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
      66             :                 return 0;
      67             : 
      68           0 :         if (!bridge->encoder) {
      69           0 :                 DRM_ERROR("Missing encoder\n");
      70           0 :                 return -ENODEV;
      71             :         }
      72             : 
      73           0 :         drm_connector_helper_add(connector,
      74             :                                  &panel_bridge_connector_helper_funcs);
      75             : 
      76           0 :         ret = drm_connector_init(bridge->dev, connector,
      77             :                                  &panel_bridge_connector_funcs,
      78           0 :                                  panel_bridge->connector_type);
      79           0 :         if (ret) {
      80           0 :                 DRM_ERROR("Failed to initialize connector\n");
      81           0 :                 return ret;
      82             :         }
      83             : 
      84           0 :         drm_panel_bridge_set_orientation(connector, bridge);
      85             : 
      86           0 :         drm_connector_attach_encoder(&panel_bridge->connector,
      87             :                                           bridge->encoder);
      88             : 
      89           0 :         if (bridge->dev->registered) {
      90           0 :                 if (connector->funcs->reset)
      91           0 :                         connector->funcs->reset(connector);
      92           0 :                 drm_connector_register(connector);
      93             :         }
      94             : 
      95             :         return 0;
      96             : }
      97             : 
      98           0 : static void panel_bridge_detach(struct drm_bridge *bridge)
      99             : {
     100           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     101           0 :         struct drm_connector *connector = &panel_bridge->connector;
     102             : 
     103             :         /*
     104             :          * Cleanup the connector if we know it was initialized.
     105             :          *
     106             :          * FIXME: This wouldn't be needed if the panel_bridge structure was
     107             :          * allocated with drmm_kzalloc(). This might be tricky since the
     108             :          * drm_device pointer can only be retrieved when the bridge is attached.
     109             :          */
     110           0 :         if (connector->dev)
     111           0 :                 drm_connector_cleanup(connector);
     112           0 : }
     113             : 
     114           0 : static void panel_bridge_pre_enable(struct drm_bridge *bridge)
     115             : {
     116           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     117             : 
     118           0 :         drm_panel_prepare(panel_bridge->panel);
     119           0 : }
     120             : 
     121           0 : static void panel_bridge_enable(struct drm_bridge *bridge)
     122             : {
     123           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     124             : 
     125           0 :         drm_panel_enable(panel_bridge->panel);
     126           0 : }
     127             : 
     128           0 : static void panel_bridge_disable(struct drm_bridge *bridge)
     129             : {
     130           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     131             : 
     132           0 :         drm_panel_disable(panel_bridge->panel);
     133           0 : }
     134             : 
     135           0 : static void panel_bridge_post_disable(struct drm_bridge *bridge)
     136             : {
     137           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     138             : 
     139           0 :         drm_panel_unprepare(panel_bridge->panel);
     140           0 : }
     141             : 
     142           0 : static int panel_bridge_get_modes(struct drm_bridge *bridge,
     143             :                                   struct drm_connector *connector)
     144             : {
     145           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     146             : 
     147           0 :         return drm_panel_get_modes(panel_bridge->panel, connector);
     148             : }
     149             : 
     150           0 : static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
     151             :                                       struct dentry *root)
     152             : {
     153           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     154           0 :         struct drm_panel *panel = panel_bridge->panel;
     155             : 
     156           0 :         root = debugfs_create_dir("panel", root);
     157           0 :         if (panel->funcs->debugfs_init)
     158           0 :                 panel->funcs->debugfs_init(panel, root);
     159           0 : }
     160             : 
     161             : static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
     162             :         .attach = panel_bridge_attach,
     163             :         .detach = panel_bridge_detach,
     164             :         .pre_enable = panel_bridge_pre_enable,
     165             :         .enable = panel_bridge_enable,
     166             :         .disable = panel_bridge_disable,
     167             :         .post_disable = panel_bridge_post_disable,
     168             :         .get_modes = panel_bridge_get_modes,
     169             :         .atomic_reset = drm_atomic_helper_bridge_reset,
     170             :         .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
     171             :         .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
     172             :         .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
     173             :         .debugfs_init = panel_bridge_debugfs_init,
     174             : };
     175             : 
     176             : /**
     177             :  * drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.
     178             :  *
     179             :  * @bridge: The drm_bridge to be checked.
     180             :  *
     181             :  * Returns true if the bridge is a panel bridge, or false otherwise.
     182             :  */
     183           0 : bool drm_bridge_is_panel(const struct drm_bridge *bridge)
     184             : {
     185           0 :         return bridge->funcs == &panel_bridge_bridge_funcs;
     186             : }
     187             : EXPORT_SYMBOL(drm_bridge_is_panel);
     188             : 
     189             : /**
     190             :  * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
     191             :  * just calls the appropriate functions from &drm_panel.
     192             :  *
     193             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     194             :  *
     195             :  * For drivers converting from directly using drm_panel: The expected
     196             :  * usage pattern is that during either encoder module probe or DSI
     197             :  * host attach, a drm_panel will be looked up through
     198             :  * drm_of_find_panel_or_bridge().  drm_panel_bridge_add() is used to
     199             :  * wrap that panel in the new bridge, and the result can then be
     200             :  * passed to drm_bridge_attach().  The drm_panel_prepare() and related
     201             :  * functions can be dropped from the encoder driver (they're now
     202             :  * called by the KMS helpers before calling into the encoder), along
     203             :  * with connector creation.  When done with the bridge (after
     204             :  * drm_mode_config_cleanup() if the bridge has already been attached), then
     205             :  * drm_panel_bridge_remove() to free it.
     206             :  *
     207             :  * The connector type is set to @panel->connector_type, which must be set to a
     208             :  * known type. Calling this function with a panel whose connector type is
     209             :  * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
     210             :  *
     211             :  * See devm_drm_panel_bridge_add() for an automatically managed version of this
     212             :  * function.
     213             :  */
     214           0 : struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
     215             : {
     216           0 :         if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
     217             :                 return ERR_PTR(-EINVAL);
     218             : 
     219           0 :         return drm_panel_bridge_add_typed(panel, panel->connector_type);
     220             : }
     221             : EXPORT_SYMBOL(drm_panel_bridge_add);
     222             : 
     223             : /**
     224             :  * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
     225             :  * an explicit connector type.
     226             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     227             :  * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
     228             :  *
     229             :  * This is just like drm_panel_bridge_add(), but forces the connector type to
     230             :  * @connector_type instead of infering it from the panel.
     231             :  *
     232             :  * This function is deprecated and should not be used in new drivers. Use
     233             :  * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
     234             :  * don't report a connector type.
     235             :  */
     236           0 : struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
     237             :                                               u32 connector_type)
     238             : {
     239             :         struct panel_bridge *panel_bridge;
     240             : 
     241           0 :         if (!panel)
     242             :                 return ERR_PTR(-EINVAL);
     243             : 
     244           0 :         panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge),
     245             :                                     GFP_KERNEL);
     246           0 :         if (!panel_bridge)
     247             :                 return ERR_PTR(-ENOMEM);
     248             : 
     249           0 :         panel_bridge->connector_type = connector_type;
     250           0 :         panel_bridge->panel = panel;
     251             : 
     252           0 :         panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs;
     253             : #ifdef CONFIG_OF
     254             :         panel_bridge->bridge.of_node = panel->dev->of_node;
     255             : #endif
     256           0 :         panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
     257           0 :         panel_bridge->bridge.type = connector_type;
     258             : 
     259           0 :         drm_bridge_add(&panel_bridge->bridge);
     260             : 
     261           0 :         return &panel_bridge->bridge;
     262             : }
     263             : EXPORT_SYMBOL(drm_panel_bridge_add_typed);
     264             : 
     265             : /**
     266             :  * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
     267             :  * created by drm_panel_bridge_add().
     268             :  *
     269             :  * @bridge: The drm_bridge being freed.
     270             :  */
     271           0 : void drm_panel_bridge_remove(struct drm_bridge *bridge)
     272             : {
     273             :         struct panel_bridge *panel_bridge;
     274             : 
     275           0 :         if (!bridge)
     276             :                 return;
     277             : 
     278           0 :         if (bridge->funcs != &panel_bridge_bridge_funcs)
     279             :                 return;
     280             : 
     281           0 :         panel_bridge = drm_bridge_to_panel_bridge(bridge);
     282             : 
     283           0 :         drm_bridge_remove(bridge);
     284           0 :         devm_kfree(panel_bridge->panel->dev, bridge);
     285             : }
     286             : EXPORT_SYMBOL(drm_panel_bridge_remove);
     287             : 
     288             : /**
     289             :  * drm_panel_bridge_set_orientation - Set the connector's panel orientation
     290             :  * from the bridge that can be transformed to panel bridge.
     291             :  *
     292             :  * @connector: The connector to be set panel orientation.
     293             :  * @bridge: The drm_bridge to be transformed to panel bridge.
     294             :  *
     295             :  * Returns 0 on success, negative errno on failure.
     296             :  */
     297           0 : int drm_panel_bridge_set_orientation(struct drm_connector *connector,
     298             :                                      struct drm_bridge *bridge)
     299             : {
     300             :         struct panel_bridge *panel_bridge;
     301             : 
     302           0 :         panel_bridge = drm_bridge_to_panel_bridge(bridge);
     303             : 
     304           0 :         return drm_connector_set_orientation_from_panel(connector,
     305             :                                                         panel_bridge->panel);
     306             : }
     307             : EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
     308             : 
     309           0 : static void devm_drm_panel_bridge_release(struct device *dev, void *res)
     310             : {
     311           0 :         struct drm_bridge **bridge = res;
     312             : 
     313           0 :         drm_panel_bridge_remove(*bridge);
     314           0 : }
     315             : 
     316             : /**
     317             :  * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
     318             :  * that just calls the appropriate functions from &drm_panel.
     319             :  * @dev: device to tie the bridge lifetime to
     320             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     321             :  *
     322             :  * This is the managed version of drm_panel_bridge_add() which automatically
     323             :  * calls drm_panel_bridge_remove() when @dev is unbound.
     324             :  */
     325           0 : struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
     326             :                                              struct drm_panel *panel)
     327             : {
     328           0 :         if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
     329             :                 return ERR_PTR(-EINVAL);
     330             : 
     331           0 :         return devm_drm_panel_bridge_add_typed(dev, panel,
     332           0 :                                                panel->connector_type);
     333             : }
     334             : EXPORT_SYMBOL(devm_drm_panel_bridge_add);
     335             : 
     336             : /**
     337             :  * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
     338             :  * &drm_connector with an explicit connector type.
     339             :  * @dev: device to tie the bridge lifetime to
     340             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     341             :  * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
     342             :  *
     343             :  * This is just like devm_drm_panel_bridge_add(), but forces the connector type
     344             :  * to @connector_type instead of infering it from the panel.
     345             :  *
     346             :  * This function is deprecated and should not be used in new drivers. Use
     347             :  * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
     348             :  * they don't report a connector type.
     349             :  */
     350           0 : struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
     351             :                                                    struct drm_panel *panel,
     352             :                                                    u32 connector_type)
     353             : {
     354             :         struct drm_bridge **ptr, *bridge;
     355             : 
     356           0 :         ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
     357             :                            GFP_KERNEL);
     358           0 :         if (!ptr)
     359             :                 return ERR_PTR(-ENOMEM);
     360             : 
     361           0 :         bridge = drm_panel_bridge_add_typed(panel, connector_type);
     362           0 :         if (IS_ERR(bridge)) {
     363           0 :                 devres_free(ptr);
     364           0 :                 return bridge;
     365             :         }
     366             : 
     367           0 :         bridge->pre_enable_prev_first = panel->prepare_prev_first;
     368             : 
     369           0 :         *ptr = bridge;
     370           0 :         devres_add(dev, ptr);
     371             : 
     372           0 :         return bridge;
     373             : }
     374             : EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
     375             : 
     376           0 : static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
     377             : {
     378           0 :         struct drm_bridge *bridge = ptr;
     379             : 
     380           0 :         drm_panel_bridge_remove(bridge);
     381           0 : }
     382             : 
     383             : /**
     384             :  * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and
     385             :  *                         &drm_connector that just calls the
     386             :  *                         appropriate functions from &drm_panel.
     387             :  *
     388             :  * @drm: DRM device to tie the bridge lifetime to
     389             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     390             :  *
     391             :  * This is the DRM-managed version of drm_panel_bridge_add() which
     392             :  * automatically calls drm_panel_bridge_remove() when @dev is cleaned
     393             :  * up.
     394             :  */
     395           0 : struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
     396             :                                          struct drm_panel *panel)
     397             : {
     398             :         struct drm_bridge *bridge;
     399             :         int ret;
     400             : 
     401           0 :         bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);
     402           0 :         if (IS_ERR(bridge))
     403             :                 return bridge;
     404             : 
     405           0 :         ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,
     406             :                                        bridge);
     407           0 :         if (ret)
     408           0 :                 return ERR_PTR(ret);
     409             : 
     410           0 :         bridge->pre_enable_prev_first = panel->prepare_prev_first;
     411             : 
     412           0 :         return bridge;
     413             : }
     414             : EXPORT_SYMBOL(drmm_panel_bridge_add);
     415             : 
     416             : /**
     417             :  * drm_panel_bridge_connector - return the connector for the panel bridge
     418             :  * @bridge: The drm_bridge.
     419             :  *
     420             :  * drm_panel_bridge creates the connector.
     421             :  * This function gives external access to the connector.
     422             :  *
     423             :  * Returns: Pointer to drm_connector
     424             :  */
     425           0 : struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
     426             : {
     427             :         struct panel_bridge *panel_bridge;
     428             : 
     429           0 :         panel_bridge = drm_bridge_to_panel_bridge(bridge);
     430             : 
     431           0 :         return &panel_bridge->connector;
     432             : }
     433             : EXPORT_SYMBOL(drm_panel_bridge_connector);
     434             : 
     435             : #ifdef CONFIG_OF
     436             : /**
     437             :  * devm_drm_of_get_bridge - Return next bridge in the chain
     438             :  * @dev: device to tie the bridge lifetime to
     439             :  * @np: device tree node containing encoder output ports
     440             :  * @port: port in the device tree node
     441             :  * @endpoint: endpoint in the device tree node
     442             :  *
     443             :  * Given a DT node's port and endpoint number, finds the connected node
     444             :  * and returns the associated bridge if any, or creates and returns a
     445             :  * drm panel bridge instance if a panel is connected.
     446             :  *
     447             :  * Returns a pointer to the bridge if successful, or an error pointer
     448             :  * otherwise.
     449             :  */
     450             : struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
     451             :                                           struct device_node *np,
     452             :                                           u32 port, u32 endpoint)
     453             : {
     454             :         struct drm_bridge *bridge;
     455             :         struct drm_panel *panel;
     456             :         int ret;
     457             : 
     458             :         ret = drm_of_find_panel_or_bridge(np, port, endpoint,
     459             :                                           &panel, &bridge);
     460             :         if (ret)
     461             :                 return ERR_PTR(ret);
     462             : 
     463             :         if (panel)
     464             :                 bridge = devm_drm_panel_bridge_add(dev, panel);
     465             : 
     466             :         return bridge;
     467             : }
     468             : EXPORT_SYMBOL(devm_drm_of_get_bridge);
     469             : 
     470             : /**
     471             :  * drmm_of_get_bridge - Return next bridge in the chain
     472             :  * @drm: device to tie the bridge lifetime to
     473             :  * @np: device tree node containing encoder output ports
     474             :  * @port: port in the device tree node
     475             :  * @endpoint: endpoint in the device tree node
     476             :  *
     477             :  * Given a DT node's port and endpoint number, finds the connected node
     478             :  * and returns the associated bridge if any, or creates and returns a
     479             :  * drm panel bridge instance if a panel is connected.
     480             :  *
     481             :  * Returns a drmm managed pointer to the bridge if successful, or an error
     482             :  * pointer otherwise.
     483             :  */
     484             : struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
     485             :                                       struct device_node *np,
     486             :                                       u32 port, u32 endpoint)
     487             : {
     488             :         struct drm_bridge *bridge;
     489             :         struct drm_panel *panel;
     490             :         int ret;
     491             : 
     492             :         ret = drm_of_find_panel_or_bridge(np, port, endpoint,
     493             :                                           &panel, &bridge);
     494             :         if (ret)
     495             :                 return ERR_PTR(ret);
     496             : 
     497             :         if (panel)
     498             :                 bridge = drmm_panel_bridge_add(drm, panel);
     499             : 
     500             :         return bridge;
     501             : }
     502             : EXPORT_SYMBOL(drmm_of_get_bridge);
     503             : 
     504             : #endif

Generated by: LCOV version 1.14