linux/drivers/gpu/drm/xilinx/xilinx_drm_encoder.c
<<
>>
Prefs
   1/*
   2 * Xilinx DRM encoder driver for Xilinx
   3 *
   4 *  Copyright (C) 2013 Xilinx, Inc.
   5 *
   6 *  Author: Hyun Woo Kwon <hyunk@xilinx.com>
   7 *
   8 * This software is licensed under the terms of the GNU General Public
   9 * License version 2, as published by the Free Software Foundation, and
  10 * may be copied, distributed, and modified under those terms.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <drm/drmP.h>
  19#include <drm/drm_crtc.h>
  20#include <drm/drm_crtc_helper.h>
  21#include <drm/drm_encoder_slave.h>
  22
  23#include <linux/err.h>
  24#include <linux/i2c.h>
  25#include <linux/of.h>
  26#include <linux/of_platform.h>
  27#include <linux/platform_device.h>
  28
  29#include "xilinx_drm_drv.h"
  30#include "xilinx_drm_encoder.h"
  31
  32struct xilinx_drm_encoder {
  33        struct drm_encoder_slave slave;
  34        struct device *dev;
  35        int dpms;
  36};
  37
  38#define to_xilinx_encoder(x)    \
  39        container_of(x, struct xilinx_drm_encoder, slave)
  40
  41/* set encoder dpms */
  42static void xilinx_drm_encoder_dpms(struct drm_encoder *base_encoder, int dpms)
  43{
  44        struct xilinx_drm_encoder *encoder;
  45        struct drm_encoder_slave *encoder_slave;
  46        const struct drm_encoder_slave_funcs *encoder_sfuncs;
  47
  48        encoder_slave = to_encoder_slave(base_encoder);
  49        encoder_sfuncs = encoder_slave->slave_funcs;
  50        encoder = to_xilinx_encoder(encoder_slave);
  51
  52        DRM_DEBUG_KMS("dpms: %d -> %d\n", encoder->dpms, dpms);
  53
  54        if (encoder->dpms == dpms)
  55                return;
  56
  57        encoder->dpms = dpms;
  58        if (encoder_sfuncs->dpms)
  59                encoder_sfuncs->dpms(base_encoder, dpms);
  60}
  61
  62/* adjust a mode if needed */
  63static bool
  64xilinx_drm_encoder_mode_fixup(struct drm_encoder *base_encoder,
  65                              const struct drm_display_mode *mode,
  66                              struct drm_display_mode *adjusted_mode)
  67{
  68        struct drm_encoder_slave *encoder_slave;
  69        const struct drm_encoder_slave_funcs *encoder_sfuncs = NULL;
  70        bool ret = true;
  71
  72        encoder_slave = to_encoder_slave(base_encoder);
  73        encoder_sfuncs = encoder_slave->slave_funcs;
  74        if (encoder_sfuncs->mode_fixup)
  75                ret = encoder_sfuncs->mode_fixup(base_encoder, mode,
  76                                                 adjusted_mode);
  77
  78        return ret;
  79}
  80
  81/* set mode to xilinx encoder */
  82static void xilinx_drm_encoder_mode_set(struct drm_encoder *base_encoder,
  83                                        struct drm_display_mode *mode,
  84                                        struct drm_display_mode *adjusted_mode)
  85{
  86        struct drm_encoder_slave *encoder_slave;
  87        const struct drm_encoder_slave_funcs *encoder_sfuncs;
  88
  89        DRM_DEBUG_KMS("h: %d, v: %d\n",
  90                      adjusted_mode->hdisplay, adjusted_mode->vdisplay);
  91        DRM_DEBUG_KMS("refresh: %d, pclock: %d khz\n",
  92                      adjusted_mode->vrefresh, adjusted_mode->clock);
  93
  94        encoder_slave = to_encoder_slave(base_encoder);
  95        encoder_sfuncs = encoder_slave->slave_funcs;
  96        if (encoder_sfuncs->mode_set)
  97                encoder_sfuncs->mode_set(base_encoder, mode, adjusted_mode);
  98}
  99
 100/* apply mode to encoder pipe */
 101static void xilinx_drm_encoder_commit(struct drm_encoder *base_encoder)
 102{
 103        /* start encoder with new mode */
 104        xilinx_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_ON);
 105}
 106
 107/* prepare encoder */
 108static void xilinx_drm_encoder_prepare(struct drm_encoder *base_encoder)
 109{
 110        xilinx_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_OFF);
 111}
 112
 113/* get crtc */
 114static struct drm_crtc *
 115xilinx_drm_encoder_get_crtc(struct drm_encoder *base_encoder)
 116{
 117        return base_encoder->crtc;
 118}
 119
 120static const struct drm_encoder_helper_funcs xilinx_drm_encoder_helper_funcs = {
 121        .dpms           = xilinx_drm_encoder_dpms,
 122        .mode_fixup     = xilinx_drm_encoder_mode_fixup,
 123        .mode_set       = xilinx_drm_encoder_mode_set,
 124        .prepare        = xilinx_drm_encoder_prepare,
 125        .commit         = xilinx_drm_encoder_commit,
 126        .get_crtc       = xilinx_drm_encoder_get_crtc,
 127};
 128
 129/* destroy encoder */
 130void xilinx_drm_encoder_destroy(struct drm_encoder *base_encoder)
 131{
 132        struct xilinx_drm_encoder *encoder;
 133        struct drm_encoder_slave *encoder_slave;
 134
 135        encoder_slave = to_encoder_slave(base_encoder);
 136        encoder = to_xilinx_encoder(encoder_slave);
 137
 138        /* make sure encoder is off */
 139        xilinx_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_OFF);
 140
 141        drm_encoder_cleanup(base_encoder);
 142        put_device(encoder->dev);
 143}
 144
 145static const struct drm_encoder_funcs xilinx_drm_encoder_funcs = {
 146        .destroy        = xilinx_drm_encoder_destroy,
 147};
 148
 149/* create encoder */
 150struct drm_encoder *xilinx_drm_encoder_create(struct drm_device *drm,
 151                                              struct device_node *node)
 152{
 153        struct xilinx_drm_encoder *encoder;
 154        struct i2c_client *i2c_slv;
 155        struct i2c_driver *i2c_driver;
 156        struct drm_i2c_encoder_driver *drm_i2c_driver;
 157        struct device_driver *device_driver;
 158        struct platform_device *platform_slv;
 159        struct platform_driver *platform_driver;
 160        struct drm_platform_encoder_driver *drm_platform_driver;
 161        int ret = 0;
 162
 163        encoder = devm_kzalloc(drm->dev, sizeof(*encoder), GFP_KERNEL);
 164        if (!encoder)
 165                return ERR_PTR(-ENOMEM);
 166
 167        encoder->dpms = DRM_MODE_DPMS_OFF;
 168
 169        /* FIXME: Use DT to figure out crtcs / clones */
 170        encoder->slave.base.possible_crtcs = 1;
 171        encoder->slave.base.possible_clones = ~0;
 172        ret = drm_encoder_init(drm, &encoder->slave.base,
 173                               &xilinx_drm_encoder_funcs,
 174                               DRM_MODE_ENCODER_TMDS, NULL);
 175        if (ret) {
 176                DRM_ERROR("failed to initialize drm encoder\n");
 177                return ERR_PTR(ret);
 178        }
 179
 180        drm_encoder_helper_add(&encoder->slave.base,
 181                               &xilinx_drm_encoder_helper_funcs);
 182
 183        /* initialize slave encoder */
 184        i2c_slv = of_find_i2c_device_by_node(node);
 185        if (i2c_slv && i2c_slv->dev.driver) {
 186                i2c_driver = to_i2c_driver(i2c_slv->dev.driver);
 187                drm_i2c_driver = to_drm_i2c_encoder_driver(i2c_driver);
 188                if (!drm_i2c_driver || !drm_i2c_driver->encoder_init) {
 189                        DRM_DEBUG_KMS("failed to initialize i2c slave\n");
 190                        ret = -EPROBE_DEFER;
 191                        goto err_out;
 192                }
 193
 194                encoder->dev = &i2c_slv->dev;
 195                ret = drm_i2c_driver->encoder_init(i2c_slv, drm,
 196                                                   &encoder->slave);
 197        } else {
 198                platform_slv = of_find_device_by_node(node);
 199                if (!platform_slv) {
 200                        DRM_DEBUG_KMS("failed to get an encoder slv\n");
 201                        return ERR_PTR(-EPROBE_DEFER);
 202                }
 203
 204                device_driver = platform_slv->dev.driver;
 205                if (!device_driver) {
 206                        DRM_DEBUG_KMS("failed to get device driver\n");
 207                        return ERR_PTR(-EPROBE_DEFER);
 208                }
 209
 210                platform_driver = to_platform_driver(device_driver);
 211                drm_platform_driver =
 212                        to_drm_platform_encoder_driver(platform_driver);
 213                if (!drm_platform_driver ||
 214                    !drm_platform_driver->encoder_init) {
 215                        DRM_DEBUG_KMS("failed to initialize platform slave\n");
 216                        ret = -EPROBE_DEFER;
 217                        goto err_out;
 218                }
 219
 220                encoder->dev = &platform_slv->dev;
 221                ret = drm_platform_driver->encoder_init(platform_slv, drm,
 222                                                        &encoder->slave);
 223        }
 224
 225        if (ret) {
 226                DRM_ERROR("failed to initialize encoder slave\n");
 227                goto err_out;
 228        }
 229
 230        if (!encoder->slave.slave_funcs) {
 231                DRM_ERROR("there's no encoder slave function\n");
 232                ret = -ENODEV;
 233                goto err_out;
 234        }
 235
 236        return &encoder->slave.base;
 237
 238err_out:
 239        return ERR_PTR(ret);
 240}
 241