Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
0004  * Author: Rob Clark <rob@ti.com>
0005  */
0006 
0007 #include <linux/list.h>
0008 
0009 #include <drm/drm_bridge.h>
0010 #include <drm/drm_crtc.h>
0011 #include <drm/drm_modeset_helper_vtables.h>
0012 #include <drm/drm_edid.h>
0013 
0014 #include "omap_drv.h"
0015 
0016 /*
0017  * encoder funcs
0018  */
0019 
0020 #define to_omap_encoder(x) container_of(x, struct omap_encoder, base)
0021 
0022 /* The encoder and connector both map to same dssdev.. the encoder
0023  * handles the 'active' parts, ie. anything the modifies the state
0024  * of the hw, and the connector handles the 'read-only' parts, like
0025  * detecting connection and reading edid.
0026  */
0027 struct omap_encoder {
0028     struct drm_encoder base;
0029     struct omap_dss_device *output;
0030 };
0031 
0032 static void omap_encoder_destroy(struct drm_encoder *encoder)
0033 {
0034     struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
0035 
0036     drm_encoder_cleanup(encoder);
0037     kfree(omap_encoder);
0038 }
0039 
0040 static const struct drm_encoder_funcs omap_encoder_funcs = {
0041     .destroy = omap_encoder_destroy,
0042 };
0043 
0044 static void omap_encoder_update_videomode_flags(struct videomode *vm,
0045                         u32 bus_flags)
0046 {
0047     if (!(vm->flags & (DISPLAY_FLAGS_DE_LOW |
0048                DISPLAY_FLAGS_DE_HIGH))) {
0049         if (bus_flags & DRM_BUS_FLAG_DE_LOW)
0050             vm->flags |= DISPLAY_FLAGS_DE_LOW;
0051         else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
0052             vm->flags |= DISPLAY_FLAGS_DE_HIGH;
0053     }
0054 
0055     if (!(vm->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
0056                DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
0057         if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
0058             vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
0059         else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
0060             vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
0061     }
0062 
0063     if (!(vm->flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
0064                DISPLAY_FLAGS_SYNC_NEGEDGE))) {
0065         if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE)
0066             vm->flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
0067         else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
0068             vm->flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
0069     }
0070 }
0071 
0072 static void omap_encoder_mode_set(struct drm_encoder *encoder,
0073                   struct drm_display_mode *mode,
0074                   struct drm_display_mode *adjusted_mode)
0075 {
0076     struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
0077     struct omap_dss_device *output = omap_encoder->output;
0078     struct drm_device *dev = encoder->dev;
0079     struct drm_connector *connector;
0080     struct drm_bridge *bridge;
0081     struct videomode vm = { 0 };
0082     u32 bus_flags;
0083 
0084     list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
0085         if (connector->encoder == encoder)
0086             break;
0087     }
0088 
0089     drm_display_mode_to_videomode(adjusted_mode, &vm);
0090 
0091     /*
0092      * HACK: This fixes the vm flags.
0093      * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and
0094      * they get lost when converting back and forth between struct
0095      * drm_display_mode and struct videomode. The hack below goes and
0096      * fetches the missing flags.
0097      *
0098      * A better solution is to use DRM's bus-flags through the whole driver.
0099      */
0100     for (bridge = output->bridge; bridge;
0101          bridge = drm_bridge_get_next_bridge(bridge)) {
0102         if (!bridge->timings)
0103             continue;
0104 
0105         bus_flags = bridge->timings->input_bus_flags;
0106         omap_encoder_update_videomode_flags(&vm, bus_flags);
0107     }
0108 
0109     bus_flags = connector->display_info.bus_flags;
0110     omap_encoder_update_videomode_flags(&vm, bus_flags);
0111 
0112     /* Set timings for all devices in the display pipeline. */
0113     dss_mgr_set_timings(output, &vm);
0114 }
0115 
0116 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
0117     .mode_set = omap_encoder_mode_set,
0118 };
0119 
0120 /* initialize encoder */
0121 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
0122                       struct omap_dss_device *output)
0123 {
0124     struct drm_encoder *encoder = NULL;
0125     struct omap_encoder *omap_encoder;
0126 
0127     omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);
0128     if (!omap_encoder)
0129         goto fail;
0130 
0131     omap_encoder->output = output;
0132 
0133     encoder = &omap_encoder->base;
0134 
0135     drm_encoder_init(dev, encoder, &omap_encoder_funcs,
0136              DRM_MODE_ENCODER_TMDS, NULL);
0137     drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);
0138 
0139     return encoder;
0140 
0141 fail:
0142     if (encoder)
0143         omap_encoder_destroy(encoder);
0144 
0145     return NULL;
0146 }