xref: /linux/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c (revision 86e2d052c2320bf12571a5d96b16c2745e1cfc5e)
10ab6ea26SBaihan Li // SPDX-License-Identifier: GPL-2.0-or-later
20ab6ea26SBaihan Li // Copyright (c) 2024 Hisilicon Limited.
30ab6ea26SBaihan Li 
40ab6ea26SBaihan Li #include <linux/io.h>
50ab6ea26SBaihan Li 
60ab6ea26SBaihan Li #include <drm/drm_probe_helper.h>
70ab6ea26SBaihan Li #include <drm/drm_simple_kms_helper.h>
80ab6ea26SBaihan Li #include <drm/drm_atomic_helper.h>
90ab6ea26SBaihan Li #include <drm/drm_modes.h>
100ab6ea26SBaihan Li #include <drm/drm_drv.h>
110ab6ea26SBaihan Li #include <drm/drm_edid.h>
120ab6ea26SBaihan Li 
130ab6ea26SBaihan Li #include "hibmc_drm_drv.h"
140ab6ea26SBaihan Li #include "dp/dp_hw.h"
150ab6ea26SBaihan Li 
16*3c7623fbSBaihan Li #define DP_MASKED_SINK_HPD_PLUG_INT	BIT(2)
17*3c7623fbSBaihan Li 
180ab6ea26SBaihan Li static int hibmc_dp_connector_get_modes(struct drm_connector *connector)
190ab6ea26SBaihan Li {
20bd1c9358SBaihan Li 	const struct drm_edid *drm_edid;
210ab6ea26SBaihan Li 	int count;
220ab6ea26SBaihan Li 
23bd1c9358SBaihan Li 	drm_edid = drm_edid_read(connector);
24bd1c9358SBaihan Li 
25bd1c9358SBaihan Li 	drm_edid_connector_update(connector, drm_edid);
26bd1c9358SBaihan Li 
27bd1c9358SBaihan Li 	count = drm_edid_connector_add_modes(connector);
28bd1c9358SBaihan Li 
29bd1c9358SBaihan Li 	drm_edid_free(drm_edid);
300ab6ea26SBaihan Li 
310ab6ea26SBaihan Li 	return count;
320ab6ea26SBaihan Li }
330ab6ea26SBaihan Li 
34*3c7623fbSBaihan Li static int hibmc_dp_detect(struct drm_connector *connector,
35*3c7623fbSBaihan Li 			   struct drm_modeset_acquire_ctx *ctx, bool force)
36*3c7623fbSBaihan Li {
37*3c7623fbSBaihan Li 	mdelay(200);
38*3c7623fbSBaihan Li 
39*3c7623fbSBaihan Li 	return drm_connector_helper_detect_from_ddc(connector, ctx, force);
40*3c7623fbSBaihan Li }
41*3c7623fbSBaihan Li 
420ab6ea26SBaihan Li static const struct drm_connector_helper_funcs hibmc_dp_conn_helper_funcs = {
430ab6ea26SBaihan Li 	.get_modes = hibmc_dp_connector_get_modes,
44*3c7623fbSBaihan Li 	.detect_ctx = hibmc_dp_detect,
450ab6ea26SBaihan Li };
460ab6ea26SBaihan Li 
47bd1c9358SBaihan Li static int hibmc_dp_late_register(struct drm_connector *connector)
48bd1c9358SBaihan Li {
49bd1c9358SBaihan Li 	struct hibmc_dp *dp = to_hibmc_dp(connector);
50bd1c9358SBaihan Li 
51*3c7623fbSBaihan Li 	hibmc_dp_enable_int(dp);
52*3c7623fbSBaihan Li 
53bd1c9358SBaihan Li 	return drm_dp_aux_register(&dp->aux);
54bd1c9358SBaihan Li }
55bd1c9358SBaihan Li 
56bd1c9358SBaihan Li static void hibmc_dp_early_unregister(struct drm_connector *connector)
57bd1c9358SBaihan Li {
58bd1c9358SBaihan Li 	struct hibmc_dp *dp = to_hibmc_dp(connector);
59bd1c9358SBaihan Li 
60bd1c9358SBaihan Li 	drm_dp_aux_unregister(&dp->aux);
61*3c7623fbSBaihan Li 
62*3c7623fbSBaihan Li 	hibmc_dp_disable_int(dp);
63bd1c9358SBaihan Li }
64bd1c9358SBaihan Li 
650ab6ea26SBaihan Li static const struct drm_connector_funcs hibmc_dp_conn_funcs = {
660ab6ea26SBaihan Li 	.reset = drm_atomic_helper_connector_reset,
670ab6ea26SBaihan Li 	.fill_modes = drm_helper_probe_single_connector_modes,
680ab6ea26SBaihan Li 	.destroy = drm_connector_cleanup,
690ab6ea26SBaihan Li 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
700ab6ea26SBaihan Li 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
71bd1c9358SBaihan Li 	.late_register = hibmc_dp_late_register,
72bd1c9358SBaihan Li 	.early_unregister = hibmc_dp_early_unregister,
732f618261SBaihan Li 	.debugfs_init = hibmc_debugfs_init,
740ab6ea26SBaihan Li };
750ab6ea26SBaihan Li 
760ab6ea26SBaihan Li static inline int hibmc_dp_prepare(struct hibmc_dp *dp, struct drm_display_mode *mode)
770ab6ea26SBaihan Li {
780ab6ea26SBaihan Li 	int ret;
790ab6ea26SBaihan Li 
800ab6ea26SBaihan Li 	hibmc_dp_display_en(dp, false);
810ab6ea26SBaihan Li 
820ab6ea26SBaihan Li 	ret = hibmc_dp_mode_set(dp, mode);
830ab6ea26SBaihan Li 	if (ret)
840ab6ea26SBaihan Li 		drm_err(dp->drm_dev, "hibmc dp mode set failed: %d\n", ret);
850ab6ea26SBaihan Li 
860ab6ea26SBaihan Li 	return ret;
870ab6ea26SBaihan Li }
880ab6ea26SBaihan Li 
890ab6ea26SBaihan Li static void hibmc_dp_encoder_enable(struct drm_encoder *drm_encoder,
900ab6ea26SBaihan Li 				    struct drm_atomic_state *state)
910ab6ea26SBaihan Li {
920ab6ea26SBaihan Li 	struct hibmc_dp *dp = container_of(drm_encoder, struct hibmc_dp, encoder);
930ab6ea26SBaihan Li 	struct drm_display_mode *mode = &drm_encoder->crtc->state->mode;
940ab6ea26SBaihan Li 
950ab6ea26SBaihan Li 	if (hibmc_dp_prepare(dp, mode))
960ab6ea26SBaihan Li 		return;
970ab6ea26SBaihan Li 
980ab6ea26SBaihan Li 	hibmc_dp_display_en(dp, true);
990ab6ea26SBaihan Li }
1000ab6ea26SBaihan Li 
1010ab6ea26SBaihan Li static void hibmc_dp_encoder_disable(struct drm_encoder *drm_encoder,
1020ab6ea26SBaihan Li 				     struct drm_atomic_state *state)
1030ab6ea26SBaihan Li {
1040ab6ea26SBaihan Li 	struct hibmc_dp *dp = container_of(drm_encoder, struct hibmc_dp, encoder);
1050ab6ea26SBaihan Li 
1060ab6ea26SBaihan Li 	hibmc_dp_display_en(dp, false);
1070ab6ea26SBaihan Li }
1080ab6ea26SBaihan Li 
1090ab6ea26SBaihan Li static const struct drm_encoder_helper_funcs hibmc_dp_encoder_helper_funcs = {
1100ab6ea26SBaihan Li 	.atomic_enable = hibmc_dp_encoder_enable,
1110ab6ea26SBaihan Li 	.atomic_disable = hibmc_dp_encoder_disable,
1120ab6ea26SBaihan Li };
1130ab6ea26SBaihan Li 
114*3c7623fbSBaihan Li irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg)
115*3c7623fbSBaihan Li {
116*3c7623fbSBaihan Li 	struct drm_device *dev = (struct drm_device *)arg;
117*3c7623fbSBaihan Li 	struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
118*3c7623fbSBaihan Li 	int idx;
119*3c7623fbSBaihan Li 
120*3c7623fbSBaihan Li 	if (!drm_dev_enter(dev, &idx))
121*3c7623fbSBaihan Li 		return -ENODEV;
122*3c7623fbSBaihan Li 
123*3c7623fbSBaihan Li 	if (priv->dp.irq_status & DP_MASKED_SINK_HPD_PLUG_INT) {
124*3c7623fbSBaihan Li 		drm_dbg_dp(&priv->dev, "HPD IN isr occur!\n");
125*3c7623fbSBaihan Li 		hibmc_dp_hpd_cfg(&priv->dp);
126*3c7623fbSBaihan Li 	} else {
127*3c7623fbSBaihan Li 		drm_dbg_dp(&priv->dev, "HPD OUT isr occur!\n");
128*3c7623fbSBaihan Li 		hibmc_dp_reset_link(&priv->dp);
129*3c7623fbSBaihan Li 	}
130*3c7623fbSBaihan Li 
131*3c7623fbSBaihan Li 	if (dev->registered)
132*3c7623fbSBaihan Li 		drm_connector_helper_hpd_irq_event(&priv->dp.connector);
133*3c7623fbSBaihan Li 
134*3c7623fbSBaihan Li 	drm_dev_exit(idx);
135*3c7623fbSBaihan Li 
136*3c7623fbSBaihan Li 	return IRQ_HANDLED;
137*3c7623fbSBaihan Li }
138*3c7623fbSBaihan Li 
1390ab6ea26SBaihan Li int hibmc_dp_init(struct hibmc_drm_private *priv)
1400ab6ea26SBaihan Li {
1410ab6ea26SBaihan Li 	struct drm_device *dev = &priv->dev;
1420ab6ea26SBaihan Li 	struct drm_crtc *crtc = &priv->crtc;
1430ab6ea26SBaihan Li 	struct hibmc_dp *dp = &priv->dp;
1440ab6ea26SBaihan Li 	struct drm_connector *connector = &dp->connector;
1450ab6ea26SBaihan Li 	struct drm_encoder *encoder = &dp->encoder;
1460ab6ea26SBaihan Li 	int ret;
1470ab6ea26SBaihan Li 
1480ab6ea26SBaihan Li 	dp->mmio = priv->mmio;
1490ab6ea26SBaihan Li 	dp->drm_dev = dev;
1500ab6ea26SBaihan Li 
1510ab6ea26SBaihan Li 	ret = hibmc_dp_hw_init(&priv->dp);
1520ab6ea26SBaihan Li 	if (ret) {
1530ab6ea26SBaihan Li 		drm_err(dev, "hibmc dp hw init failed: %d\n", ret);
1540ab6ea26SBaihan Li 		return ret;
1550ab6ea26SBaihan Li 	}
1560ab6ea26SBaihan Li 
1570ab6ea26SBaihan Li 	hibmc_dp_display_en(&priv->dp, false);
1580ab6ea26SBaihan Li 
1590ab6ea26SBaihan Li 	encoder->possible_crtcs = drm_crtc_mask(crtc);
1600ab6ea26SBaihan Li 	ret = drmm_encoder_init(dev, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
1610ab6ea26SBaihan Li 	if (ret) {
1620ab6ea26SBaihan Li 		drm_err(dev, "init dp encoder failed: %d\n", ret);
1630ab6ea26SBaihan Li 		return ret;
1640ab6ea26SBaihan Li 	}
1650ab6ea26SBaihan Li 
1660ab6ea26SBaihan Li 	drm_encoder_helper_add(encoder, &hibmc_dp_encoder_helper_funcs);
1670ab6ea26SBaihan Li 
168bd1c9358SBaihan Li 	ret = drm_connector_init_with_ddc(dev, connector, &hibmc_dp_conn_funcs,
169bd1c9358SBaihan Li 					  DRM_MODE_CONNECTOR_DisplayPort, &dp->aux.ddc);
1700ab6ea26SBaihan Li 	if (ret) {
1710ab6ea26SBaihan Li 		drm_err(dev, "init dp connector failed: %d\n", ret);
1720ab6ea26SBaihan Li 		return ret;
1730ab6ea26SBaihan Li 	}
1740ab6ea26SBaihan Li 
1750ab6ea26SBaihan Li 	drm_connector_helper_add(connector, &hibmc_dp_conn_helper_funcs);
1760ab6ea26SBaihan Li 
1770ab6ea26SBaihan Li 	drm_connector_attach_encoder(connector, encoder);
1780ab6ea26SBaihan Li 
179*3c7623fbSBaihan Li 	connector->polled = DRM_CONNECTOR_POLL_HPD;
180*3c7623fbSBaihan Li 
1810ab6ea26SBaihan Li 	return 0;
1820ab6ea26SBaihan Li }
183