diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_encoder.c')
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_encoder.c | 186 |
1 files changed, 71 insertions, 115 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index c29451ba65da..195715b162e3 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -1,29 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * drivers/gpu/drm/omapdrm/omap_encoder.c - * - * Copyright (C) 2011 Texas Instruments + * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "omap_drv.h" - -#include "drm_crtc.h" -#include "drm_crtc_helper.h" - #include <linux/list.h> +#include <drm/drm_bridge.h> +#include <drm/drm_crtc.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_edid.h> + +#include "omap_drv.h" /* * encoder funcs @@ -38,19 +26,13 @@ */ struct omap_encoder { struct drm_encoder base; - struct omap_dss_device *dssdev; + struct omap_dss_device *output; }; -struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder) -{ - struct omap_encoder *omap_encoder = to_omap_encoder(encoder); - - return omap_encoder->dssdev; -} - static void omap_encoder_destroy(struct drm_encoder *encoder) { struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + drm_encoder_cleanup(encoder); kfree(omap_encoder); } @@ -59,109 +41,83 @@ static const struct drm_encoder_funcs omap_encoder_funcs = { .destroy = omap_encoder_destroy, }; -/* - * The CRTC drm_crtc_helper_set_mode() doesn't really give us the right - * order.. the easiest way to work around this for now is to make all - * the encoder-helper's no-op's and have the omap_crtc code take care - * of the sequencing and call us in the right points. - * - * Eventually to handle connecting CRTCs to different encoders properly, - * either the CRTC helpers need to change or we need to replace - * drm_crtc_helper_set_mode(), but lets wait until atomic-modeset for - * that. - */ - -static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) -{ -} - -static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - -static void omap_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ -} - -static void omap_encoder_prepare(struct drm_encoder *encoder) +static void omap_encoder_update_videomode_flags(struct videomode *vm, + u32 bus_flags) { -} - -static void omap_encoder_commit(struct drm_encoder *encoder) -{ -} - -static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { - .dpms = omap_encoder_dpms, - .mode_fixup = omap_encoder_mode_fixup, - .mode_set = omap_encoder_mode_set, - .prepare = omap_encoder_prepare, - .commit = omap_encoder_commit, -}; + if (!(vm->flags & (DISPLAY_FLAGS_DE_LOW | + DISPLAY_FLAGS_DE_HIGH))) { + if (bus_flags & DRM_BUS_FLAG_DE_LOW) + vm->flags |= DISPLAY_FLAGS_DE_LOW; + else if (bus_flags & DRM_BUS_FLAG_DE_HIGH) + vm->flags |= DISPLAY_FLAGS_DE_HIGH; + } -/* - * Instead of relying on the helpers for modeset, the omap_crtc code - * calls these functions in the proper sequence. - */ + if (!(vm->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE | + DISPLAY_FLAGS_PIXDATA_NEGEDGE))) { + if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) + vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; + else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) + vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; + } -int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled) -{ - struct omap_encoder *omap_encoder = to_omap_encoder(encoder); - struct omap_dss_device *dssdev = omap_encoder->dssdev; - struct omap_dss_driver *dssdrv = dssdev->driver; - - if (enabled) { - return dssdrv->enable(dssdev); - } else { - dssdrv->disable(dssdev); - return 0; + if (!(vm->flags & (DISPLAY_FLAGS_SYNC_POSEDGE | + DISPLAY_FLAGS_SYNC_NEGEDGE))) { + if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE) + vm->flags |= DISPLAY_FLAGS_SYNC_POSEDGE; + else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE) + vm->flags |= DISPLAY_FLAGS_SYNC_NEGEDGE; } } -int omap_encoder_update(struct drm_encoder *encoder, - struct omap_overlay_manager *mgr, - struct omap_video_timings *timings) +static void omap_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; struct omap_encoder *omap_encoder = to_omap_encoder(encoder); - struct omap_dss_device *dssdev = omap_encoder->dssdev; - struct omap_dss_driver *dssdrv = dssdev->driver; - int ret; - - dssdev->output->manager = mgr; - - if (dssdrv->check_timings) { - ret = dssdrv->check_timings(dssdev, timings); - } else { - struct omap_video_timings t = {0}; - - dssdrv->get_timings(dssdev, &t); + struct omap_dss_device *output = omap_encoder->output; + struct drm_device *dev = encoder->dev; + struct drm_connector *connector; + struct videomode vm = { 0 }; + u32 bus_flags; - if (memcmp(timings, &t, sizeof(struct omap_video_timings))) - ret = -EINVAL; - else - ret = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder == encoder) + break; } - if (ret) { - dev_err(dev->dev, "could not set timings: %d\n", ret); - return ret; + drm_display_mode_to_videomode(adjusted_mode, &vm); + + /* + * HACK: This fixes the vm flags. + * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and + * they get lost when converting back and forth between struct + * drm_display_mode and struct videomode. The hack below goes and + * fetches the missing flags. + * + * A better solution is to use DRM's bus-flags through the whole driver. + */ + drm_for_each_bridge_in_chain_from(output->bridge, bridge) { + if (!bridge->timings) + continue; + + bus_flags = bridge->timings->input_bus_flags; + omap_encoder_update_videomode_flags(&vm, bus_flags); } - if (dssdrv->set_timings) - dssdrv->set_timings(dssdev, timings); + bus_flags = connector->display_info.bus_flags; + omap_encoder_update_videomode_flags(&vm, bus_flags); - return 0; + /* Set timings for all devices in the display pipeline. */ + dss_mgr_set_timings(output, &vm); } +static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { + .mode_set = omap_encoder_mode_set, +}; + /* initialize encoder */ struct drm_encoder *omap_encoder_init(struct drm_device *dev, - struct omap_dss_device *dssdev) + struct omap_dss_device *output) { struct drm_encoder *encoder = NULL; struct omap_encoder *omap_encoder; @@ -170,12 +126,12 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev, if (!omap_encoder) goto fail; - omap_encoder->dssdev = dssdev; + omap_encoder->output = output; encoder = &omap_encoder->base; drm_encoder_init(dev, encoder, &omap_encoder_funcs, - DRM_MODE_ENCODER_TMDS); + DRM_MODE_ENCODER_TMDS, NULL); drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); return encoder; |
