linux/drivers/gpu/drm/omapdrm/omap_encoder.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
   3 * Author: Rob Clark <rob@ti.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License version 2 as published by
   7 * the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include <linux/list.h>
  19
  20#include <drm/drm_crtc.h>
  21#include <drm/drm_crtc_helper.h>
  22#include <drm/drm_edid.h>
  23
  24#include "omap_drv.h"
  25
  26/*
  27 * encoder funcs
  28 */
  29
  30#define to_omap_encoder(x) container_of(x, struct omap_encoder, base)
  31
  32/* The encoder and connector both map to same dssdev.. the encoder
  33 * handles the 'active' parts, ie. anything the modifies the state
  34 * of the hw, and the connector handles the 'read-only' parts, like
  35 * detecting connection and reading edid.
  36 */
  37struct omap_encoder {
  38        struct drm_encoder base;
  39        struct omap_dss_device *dssdev;
  40};
  41
  42struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder)
  43{
  44        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
  45
  46        return omap_encoder->dssdev;
  47}
  48
  49static void omap_encoder_destroy(struct drm_encoder *encoder)
  50{
  51        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
  52
  53        drm_encoder_cleanup(encoder);
  54        kfree(omap_encoder);
  55}
  56
  57static const struct drm_encoder_funcs omap_encoder_funcs = {
  58        .destroy = omap_encoder_destroy,
  59};
  60
  61static void omap_encoder_mode_set(struct drm_encoder *encoder,
  62                                struct drm_display_mode *mode,
  63                                struct drm_display_mode *adjusted_mode)
  64{
  65        struct drm_device *dev = encoder->dev;
  66        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
  67        struct omap_dss_device *dssdev = omap_encoder->dssdev;
  68        struct drm_connector *connector;
  69        bool hdmi_mode;
  70        int r;
  71
  72        hdmi_mode = false;
  73        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  74                if (connector->encoder == encoder) {
  75                        hdmi_mode = omap_connector_get_hdmi_mode(connector);
  76                        break;
  77                }
  78        }
  79
  80        if (dssdev->driver->set_hdmi_mode)
  81                dssdev->driver->set_hdmi_mode(dssdev, hdmi_mode);
  82
  83        if (hdmi_mode && dssdev->driver->set_hdmi_infoframe) {
  84                struct hdmi_avi_infoframe avi;
  85
  86                r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode,
  87                                                             false);
  88                if (r == 0)
  89                        dssdev->driver->set_hdmi_infoframe(dssdev, &avi);
  90        }
  91}
  92
  93static void omap_encoder_disable(struct drm_encoder *encoder)
  94{
  95        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
  96        struct omap_dss_device *dssdev = omap_encoder->dssdev;
  97        struct omap_dss_driver *dssdrv = dssdev->driver;
  98
  99        dssdrv->disable(dssdev);
 100}
 101
 102static int omap_encoder_update(struct drm_encoder *encoder,
 103                               enum omap_channel channel,
 104                               struct videomode *vm)
 105{
 106        struct drm_device *dev = encoder->dev;
 107        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
 108        struct omap_dss_device *dssdev = omap_encoder->dssdev;
 109        struct omap_dss_driver *dssdrv = dssdev->driver;
 110        int ret;
 111
 112        if (dssdrv->check_timings) {
 113                ret = dssdrv->check_timings(dssdev, vm);
 114        } else {
 115                struct videomode t = {0};
 116
 117                dssdrv->get_timings(dssdev, &t);
 118
 119                if (memcmp(vm, &t, sizeof(*vm)))
 120                        ret = -EINVAL;
 121                else
 122                        ret = 0;
 123        }
 124
 125        if (ret) {
 126                dev_err(dev->dev, "could not set timings: %d\n", ret);
 127                return ret;
 128        }
 129
 130        if (dssdrv->set_timings)
 131                dssdrv->set_timings(dssdev, vm);
 132
 133        return 0;
 134}
 135
 136static void omap_encoder_enable(struct drm_encoder *encoder)
 137{
 138        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
 139        struct omap_dss_device *dssdev = omap_encoder->dssdev;
 140        struct omap_dss_driver *dssdrv = dssdev->driver;
 141        int r;
 142
 143        omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc),
 144                            omap_crtc_timings(encoder->crtc));
 145
 146        r = dssdrv->enable(dssdev);
 147        if (r)
 148                dev_err(encoder->dev->dev,
 149                        "Failed to enable display '%s': %d\n",
 150                        dssdev->name, r);
 151}
 152
 153static int omap_encoder_atomic_check(struct drm_encoder *encoder,
 154                                     struct drm_crtc_state *crtc_state,
 155                                     struct drm_connector_state *conn_state)
 156{
 157        return 0;
 158}
 159
 160static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
 161        .mode_set = omap_encoder_mode_set,
 162        .disable = omap_encoder_disable,
 163        .enable = omap_encoder_enable,
 164        .atomic_check = omap_encoder_atomic_check,
 165};
 166
 167/* initialize encoder */
 168struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 169                struct omap_dss_device *dssdev)
 170{
 171        struct drm_encoder *encoder = NULL;
 172        struct omap_encoder *omap_encoder;
 173
 174        omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);
 175        if (!omap_encoder)
 176                goto fail;
 177
 178        omap_encoder->dssdev = dssdev;
 179
 180        encoder = &omap_encoder->base;
 181
 182        drm_encoder_init(dev, encoder, &omap_encoder_funcs,
 183                         DRM_MODE_ENCODER_TMDS, NULL);
 184        drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);
 185
 186        return encoder;
 187
 188fail:
 189        if (encoder)
 190                omap_encoder_destroy(encoder);
 191
 192        return NULL;
 193}
 194