linux/drivers/gpu/drm/msm/dp/dp_drm.c

145 lines
3.7 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_crtc.h>
#include "msm_drv.h"
#include "msm_kms.h"
#include "dp_drm.h"
/**
* dp_bridge_detect - callback to determine if connector is connected
* @bridge: Pointer to drm bridge structure
* Returns: Bridge's 'is connected' status
*/
static enum drm_connector_status dp_bridge_detect(struct drm_bridge *bridge)
{
struct msm_dp *dp;
dp = to_dp_bridge(bridge)->dp_display;
drm_dbg_dp(dp->drm_dev, "is_connected = %s\n",
(dp->is_connected) ? "true" : "false");
return (dp->is_connected) ? connector_status_connected :
connector_status_disconnected;
}
/**
* dp_bridge_get_modes - callback to add drm modes via drm_mode_probed_add()
* @bridge: Poiner to drm bridge
* @connector: Pointer to drm connector structure
* Returns: Number of modes added
*/
static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector)
{
int rc = 0;
struct msm_dp *dp;
if (!connector)
return 0;
dp = to_dp_bridge(bridge)->dp_display;
/* pluggable case assumes EDID is read when HPD */
if (dp->is_connected) {
rc = dp_display_get_modes(dp);
if (rc <= 0) {
DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc);
return rc;
}
} else {
drm_dbg_dp(connector->dev, "No sink connected\n");
}
return rc;
}
static const struct drm_bridge_funcs dp_bridge_ops = {
.enable = dp_bridge_enable,
.disable = dp_bridge_disable,
.post_disable = dp_bridge_post_disable,
.mode_set = dp_bridge_mode_set,
.mode_valid = dp_bridge_mode_valid,
.get_modes = dp_bridge_get_modes,
.detect = dp_bridge_detect,
};
struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder)
{
int rc;
struct msm_dp_bridge *dp_bridge;
struct drm_bridge *bridge;
dp_bridge = devm_kzalloc(dev->dev, sizeof(*dp_bridge), GFP_KERNEL);
if (!dp_bridge)
return ERR_PTR(-ENOMEM);
dp_bridge->dp_display = dp_display;
bridge = &dp_bridge->bridge;
bridge->funcs = &dp_bridge_ops;
bridge->type = dp_display->connector_type;
/*
* Many ops only make sense for DP. Why?
* - Detect/HPD are used by DRM to know if a display is _physically_
* there, not whether the display is powered on / finished initting.
* On eDP we assume the display is always there because you can't
* know until power is applied. If we don't implement the ops DRM will
* assume our display is always there.
* - Currently eDP mode reading is driven by the panel driver. This
* allows the panel driver to properly power itself on to read the
* modes.
*/
if (!dp_display->is_edp) {
bridge->ops =
DRM_BRIDGE_OP_DETECT |
DRM_BRIDGE_OP_HPD |
DRM_BRIDGE_OP_MODES;
}
drm/msm: properly add and remove internal bridges Add calls to drm_bridge_add()/drm_bridge_remove() DRM bridges created by the driver. This fixes the following warning. WARNING: CPU: 0 PID: 1 at kernel/locking/mutex.c:579 __mutex_lock+0x840/0x9f4 DEBUG_LOCKS_WARN_ON(lock->magic != lock) Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.18.0-rc1-00002-g3054695a0d27-dirty #55 Hardware name: Generic DT based system unwind_backtrace from show_stack+0x10/0x14 show_stack from dump_stack_lvl+0x58/0x70 dump_stack_lvl from __warn+0xc8/0x1e8 __warn from warn_slowpath_fmt+0x78/0xa8 warn_slowpath_fmt from __mutex_lock+0x840/0x9f4 __mutex_lock from mutex_lock_nested+0x1c/0x24 mutex_lock_nested from drm_bridge_hpd_enable+0x2c/0x84 drm_bridge_hpd_enable from msm_hdmi_modeset_init+0xc0/0x21c msm_hdmi_modeset_init from mdp4_kms_init+0x53c/0x90c mdp4_kms_init from msm_drm_bind+0x514/0x698 msm_drm_bind from try_to_bring_up_aggregate_device+0x160/0x1bc try_to_bring_up_aggregate_device from component_master_add_with_match+0xc4/0xf8 component_master_add_with_match from msm_pdev_probe+0x274/0x350 msm_pdev_probe from platform_probe+0x5c/0xbc platform_probe from really_probe.part.0+0x9c/0x290 really_probe.part.0 from __driver_probe_device+0xa8/0x13c __driver_probe_device from driver_probe_device+0x34/0x10c driver_probe_device from __driver_attach+0xbc/0x178 __driver_attach from bus_for_each_dev+0x74/0xc0 bus_for_each_dev from bus_add_driver+0x160/0x1e4 bus_add_driver from driver_register+0x88/0x118 driver_register from do_one_initcall+0x6c/0x334 do_one_initcall from kernel_init_freeable+0x1bc/0x220 kernel_init_freeable from kernel_init+0x18/0x12c kernel_init from ret_from_fork+0x14/0x2c Fixes: 3d3f8b1f8b62 ("drm/bridge: make bridge registration independent of drm flow") Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Reviewed-by: Stephen Boyd <swboyd@chromium.org> Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com> Patchwork: https://patchwork.freedesktop.org/patch/481778/ Link: https://lore.kernel.org/r/20220411234953.2425280-1-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
2022-04-11 23:49:53 +00:00
drm_bridge_add(bridge);
rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (rc) {
DRM_ERROR("failed to attach bridge, rc=%d\n", rc);
drm/msm: properly add and remove internal bridges Add calls to drm_bridge_add()/drm_bridge_remove() DRM bridges created by the driver. This fixes the following warning. WARNING: CPU: 0 PID: 1 at kernel/locking/mutex.c:579 __mutex_lock+0x840/0x9f4 DEBUG_LOCKS_WARN_ON(lock->magic != lock) Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.18.0-rc1-00002-g3054695a0d27-dirty #55 Hardware name: Generic DT based system unwind_backtrace from show_stack+0x10/0x14 show_stack from dump_stack_lvl+0x58/0x70 dump_stack_lvl from __warn+0xc8/0x1e8 __warn from warn_slowpath_fmt+0x78/0xa8 warn_slowpath_fmt from __mutex_lock+0x840/0x9f4 __mutex_lock from mutex_lock_nested+0x1c/0x24 mutex_lock_nested from drm_bridge_hpd_enable+0x2c/0x84 drm_bridge_hpd_enable from msm_hdmi_modeset_init+0xc0/0x21c msm_hdmi_modeset_init from mdp4_kms_init+0x53c/0x90c mdp4_kms_init from msm_drm_bind+0x514/0x698 msm_drm_bind from try_to_bring_up_aggregate_device+0x160/0x1bc try_to_bring_up_aggregate_device from component_master_add_with_match+0xc4/0xf8 component_master_add_with_match from msm_pdev_probe+0x274/0x350 msm_pdev_probe from platform_probe+0x5c/0xbc platform_probe from really_probe.part.0+0x9c/0x290 really_probe.part.0 from __driver_probe_device+0xa8/0x13c __driver_probe_device from driver_probe_device+0x34/0x10c driver_probe_device from __driver_attach+0xbc/0x178 __driver_attach from bus_for_each_dev+0x74/0xc0 bus_for_each_dev from bus_add_driver+0x160/0x1e4 bus_add_driver from driver_register+0x88/0x118 driver_register from do_one_initcall+0x6c/0x334 do_one_initcall from kernel_init_freeable+0x1bc/0x220 kernel_init_freeable from kernel_init+0x18/0x12c kernel_init from ret_from_fork+0x14/0x2c Fixes: 3d3f8b1f8b62 ("drm/bridge: make bridge registration independent of drm flow") Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Reviewed-by: Stephen Boyd <swboyd@chromium.org> Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com> Patchwork: https://patchwork.freedesktop.org/patch/481778/ Link: https://lore.kernel.org/r/20220411234953.2425280-1-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
2022-04-11 23:49:53 +00:00
drm_bridge_remove(bridge);
return ERR_PTR(rc);
}
if (dp_display->next_bridge) {
rc = drm_bridge_attach(dp_display->encoder,
dp_display->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (rc < 0) {
DRM_ERROR("failed to attach panel bridge: %d\n", rc);
drm_bridge_remove(bridge);
return ERR_PTR(rc);
}
}
return bridge;
}
/* connector initialization */
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display)
{
struct drm_connector *connector = NULL;
connector = drm_bridge_connector_init(dp_display->drm_dev, dp_display->encoder);
if (IS_ERR(connector))
return connector;
drm_connector_attach_encoder(connector, dp_display->encoder);
return connector;
}