linux/drivers/gpu/drm/xilinx/xilinx_drm_connector.c
<<
>>
Prefs
   1/*
   2 * Xilinx DRM connector 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/device.h>
  24
  25#include "xilinx_drm_drv.h"
  26#include "xilinx_drm_connector.h"
  27
  28struct xilinx_drm_connector {
  29        struct drm_connector base;
  30        struct drm_encoder *encoder;
  31};
  32
  33struct xilinx_drm_connector_type {
  34        const char *name;
  35        const int type;
  36};
  37
  38#define to_xilinx_connector(x)  \
  39        container_of(x, struct xilinx_drm_connector, base)
  40
  41/* get mode list */
  42static int xilinx_drm_connector_get_modes(struct drm_connector *base_connector)
  43{
  44        struct xilinx_drm_connector *connector =
  45                to_xilinx_connector(base_connector);
  46        struct drm_encoder *encoder = connector->encoder;
  47        struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
  48        const struct drm_encoder_slave_funcs *encoder_sfuncs =
  49                encoder_slave->slave_funcs;
  50        int count = 0;
  51
  52        if (encoder_sfuncs->get_modes)
  53                count = encoder_sfuncs->get_modes(encoder, base_connector);
  54
  55        return count;
  56}
  57
  58/* check if mode is valid */
  59static int xilinx_drm_connector_mode_valid(struct drm_connector *base_connector,
  60                                           struct drm_display_mode *mode)
  61{
  62        struct xilinx_drm_connector *connector =
  63                to_xilinx_connector(base_connector);
  64        struct drm_encoder *encoder = connector->encoder;
  65        struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
  66        const struct drm_encoder_slave_funcs *encoder_sfuncs =
  67                encoder_slave->slave_funcs;
  68        int ret = MODE_OK;
  69
  70        if (encoder_sfuncs->mode_valid)
  71                ret = encoder_sfuncs->mode_valid(encoder, mode);
  72
  73        return ret;
  74}
  75
  76/* find best encoder: return stored encoder */
  77static struct drm_encoder *
  78xilinx_drm_connector_best_encoder(struct drm_connector *base_connector)
  79{
  80        struct xilinx_drm_connector *connector =
  81                to_xilinx_connector(base_connector);
  82
  83        return connector->encoder;
  84}
  85
  86static struct drm_connector_helper_funcs xilinx_drm_connector_helper_funcs = {
  87        .get_modes      = xilinx_drm_connector_get_modes,
  88        .mode_valid     = xilinx_drm_connector_mode_valid,
  89        .best_encoder   = xilinx_drm_connector_best_encoder,
  90};
  91
  92static enum drm_connector_status
  93xilinx_drm_connector_detect(struct drm_connector *base_connector, bool force)
  94{
  95        struct xilinx_drm_connector *connector =
  96                to_xilinx_connector(base_connector);
  97        enum drm_connector_status status = connector_status_unknown;
  98        struct drm_encoder *encoder = connector->encoder;
  99        struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
 100        const struct drm_encoder_slave_funcs *encoder_sfuncs =
 101                encoder_slave->slave_funcs;
 102
 103        if (encoder_sfuncs->detect)
 104                status = encoder_sfuncs->detect(encoder, base_connector);
 105
 106        /* some connector ignores the first hpd, so try again if forced */
 107        if (force && (status != connector_status_connected))
 108                status = encoder_sfuncs->detect(encoder, base_connector);
 109
 110        DRM_DEBUG_KMS("status: %d\n", status);
 111
 112        return status;
 113}
 114
 115/* destroy connector */
 116void xilinx_drm_connector_destroy(struct drm_connector *base_connector)
 117{
 118        drm_connector_unregister(base_connector);
 119        drm_connector_cleanup(base_connector);
 120}
 121
 122static struct drm_connector_funcs xilinx_drm_connector_funcs = {
 123        .dpms           = drm_helper_connector_dpms,
 124        .fill_modes     = drm_helper_probe_single_connector_modes,
 125        .detect         = xilinx_drm_connector_detect,
 126        .destroy        = xilinx_drm_connector_destroy,
 127};
 128
 129static const struct xilinx_drm_connector_type connector_types[] = {
 130        { "HDMIA", DRM_MODE_CONNECTOR_HDMIA },
 131        { "DisplayPort", DRM_MODE_CONNECTOR_DisplayPort },
 132};
 133
 134/* create connector */
 135struct drm_connector *
 136xilinx_drm_connector_create(struct drm_device *drm,
 137                            struct drm_encoder *base_encoder, int id)
 138{
 139        struct xilinx_drm_connector *connector;
 140        const char *string;
 141        int type = DRM_MODE_CONNECTOR_Unknown;
 142        int i, ret;
 143
 144        connector = devm_kzalloc(drm->dev, sizeof(*connector), GFP_KERNEL);
 145        if (!connector)
 146                return ERR_PTR(-ENOMEM);
 147
 148        connector->base.polled = DRM_CONNECTOR_POLL_HPD |
 149                                 DRM_CONNECTOR_POLL_CONNECT |
 150                                 DRM_CONNECTOR_POLL_DISCONNECT;
 151
 152        ret = of_property_read_string_index(drm->dev->of_node,
 153                                            "xlnx,connector-type", id, &string);
 154        if (ret < 0) {
 155                dev_err(drm->dev, "No connector type in DT\n");
 156                return ERR_PTR(ret);
 157        }
 158
 159        for (i = 0; i < ARRAY_SIZE(connector_types); i++)
 160                if (strcmp(connector_types[i].name, string) == 0) {
 161                        type = connector_types[i].type;
 162                        break;
 163                }
 164
 165        if (type == DRM_MODE_CONNECTOR_Unknown) {
 166                dev_err(drm->dev, "Unknown connector type in DT\n");
 167                return ERR_PTR(-EINVAL);
 168        }
 169
 170        ret = drm_connector_init(drm, &connector->base,
 171                                 &xilinx_drm_connector_funcs, type);
 172        if (ret) {
 173                DRM_ERROR("failed to initialize connector\n");
 174                return ERR_PTR(ret);
 175        }
 176
 177        drm_connector_helper_add(&connector->base,
 178                                 &xilinx_drm_connector_helper_funcs);
 179
 180        /* add entry for connector */
 181        ret = drm_connector_register(&connector->base);
 182        if (ret) {
 183                DRM_ERROR("failed to register a connector\n");
 184                goto err_register;
 185        }
 186
 187        /* connect connector and encoder */
 188        ret = drm_mode_connector_attach_encoder(&connector->base, base_encoder);
 189        if (ret) {
 190                DRM_ERROR("failed to attach connector to encoder\n");
 191                goto err_attach;
 192        }
 193        connector->encoder = base_encoder;
 194        connector->base.dpms = DRM_MODE_DPMS_OFF;
 195
 196        return &connector->base;
 197
 198err_attach:
 199        drm_connector_unregister(&connector->base);
 200err_register:
 201        drm_connector_cleanup(&connector->base);
 202        return ERR_PTR(ret);
 203}
 204