cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dp_drm.c (3830B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <drm/drm_atomic_helper.h>
      7#include <drm/drm_atomic.h>
      8#include <drm/drm_bridge.h>
      9#include <drm/drm_bridge_connector.h>
     10#include <drm/drm_crtc.h>
     11
     12#include "msm_drv.h"
     13#include "msm_kms.h"
     14#include "dp_drm.h"
     15
     16/**
     17 * dp_bridge_detect - callback to determine if connector is connected
     18 * @bridge: Pointer to drm bridge structure
     19 * Returns: Bridge's 'is connected' status
     20 */
     21static enum drm_connector_status dp_bridge_detect(struct drm_bridge *bridge)
     22{
     23	struct msm_dp *dp;
     24
     25	dp = to_dp_bridge(bridge)->dp_display;
     26
     27	drm_dbg_dp(dp->drm_dev, "is_connected = %s\n",
     28		(dp->is_connected) ? "true" : "false");
     29
     30	return (dp->is_connected) ? connector_status_connected :
     31					connector_status_disconnected;
     32}
     33
     34/**
     35 * dp_bridge_get_modes - callback to add drm modes via drm_mode_probed_add()
     36 * @bridge: Poiner to drm bridge
     37 * @connector: Pointer to drm connector structure
     38 * Returns: Number of modes added
     39 */
     40static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector)
     41{
     42	int rc = 0;
     43	struct msm_dp *dp;
     44
     45	if (!connector)
     46		return 0;
     47
     48	dp = to_dp_bridge(bridge)->dp_display;
     49
     50	/* pluggable case assumes EDID is read when HPD */
     51	if (dp->is_connected) {
     52		rc = dp_display_get_modes(dp);
     53		if (rc <= 0) {
     54			DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc);
     55			return rc;
     56		}
     57	} else {
     58		drm_dbg_dp(connector->dev, "No sink connected\n");
     59	}
     60	return rc;
     61}
     62
     63static const struct drm_bridge_funcs dp_bridge_ops = {
     64	.enable       = dp_bridge_enable,
     65	.disable      = dp_bridge_disable,
     66	.post_disable = dp_bridge_post_disable,
     67	.mode_set     = dp_bridge_mode_set,
     68	.mode_valid   = dp_bridge_mode_valid,
     69	.get_modes    = dp_bridge_get_modes,
     70	.detect       = dp_bridge_detect,
     71};
     72
     73struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
     74			struct drm_encoder *encoder)
     75{
     76	int rc;
     77	struct msm_dp_bridge *dp_bridge;
     78	struct drm_bridge *bridge;
     79
     80	dp_bridge = devm_kzalloc(dev->dev, sizeof(*dp_bridge), GFP_KERNEL);
     81	if (!dp_bridge)
     82		return ERR_PTR(-ENOMEM);
     83
     84	dp_bridge->dp_display = dp_display;
     85
     86	bridge = &dp_bridge->bridge;
     87	bridge->funcs = &dp_bridge_ops;
     88	bridge->type = dp_display->connector_type;
     89
     90	/*
     91	 * Many ops only make sense for DP. Why?
     92	 * - Detect/HPD are used by DRM to know if a display is _physically_
     93	 *   there, not whether the display is powered on / finished initting.
     94	 *   On eDP we assume the display is always there because you can't
     95	 *   know until power is applied. If we don't implement the ops DRM will
     96	 *   assume our display is always there.
     97	 * - Currently eDP mode reading is driven by the panel driver. This
     98	 *   allows the panel driver to properly power itself on to read the
     99	 *   modes.
    100	 */
    101	if (!dp_display->is_edp) {
    102		bridge->ops =
    103			DRM_BRIDGE_OP_DETECT |
    104			DRM_BRIDGE_OP_HPD |
    105			DRM_BRIDGE_OP_MODES;
    106	}
    107
    108	drm_bridge_add(bridge);
    109
    110	rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
    111	if (rc) {
    112		DRM_ERROR("failed to attach bridge, rc=%d\n", rc);
    113		drm_bridge_remove(bridge);
    114
    115		return ERR_PTR(rc);
    116	}
    117
    118	if (dp_display->next_bridge) {
    119		rc = drm_bridge_attach(dp_display->encoder,
    120					dp_display->next_bridge, bridge,
    121					DRM_BRIDGE_ATTACH_NO_CONNECTOR);
    122		if (rc < 0) {
    123			DRM_ERROR("failed to attach panel bridge: %d\n", rc);
    124			drm_bridge_remove(bridge);
    125			return ERR_PTR(rc);
    126		}
    127	}
    128
    129	return bridge;
    130}
    131
    132/* connector initialization */
    133struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display)
    134{
    135	struct drm_connector *connector = NULL;
    136
    137	connector = drm_bridge_connector_init(dp_display->drm_dev, dp_display->encoder);
    138	if (IS_ERR(connector))
    139		return connector;
    140
    141	drm_connector_attach_encoder(connector, dp_display->encoder);
    142
    143	return connector;
    144}