root/drivers/gpu/drm/bridge/panel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. drm_bridge_to_panel_bridge
  2. drm_connector_to_panel_bridge
  3. panel_bridge_connector_get_modes
  4. panel_bridge_attach
  5. panel_bridge_detach
  6. panel_bridge_pre_enable
  7. panel_bridge_enable
  8. panel_bridge_disable
  9. panel_bridge_post_disable
  10. drm_panel_bridge_add
  11. drm_panel_bridge_remove
  12. devm_drm_panel_bridge_release
  13. devm_drm_panel_bridge_add

   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_connector.h>
   9 #include <drm/drm_encoder.h>
  10 #include <drm/drm_modeset_helper_vtables.h>
  11 #include <drm/drm_panel.h>
  12 #include <drm/drm_print.h>
  13 #include <drm/drm_probe_helper.h>
  14 
  15 struct panel_bridge {
  16         struct drm_bridge bridge;
  17         struct drm_connector connector;
  18         struct drm_panel *panel;
  19         u32 connector_type;
  20 };
  21 
  22 static inline struct panel_bridge *
  23 drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
  24 {
  25         return container_of(bridge, struct panel_bridge, bridge);
  26 }
  27 
  28 static inline struct panel_bridge *
  29 drm_connector_to_panel_bridge(struct drm_connector *connector)
  30 {
  31         return container_of(connector, struct panel_bridge, connector);
  32 }
  33 
  34 static int panel_bridge_connector_get_modes(struct drm_connector *connector)
  35 {
  36         struct panel_bridge *panel_bridge =
  37                 drm_connector_to_panel_bridge(connector);
  38 
  39         return drm_panel_get_modes(panel_bridge->panel);
  40 }
  41 
  42 static const struct drm_connector_helper_funcs
  43 panel_bridge_connector_helper_funcs = {
  44         .get_modes = panel_bridge_connector_get_modes,
  45 };
  46 
  47 static const struct drm_connector_funcs panel_bridge_connector_funcs = {
  48         .reset = drm_atomic_helper_connector_reset,
  49         .fill_modes = drm_helper_probe_single_connector_modes,
  50         .destroy = drm_connector_cleanup,
  51         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
  52         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
  53 };
  54 
  55 static int panel_bridge_attach(struct drm_bridge *bridge)
  56 {
  57         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
  58         struct drm_connector *connector = &panel_bridge->connector;
  59         int ret;
  60 
  61         if (!bridge->encoder) {
  62                 DRM_ERROR("Missing encoder\n");
  63                 return -ENODEV;
  64         }
  65 
  66         drm_connector_helper_add(connector,
  67                                  &panel_bridge_connector_helper_funcs);
  68 
  69         ret = drm_connector_init(bridge->dev, connector,
  70                                  &panel_bridge_connector_funcs,
  71                                  panel_bridge->connector_type);
  72         if (ret) {
  73                 DRM_ERROR("Failed to initialize connector\n");
  74                 return ret;
  75         }
  76 
  77         drm_connector_attach_encoder(&panel_bridge->connector,
  78                                           bridge->encoder);
  79 
  80         ret = drm_panel_attach(panel_bridge->panel, &panel_bridge->connector);
  81         if (ret < 0)
  82                 return ret;
  83 
  84         return 0;
  85 }
  86 
  87 static void panel_bridge_detach(struct drm_bridge *bridge)
  88 {
  89         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
  90 
  91         drm_panel_detach(panel_bridge->panel);
  92 }
  93 
  94 static void panel_bridge_pre_enable(struct drm_bridge *bridge)
  95 {
  96         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
  97 
  98         drm_panel_prepare(panel_bridge->panel);
  99 }
 100 
 101 static void panel_bridge_enable(struct drm_bridge *bridge)
 102 {
 103         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 104 
 105         drm_panel_enable(panel_bridge->panel);
 106 }
 107 
 108 static void panel_bridge_disable(struct drm_bridge *bridge)
 109 {
 110         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 111 
 112         drm_panel_disable(panel_bridge->panel);
 113 }
 114 
 115 static void panel_bridge_post_disable(struct drm_bridge *bridge)
 116 {
 117         struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 118 
 119         drm_panel_unprepare(panel_bridge->panel);
 120 }
 121 
 122 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
 123         .attach = panel_bridge_attach,
 124         .detach = panel_bridge_detach,
 125         .pre_enable = panel_bridge_pre_enable,
 126         .enable = panel_bridge_enable,
 127         .disable = panel_bridge_disable,
 128         .post_disable = panel_bridge_post_disable,
 129 };
 130 
 131 /**
 132  * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
 133  * just calls the appropriate functions from &drm_panel.
 134  *
 135  * @panel: The drm_panel being wrapped.  Must be non-NULL.
 136  * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be
 137  * created.
 138  *
 139  * For drivers converting from directly using drm_panel: The expected
 140  * usage pattern is that during either encoder module probe or DSI
 141  * host attach, a drm_panel will be looked up through
 142  * drm_of_find_panel_or_bridge().  drm_panel_bridge_add() is used to
 143  * wrap that panel in the new bridge, and the result can then be
 144  * passed to drm_bridge_attach().  The drm_panel_prepare() and related
 145  * functions can be dropped from the encoder driver (they're now
 146  * called by the KMS helpers before calling into the encoder), along
 147  * with connector creation.  When done with the bridge (after
 148  * drm_mode_config_cleanup() if the bridge has already been attached), then
 149  * drm_panel_bridge_remove() to free it.
 150  *
 151  * See devm_drm_panel_bridge_add() for an automatically manged version of this
 152  * function.
 153  */
 154 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
 155                                         u32 connector_type)
 156 {
 157         struct panel_bridge *panel_bridge;
 158 
 159         if (!panel)
 160                 return ERR_PTR(-EINVAL);
 161 
 162         panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge),
 163                                     GFP_KERNEL);
 164         if (!panel_bridge)
 165                 return ERR_PTR(-ENOMEM);
 166 
 167         panel_bridge->connector_type = connector_type;
 168         panel_bridge->panel = panel;
 169 
 170         panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs;
 171 #ifdef CONFIG_OF
 172         panel_bridge->bridge.of_node = panel->dev->of_node;
 173 #endif
 174 
 175         drm_bridge_add(&panel_bridge->bridge);
 176 
 177         return &panel_bridge->bridge;
 178 }
 179 EXPORT_SYMBOL(drm_panel_bridge_add);
 180 
 181 /**
 182  * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
 183  * created by drm_panel_bridge_add().
 184  *
 185  * @bridge: The drm_bridge being freed.
 186  */
 187 void drm_panel_bridge_remove(struct drm_bridge *bridge)
 188 {
 189         struct panel_bridge *panel_bridge;
 190 
 191         if (!bridge)
 192                 return;
 193 
 194         if (bridge->funcs != &panel_bridge_bridge_funcs)
 195                 return;
 196 
 197         panel_bridge = drm_bridge_to_panel_bridge(bridge);
 198 
 199         drm_bridge_remove(bridge);
 200         devm_kfree(panel_bridge->panel->dev, bridge);
 201 }
 202 EXPORT_SYMBOL(drm_panel_bridge_remove);
 203 
 204 static void devm_drm_panel_bridge_release(struct device *dev, void *res)
 205 {
 206         struct drm_bridge **bridge = res;
 207 
 208         drm_panel_bridge_remove(*bridge);
 209 }
 210 
 211 /**
 212  * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
 213  * that just calls the appropriate functions from &drm_panel.
 214  * @dev: device to tie the bridge lifetime to
 215  * @panel: The drm_panel being wrapped.  Must be non-NULL.
 216  * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be
 217  * created.
 218  *
 219  * This is the managed version of drm_panel_bridge_add() which automatically
 220  * calls drm_panel_bridge_remove() when @dev is unbound.
 221  */
 222 struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
 223                                              struct drm_panel *panel,
 224                                              u32 connector_type)
 225 {
 226         struct drm_bridge **ptr, *bridge;
 227 
 228         ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
 229                            GFP_KERNEL);
 230         if (!ptr)
 231                 return ERR_PTR(-ENOMEM);
 232 
 233         bridge = drm_panel_bridge_add(panel, connector_type);
 234         if (!IS_ERR(bridge)) {
 235                 *ptr = bridge;
 236                 devres_add(dev, ptr);
 237         } else {
 238                 devres_free(ptr);
 239         }
 240 
 241         return bridge;
 242 }
 243 EXPORT_SYMBOL(devm_drm_panel_bridge_add);

/* [<][>][^][v][top][bottom][index][help] */