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