linux/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2014 Red Hat
   4 * Author: Rob Clark <robdclark@gmail.com>
   5 * Author: Vinay Simha <vinaysimha@inforcecomputing.com>
   6 */
   7
   8#include <linux/gpio.h>
   9
  10#include "mdp4_kms.h"
  11
  12struct mdp4_lvds_connector {
  13        struct drm_connector base;
  14        struct drm_encoder *encoder;
  15        struct device_node *panel_node;
  16        struct drm_panel *panel;
  17};
  18#define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
  19
  20static enum drm_connector_status mdp4_lvds_connector_detect(
  21                struct drm_connector *connector, bool force)
  22{
  23        struct mdp4_lvds_connector *mdp4_lvds_connector =
  24                        to_mdp4_lvds_connector(connector);
  25
  26        if (!mdp4_lvds_connector->panel) {
  27                mdp4_lvds_connector->panel =
  28                        of_drm_find_panel(mdp4_lvds_connector->panel_node);
  29                if (IS_ERR(mdp4_lvds_connector->panel))
  30                        mdp4_lvds_connector->panel = NULL;
  31        }
  32
  33        return mdp4_lvds_connector->panel ?
  34                        connector_status_connected :
  35                        connector_status_disconnected;
  36}
  37
  38static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
  39{
  40        struct mdp4_lvds_connector *mdp4_lvds_connector =
  41                        to_mdp4_lvds_connector(connector);
  42
  43        drm_connector_cleanup(connector);
  44
  45        kfree(mdp4_lvds_connector);
  46}
  47
  48static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
  49{
  50        struct mdp4_lvds_connector *mdp4_lvds_connector =
  51                        to_mdp4_lvds_connector(connector);
  52        struct drm_panel *panel = mdp4_lvds_connector->panel;
  53        int ret = 0;
  54
  55        if (panel) {
  56                drm_panel_attach(panel, connector);
  57
  58                ret = panel->funcs->get_modes(panel);
  59
  60                drm_panel_detach(panel);
  61        }
  62
  63        return ret;
  64}
  65
  66static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
  67                                 struct drm_display_mode *mode)
  68{
  69        struct mdp4_lvds_connector *mdp4_lvds_connector =
  70                        to_mdp4_lvds_connector(connector);
  71        struct drm_encoder *encoder = mdp4_lvds_connector->encoder;
  72        long actual, requested;
  73
  74        requested = 1000 * mode->clock;
  75        actual = mdp4_lcdc_round_pixclk(encoder, requested);
  76
  77        DBG("requested=%ld, actual=%ld", requested, actual);
  78
  79        if (actual != requested)
  80                return MODE_CLOCK_RANGE;
  81
  82        return MODE_OK;
  83}
  84
  85static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
  86        .detect = mdp4_lvds_connector_detect,
  87        .fill_modes = drm_helper_probe_single_connector_modes,
  88        .destroy = mdp4_lvds_connector_destroy,
  89        .reset = drm_atomic_helper_connector_reset,
  90        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
  91        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
  92};
  93
  94static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs = {
  95        .get_modes = mdp4_lvds_connector_get_modes,
  96        .mode_valid = mdp4_lvds_connector_mode_valid,
  97};
  98
  99/* initialize connector */
 100struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
 101                struct device_node *panel_node, struct drm_encoder *encoder)
 102{
 103        struct drm_connector *connector = NULL;
 104        struct mdp4_lvds_connector *mdp4_lvds_connector;
 105
 106        mdp4_lvds_connector = kzalloc(sizeof(*mdp4_lvds_connector), GFP_KERNEL);
 107        if (!mdp4_lvds_connector)
 108                return ERR_PTR(-ENOMEM);
 109
 110        mdp4_lvds_connector->encoder = encoder;
 111        mdp4_lvds_connector->panel_node = panel_node;
 112
 113        connector = &mdp4_lvds_connector->base;
 114
 115        drm_connector_init(dev, connector, &mdp4_lvds_connector_funcs,
 116                        DRM_MODE_CONNECTOR_LVDS);
 117        drm_connector_helper_add(connector, &mdp4_lvds_connector_helper_funcs);
 118
 119        connector->polled = 0;
 120
 121        connector->interlace_allowed = 0;
 122        connector->doublescan_allowed = 0;
 123
 124        drm_connector_attach_encoder(connector, encoder);
 125
 126        return connector;
 127}
 128