linux/drivers/gpu/drm/xylon/xylon_encoder.c
<<
>>
Prefs
   1/*
   2 * Xylon DRM encoder functions
   3 *
   4 * Copyright (C) 2014 Xylon d.o.o.
   5 * Author: Davor Joja <davor.joja@logicbricks.com>
   6 *
   7 * Reused Xilinx DRM encoder driver.
   8 * Copyright (C) 2013 Xilinx, Inc.
   9 *
  10 * This software is licensed under the terms of the GNU General Public
  11 * License version 2, as published by the Free Software Foundation, and
  12 * may be copied, distributed, and modified under those terms.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 */
  19
  20#include <drm/drmP.h>
  21#include <drm/drm_crtc.h>
  22#include <drm/drm_crtc_helper.h>
  23#include <drm/drm_encoder_slave.h>
  24
  25#include <linux/hdmi.h>
  26#include <linux/err.h>
  27#include <linux/i2c.h>
  28#include <linux/of.h>
  29#include <linux/platform_device.h>
  30
  31#include "xylon_drv.h"
  32#include "xylon_encoder.h"
  33
  34struct xylon_drm_encoder {
  35        struct drm_encoder_slave slave;
  36        struct i2c_client *client;
  37        int dpms;
  38};
  39
  40#define to_xylon_encoder(x) container_of(x, struct xylon_drm_encoder, slave)
  41
  42static void xylon_drm_encoder_dpms(struct drm_encoder *base_encoder, int dpms)
  43{
  44        struct xylon_drm_encoder *encoder;
  45        struct drm_encoder_slave *encoder_slave;
  46        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_xylon_encoder(encoder_slave);
  51
  52        if (encoder->dpms == dpms)
  53                return;
  54
  55        encoder->dpms = dpms;
  56        if (encoder_sfuncs->dpms)
  57                encoder_sfuncs->dpms(base_encoder, dpms);
  58}
  59
  60static bool
  61xylon_drm_encoder_mode_fixup(struct drm_encoder *base_encoder,
  62                             const struct drm_display_mode *mode,
  63                             struct drm_display_mode *adjusted_mode)
  64{
  65        struct drm_encoder_slave *encoder_slave;
  66        struct drm_encoder_slave_funcs *encoder_sfuncs;
  67        bool ret = true;
  68
  69        encoder_slave = to_encoder_slave(base_encoder);
  70        encoder_sfuncs = encoder_slave->slave_funcs;
  71        if (encoder_sfuncs->mode_fixup)
  72                ret = encoder_sfuncs->mode_fixup(base_encoder, mode,
  73                                                 adjusted_mode);
  74
  75        return ret;
  76}
  77
  78static void xylon_drm_encoder_mode_set(struct drm_encoder *base_encoder,
  79                                       struct drm_display_mode *mode,
  80                                       struct drm_display_mode *adjusted_mode)
  81{
  82        struct xylon_drm_encoder *encoder;
  83        struct drm_device *dev = base_encoder->dev;
  84        struct drm_encoder_slave *encoder_slave;
  85        struct drm_encoder_slave_funcs *encoder_sfuncs;
  86        struct drm_connector *iter;
  87        struct drm_connector *connector = NULL;
  88
  89        DRM_DEBUG("h: %d, v: %d\n",
  90                  adjusted_mode->hdisplay, adjusted_mode->vdisplay);
  91        DRM_DEBUG("refresh: %d, pclock: %d khz\n",
  92                  adjusted_mode->vrefresh, adjusted_mode->clock);
  93
  94        encoder_slave = to_encoder_slave(base_encoder);
  95        encoder = to_xylon_encoder(encoder_slave);
  96
  97        list_for_each_entry(iter, &dev->mode_config.connector_list, head) {
  98                if (iter->encoder == base_encoder) {
  99                        connector = iter;
 100                        break;
 101                }
 102        }
 103        if (!connector) {
 104                DRM_ERROR("failed find a connector\n");
 105                return;
 106        }
 107
 108        encoder_sfuncs = encoder_slave->slave_funcs;
 109        if (encoder_sfuncs->mode_set)
 110                encoder_sfuncs->mode_set(base_encoder, mode, adjusted_mode);
 111}
 112
 113static void xylon_drm_encoder_commit(struct drm_encoder *base_encoder)
 114{
 115        xylon_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_ON);
 116}
 117
 118static void xylon_drm_encoder_prepare(struct drm_encoder *base_encoder)
 119{
 120        xylon_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_OFF);
 121}
 122
 123static struct drm_crtc *
 124xylon_drm_encoder_get_crtc(struct drm_encoder *base_encoder)
 125{
 126        return base_encoder->crtc;
 127}
 128
 129static struct drm_encoder_helper_funcs xylon_drm_encoder_helper_funcs = {
 130        .dpms = xylon_drm_encoder_dpms,
 131        .mode_fixup = xylon_drm_encoder_mode_fixup,
 132        .mode_set = xylon_drm_encoder_mode_set,
 133        .prepare = xylon_drm_encoder_prepare,
 134        .commit = xylon_drm_encoder_commit,
 135        .get_crtc = xylon_drm_encoder_get_crtc,
 136};
 137
 138static void xylon_drm_encoder_destroy(struct drm_encoder *base_encoder)
 139{
 140        struct xylon_drm_encoder *encoder;
 141        struct drm_encoder_slave *encoder_slave;
 142
 143        encoder_slave = to_encoder_slave(base_encoder);
 144        encoder = to_xylon_encoder(encoder_slave);
 145
 146        xylon_drm_encoder_dpms(base_encoder, DRM_MODE_DPMS_OFF);
 147
 148        drm_encoder_cleanup(base_encoder);
 149        put_device(&encoder->client->dev);
 150}
 151
 152static struct drm_encoder_funcs xylon_drm_encoder_funcs = {
 153        .destroy = xylon_drm_encoder_destroy,
 154};
 155
 156struct drm_encoder *xylon_drm_encoder_create(struct drm_device *dev)
 157{
 158        struct xylon_drm_encoder *encoder;
 159        struct device_node *sub_node;
 160        struct i2c_driver *i2c_driver;
 161        struct drm_i2c_encoder_driver *drm_i2c_driver;
 162        int ret;
 163
 164        encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL);
 165        if (!encoder)
 166                return ERR_PTR(-ENOMEM);
 167
 168        encoder->dpms = DRM_MODE_DPMS_OFF;
 169
 170        encoder->slave.base.possible_crtcs = 1;
 171        ret = drm_encoder_init(dev, &encoder->slave.base,
 172                               &xylon_drm_encoder_funcs,
 173                               DRM_MODE_ENCODER_TMDS);
 174        if (ret) {
 175                DRM_ERROR("failed initialize encoder\n");
 176                return ERR_PTR(ret);
 177        }
 178
 179        drm_encoder_helper_add(&encoder->slave.base,
 180                               &xylon_drm_encoder_helper_funcs);
 181
 182        sub_node = of_parse_phandle(dev->dev->of_node, "encoder", 0);
 183        if (!sub_node) {
 184                DRM_ERROR("failed get encoder\n");
 185                return ERR_PTR(-ENODEV);
 186        }
 187
 188        encoder->client = of_find_i2c_device_by_node(sub_node);
 189        of_node_put(sub_node);
 190        if (!encoder->client || !encoder->client->dev.driver) {
 191                DRM_INFO("failed find encoder\n");
 192                return ERR_PTR(-EPROBE_DEFER);
 193        }
 194
 195        i2c_driver = to_i2c_driver(encoder->client->dev.driver);
 196        drm_i2c_driver = to_drm_i2c_encoder_driver(i2c_driver);
 197        if (!drm_i2c_driver) {
 198                DRM_ERROR("failed initialize encoder driver\n");
 199                return ERR_PTR(-EPROBE_DEFER);
 200        }
 201
 202        ret = drm_i2c_driver->encoder_init(encoder->client, dev,
 203                                           &encoder->slave);
 204        if (ret) {
 205                DRM_ERROR("failed initialize encoder\n");
 206                return ERR_PTR(ret);
 207        }
 208
 209        if (!encoder->slave.slave_funcs) {
 210                DRM_ERROR("failed check encoder function\n");
 211                return ERR_PTR(-ENODEV);
 212        }
 213
 214        return &encoder->slave.base;
 215}
 216