root/drivers/gpu/drm/omapdrm/omap_encoder.c

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

DEFINITIONS

This source file includes following definitions.
  1. omap_encoder_destroy
  2. omap_encoder_update_videomode_flags
  3. omap_encoder_hdmi_mode_set
  4. omap_encoder_mode_set
  5. omap_encoder_disable
  6. omap_encoder_enable
  7. omap_encoder_atomic_check
  8. omap_encoder_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
   4  * Author: Rob Clark <rob@ti.com>
   5  */
   6 
   7 #include <linux/list.h>
   8 
   9 #include <drm/drm_crtc.h>
  10 #include <drm/drm_modeset_helper_vtables.h>
  11 #include <drm/drm_edid.h>
  12 #include <drm/drm_panel.h>
  13 
  14 #include "omap_drv.h"
  15 
  16 /*
  17  * encoder funcs
  18  */
  19 
  20 #define to_omap_encoder(x) container_of(x, struct omap_encoder, base)
  21 
  22 /* The encoder and connector both map to same dssdev.. the encoder
  23  * handles the 'active' parts, ie. anything the modifies the state
  24  * of the hw, and the connector handles the 'read-only' parts, like
  25  * detecting connection and reading edid.
  26  */
  27 struct omap_encoder {
  28         struct drm_encoder base;
  29         struct omap_dss_device *output;
  30 };
  31 
  32 static void omap_encoder_destroy(struct drm_encoder *encoder)
  33 {
  34         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
  35 
  36         drm_encoder_cleanup(encoder);
  37         kfree(omap_encoder);
  38 }
  39 
  40 static const struct drm_encoder_funcs omap_encoder_funcs = {
  41         .destroy = omap_encoder_destroy,
  42 };
  43 
  44 static void omap_encoder_update_videomode_flags(struct videomode *vm,
  45                                                 u32 bus_flags)
  46 {
  47         if (!(vm->flags & (DISPLAY_FLAGS_DE_LOW |
  48                            DISPLAY_FLAGS_DE_HIGH))) {
  49                 if (bus_flags & DRM_BUS_FLAG_DE_LOW)
  50                         vm->flags |= DISPLAY_FLAGS_DE_LOW;
  51                 else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
  52                         vm->flags |= DISPLAY_FLAGS_DE_HIGH;
  53         }
  54 
  55         if (!(vm->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
  56                            DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
  57                 if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
  58                         vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
  59                 else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
  60                         vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
  61         }
  62 
  63         if (!(vm->flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
  64                            DISPLAY_FLAGS_SYNC_NEGEDGE))) {
  65                 if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE)
  66                         vm->flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
  67                 else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
  68                         vm->flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
  69         }
  70 }
  71 
  72 static void omap_encoder_hdmi_mode_set(struct drm_connector *connector,
  73                                        struct drm_encoder *encoder,
  74                                        struct drm_display_mode *adjusted_mode)
  75 {
  76         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
  77         struct omap_dss_device *dssdev = omap_encoder->output;
  78         bool hdmi_mode;
  79 
  80         hdmi_mode = omap_connector_get_hdmi_mode(connector);
  81 
  82         if (dssdev->ops->hdmi.set_hdmi_mode)
  83                 dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode);
  84 
  85         if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) {
  86                 struct hdmi_avi_infoframe avi;
  87                 int r;
  88 
  89                 r = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
  90                                                              adjusted_mode);
  91                 if (r == 0)
  92                         dssdev->ops->hdmi.set_infoframe(dssdev, &avi);
  93         }
  94 }
  95 
  96 static void omap_encoder_mode_set(struct drm_encoder *encoder,
  97                                   struct drm_display_mode *mode,
  98                                   struct drm_display_mode *adjusted_mode)
  99 {
 100         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
 101         struct omap_dss_device *output = omap_encoder->output;
 102         struct omap_dss_device *dssdev;
 103         struct drm_device *dev = encoder->dev;
 104         struct drm_connector *connector;
 105         struct drm_bridge *bridge;
 106         struct videomode vm = { 0 };
 107         u32 bus_flags;
 108 
 109         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 110                 if (connector->encoder == encoder)
 111                         break;
 112         }
 113 
 114         drm_display_mode_to_videomode(adjusted_mode, &vm);
 115 
 116         /*
 117          * HACK: This fixes the vm flags.
 118          * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and
 119          * they get lost when converting back and forth between struct
 120          * drm_display_mode and struct videomode. The hack below goes and
 121          * fetches the missing flags.
 122          *
 123          * A better solution is to use DRM's bus-flags through the whole driver.
 124          */
 125         for (dssdev = output; dssdev; dssdev = dssdev->next)
 126                 omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
 127 
 128         for (bridge = output->bridge; bridge; bridge = bridge->next) {
 129                 if (!bridge->timings)
 130                         continue;
 131 
 132                 bus_flags = bridge->timings->input_bus_flags;
 133                 omap_encoder_update_videomode_flags(&vm, bus_flags);
 134         }
 135 
 136         bus_flags = connector->display_info.bus_flags;
 137         omap_encoder_update_videomode_flags(&vm, bus_flags);
 138 
 139         /* Set timings for all devices in the display pipeline. */
 140         dss_mgr_set_timings(output, &vm);
 141 
 142         for (dssdev = output; dssdev; dssdev = dssdev->next) {
 143                 if (dssdev->ops->set_timings)
 144                         dssdev->ops->set_timings(dssdev, adjusted_mode);
 145         }
 146 
 147         /* Set the HDMI mode and HDMI infoframe if applicable. */
 148         if (output->type == OMAP_DISPLAY_TYPE_HDMI)
 149                 omap_encoder_hdmi_mode_set(connector, encoder, adjusted_mode);
 150 }
 151 
 152 static void omap_encoder_disable(struct drm_encoder *encoder)
 153 {
 154         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
 155         struct omap_dss_device *dssdev = omap_encoder->output;
 156         struct drm_device *dev = encoder->dev;
 157 
 158         dev_dbg(dev->dev, "disable(%s)\n", dssdev->name);
 159 
 160         /* Disable the panel if present. */
 161         if (dssdev->panel) {
 162                 drm_panel_disable(dssdev->panel);
 163                 drm_panel_unprepare(dssdev->panel);
 164         }
 165 
 166         /*
 167          * Disable the chain of external devices, starting at the one at the
 168          * internal encoder's output.
 169          */
 170         omapdss_device_disable(dssdev->next);
 171 
 172         /*
 173          * Disable the internal encoder. This will disable the DSS output. The
 174          * DSI is treated as an exception as DSI pipelines still use the legacy
 175          * flow where the pipeline output controls the encoder.
 176          */
 177         if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) {
 178                 dssdev->ops->disable(dssdev);
 179                 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 180         }
 181 
 182         /*
 183          * Perform the post-disable operations on the chain of external devices
 184          * to complete the display pipeline disable.
 185          */
 186         omapdss_device_post_disable(dssdev->next);
 187 }
 188 
 189 static void omap_encoder_enable(struct drm_encoder *encoder)
 190 {
 191         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
 192         struct omap_dss_device *dssdev = omap_encoder->output;
 193         struct drm_device *dev = encoder->dev;
 194 
 195         dev_dbg(dev->dev, "enable(%s)\n", dssdev->name);
 196 
 197         /* Prepare the chain of external devices for pipeline enable. */
 198         omapdss_device_pre_enable(dssdev->next);
 199 
 200         /*
 201          * Enable the internal encoder. This will enable the DSS output. The
 202          * DSI is treated as an exception as DSI pipelines still use the legacy
 203          * flow where the pipeline output controls the encoder.
 204          */
 205         if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) {
 206                 dssdev->ops->enable(dssdev);
 207                 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 208         }
 209 
 210         /*
 211          * Enable the chain of external devices, starting at the one at the
 212          * internal encoder's output.
 213          */
 214         omapdss_device_enable(dssdev->next);
 215 
 216         /* Enable the panel if present. */
 217         if (dssdev->panel) {
 218                 drm_panel_prepare(dssdev->panel);
 219                 drm_panel_enable(dssdev->panel);
 220         }
 221 }
 222 
 223 static int omap_encoder_atomic_check(struct drm_encoder *encoder,
 224                                      struct drm_crtc_state *crtc_state,
 225                                      struct drm_connector_state *conn_state)
 226 {
 227         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
 228         enum drm_mode_status status;
 229 
 230         status = omap_connector_mode_fixup(omap_encoder->output,
 231                                            &crtc_state->mode,
 232                                            &crtc_state->adjusted_mode);
 233         if (status != MODE_OK) {
 234                 dev_err(encoder->dev->dev, "invalid timings: %d\n", status);
 235                 return -EINVAL;
 236         }
 237 
 238         return 0;
 239 }
 240 
 241 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
 242         .mode_set = omap_encoder_mode_set,
 243         .disable = omap_encoder_disable,
 244         .enable = omap_encoder_enable,
 245         .atomic_check = omap_encoder_atomic_check,
 246 };
 247 
 248 /* initialize encoder */
 249 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 250                                       struct omap_dss_device *output)
 251 {
 252         struct drm_encoder *encoder = NULL;
 253         struct omap_encoder *omap_encoder;
 254 
 255         omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);
 256         if (!omap_encoder)
 257                 goto fail;
 258 
 259         omap_encoder->output = output;
 260 
 261         encoder = &omap_encoder->base;
 262 
 263         drm_encoder_init(dev, encoder, &omap_encoder_funcs,
 264                          DRM_MODE_ENCODER_TMDS, NULL);
 265         drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);
 266 
 267         return encoder;
 268 
 269 fail:
 270         if (encoder)
 271                 omap_encoder_destroy(encoder);
 272 
 273         return NULL;
 274 }

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