LCOV - code coverage report
Current view: top level - drivers/gpu/drm/bridge - panel.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 94 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 16 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_modeset_helper_vtables.h>
      12             : #include <drm/drm_of.h>
      13             : #include <drm/drm_panel.h>
      14             : #include <drm/drm_print.h>
      15             : #include <drm/drm_probe_helper.h>
      16             : 
      17             : struct panel_bridge {
      18             :         struct drm_bridge bridge;
      19             :         struct drm_connector connector;
      20             :         struct drm_panel *panel;
      21             :         u32 connector_type;
      22             : };
      23             : 
      24             : static inline struct panel_bridge *
      25             : drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
      26             : {
      27           0 :         return container_of(bridge, struct panel_bridge, bridge);
      28             : }
      29             : 
      30             : static inline struct panel_bridge *
      31             : drm_connector_to_panel_bridge(struct drm_connector *connector)
      32             : {
      33           0 :         return container_of(connector, struct panel_bridge, connector);
      34             : }
      35             : 
      36           0 : static int panel_bridge_connector_get_modes(struct drm_connector *connector)
      37             : {
      38           0 :         struct panel_bridge *panel_bridge =
      39             :                 drm_connector_to_panel_bridge(connector);
      40             : 
      41           0 :         return drm_panel_get_modes(panel_bridge->panel, connector);
      42             : }
      43             : 
      44             : static const struct drm_connector_helper_funcs
      45             : panel_bridge_connector_helper_funcs = {
      46             :         .get_modes = panel_bridge_connector_get_modes,
      47             : };
      48             : 
      49             : static const struct drm_connector_funcs panel_bridge_connector_funcs = {
      50             :         .reset = drm_atomic_helper_connector_reset,
      51             :         .fill_modes = drm_helper_probe_single_connector_modes,
      52             :         .destroy = drm_connector_cleanup,
      53             :         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
      54             :         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
      55             : };
      56             : 
      57           0 : static int panel_bridge_attach(struct drm_bridge *bridge,
      58             :                                enum drm_bridge_attach_flags flags)
      59             : {
      60           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
      61           0 :         struct drm_connector *connector = &panel_bridge->connector;
      62             :         int ret;
      63             : 
      64           0 :         if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
      65             :                 return 0;
      66             : 
      67           0 :         if (!bridge->encoder) {
      68           0 :                 DRM_ERROR("Missing encoder\n");
      69           0 :                 return -ENODEV;
      70             :         }
      71             : 
      72           0 :         drm_connector_helper_add(connector,
      73             :                                  &panel_bridge_connector_helper_funcs);
      74             : 
      75           0 :         ret = drm_connector_init(bridge->dev, connector,
      76             :                                  &panel_bridge_connector_funcs,
      77           0 :                                  panel_bridge->connector_type);
      78           0 :         if (ret) {
      79           0 :                 DRM_ERROR("Failed to initialize connector\n");
      80           0 :                 return ret;
      81             :         }
      82             : 
      83           0 :         drm_connector_attach_encoder(&panel_bridge->connector,
      84             :                                           bridge->encoder);
      85             : 
      86           0 :         if (bridge->dev->registered) {
      87           0 :                 if (connector->funcs->reset)
      88           0 :                         connector->funcs->reset(connector);
      89           0 :                 drm_connector_register(connector);
      90             :         }
      91             : 
      92             :         return 0;
      93             : }
      94             : 
      95           0 : static void panel_bridge_detach(struct drm_bridge *bridge)
      96             : {
      97           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
      98           0 :         struct drm_connector *connector = &panel_bridge->connector;
      99             : 
     100             :         /*
     101             :          * Cleanup the connector if we know it was initialized.
     102             :          *
     103             :          * FIXME: This wouldn't be needed if the panel_bridge structure was
     104             :          * allocated with drmm_kzalloc(). This might be tricky since the
     105             :          * drm_device pointer can only be retrieved when the bridge is attached.
     106             :          */
     107           0 :         if (connector->dev)
     108           0 :                 drm_connector_cleanup(connector);
     109           0 : }
     110             : 
     111           0 : static void panel_bridge_pre_enable(struct drm_bridge *bridge)
     112             : {
     113           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     114             : 
     115           0 :         drm_panel_prepare(panel_bridge->panel);
     116           0 : }
     117             : 
     118           0 : static void panel_bridge_enable(struct drm_bridge *bridge)
     119             : {
     120           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     121             : 
     122           0 :         drm_panel_enable(panel_bridge->panel);
     123           0 : }
     124             : 
     125           0 : static void panel_bridge_disable(struct drm_bridge *bridge)
     126             : {
     127           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     128             : 
     129           0 :         drm_panel_disable(panel_bridge->panel);
     130           0 : }
     131             : 
     132           0 : static void panel_bridge_post_disable(struct drm_bridge *bridge)
     133             : {
     134           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     135             : 
     136           0 :         drm_panel_unprepare(panel_bridge->panel);
     137           0 : }
     138             : 
     139           0 : static int panel_bridge_get_modes(struct drm_bridge *bridge,
     140             :                                   struct drm_connector *connector)
     141             : {
     142           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     143             : 
     144           0 :         return drm_panel_get_modes(panel_bridge->panel, connector);
     145             : }
     146             : 
     147           0 : static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
     148             :                                       struct dentry *root)
     149             : {
     150           0 :         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
     151           0 :         struct drm_panel *panel = panel_bridge->panel;
     152             : 
     153           0 :         root = debugfs_create_dir("panel", root);
     154           0 :         if (panel->funcs->debugfs_init)
     155           0 :                 panel->funcs->debugfs_init(panel, root);
     156           0 : }
     157             : 
     158             : static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
     159             :         .attach = panel_bridge_attach,
     160             :         .detach = panel_bridge_detach,
     161             :         .pre_enable = panel_bridge_pre_enable,
     162             :         .enable = panel_bridge_enable,
     163             :         .disable = panel_bridge_disable,
     164             :         .post_disable = panel_bridge_post_disable,
     165             :         .get_modes = panel_bridge_get_modes,
     166             :         .atomic_reset = drm_atomic_helper_bridge_reset,
     167             :         .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
     168             :         .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
     169             :         .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
     170             :         .debugfs_init = panel_bridge_debugfs_init,
     171             : };
     172             : 
     173             : /**
     174             :  * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
     175             :  * just calls the appropriate functions from &drm_panel.
     176             :  *
     177             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     178             :  *
     179             :  * For drivers converting from directly using drm_panel: The expected
     180             :  * usage pattern is that during either encoder module probe or DSI
     181             :  * host attach, a drm_panel will be looked up through
     182             :  * drm_of_find_panel_or_bridge().  drm_panel_bridge_add() is used to
     183             :  * wrap that panel in the new bridge, and the result can then be
     184             :  * passed to drm_bridge_attach().  The drm_panel_prepare() and related
     185             :  * functions can be dropped from the encoder driver (they're now
     186             :  * called by the KMS helpers before calling into the encoder), along
     187             :  * with connector creation.  When done with the bridge (after
     188             :  * drm_mode_config_cleanup() if the bridge has already been attached), then
     189             :  * drm_panel_bridge_remove() to free it.
     190             :  *
     191             :  * The connector type is set to @panel->connector_type, which must be set to a
     192             :  * known type. Calling this function with a panel whose connector type is
     193             :  * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
     194             :  *
     195             :  * See devm_drm_panel_bridge_add() for an automatically managed version of this
     196             :  * function.
     197             :  */
     198           0 : struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
     199             : {
     200           0 :         if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
     201             :                 return ERR_PTR(-EINVAL);
     202             : 
     203           0 :         return drm_panel_bridge_add_typed(panel, panel->connector_type);
     204             : }
     205             : EXPORT_SYMBOL(drm_panel_bridge_add);
     206             : 
     207             : /**
     208             :  * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
     209             :  * an explicit connector type.
     210             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     211             :  * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
     212             :  *
     213             :  * This is just like drm_panel_bridge_add(), but forces the connector type to
     214             :  * @connector_type instead of infering it from the panel.
     215             :  *
     216             :  * This function is deprecated and should not be used in new drivers. Use
     217             :  * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
     218             :  * don't report a connector type.
     219             :  */
     220           0 : struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
     221             :                                               u32 connector_type)
     222             : {
     223             :         struct panel_bridge *panel_bridge;
     224             : 
     225           0 :         if (!panel)
     226             :                 return ERR_PTR(-EINVAL);
     227             : 
     228           0 :         panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge),
     229             :                                     GFP_KERNEL);
     230           0 :         if (!panel_bridge)
     231             :                 return ERR_PTR(-ENOMEM);
     232             : 
     233           0 :         panel_bridge->connector_type = connector_type;
     234           0 :         panel_bridge->panel = panel;
     235             : 
     236           0 :         panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs;
     237             : #ifdef CONFIG_OF
     238             :         panel_bridge->bridge.of_node = panel->dev->of_node;
     239             : #endif
     240           0 :         panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
     241           0 :         panel_bridge->bridge.type = connector_type;
     242             : 
     243           0 :         drm_bridge_add(&panel_bridge->bridge);
     244             : 
     245           0 :         return &panel_bridge->bridge;
     246             : }
     247             : EXPORT_SYMBOL(drm_panel_bridge_add_typed);
     248             : 
     249             : /**
     250             :  * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
     251             :  * created by drm_panel_bridge_add().
     252             :  *
     253             :  * @bridge: The drm_bridge being freed.
     254             :  */
     255           0 : void drm_panel_bridge_remove(struct drm_bridge *bridge)
     256             : {
     257             :         struct panel_bridge *panel_bridge;
     258             : 
     259           0 :         if (!bridge)
     260             :                 return;
     261             : 
     262           0 :         if (bridge->funcs != &panel_bridge_bridge_funcs)
     263             :                 return;
     264             : 
     265           0 :         panel_bridge = drm_bridge_to_panel_bridge(bridge);
     266             : 
     267           0 :         drm_bridge_remove(bridge);
     268           0 :         devm_kfree(panel_bridge->panel->dev, bridge);
     269             : }
     270             : EXPORT_SYMBOL(drm_panel_bridge_remove);
     271             : 
     272           0 : static void devm_drm_panel_bridge_release(struct device *dev, void *res)
     273             : {
     274           0 :         struct drm_bridge **bridge = res;
     275             : 
     276           0 :         drm_panel_bridge_remove(*bridge);
     277           0 : }
     278             : 
     279             : /**
     280             :  * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
     281             :  * that just calls the appropriate functions from &drm_panel.
     282             :  * @dev: device to tie the bridge lifetime to
     283             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     284             :  *
     285             :  * This is the managed version of drm_panel_bridge_add() which automatically
     286             :  * calls drm_panel_bridge_remove() when @dev is unbound.
     287             :  */
     288           0 : struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
     289             :                                              struct drm_panel *panel)
     290             : {
     291           0 :         if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
     292             :                 return ERR_PTR(-EINVAL);
     293             : 
     294           0 :         return devm_drm_panel_bridge_add_typed(dev, panel,
     295           0 :                                                panel->connector_type);
     296             : }
     297             : EXPORT_SYMBOL(devm_drm_panel_bridge_add);
     298             : 
     299             : /**
     300             :  * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
     301             :  * &drm_connector with an explicit connector type.
     302             :  * @dev: device to tie the bridge lifetime to
     303             :  * @panel: The drm_panel being wrapped.  Must be non-NULL.
     304             :  * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
     305             :  *
     306             :  * This is just like devm_drm_panel_bridge_add(), but forces the connector type
     307             :  * to @connector_type instead of infering it from the panel.
     308             :  *
     309             :  * This function is deprecated and should not be used in new drivers. Use
     310             :  * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
     311             :  * they don't report a connector type.
     312             :  */
     313           0 : struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
     314             :                                                    struct drm_panel *panel,
     315             :                                                    u32 connector_type)
     316             : {
     317             :         struct drm_bridge **ptr, *bridge;
     318             : 
     319           0 :         ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
     320             :                            GFP_KERNEL);
     321           0 :         if (!ptr)
     322             :                 return ERR_PTR(-ENOMEM);
     323             : 
     324           0 :         bridge = drm_panel_bridge_add_typed(panel, connector_type);
     325           0 :         if (!IS_ERR(bridge)) {
     326           0 :                 *ptr = bridge;
     327           0 :                 devres_add(dev, ptr);
     328             :         } else {
     329           0 :                 devres_free(ptr);
     330             :         }
     331             : 
     332             :         return bridge;
     333             : }
     334             : EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
     335             : 
     336             : /**
     337             :  * drm_panel_bridge_connector - return the connector for the panel bridge
     338             :  * @bridge: The drm_bridge.
     339             :  *
     340             :  * drm_panel_bridge creates the connector.
     341             :  * This function gives external access to the connector.
     342             :  *
     343             :  * Returns: Pointer to drm_connector
     344             :  */
     345           0 : struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
     346             : {
     347             :         struct panel_bridge *panel_bridge;
     348             : 
     349           0 :         panel_bridge = drm_bridge_to_panel_bridge(bridge);
     350             : 
     351           0 :         return &panel_bridge->connector;
     352             : }
     353             : EXPORT_SYMBOL(drm_panel_bridge_connector);
     354             : 
     355             : #ifdef CONFIG_OF
     356             : /**
     357             :  * devm_drm_of_get_bridge - Return next bridge in the chain
     358             :  * @dev: device to tie the bridge lifetime to
     359             :  * @np: device tree node containing encoder output ports
     360             :  * @port: port in the device tree node
     361             :  * @endpoint: endpoint in the device tree node
     362             :  *
     363             :  * Given a DT node's port and endpoint number, finds the connected node
     364             :  * and returns the associated bridge if any, or creates and returns a
     365             :  * drm panel bridge instance if a panel is connected.
     366             :  *
     367             :  * Returns a pointer to the bridge if successful, or an error pointer
     368             :  * otherwise.
     369             :  */
     370             : struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
     371             :                                           struct device_node *np,
     372             :                                           u32 port, u32 endpoint)
     373             : {
     374             :         struct drm_bridge *bridge;
     375             :         struct drm_panel *panel;
     376             :         int ret;
     377             : 
     378             :         ret = drm_of_find_panel_or_bridge(np, port, endpoint,
     379             :                                           &panel, &bridge);
     380             :         if (ret)
     381             :                 return ERR_PTR(ret);
     382             : 
     383             :         if (panel)
     384             :                 bridge = devm_drm_panel_bridge_add(dev, panel);
     385             : 
     386             :         return bridge;
     387             : }
     388             : EXPORT_SYMBOL(devm_drm_of_get_bridge);
     389             : #endif

Generated by: LCOV version 1.14