147 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/4 * Author: Rob Clark <rob@ti.com>5 */6 7#include <linux/list.h>8 9#include <drm/drm_bridge.h>10#include <drm/drm_crtc.h>11#include <drm/drm_modeset_helper_vtables.h>12#include <drm/drm_edid.h>13 14#include "omap_drv.h"15 16/*17 * encoder funcs18 */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 encoder23 * handles the 'active' parts, ie. anything the modifies the state24 * of the hw, and the connector handles the 'read-only' parts, like25 * detecting connection and reading edid.26 */27struct omap_encoder {28 struct drm_encoder base;29 struct omap_dss_device *output;30};31 32static 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 40static const struct drm_encoder_funcs omap_encoder_funcs = {41 .destroy = omap_encoder_destroy,42};43 44static 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 72static void omap_encoder_mode_set(struct drm_encoder *encoder,73 struct drm_display_mode *mode,74 struct drm_display_mode *adjusted_mode)75{76 struct omap_encoder *omap_encoder = to_omap_encoder(encoder);77 struct omap_dss_device *output = omap_encoder->output;78 struct drm_device *dev = encoder->dev;79 struct drm_connector *connector;80 struct drm_bridge *bridge;81 struct videomode vm = { 0 };82 u32 bus_flags;83 84 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {85 if (connector->encoder == encoder)86 break;87 }88 89 drm_display_mode_to_videomode(adjusted_mode, &vm);90 91 /*92 * HACK: This fixes the vm flags.93 * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and94 * they get lost when converting back and forth between struct95 * drm_display_mode and struct videomode. The hack below goes and96 * fetches the missing flags.97 *98 * A better solution is to use DRM's bus-flags through the whole driver.99 */100 for (bridge = output->bridge; bridge;101 bridge = drm_bridge_get_next_bridge(bridge)) {102 if (!bridge->timings)103 continue;104 105 bus_flags = bridge->timings->input_bus_flags;106 omap_encoder_update_videomode_flags(&vm, bus_flags);107 }108 109 bus_flags = connector->display_info.bus_flags;110 omap_encoder_update_videomode_flags(&vm, bus_flags);111 112 /* Set timings for all devices in the display pipeline. */113 dss_mgr_set_timings(output, &vm);114}115 116static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {117 .mode_set = omap_encoder_mode_set,118};119 120/* initialize encoder */121struct drm_encoder *omap_encoder_init(struct drm_device *dev,122 struct omap_dss_device *output)123{124 struct drm_encoder *encoder = NULL;125 struct omap_encoder *omap_encoder;126 127 omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);128 if (!omap_encoder)129 goto fail;130 131 omap_encoder->output = output;132 133 encoder = &omap_encoder->base;134 135 drm_encoder_init(dev, encoder, &omap_encoder_funcs,136 DRM_MODE_ENCODER_TMDS, NULL);137 drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);138 139 return encoder;140 141fail:142 if (encoder)143 omap_encoder_destroy(encoder);144 145 return NULL;146}147