Hi,
On 9/16/21 11:40 AM, Jani Nikula wrote:
Cc: Ville for input here, see question inline.
On Mon, 06 Sep 2021, Hans de Goede hdegoede@redhat.com wrote:
Add support for eDP panels with a built-in privacy screen using the new drm_privacy_screen class.
One thing which stands out here is the addition of these 2 lines to intel_atomic_commit_tail:
for_each_new_connector_in_state(&state->base, connector, ... drm_connector_update_privacy_screen(connector, state);
It may seem more logical to instead take care of updating the privacy-screen state by marking the crtc as needing a modeset and then do this in both the encoder update_pipe (for fast-sets) and enable (for full modesets) callbacks. But ATM these callbacks only get passed the new connector_state and these callbacks are all called after drm_atomic_helper_swap_state() at which point there is no way to get the old state from the new state.
Without access to the old state, we do not know if the sw_state of the privacy-screen has changes so we would need to call drm_privacy_screen_set_sw_state() unconditionally. This is undesirable since all current known privacy-screen providers use ACPI calls which are somewhat expensive to make.
Also, as all providers use ACPI calls, rather then poking GPU registers, there is no need to order this together with other encoder operations. Since no GPU poking is involved having this as a separate step of the commit process actually is the logical thing to do.
Reviewed-by: Emil Velikov emil.l.velikov@gmail.com Signed-off-by: Hans de Goede hdegoede@redhat.com
drivers/gpu/drm/i915/display/intel_display.c | 5 +++++ drivers/gpu/drm/i915/display/intel_dp.c | 10 ++++++++++ drivers/gpu/drm/i915/i915_pci.c | 12 ++++++++++++ 3 files changed, 27 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 5560d2f4c352..7285873d329a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -10140,6 +10140,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) struct drm_device *dev = state->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_crtc_state *new_crtc_state, *old_crtc_state;
- struct drm_connector_state *new_connector_state;
- struct drm_connector *connector; struct intel_crtc *crtc; u64 put_domains[I915_MAX_PIPES] = {}; intel_wakeref_t wakeref = 0;
@@ -10237,6 +10239,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_color_load_luts(new_crtc_state); }
- for_each_new_connector_in_state(&state->base, connector, new_connector_state, i)
drm_connector_update_privacy_screen(connector, &state->base);
- /*
- Now that the vblank has passed, we can go ahead and program the
- optimal watermarks on platforms that need two-step watermark
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7f8e8865048f..3aa2072cccf6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -37,6 +37,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_dp_helper.h> #include <drm/drm_edid.h> +#include <drm/drm_privacy_screen_consumer.h> #include <drm/drm_probe_helper.h>
#include "g4x_dp.h" @@ -5217,6 +5218,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct drm_connector *connector = &intel_connector->base; struct drm_display_mode *fixed_mode = NULL; struct drm_display_mode *downclock_mode = NULL;
- struct drm_privacy_screen *privacy_screen; bool has_dpcd; enum pipe pipe = INVALID_PIPE; struct edid *edid;
@@ -5308,6 +5310,14 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, fixed_mode->hdisplay, fixed_mode->vdisplay); }
- privacy_screen = drm_privacy_screen_get(dev->dev, NULL);
- if (!IS_ERR(privacy_screen)) {
drm_connector_attach_privacy_screen_provider(connector,
privacy_screen);
- } else if (PTR_ERR(privacy_screen) != -ENODEV) {
drm_warn(&dev_priv->drm, "Error getting privacy-screen\n");
- }
- return true;
out_vdd_off: diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 146f7e39182a..d6913f567a1c 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -25,6 +25,7 @@ #include <linux/vga_switcheroo.h>
#include <drm/drm_drv.h> +#include <drm/drm_privacy_screen_consumer.h> #include <drm/i915_pciids.h>
#include "i915_drv.h" @@ -1167,6 +1168,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct intel_device_info *intel_info = (struct intel_device_info *) ent->driver_data;
struct drm_privacy_screen *privacy_screen; int err;
if (intel_info->require_force_probe &&
@@ -1195,7 +1197,17 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (vga_switcheroo_client_probe_defer(pdev)) return -EPROBE_DEFER;
- /*
* We do not handle -EPROBE_DEFER further into the probe process, so
* check if we have a laptop-panel privacy-screen for which the driver
* has not loaded yet here.
*/
- privacy_screen = drm_privacy_screen_get(&pdev->dev, NULL);
- if (IS_ERR(privacy_screen) && PTR_ERR(privacy_screen) == -EPROBE_DEFER)
return -EPROBE_DEFER;
- err = i915_driver_probe(pdev, ent);
- drm_privacy_screen_put(privacy_screen); if (err) return err;
Ideally, neither i915_pci_probe() nor i915_driver_probe() should assume we have display. We might not. We should not wait if we are never going to initialize display.
Good point.
Alas, we'll only know after i915_driver_probe() -> i915_driver_mmio_probe() -> intel_device_info_runtime_init(), which modifies ->pipe_mask, which is the single point of truth. See HAS_DISPLAY().
We do have tests for failing probe at various points (see the i915_inject_probe_failure() calls) to stress the cleanup paths in CI. Part of the point was to prepare us for -EPROBE_DEFER returns.
Looks like the earliest/cleanest point for checking this is in intel_modeset_init_noirq(), i.e. first display init call. But I admit it gives me an uneasy feeling to return -EPROBE_DEFER at that stage.
Ack, this is why I added the get + put here. Theoretically I could also just have put the return -EPROBE_DEFER inside intel_edp_init_connector() (changing its return type) but I did not feel comfortable with doing that...
I think that just leaving this functionally as is, with the refactor which you suggest below is best for now. drm_privacy_screen_get() will only return -EPROBE_DEFER if there is an entry in the lookup-table which the drm_privacy class code keeps this lookup table matches on the dev_name() of the GPU's PCI-device. So assuming the lookup table contains the correct dev_name() then there should be no match for any GPU-s without a display.
Note ATM this is not true since the lookup added for the thinkpad_acpi providing privacy-screen support case specifies NULL as dev_name, which gets interpreted as a wildcard, but I can easily replace that with "0000:00:02.0" before pushing this out. Which at least avoids delaying probing of any discrete Intel GPUs which I guess may not have displays.
That does still leave the case of a hybrid GPU laptop where all displays are connected to the discrete-GPU and the iGPU is only left enabled for quick-sync functionality. But I'm not sure if that case is even detected by HAS_DISPLAY(), since the hw then still has display-pipes.
Worst case scenario here is that we delay i915 binding to the device until thinkpad_acpi loads, which I think is not too bad.
Note a downside of replace the NULL devname in the lookup with "0000:00:02.0" is that that will not work for hybrid-gfx laptops with the panel connected to the discrete-GPU atm this is not supported anyways since amdgpu and nouveau lack a patch similar to this one.
But the plan was for this to work automatically as soon as nouveau / amdgpu get support assuming that e.g. only either i915 or nouveau would see the LCD panel and thus would trigger the code in e.g. intel_edp_init_connector().
But if you feel more comfortable about this if I change the dev_name in the lookup to "0000:00:02.0" I can do that and we can cross the hybrid-gfx case when we hit that. The whole need to tie a random vendor ACPI interface for privacy-screen control together with the drm-subsys is a bit messy anyways, so some of this we (I?) will need to figure out as we go.
The only -EPROBE_DEFER return we currently have is the vga switcheroo stuff you see in the patch context, and most platforms never return that.
Ville, I'd like to get your thoughts on that.
Anyway, even if we decide not to, err, defer returning -EPROBE_DEFER, I think we should abstract this better. For example, add a intel_modeset_probe_defer() function in intel_display.c that checks this, and call that as the first thing in i915_driver_probe(). Just to keep the display specific code out of the high level functions, even if that is functionally the same as what you're doing here.
I'm fine with refactoring this a bit and adding an intel_modeset_probe_defer() helper for this, I assume I should also move the vga_switcheroo_client_probe_defer(pdev) check there?
As you suggested yourself in your reply to the coverletter I will push out the rest of the series to drm-misc-next while we figure this out. Assuming Lyude is happy with the answers which I gave to her remarks about some of the other patches.
Regards,
Hans