root/drivers/gpu/drm/exynos/exynos_drm_dpi.c

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

DEFINITIONS

This source file includes following definitions.
  1. encoder_to_dpi
  2. exynos_dpi_detect
  3. exynos_dpi_connector_destroy
  4. exynos_dpi_get_modes
  5. exynos_dpi_create_connector
  6. exynos_dpi_mode_set
  7. exynos_dpi_enable
  8. exynos_dpi_disable
  9. exynos_dpi_parse_dt
  10. exynos_dpi_bind
  11. exynos_dpi_probe
  12. exynos_dpi_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Exynos DRM Parallel output support.
   4  *
   5  * Copyright (c) 2014 Samsung Electronics Co., Ltd
   6  *
   7  * Contacts: Andrzej Hajda <a.hajda@samsung.com>
   8 */
   9 
  10 #include <linux/of_graph.h>
  11 #include <linux/regulator/consumer.h>
  12 
  13 #include <drm/drm_atomic_helper.h>
  14 #include <drm/drm_panel.h>
  15 #include <drm/drm_print.h>
  16 #include <drm/drm_probe_helper.h>
  17 
  18 #include <video/of_videomode.h>
  19 #include <video/videomode.h>
  20 
  21 #include "exynos_drm_crtc.h"
  22 
  23 struct exynos_dpi {
  24         struct drm_encoder encoder;
  25         struct device *dev;
  26         struct device_node *panel_node;
  27 
  28         struct drm_panel *panel;
  29         struct drm_connector connector;
  30 
  31         struct videomode *vm;
  32 };
  33 
  34 #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
  35 
  36 static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e)
  37 {
  38         return container_of(e, struct exynos_dpi, encoder);
  39 }
  40 
  41 static enum drm_connector_status
  42 exynos_dpi_detect(struct drm_connector *connector, bool force)
  43 {
  44         struct exynos_dpi *ctx = connector_to_dpi(connector);
  45 
  46         if (ctx->panel && !ctx->panel->connector)
  47                 drm_panel_attach(ctx->panel, &ctx->connector);
  48 
  49         return connector_status_connected;
  50 }
  51 
  52 static void exynos_dpi_connector_destroy(struct drm_connector *connector)
  53 {
  54         drm_connector_unregister(connector);
  55         drm_connector_cleanup(connector);
  56 }
  57 
  58 static const struct drm_connector_funcs exynos_dpi_connector_funcs = {
  59         .detect = exynos_dpi_detect,
  60         .fill_modes = drm_helper_probe_single_connector_modes,
  61         .destroy = exynos_dpi_connector_destroy,
  62         .reset = drm_atomic_helper_connector_reset,
  63         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
  64         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
  65 };
  66 
  67 static int exynos_dpi_get_modes(struct drm_connector *connector)
  68 {
  69         struct exynos_dpi *ctx = connector_to_dpi(connector);
  70 
  71         /* fimd timings gets precedence over panel modes */
  72         if (ctx->vm) {
  73                 struct drm_display_mode *mode;
  74 
  75                 mode = drm_mode_create(connector->dev);
  76                 if (!mode) {
  77                         DRM_DEV_ERROR(ctx->dev,
  78                                       "failed to create a new display mode\n");
  79                         return 0;
  80                 }
  81                 drm_display_mode_from_videomode(ctx->vm, mode);
  82                 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
  83                 drm_mode_probed_add(connector, mode);
  84                 return 1;
  85         }
  86 
  87         if (ctx->panel)
  88                 return ctx->panel->funcs->get_modes(ctx->panel);
  89 
  90         return 0;
  91 }
  92 
  93 static const struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
  94         .get_modes = exynos_dpi_get_modes,
  95 };
  96 
  97 static int exynos_dpi_create_connector(struct drm_encoder *encoder)
  98 {
  99         struct exynos_dpi *ctx = encoder_to_dpi(encoder);
 100         struct drm_connector *connector = &ctx->connector;
 101         int ret;
 102 
 103         connector->polled = DRM_CONNECTOR_POLL_HPD;
 104 
 105         ret = drm_connector_init(encoder->dev, connector,
 106                                  &exynos_dpi_connector_funcs,
 107                                  DRM_MODE_CONNECTOR_VGA);
 108         if (ret) {
 109                 DRM_DEV_ERROR(ctx->dev,
 110                               "failed to initialize connector with drm\n");
 111                 return ret;
 112         }
 113 
 114         drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs);
 115         drm_connector_attach_encoder(connector, encoder);
 116 
 117         return 0;
 118 }
 119 
 120 static void exynos_dpi_mode_set(struct drm_encoder *encoder,
 121                                 struct drm_display_mode *mode,
 122                                 struct drm_display_mode *adjusted_mode)
 123 {
 124 }
 125 
 126 static void exynos_dpi_enable(struct drm_encoder *encoder)
 127 {
 128         struct exynos_dpi *ctx = encoder_to_dpi(encoder);
 129 
 130         if (ctx->panel) {
 131                 drm_panel_prepare(ctx->panel);
 132                 drm_panel_enable(ctx->panel);
 133         }
 134 }
 135 
 136 static void exynos_dpi_disable(struct drm_encoder *encoder)
 137 {
 138         struct exynos_dpi *ctx = encoder_to_dpi(encoder);
 139 
 140         if (ctx->panel) {
 141                 drm_panel_disable(ctx->panel);
 142                 drm_panel_unprepare(ctx->panel);
 143         }
 144 }
 145 
 146 static const struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
 147         .mode_set = exynos_dpi_mode_set,
 148         .enable = exynos_dpi_enable,
 149         .disable = exynos_dpi_disable,
 150 };
 151 
 152 static const struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
 153         .destroy = drm_encoder_cleanup,
 154 };
 155 
 156 enum {
 157         FIMD_PORT_IN0,
 158         FIMD_PORT_IN1,
 159         FIMD_PORT_IN2,
 160         FIMD_PORT_RGB,
 161         FIMD_PORT_WRB,
 162 };
 163 
 164 static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
 165 {
 166         struct device *dev = ctx->dev;
 167         struct device_node *dn = dev->of_node;
 168         struct device_node *np;
 169 
 170         ctx->panel_node = of_graph_get_remote_node(dn, FIMD_PORT_RGB, 0);
 171 
 172         np = of_get_child_by_name(dn, "display-timings");
 173         if (np) {
 174                 struct videomode *vm;
 175                 int ret;
 176 
 177                 of_node_put(np);
 178 
 179                 vm = devm_kzalloc(dev, sizeof(*ctx->vm), GFP_KERNEL);
 180                 if (!vm)
 181                         return -ENOMEM;
 182 
 183                 ret = of_get_videomode(dn, vm, 0);
 184                 if (ret < 0) {
 185                         devm_kfree(dev, vm);
 186                         return ret;
 187                 }
 188 
 189                 ctx->vm = vm;
 190 
 191                 return 0;
 192         }
 193 
 194         if (!ctx->panel_node)
 195                 return -EINVAL;
 196 
 197         return 0;
 198 }
 199 
 200 int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
 201 {
 202         int ret;
 203 
 204         drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs,
 205                          DRM_MODE_ENCODER_TMDS, NULL);
 206 
 207         drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);
 208 
 209         ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
 210         if (ret < 0)
 211                 return ret;
 212 
 213         ret = exynos_dpi_create_connector(encoder);
 214         if (ret) {
 215                 DRM_DEV_ERROR(encoder_to_dpi(encoder)->dev,
 216                               "failed to create connector ret = %d\n", ret);
 217                 drm_encoder_cleanup(encoder);
 218                 return ret;
 219         }
 220 
 221         return 0;
 222 }
 223 
 224 struct drm_encoder *exynos_dpi_probe(struct device *dev)
 225 {
 226         struct exynos_dpi *ctx;
 227         int ret;
 228 
 229         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 230         if (!ctx)
 231                 return ERR_PTR(-ENOMEM);
 232 
 233         ctx->dev = dev;
 234 
 235         ret = exynos_dpi_parse_dt(ctx);
 236         if (ret < 0) {
 237                 devm_kfree(dev, ctx);
 238                 return NULL;
 239         }
 240 
 241         if (ctx->panel_node) {
 242                 ctx->panel = of_drm_find_panel(ctx->panel_node);
 243                 if (IS_ERR(ctx->panel))
 244                         return ERR_CAST(ctx->panel);
 245         }
 246 
 247         return &ctx->encoder;
 248 }
 249 
 250 int exynos_dpi_remove(struct drm_encoder *encoder)
 251 {
 252         struct exynos_dpi *ctx = encoder_to_dpi(encoder);
 253 
 254         exynos_dpi_disable(&ctx->encoder);
 255 
 256         if (ctx->panel)
 257                 drm_panel_detach(ctx->panel);
 258 
 259         return 0;
 260 }

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