1/* 2 * R-Car Display Unit HDMI Connector 3 * 4 * Copyright (C) 2014 Renesas Electronics Corporation 5 * 6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14#include <drm/drmP.h> 15#include <drm/drm_atomic_helper.h> 16#include <drm/drm_crtc.h> 17#include <drm/drm_crtc_helper.h> 18#include <drm/drm_encoder_slave.h> 19 20#include "rcar_du_drv.h" 21#include "rcar_du_encoder.h" 22#include "rcar_du_hdmicon.h" 23#include "rcar_du_kms.h" 24 25#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs) 26 27static int rcar_du_hdmi_connector_get_modes(struct drm_connector *connector) 28{ 29 struct rcar_du_connector *con = to_rcar_connector(connector); 30 struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder); 31 struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); 32 33 if (sfuncs->get_modes == NULL) 34 return 0; 35 36 return sfuncs->get_modes(encoder, connector); 37} 38 39static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector, 40 struct drm_display_mode *mode) 41{ 42 struct rcar_du_connector *con = to_rcar_connector(connector); 43 struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder); 44 struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); 45 46 if (sfuncs->mode_valid == NULL) 47 return MODE_OK; 48 49 return sfuncs->mode_valid(encoder, mode); 50} 51 52static const struct drm_connector_helper_funcs connector_helper_funcs = { 53 .get_modes = rcar_du_hdmi_connector_get_modes, 54 .mode_valid = rcar_du_hdmi_connector_mode_valid, 55 .best_encoder = rcar_du_connector_best_encoder, 56}; 57 58static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector) 59{ 60 drm_connector_unregister(connector); 61 drm_connector_cleanup(connector); 62} 63 64static enum drm_connector_status 65rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force) 66{ 67 struct rcar_du_connector *con = to_rcar_connector(connector); 68 struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder); 69 struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); 70 71 if (sfuncs->detect == NULL) 72 return connector_status_unknown; 73 74 return sfuncs->detect(encoder, connector); 75} 76 77static const struct drm_connector_funcs connector_funcs = { 78 .dpms = drm_atomic_helper_connector_dpms, 79 .reset = drm_atomic_helper_connector_reset, 80 .detect = rcar_du_hdmi_connector_detect, 81 .fill_modes = drm_helper_probe_single_connector_modes, 82 .destroy = rcar_du_hdmi_connector_destroy, 83 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 84 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 85}; 86 87int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, 88 struct rcar_du_encoder *renc) 89{ 90 struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); 91 struct rcar_du_connector *rcon; 92 struct drm_connector *connector; 93 int ret; 94 95 rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL); 96 if (rcon == NULL) 97 return -ENOMEM; 98 99 connector = &rcon->connector; 100 connector->display_info.width_mm = 0; 101 connector->display_info.height_mm = 0; 102 connector->interlace_allowed = true; 103 connector->polled = DRM_CONNECTOR_POLL_HPD; 104 105 ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, 106 DRM_MODE_CONNECTOR_HDMIA); 107 if (ret < 0) 108 return ret; 109 110 drm_connector_helper_add(connector, &connector_helper_funcs); 111 ret = drm_connector_register(connector); 112 if (ret < 0) 113 return ret; 114 115 connector->dpms = DRM_MODE_DPMS_OFF; 116 drm_object_property_set_value(&connector->base, 117 rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); 118 119 ret = drm_mode_connector_attach_encoder(connector, encoder); 120 if (ret < 0) 121 return ret; 122 123 rcon->encoder = renc; 124 125 return 0; 126} 127