Created
July 21, 2026 17:08
-
-
Save john-tornblom/0d5fcd4da4bce432a65123a5251934ec to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- a/drivers/ps5/hdmi.c 2026-07-16 16:29:55.397400541 +0200 | |
| +++ b/drivers/ps5/hdmi.c 2026-07-16 16:35:02.223150675 +0200 | |
| @@ -4,6 +4,7 @@ | |
| #include <linux/module.h> | |
| #include <linux/ps5.h> | |
| +#include <linux/workqueue.h> | |
| #include <drm/drm_edid.h> | |
| #define HDMI_IC_TYPE_FLAVA3 2 | |
| @@ -108,6 +109,16 @@ | |
| static u8 dp_polarity; | |
| static u8 dp_ch_swap; | |
| +/* | |
| + * Last output config successfully applied by the DRM/DC commit path. Cached | |
| + * here so it can be replayed on a hotplug reconnect, where DC performs no | |
| + * modeset (the internal APU->converter DP link never drops) and therefore | |
| + * never re-runs the converter bring-up itself. | |
| + */ | |
| +static struct drm_display_mode hdmi_cached_mode; | |
| +static bool hdmi_cached_mode_valid; | |
| +static int hdmi_cached_channels; | |
| + | |
| static void i2c_init(u8 code) | |
| { | |
| i2c_ctx.msg_cur = i2c_ctx.msg_buf; | |
| @@ -1107,6 +1118,9 @@ | |
| void sceHdmiSetVideoConfig(const struct drm_display_mode *mode) | |
| { | |
| + hdmi_cached_mode = *mode; | |
| + hdmi_cached_mode_valid = true; | |
| + | |
| if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) { | |
| setHdmiVideoConfigFlava3(mode); | |
| } else { | |
| @@ -1129,6 +1143,8 @@ | |
| void sceHdmiSetAudioConfig(int channels) | |
| { | |
| + hdmi_cached_channels = channels; | |
| + | |
| if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) { | |
| sceHdmiSetAudioConfigFlava3(channels); | |
| } else { | |
| @@ -1227,6 +1243,38 @@ | |
| edid[0x7f] = -sum & 0xff; | |
| } | |
| +/* | |
| + * Replay the full converter bring-up for the last-applied mode. | |
| + * | |
| + * On an input-source swap or replug the sink disappears and comes back, so the | |
| + * converter's downstream HDMI transmitter is left cold. The internal | |
| + * APU->converter DP link never drops, so DC sees no change, performs no | |
| + * modeset, and never re-runs the init sequence from amdgpu_dm_commit_streams()/ | |
| + * amdgpu_dm_atomic_commit_tail(). We reproduce that sequence here. | |
| + * | |
| + * Deferred to a workqueue: the sequence sleeps (icc_query() round-trips plus | |
| + * hundreds of ms of i2c_delay()), and the ICC notification callback may run in | |
| + * a context that cannot. | |
| + */ | |
| +static void hdmi_replay_work_fn(struct work_struct *work) | |
| +{ | |
| + if (!hdmi_cached_mode_valid) { | |
| + /* | |
| + * Nothing has been applied yet (e.g. the boot-time EDID | |
| + * notification, which arrives before the first DC commit). The | |
| + * normal DC path will perform the initial bring-up. | |
| + */ | |
| + return; | |
| + } | |
| + | |
| + sceHdmiInitVideoConfig(); | |
| + sceHdmiSetVideoConfig(&hdmi_cached_mode); | |
| + sceHdmiDeviceSetVideoMute(0); | |
| + sceHdmiSetAudioConfig(hdmi_cached_channels); | |
| + sceHdmiSetAudioMute(0); | |
| +} | |
| +static DECLARE_WORK(hdmi_replay_work, hdmi_replay_work_fn); | |
| + | |
| void hdmi_notification_handler(struct icc_msg *msg) | |
| { | |
| if (msg->data[1] == 0x02) { | |
| @@ -1234,6 +1282,14 @@ | |
| real_edid = drm_edid_alloc(&msg->data[4], *(u16 *)&msg->data[2]); | |
| pr_info("got real edid\n"); | |
| sceHdmiOutputMode(); | |
| + | |
| + /* | |
| + * Sink (re)appeared. If this is a reconnect rather than | |
| + * the initial boot detection, the converter is cold and | |
| + * DC will not re-init it for us, so replay the last | |
| + * applied config to restore output. | |
| + */ | |
| + schedule_work(&hdmi_replay_work); | |
| } | |
| } | |
| EXPORT_SYMBOL(hdmi_notification_handler); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment