Skip to content

Interrupt-based HDMI Hotplug Detection #4313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 7, 2021

Conversation

mripard
Copy link
Contributor

@mripard mripard commented Apr 29, 2021

Hi,

So far the HDMI driver was relying on polling every 10s for the HDMI connector status which could lead to issues when the cable was quickly unplugged and then plugged back, or when a device like an HDMI bridge would just create a short hotplug pulse.

Here's a PR that converts that logic to rely on either the controller interrupts (for the BCM2711) or the HPD gpio interrupt (for earlier SoCs) to remove that limitation.

@6by9
Copy link
Contributor

6by9 commented Apr 29, 2021

I'll test in a moment, but looks good based on the patches.

@6by9
Copy link
Contributor

6by9 commented Apr 29, 2021

checkpatch complains on the last patch

CHECK: Blank lines aren't necessary after an open brace '{'
#69: FILE: drivers/gpu/drm/vc4/vc4_hdmi.c:2278:
+	} else if (vc4_hdmi->hpd_gpio) {
+

WARNING: Missing a blank line after declarations
#71: FILE: drivers/gpu/drm/vc4/vc4_hdmi.c:2280:
+		int irq = gpiod_to_irq(vc4_hdmi->hpd_gpio);
+		if (irq < 0)

WARNING: line length of 106 exceeds 100 columns
#76: FILE: drivers/gpu/drm/vc4/vc4_hdmi.c:2285:
+						IRQF_ONESHOT | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,

total: 0 errors, 2 warnings, 1 checks, 76 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

"[PATCH] drm/vc4: hdmi: Rely on interrupts to handle hotplug" has style problems, please review.

@6by9
Copy link
Contributor

6by9 commented Apr 29, 2021

Certainly works nicely for 2711.
Now building for 2710 to test the GPIO variant....

@pelwell
Copy link
Contributor

pelwell commented Apr 29, 2021

Are we convinced that the non-2711 version doesn't cause both the VPU and the ARM to use GPIO interrupts for the same bank?

@6by9
Copy link
Contributor

6by9 commented Apr 29, 2021

Are we convinced that the non-2711 version doesn't cause both the VPU and the ARM to use GPIO interrupts for the same bank?

Hmm, slight can of worms.

Most cases are GPIO46. 3B+ is GPIO28.

Pi1 has SD_CARD_DETECT on GPIO47, but I don't immediately see any firmware code looking at the pin_define for that.

Power low is a BANK1 input on some boards. I thought it was polled and it is, but it is using the event status flags from the GPIO block to capture brief pulses (not using the interrupt itself though).
Checking the datasheet and firmware driver, the datasheet says interrupts are generated based on when bits get set in the event detect status registers, and the firmware will be setting those even though it isn't apparently asking for the interrupt. Is that going to mean that the ARM would risk spinning on an interrupt that won't be serviced until the VPU's polling gets around to asking for the state?
When the power low signal is on the GPIO expander it's just polled, so do we lose that much if the firmware is changed to just poll internal GPIOs too? The APX803 already gives a (typical) 200ms pulse, and the temp_check thread is sleeping for 100ms between each iteration.

I'm just noting that CM3 and Pi3B (not +) have HPD on the GPIO expander, so no interrupt support there.
Is it plausible to drop back to polled if we can't register for the interrupt?

(Edited to correct pulse time. 240ms is APX803S. APX803 is now not recommended for new designs)

@pelwell
Copy link
Contributor

pelwell commented Apr 29, 2021

Is that going to mean that the ARM would risk spinning on an interrupt that won't be serviced until the VPU's polling gets around to asking for the state?

I think it's more that the ARM would see unexpected interrupts, but it would then acknowledge them - the driver doesn't keep a record of those which are expected and ignore them otherwise.

@6by9
Copy link
Contributor

6by9 commented Apr 29, 2021

I think it's more that the ARM would see unexpected interrupts, but it would then acknowledge them - the driver doesn't keep a record of those which are expected and ignore them otherwise.

I think it's going to clear those flags from the GPEDS register out from under the firmware (via bcm2835_gpio_irq_ack), so the firmware wouldn't see any low voltage events.
Otherwise the bits will still be set in GP_EDS, so the interrupt would be asserted, and they're level triggered, hence spinning.

@6by9
Copy link
Contributor

6by9 commented Apr 29, 2021

Something not quite so happy on Pi3B+. Booted OK, disconnected HDMI and splat:

[   56.420943] 8<--- cut here ---
[   56.421049] Unable to handle kernel NULL pointer dereference at virtual address 00000280
[   56.421219] pgd = 49d26c83
[   56.421292] [00000280] *pgd=00000000
[   56.421397] Internal error: Oops: 5 [#1] SMP ARM
<snip>
[   56.493983] Backtrace: 
[   56.496234] [<7f3ef084>] (vc4_hdmi_encoder_pre_crtc_configure [vc4]) from [<7f3d9438>] (vc4_crtc_atomic_enable+0x64/0x540 [vc4])
[   56.498521]  r9:81743370 r8:8365f440 r7:82f29284 r6:861fc640 r5:82f2f800 r4:834fa040
[   56.500862] [<7f3d93d4>] (vc4_crtc_atomic_enable [vc4]) from [<7f38d5e0>] (drm_atomic_helper_commit_modeset_enables+0x220/0x290 [drm_kms_helper])
[   56.503119]  r10:82f2f800 r9:81743370 r8:8365f440 r7:7f3fe118 r6:834fa040 r5:861fc640
[   56.505315]  r4:00000003
[   56.507520] [<7f38d3c0>] (drm_atomic_helper_commit_modeset_enables [drm_kms_helper]) from [<7f3e1b24>] (vc4_atomic_complete_commit+0x1e4/0x688 [vc4])
[   56.509731]  r9:81743370 r8:8365f440 r7:00000000 r6:00000000 r5:82f2f800 r4:861fc640
[   56.512019] [<7f3e1940>] (vc4_atomic_complete_commit [vc4]) from [<7f3e20bc>] (vc4_atomic_commit+0xf4/0x1c8 [vc4])
[   56.514273]  r9:81743370 r8:82f2fce8 r7:00000000 r6:82f2f800 r5:00000000 r4:861fc640
[   56.516733] [<7f3e1fc8>] (vc4_atomic_commit [vc4]) from [<7f2dea00>] (drm_atomic_commit+0x5c/0x60 [drm])
[   56.519030]  r8:00000001 r7:82fc0640 r6:82f2f800 r5:861fc640 r4:00000000 r3:7f3e1fc8
[   56.521590] [<7f2de9a4>] (drm_atomic_commit [drm]) from [<7f2f54f4>] (drm_client_modeset_commit_atomic+0x204/0x244 [drm])
[   56.523958]  r6:00000001 r5:82f2f9c0 r4:861fc640 r3:00000000
[   56.526577] [<7f2f52f0>] (drm_client_modeset_commit_atomic [drm]) from [<7f2f5624>] (drm_client_modeset_commit_locked+0x6c/0x194 [drm])
[   56.529040]  r10:80188414 r9:84d86840 r8:82f31000 r7:82f2f89c r6:82f310b4 r5:82f31018
[   56.531499]  r4:82f2f800
[   56.534177] [<7f2f55b8>] (drm_client_modeset_commit_locked [drm]) from [<7f2f5780>] (drm_client_modeset_commit+0x34/0x50 [drm])
[   56.536704]  r8:82f31500 r7:82f2f89c r6:82f310b4 r5:82f2f800 r4:82f31000
[   56.539411] [<7f2f574c>] (drm_client_modeset_commit [drm]) from [<7f396388>] (__drm_fb_helper_restore_fbdev_mode_unlocked+0x68/0xc4 [drm_kms_helper])
[   56.542016]  r5:00000000 r4:82f31000
[   56.544700] [<7f396320>] (__drm_fb_helper_restore_fbdev_mode_unlocked [drm_kms_helper]) from [<7f39649c>] (drm_fb_helper_set_par+0x48/0x74 [drm_kms_helper])
[   56.547395]  r6:82f310b4 r5:00000000 r4:00000000 r3:00000000
[   56.550192] [<7f396454>] (drm_fb_helper_set_par [drm_kms_helper]) from [<7f396578>] (drm_fb_helper_hotplug_event.part.5+0xb0/0xc8 [drm_kms_helper])
[   56.552964]  r4:82f31000 r3:98b07eb0
[   56.555827] [<7f3964c8>] (drm_fb_helper_hotplug_event.part.5 [drm_kms_helper]) from [<7f39663c>] (drm_fbdev_client_hotplug+0x4c/0x180 [drm_kms_helper])
[   56.558692]  r6:82f2f8b0 r5:82f2f800 r4:82f31000 r3:00000001
[   56.561722] [<7f3965f0>] (drm_fbdev_client_hotplug [drm_kms_helper]) from [<7f2f4a34>] (drm_client_dev_hotplug+0x7c/0xbc [drm])
[   56.564655]  r7:82f2f89c r6:82f2f8b0 r5:82f2f800 r4:82f31000
[   56.567754] [<7f2f49b8>] (drm_client_dev_hotplug [drm]) from [<7f382a44>] (drm_kms_helper_hotplug_event+0x3c/0x40 [drm_kms_helper])
[   56.570746]  r7:00000000 r6:82f31500 r5:84d86864 r4:82f2f800
[   56.573825] [<7f382a08>] (drm_kms_helper_hotplug_event [drm_kms_helper]) from [<7f3e5a9c>] (vc4_hdmi_hpd_irq_thread+0x24/0x2c [vc4])
[   56.576883]  r4:84d86840 r3:7f3e5a78
[   56.579960] [<7f3e5a78>] (vc4_hdmi_hpd_irq_thread [vc4]) from [<80188440>] (irq_thread_fn+0x2c/0x6c)
[   56.583050] [<80188414>] (irq_thread_fn) from [<801881e4>] (irq_thread+0x140/0x238)
<snip>
[   56.623573] ---[ end trace 8f2ba2b01df2a37d ]---
[   56.626814] genirq: exiting task "irq/200-vc4 hdm" (271) is an active IRQ thread (irq 200)

It seems repeatable too.
DRM logging immediately before was

[   30.305771] vc4-drm soc:gpu: [drm:drm_fb_helper_hotplug_event.part.5 [drm_kms_helper]] 
[   30.306124] [drm:drm_client_modeset_probe [drm]] 
[   30.306306] [drm:drm_helper_probe_single_connector_modes [drm_kms_helper]] [CONNECTOR:32:HDMI-A-1]
[   30.308521] [drm:drm_helper_probe_single_connector_modes [drm_kms_helper]] [CONNECTOR:32:HDMI-A-1] status updated from connected to disconnected
[   30.308690] [drm:drm_helper_probe_single_connector_modes [drm_kms_helper]] [CONNECTOR:32:HDMI-A-1] disconnected
[   30.309046] [drm:drm_connector_update_edid_property [drm]] [CONNECTOR:32:HDMI-A-1] Edid was changed.
[   30.309354] [drm:drm_connector_update_edid_property [drm]] Updating change counter to 3
[   30.309582] [drm:drm_helper_probe_single_connector_modes [drm_kms_helper]] [CONNECTOR:51:Composite-1]
[   30.309817] [drm:drm_helper_probe_single_connector_modes [drm_kms_helper]] [CONNECTOR:51:Composite-1] probed modes :
[   30.310132] [drm:drm_mode_debug_printmodeline [drm]] Modeline "720x480": 63 13500 720 734 798 858 480 483 486 502 0x40 0x10
[   30.310436] [drm:drm_client_modeset_probe [drm]] connector 32 enabled? no
[   30.310738] [drm:drm_client_modeset_probe [drm]] connector 51 enabled? no
[   30.311061] [drm:drm_client_modeset_probe [drm]] Not using firmware configuration
[   30.311372] [drm:drm_client_modeset_probe [drm]] looking for cmdline mode on connector 51
[   30.311676] [drm:drm_client_modeset_probe [drm]] looking for preferred mode on connector 51 0
[   30.311978] [drm:drm_client_modeset_probe [drm]] found mode 720x480
[   30.312282] [drm:drm_client_modeset_probe [drm]] picking CRTCs for 1366x768 config
[   30.312595] [drm:drm_client_modeset_probe [drm]] desired mode 720x480 set on crtc 85 (0,0)
[   30.312924] [drm:drm_atomic_state_init [drm]] Allocated atomic state 386f9ee8
[   30.313239] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:58:plane-0] 7e55fef0 state to 386f9ee8
[   30.313549] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:65:plane-1] 6b0f9608 state to 386f9ee8
[   30.313860] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:72:plane-2] afcada19 state to 386f9ee8
[   30.314175] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:79:plane-3] dfd3260a state to 386f9ee8
[   30.314486] [drm:drm_atomic_get_crtc_state [drm]] Added [CRTC:85:crtc-3] 75b0a6f2 state to 386f9ee8
[   30.314794] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:86:plane-4] a34b714a state to 386f9ee8
[   30.315101] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:86:plane-4] state a34b714a
[   30.315409] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:92:plane-5] d9ab89f8 state to 386f9ee8
[   30.315714] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:92:plane-5] state d9ab89f8
[   30.316151] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:98:plane-6] e1630384 state to 386f9ee8
[   30.316473] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:98:plane-6] state e1630384
[   30.316810] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:104:plane-7] 46671841 state to 386f9ee8
[   30.317135] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:104:plane-7] state 46671841
[   30.317453] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:110:plane-8] 44afe209 state to 386f9ee8
[   30.317768] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:110:plane-8] state 44afe209
[   30.318092] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:116:plane-9] 36072862 state to 386f9ee8
[   30.318417] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:116:plane-9] state 36072862
[   30.318750] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:122:plane-10] 12c4b5e0 state to 386f9ee8
[   30.319077] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:122:plane-10] state 12c4b5e0
[   30.319402] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:128:plane-11] 21cabd83 state to 386f9ee8
[   30.319716] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:128:plane-11] state 21cabd83
[   30.320049] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:134:plane-12] 639d70f0 state to 386f9ee8
[   30.320373] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:134:plane-12] state 639d70f0
[   30.320706] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:140:plane-13] 04ae71f6 state to 386f9ee8
[   30.321030] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:140:plane-13] state 04ae71f6
[   30.321360] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:146:plane-14] 1783f23d state to 386f9ee8
[   30.321684] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:146:plane-14] state 1783f23d
[   30.322013] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:152:plane-15] 13620109 state to 386f9ee8
[   30.322332] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:152:plane-15] state 13620109
[   30.322662] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:158:plane-16] 2802e9ec state to 386f9ee8
[   30.322987] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:158:plane-16] state 2802e9ec
[   30.323348] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:164:plane-17] deabecb7 state to 386f9ee8
[   30.323814] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:164:plane-17] state deabecb7
[   30.324300] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:170:plane-18] 4728c38f state to 386f9ee8
[   30.324659] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:170:plane-18] state 4728c38f
[   30.325033] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:176:plane-19] 22024be9 state to 386f9ee8
[   30.325353] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:176:plane-19] state 22024be9
[   30.325693] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:182:plane-20] 7251088e state to 386f9ee8
[   30.326097] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:182:plane-20] state 7251088e
[   30.326423] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:188:plane-21] 59cff5f8 state to 386f9ee8
[   30.326768] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:188:plane-21] state 59cff5f8
[   30.327091] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:194:plane-22] 15ba17f3 state to 386f9ee8
[   30.327411] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:194:plane-22] state 15ba17f3
[   30.327729] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:200:plane-23] b0a4e28e state to 386f9ee8
[   30.328040] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:200:plane-23] state b0a4e28e
[   30.328371] [drm:drm_atomic_get_crtc_state [drm]] Added [CRTC:64:crtc-0] 20f2bdae state to 386f9ee8
[   30.328686] [drm:drm_atomic_set_mode_for_crtc [drm]] Set [NOMODE] for [CRTC:64:crtc-0] state 20f2bdae
[   30.329007] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:58:plane-0] state 7e55fef0
[   30.329325] [drm:drm_atomic_add_affected_connectors [drm]] Adding all current connectors for [CRTC:64:crtc-0] to 386f9ee8
[   30.329664] [drm:drm_atomic_get_crtc_state [drm]] Added [CRTC:71:crtc-1] 08a47067 state to 386f9ee8
[   30.329978] [drm:drm_atomic_set_mode_for_crtc [drm]] Set [NOMODE] for [CRTC:71:crtc-1] state 08a47067
[   30.330298] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:65:plane-1] state 6b0f9608
[   30.330613] [drm:drm_atomic_add_affected_connectors [drm]] Adding all current connectors for [CRTC:71:crtc-1] to 386f9ee8
[   30.330953] [drm:drm_atomic_get_crtc_state [drm]] Added [CRTC:78:crtc-2] f0da0d08 state to 386f9ee8
[   30.331297] [drm:drm_atomic_set_mode_for_crtc [drm]] Set [NOMODE] for [CRTC:78:crtc-2] state f0da0d08
[   30.331627] [drm:drm_atomic_set_fb_for_plane [drm]] Set [NOFB] for [PLANE:72:plane-2] state afcada19
[   30.331965] [drm:drm_atomic_add_affected_connectors [drm]] Adding all current connectors for [CRTC:78:crtc-2] to 386f9ee8
[   30.332340] [drm:drm_atomic_set_mode_for_crtc [drm]] Set [MODE:720x480] for [CRTC:85:crtc-3] state 75b0a6f2
[   30.332667] [drm:drm_atomic_set_fb_for_plane [drm]] Set [FB:207] for [PLANE:79:plane-3] state dfd3260a
[   30.332990] [drm:drm_atomic_add_affected_connectors [drm]] Adding all current connectors for [CRTC:85:crtc-3] to 386f9ee8
[   30.333318] [drm:drm_atomic_get_connector_state [drm]] Added [CONNECTOR:32:HDMI-A-1] 6da7bde3 state to 386f9ee8
[   30.333655] [drm:drm_atomic_set_crtc_for_connector [drm]] Link [CONNECTOR:32:HDMI-A-1] state 6da7bde3 to [NOCRTC]
[   30.333981] [drm:drm_atomic_get_connector_state [drm]] Added [CONNECTOR:51:Composite-1] 1e765c44 state to 386f9ee8
[   30.334301] [drm:drm_atomic_set_crtc_for_connector [drm]] Link [CONNECTOR:51:Composite-1] state 1e765c44 to [CRTC:85:crtc-3]
[   30.334622] [drm:drm_atomic_check_only [drm]] checking 386f9ee8
[   30.334973] [drm:drm_atomic_get_private_obj_state [drm]] Added new private object 1825b400 state fb8c3dea to 386f9ee8
[   30.335169] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CRTC:85:crtc-3] mode changed
[   30.335368] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Updating routing for [CONNECTOR:32:HDMI-A-1]
[   30.335526] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Disabling [CONNECTOR:32:HDMI-A-1]
[   30.335728] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Updating routing for [CONNECTOR:51:Composite-1]
[   30.335905] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CONNECTOR:51:Composite-1] using [ENCODER:50:TV-50] on [CRTC:85:crtc-3]
[   30.336067] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CRTC:85:crtc-3] needs all connectors, enable: y, active: y
[   30.336423] [drm:drm_atomic_add_affected_connectors [drm]] Adding all current connectors for [CRTC:85:crtc-3] to 386f9ee8
[   30.336775] [drm:drm_atomic_add_affected_planes [drm]] Adding all current planes for [CRTC:85:crtc-3] to 386f9ee8
[   30.337128] [drm:drm_atomic_add_encoder_bridges [drm]] Adding all bridges for [encoder:31:TMDS-31] to 386f9ee8
[   30.337448] [drm:drm_atomic_add_encoder_bridges [drm]] Adding all bridges for [encoder:50:TV-50] to 386f9ee8
[   30.337862] [drm:drm_atomic_get_private_obj_state [drm]] Added new private object 9d1b5b47 state 2e02d318 to 386f9ee8
[   30.338201] [drm:drm_atomic_commit [drm]] committing 386f9ee8
[   30.338542] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] disabling [ENCODER:31:TMDS-31]
[   30.338710] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] disabling [CRTC:85:crtc-3]
[   30.359163] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] modeset on [ENCODER:50:TV-50]
[   30.359352] [drm:drm_atomic_helper_commit_modeset_enables [drm_kms_helper]] enabling [CRTC:85:crtc-3]

I do need to find a new Pi3 to test with generally as this one is INCREDIBLY sensitive to power supply glitches/earthing changes. Boot without HDMI connected, and touching the HDMI cable from the monitor to the HDMI socket of the Pi is enough to reboot it :-(

@mripard
Copy link
Contributor Author

mripard commented Apr 29, 2021

Sorry, it looks like something went wrong during my rebase. I'll have a look tomorrow at that crash.

I have the same issue with my Pi3, I've been using my tc358743 to trigger HPD pulses without crashing it

@mripard
Copy link
Contributor Author

mripard commented Apr 29, 2021

I looked into it and for some reason the 5.10 kernel differs a bit from mainline there. I'm not sure why exactly yet, but it seems that during the atomic commit that enables back the CRTC when the display is found to be connected again the pointers we usually follow aren't set anymore, and thus we end up dereferencing null pointers. I just pushed some quick fixes that should allow you to test this.

@6by9
Copy link
Contributor

6by9 commented Apr 29, 2021

Thanks, I'll have a look in the morning.
It seems odd that 2711 is happy but 2710 isn't, but that's just the way of things sometimes.

@6by9
Copy link
Contributor

6by9 commented Apr 30, 2021

OK, so Pi3B is an issue (so CM3 will be as well) due to HPD being on the GPIO expander.
Minor diff of:

--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1392,8 +1392,9 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_crtc *crtc,
 {
        struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+       struct drm_connector *connector = &vc4_hdmi->connector;
        struct drm_connector_state *conn_state =
-               vc4_hdmi_encoder_get_connector_state(encoder, state);
+               drm_atomic_get_new_connector_state(state, connector);
 
        if (vc4_hdmi->variant->csc_setup)
                vc4_hdmi->variant->csc_setup(vc4_hdmi, conn_state, mode);
@@ -2271,8 +2272,12 @@ static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi)
        } else if (vc4_hdmi->hpd_gpio) {
 
                int irq = gpiod_to_irq(vc4_hdmi->hpd_gpio);
-               if (irq < 0)
-                       return irq;
+               if (irq < 0) {
+                       vc4_hdmi->connector.polled =
+                                       (DRM_CONNECTOR_POLL_CONNECT |
+                                        DRM_CONNECTOR_POLL_DISCONNECT);
+                       return 0;
+               }
 
                ret = devm_request_threaded_irq(dev, irq,
                                                NULL, vc4_hdmi_hpd_irq_thread,

so that we drop back to polled if we can't acquire the IRQ.

Some of my woes are probably self inflicted as I'm testing on top of the YCbCr output patches, and with 2711 gamma support thrown in. It's still blowing up for me on Pi3 with the above diff:

[   39.574394] [drm:drm_atomic_helper_commit_modeset_enables [drm_kms_helper]] enabling [CRTC:85:crtc-3]
[   39.574701] 8<--- cut here ---
[   39.574808] Unable to handle kernel NULL pointer dereference at virtual address 00000280
<snip>
[   39.671645] Backtrace: 
[   39.675758] [<7f350b68>] (vc4_hdmi_encoder_pre_crtc_enable [vc4]) from [<7f3437a4>] (vc4_crtc_atomic_enable+0x3c8/0x54c [vc4])
[   39.679791]  r6:0016f002 r5:00168000 r4:82f81040 r3:7f350b68
[   39.683952] [<7f3433dc>] (vc4_crtc_atomic_enable [vc4]) from [<7f4355e0>] (drm_atomic_helper_commit_modeset_enables+0x220/0x290 [drm_kms_helper])
[   39.688110]  r10:83403800 r9:85f47130 r8:8364b040 r7:7f368118 r6:82f81040 r5:826b3200
[   39.692273]  r4:00000003
[   39.696578] [<7f4353c0>] (drm_atomic_helper_commit_modeset_enables [drm_kms_helper]) from [<7f34bb38>] (vc4_atomic_complete_commit+0x1e4/0x688 [vc4])
[   39.700946]  r9:85f47130 r8:8364b040 r7:00000000 r6:00000000 r5:83403800 r4:826b3200
[   39.705493] [<7f34b954>] (vc4_atomic_complete_commit [vc4]) from [<7f34c0d0>] (vc4_atomic_commit+0xf4/0x1c8 [vc4])
[   39.709968]  r9:85f47130 r8:83403ce8 r7:00000000 r6:83403800 r5:00000000 r4:826b3200
[   39.714844] [<7f34bfdc>] (vc4_atomic_commit [vc4]) from [<7f3bba00>] (drm_atomic_commit+0x5c/0x60 [drm])
[   39.719450]  r8:00000001 r7:8348be40 r6:83403800 r5:826b3200 r4:00000000 r3:7f34bfdc
[   39.724591] [<7f3bb9a4>] (drm_atomic_commit [drm]) from [<7f3d24f4>] (drm_client_modeset_commit_atomic+0x204/0x244 [drm])
[   39.729326]  r6:00000001 r5:834039c0 r4:826b3200 r3:00000000
[   39.734528] [<7f3d22f0>] (drm_client_modeset_commit_atomic [drm]) from [<7f3d2624>] (drm_client_modeset_commit_locked+0x6c/0x194 [drm])
[   39.739412]  r10:834038ec r9:00000000 r8:82cdbd00 r7:8340389c r6:82cdbdb4 r5:82cdbd18
[   39.744300]  r4:83403800
[   39.749611] [<7f3d25b8>] (drm_client_modeset_commit_locked [drm]) from [<7f3d2780>] (drm_client_modeset_commit+0x34/0x50 [drm])
[   39.754617]  r8:83403800 r7:8340389c r6:82cdbdb4 r5:83403800 r4:82cdbd00
[   39.759979] [<7f3d274c>] (drm_client_modeset_commit [drm]) from [<7f43e388>] (__drm_fb_helper_restore_fbdev_mode_unlocked+0x68/0xc4 [drm_kms_helper])
[   39.765153]  r5:00000000 r4:82cdbd00
[   39.770496] [<7f43e320>] (__drm_fb_helper_restore_fbdev_mode_unlocked [drm_kms_helper]) from [<7f43e49c>] (drm_fb_helper_set_par+0x48/0x74 [drm_kms_helper])
[   39.775864]  r6:82cdbdb4 r5:00000000 r4:00000000 r3:00000000
[   39.781431] [<7f43e454>] (drm_fb_helper_set_par [drm_kms_helper]) from [<7f43e578>] (drm_fb_helper_hotplug_event.part.5+0xb0/0xc8 [drm_kms_helper])
[   39.786956]  r4:82cdbd00 r3:6f718cd2
[   39.792679] [<7f43e4c8>] (drm_fb_helper_hotplug_event.part.5 [drm_kms_helper]) from [<7f43e63c>] (drm_fbdev_client_hotplug+0x4c/0x180 [drm_kms_helper])
[   39.798399]  r6:834038b0 r5:83403800 r4:82cdbd00 r3:00000001
[   39.804444] [<7f43e5f0>] (drm_fbdev_client_hotplug [drm_kms_helper]) from [<7f3d1a34>] (drm_client_dev_hotplug+0x7c/0xbc [drm])
[   39.810283]  r7:8340389c r6:834038b0 r5:83403800 r4:82cdbd00
[   39.816477] [<7f3d19b8>] (drm_client_dev_hotplug [drm]) from [<7f42aa44>] (drm_kms_helper_hotplug_event+0x3c/0x40 [drm_kms_helper])
[   39.822454]  r7:00000001 r6:00000001 r5:83403a00 r4:83403800
[   39.828629] [<7f42aa08>] (drm_kms_helper_hotplug_event [drm_kms_helper]) from [<7f42ae9c>] (output_poll_execute+0xc4/0x1c4 [drm_kms_helper])
[   39.834756]  r4:80f05008 r3:00000000
[   39.840957] [<7f42add8>] (output_poll_execute [drm_kms_helper]) from [<8013c820>] (process_one_work+0x180/0x4e0)
[   39.847209]  r10:00000000 r9:baacea05 r8:00000000 r7:baacea00 r6:baacb680 r5:83403a00
[   39.853465]  r4:8158b680
[   39.859660] [<8013c6a0>] (process_one_work) from [<8013d9d0>] (worker_thread+0x54/0x5ac)
[   39.865941]  r10:8158b680 r9:81688038 r8:80f03d00 r7:baacb698 r6:00000008 r5:8158b694
[   39.872235]  r4:baacb680
[   39.878466] [<8013d97c>] (worker_thread) from [<801436bc>] (kthread+0x13c/0x168)
[   39.884775]  r10:8168c024 r9:81523e74 r8:8158b680 r7:8013d97c r6:00000000 r5:8163e340
[   39.891082]  r4:8168c000
[   39.897331] [<80143580>] (kthread) from [<801000ec>] (ret_from_fork+0x14/0x28)

I'll clean up my tree and retest with just these patches.

@mripard
Copy link
Contributor Author

mripard commented Apr 30, 2021

The fallback on the polling looks great. If it ever causes an issue on those boards, I guess we can always try to figure out if the internal hotplug logic actually works.

The crash you have should be fixed by using the commits I pushed yesterday night

@6by9
Copy link
Contributor

6by9 commented Apr 30, 2021

The hotplug logic has worked so far, it's just a little slow to notice changes, and will certainly miss your 200ms pulse on changing the EDID of a TC358743.

I have your patches from last night, but still get encoder->crtc = NULL in vc4_hdmi_encoder_pre_crtc_enable when trying to get to the mode.

This is actually DISABLING HDMI, and ENABLING composite - they share a PV on Pi0-3. Getting the call into vc4_hdmi_encoder_pre_crtc_enable therefore seems a little odd as we are not enabling the HDMI encoder, and the HDMI encoder not being linked to a crtc would be correct (the VEC encoder will be linked to it).

[   50.432330] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CRTC:83:crtc-3] mode changed
[   50.432701] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Updating routing for [CONNECTOR:32:HDMI-A-1]
[   50.432863] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Disabling [CONNECTOR:32:HDMI-A-1]
[   50.433081] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Updating routing for [CONNECTOR:49:Composite-1]
[   50.433439] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CONNECTOR:49:Composite-1] using [ENCODER:48:TV-48] on [CRTC:83:crtc-3]
[   50.433659] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CRTC:83:crtc-3] needs all connectors, enable: y, active: y
[   50.434072] [drm:drm_atomic_add_affected_connectors [drm]] Adding all current connectors for [CRTC:83:crtc-3] to c1d859de
[   50.434539] [drm:drm_atomic_add_affected_planes [drm]] Adding all current planes for [CRTC:83:crtc-3] to c1d859de
[   50.435098] [drm:drm_atomic_add_encoder_bridges [drm]] Adding all bridges for [encoder:31:TMDS-31] to c1d859de
[   50.435706] [drm:drm_atomic_add_encoder_bridges [drm]] Adding all bridges for [encoder:48:TV-48] to c1d859de
[   50.436648] [drm:drm_atomic_get_private_obj_state [drm]] Added new private object e7c36516 state 8151f951 to c1d859de
[   50.437179] [drm:drm_atomic_commit [drm]] committing c1d859de
[   50.437532] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] disabling [ENCODER:31:TMDS-31]
[   50.437786] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] disabling [CRTC:83:crtc-3]
[   50.458382] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] modeset on [ENCODER:48:TV-48]
[   50.458597] [drm:drm_atomic_helper_commit_modeset_enables [drm_kms_helper]] enabling [CRTC:83:crtc-3]

I suspect that this path has been wrong for a while, but we're only just noticing it.

@mripard
Copy link
Contributor Author

mripard commented Apr 30, 2021

The hotplug logic has worked so far, it's just a little slow to notice changes, and will certainly miss your 200ms pulse on changing the EDID of a TC358743.

You mean with boards that would rely on polling, or on the 3B+ or 4?

I have your patches from last night, but still get encoder->crtc = NULL in vc4_hdmi_encoder_pre_crtc_enable when trying to get to the mode.

This is actually DISABLING HDMI, and ENABLING composite - they share a PV on Pi0-3. Getting the call into vc4_hdmi_encoder_pre_crtc_enable therefore seems a little odd as we are not enabling the HDMI encoder, and the HDMI encoder not being linked to a crtc would be correct (the VEC encoder will be linked to it).

[   50.432330] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CRTC:83:crtc-3] mode changed
[   50.432701] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Updating routing for [CONNECTOR:32:HDMI-A-1]
[   50.432863] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Disabling [CONNECTOR:32:HDMI-A-1]
[   50.433081] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Updating routing for [CONNECTOR:49:Composite-1]
[   50.433439] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CONNECTOR:49:Composite-1] using [ENCODER:48:TV-48] on [CRTC:83:crtc-3]
[   50.433659] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CRTC:83:crtc-3] needs all connectors, enable: y, active: y
[   50.434072] [drm:drm_atomic_add_affected_connectors [drm]] Adding all current connectors for [CRTC:83:crtc-3] to c1d859de
[   50.434539] [drm:drm_atomic_add_affected_planes [drm]] Adding all current planes for [CRTC:83:crtc-3] to c1d859de
[   50.435098] [drm:drm_atomic_add_encoder_bridges [drm]] Adding all bridges for [encoder:31:TMDS-31] to c1d859de
[   50.435706] [drm:drm_atomic_add_encoder_bridges [drm]] Adding all bridges for [encoder:48:TV-48] to c1d859de
[   50.436648] [drm:drm_atomic_get_private_obj_state [drm]] Added new private object e7c36516 state 8151f951 to c1d859de
[   50.437179] [drm:drm_atomic_commit [drm]] committing c1d859de
[   50.437532] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] disabling [ENCODER:31:TMDS-31]
[   50.437786] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] disabling [CRTC:83:crtc-3]
[   50.458382] [drm:drm_atomic_helper_commit_modeset_disables [drm_kms_helper]] modeset on [ENCODER:48:TV-48]
[   50.458597] [drm:drm_atomic_helper_commit_modeset_enables [drm_kms_helper]] enabling [CRTC:83:crtc-3]

I suspect that this path has been wrong for a while, but we're only just noticing it.

That's a good lead, I'll look into it, thanks!

@mripard
Copy link
Contributor Author

mripard commented Apr 30, 2021

The issue is with 3cf3d39 that has been merged in the 5.10 branch but not in mainline.

The issue it was trying to work around is that at boot, the entities don't have a state yet so one cannot rely on the connector->state to get back the encoder, and then disable it to prevent the stuck pixel. However the code relies on the 1:1 mapping of the pixelvalve and encoders that we have on the RPi4, and here that assumption is broken.

I'll try to see if testing for connector->state and then using the old logic if it's !NULL would work to fix this

@6by9
Copy link
Contributor

6by9 commented Apr 30, 2021

You mean with boards that would rely on polling, or on the 3B+ or 4?

Having to poll on 3B and CM3 will mean we miss short pulses. All other platforms can be interrupt driven, so should be responsive.
When you referred to

figure out if the internal hotplug logic actually works.

I'm assuming you meant the polling logic within the core.

My issues on 3B+ may be a partial red herring. This board is seemingly unhappy with hotplugging HDMI at all, and will easily reboot on me.
3B (where we're polling) is working OK
2B isn't working - whilst I can see the GPIO status change (GPIO46), I don't appear to get any interrupts, and proc/interrupts doesn't register any as having occurred. I wonder if anyone has actually tried using BANK1 GPIO interrupts before.

Can I suggest that we split this PR to only deal with 2711, and we'll sort the GPIO path out later?

@mripard
Copy link
Contributor Author

mripard commented Apr 30, 2021

You mean with boards that would rely on polling, or on the 3B+ or 4?

Having to poll on 3B and CM3 will mean we miss short pulses. All other platforms can be interrupt driven, so should be responsive.
When you referred to

figure out if the internal hotplug logic actually works.

I'm assuming you meant the polling logic within the core.

No, sorry, I meant the HOTPLUG_INT registers in the HDMI controller you weren't sure if they were usable.

My issues on 3B+ may be a partial red herring. This board is seemingly unhappy with hotplugging HDMI at all, and will easily reboot on me.
3B (where we're polling) is working OK
2B isn't working - whilst I can see the GPIO status change (GPIO46), I don't appear to get any interrupts, and proc/interrupts doesn't register any as having occurred. I wonder if anyone has actually tried using BANK1 GPIO interrupts before.

Can I suggest that we split this PR to only deal with 2711, and we'll sort the GPIO path out later?

Sure. The encoder retrieval logic is completely broken though on the Pi3, so we'll want to fix that too. I'll try to fix it next week and will let you know

mripard added 5 commits May 5, 2021 15:37
The current core while setting the min and max rate properly in the
clk_request structure will not make sure that the requested rate is
within these boundaries, leaving it to each and every driver to make
sure it is.

Add a clamp call to make sure it's always done.

Signed-off-by: Maxime Ripard <[email protected]>
This reverts commit 3cf3d39.

This commit was making the assumption that we had a 1:1 mapping between
the encoders and their CRTC. While this is true for the HDMI controllers
on the BCM2711, this isn't true for the other encoders (DSI0 and DPI
share the PixelValve 0, and DSI1 and SMI share the PixelValve1), and
this isn't true at all on the older SoCs, effectively breaking the
encoder retrieval logic.

Signed-off-by: Maxime Ripard <[email protected]>
The vc4_crtc_config_pv will need to access the drm_atomic_state
structure and its only parent function, vc4_crtc_atomic_enable already
has access to it. Let's pass it as a parameter.

Fixes: 792c313 ("drm/vc4: encoder: Add finer-grained encoder callbacks")
Signed-off-by: Maxime Ripard <[email protected]>
The vc4_get_crtc_encoder function currently only works when the
connector->state->crtc pointer is set, which is only true when the
connector is currently enabled.

However, we use it as part of the disable path as well, and our lookup
will fail in that case, resulting in it returning a null pointer we
can't act on.

We can access the connector that used to be connected to that crtc
though using the old connector state in the disable path.

Since we want to support both the enable and disable path, we can
support it by passing the state accessor variant as a function pointer,
together with the atomic state.

Fixes: 792c313 ("drm/vc4: encoder: Add finer-grained encoder callbacks")
Signed-off-by: Maxime Ripard <[email protected]>
At boot, we can't rely on the vc4_get_crtc_encoder since we don't have a
state yet and thus will not be able to figure out which connector is
attached to our CRTC.

However, we have a muxing bit in the CRTC register we can use to get the
encoder currently connected to the pixelvalve. We can thus read that
register, lookup the associated register through the vc4_pv_data
structure, and then pass it to vc4_crtc_disable so that we can perform
the proper operations.

Fixes: 875a4d5 ("drm/vc4: drv: Disable the CRTC at boot time")
Signed-off-by: Maxime Ripard <[email protected]>
@mripard mripard force-pushed the rpi/5.10-hotplug-irq branch from a0b2234 to 42e984a Compare May 6, 2021 15:50
@mripard
Copy link
Contributor Author

mripard commented May 6, 2021

I just pushed a new version that addresses the encoder retrieval logic, fixes the CPU hang we were seeing during a hotplug on the Pi3B+ (and was there but hidden away on the Pi4), and adds the interrupt-based hotplug on the Pi4.

mripard added 4 commits May 6, 2021 17:59
pm_runtime_get_sync increases the PM usage counter even if it fails, and
forgetting to do so will result in a reference leak. We can't really do
anything in atomic_enable in case of a failure though, and we probably
can't recover either, but at least switching to
pm_runtime_resume_and_get makes us play nice with the PM subsystem.

Fixes: 4f6e3d6 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
Signed-off-by: Maxime Ripard <[email protected]>
If the HPD GPIO is not available and drm_probe_ddc fails, we end up
reading the HDMI_HOTPLUG register, but the controller might be powered
off resulting in a CPU hang. Make sure we have the power domain and the
HSM clock powered during the detect cycle to prevent the hang from
happening.

Fixes: 4f6e3d6 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
Signed-off-by: Maxime Ripard <[email protected]>
When we have the entire DRM state, retrieving the connector state only
requires the drm_connector pointer. Fortunately for us, we have
allocated it as a part of the vc4_hdmi structure, so we can retrieve get
a pointer by simply accessing our field in that structure.

Signed-off-by: Maxime Ripard <[email protected]>
DRM currently polls for the HDMI connector status every 10s, which can
be an issue when we connect/disconnect a display quickly or the device
on the other end only issues a hotplug pulse (for example on EDID
change).

Switch the driver to rely on the internal controller logic for the
BCM2711/RPi4.

Signed-off-by: Maxime Ripard <[email protected]>
@mripard mripard force-pushed the rpi/5.10-hotplug-irq branch from 42e984a to 671a806 Compare May 6, 2021 16:00
@pelwell pelwell merged commit 63203e2 into raspberrypi:rpi-5.10.y May 7, 2021
if (ret)
return ret;

connector->polled = DRM_CONNECTOR_POLL_HPD;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't compile (error: ‘connector’ undeclared). @mripard was there something lost in a rebase?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it needs:

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index f84c8257bd7e..f1930549de1f 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -2177,6 +2177,7 @@ static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
 static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi)
 {
        struct platform_device *pdev = vc4_hdmi->pdev;
+       struct drm_connector *connector = &vc4_hdmi->connector;
        struct device *dev = &pdev->dev;
        int ret;

popcornmix added a commit to raspberrypi/firmware that referenced this pull request May 7, 2021
See: raspberrypi/linux#4313

kernel: drm/vc4: hdmi: Add a workqueue to set scrambling
See: raspberrypi/linux#4329
popcornmix added a commit to Hexxeh/rpi-firmware that referenced this pull request May 7, 2021
See: raspberrypi/linux#4313

kernel: drm/vc4: hdmi: Add a workqueue to set scrambling
See: raspberrypi/linux#4329
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants