static enum drm_connector_status
zynqmp_dp_connector_detect(struct drm_connector *connector, bool force)
{
if () {
....
return connector_status_connected;
}
disconnected:
return connector_status_disconnected;
}
bool drm_helper_hpd_irq_event(struct drm_device *dev)
{
...
connector->status = drm_helper_probe_detect(connector, NULL, false);
....
if (changed)
drm_kms_helper_hotplug_event(dev);
return changed;
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);
void drm_kms_helper_hotplug_event(struct drm_device *dev)
{
/* send a uevent + call fbdev */
drm_sysfs_hotplug_event(dev);
if (dev->mode_config.funcs->output_poll_changed)
dev->mode_config.funcs->output_poll_changed(dev);
}
EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
https://github.com/Xilinx/meta-petalinux/blob/4e84d60865bf505d1ea425f3e5c84e37bf8f7455/recipes-core/udev/eudev/monitor-hotplug.sh
#!/bin/sh
#Adapt this script to your needs.
DEVICES=$(find /sys/class/drm/*/status)
#inspired by /etc/acpd/lid.sh and the function it sources
displaynum=`ls /tmp/.X11-unix/* | sed s#/tmp/.X11-unix/X##`
display=":$displaynum.0"
export DISPLAY=":$displaynum.0"
# from https://wiki.archlinux.org/index.php/Acpid#Laptop_Monitor_Power_Off
export XAUTHORITY=$(ps -C Xorg -f --no-header | sed -n 's/.*-auth //; s/ -[^ ].*//; p')
for i in /sys/class/drm/*/*/status ; do
status=$(cat $i);
connector=${i%/status*};
connector=${connector#*-};
if [ "$status" == "disconnected" ];
then
xset dpms force off
elif [ "$status" == "connected" ];
then
xset dpms force on
if [ "$(xrandr | grep '\*')" = "" ];
then
xrandr --output $connector --auto
fi
fi
done
static void
zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
...
pm_runtime_get_sync(disp->dev);
ret = zynqmp_disp_clk_enable(disp->pclk, &disp->pclk_en);
if (ret) {
dev_err(disp->dev, "failed to enable a pixel clock\n");
return;
}
...
zynqmp_disp_enable(disp);
...
}
static void
zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
...
zynqmp_disp_clk_disable(disp->pclk, &disp->pclk_en);
zynqmp_disp_plane_disable(crtc->primary);
zynqmp_disp_disable(disp, true);
pm_runtime_put_sync(disp->dev);
}
static void zynqmp_dp_encoder_enable(struct drm_encoder *encoder)
{
...
pm_runtime_get_sync(dp->dev);
dp->enabled = true;
zynqmp_dp_init_aux(dp);
...
if (zynqmp_disp_aud_enabled(dp->dpsub->disp))
zynqmp_dp_write(iomem, ZYNQMP_DP_TX_AUDIO_CONTROL, 1);
zynqmp_dp_write(iomem, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0);
if (dp->status == connector_status_connected) {
for (i = 0; i < 3; i++) {
ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER,
DP_SET_POWER_D0);
if (ret == 1)
break;
usleep_range(300, 500);
}
/* Some monitors take time to wake up properly */
msleep(zynqmp_dp_power_on_delay_ms);
}
...
zynqmp_dp_write(iomem, ZYNQMP_DP_TX_SW_RESET,
ZYNQMP_DP_TX_SW_RESET_ALL);
zynqmp_dp_write(iomem, ZYNQMP_DP_TX_ENABLE_MAIN_STREAM, 1);
}
static void zynqmp_dp_encoder_disable(struct drm_encoder *encoder)
{
...
zynqmp_dp_write(iomem, ZYNQMP_DP_TX_ENABLE_MAIN_STREAM, 0);
drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
zynqmp_dp_write(iomem, ZYNQMP_DP_TX_PHY_POWER_DOWN,
ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL);
if (zynqmp_disp_aud_enabled(dp->dpsub->disp))
zynqmp_dp_write(iomem, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
pm_runtime_put_sync(dp->dev);
}
static int __maybe_unused xlnx_pm_suspend(struct device *dev)
{
struct xlnx_drm *xlnx_drm = dev_get_drvdata(dev);
struct drm_device *drm = xlnx_drm->drm;
drm_kms_helper_poll_disable(drm);
xlnx_drm->suspend_state = drm_atomic_helper_suspend(drm);
if (IS_ERR(xlnx_drm->suspend_state)) {
drm_kms_helper_poll_enable(drm);
return PTR_ERR(xlnx_drm->suspend_state);
}
return 0;
}
static int __maybe_unused xlnx_pm_resume(struct device *dev)
{
struct xlnx_drm *xlnx_drm = dev_get_drvdata(dev);
struct drm_device *drm = xlnx_drm->drm;
drm_atomic_helper_resume(drm, xlnx_drm->suspend_state);
drm_kms_helper_poll_enable(drm);
return 0;
}