[PATCH 9/9] drm/i915: Add privacy-screen support

Hans de Goede hdegoede at redhat.com
Fri Sep 17 14:23:00 UTC 2021


Hi,

On 9/16/21 4:04 PM, Ville Syrjälä wrote:
> On Thu, Sep 16, 2021 at 12:40:11PM +0300, Jani Nikula wrote:
>>
>> Cc: Ville for input here, see question inline.
>>
>> On Mon, 06 Sep 2021, Hans de Goede <hdegoede at 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 at gmail.com>
>>> Signed-off-by: Hans de Goede <hdegoede at 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.
>>
>> 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. 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.
> 
> I'm just scaread about everything to do with deferred probing.
> 
> For example, I don't even know what would happen if you have some kind
> of mismatch betwen i915 and thinkpad_acpi y/m/n? Or you have one but not
> the other in the initrd? Is the machine at least guaranteed to boot
> properly and light up the display at some point?

If i915 us builtin and thinkpad_acpi is m and the machine is a ThinkPad
with a privacy-screen then the  i915 driver's probe won't get past
the added check until the thinkpad_acpi driver has loaded.

Same for i915 being in the initrd and thinkpad_acpi not, then
the i915 driver's probe won't get past
the added check until we've pivoted to the real root and the
thinkpad_acpi module is loaded from the real-root.

Note that the boot will otherwise continue normally and we will
still have console output (and even e.g. a plymouth splash after
a timeout) on the efifb.


> 
> But yeah, failing the probe at some stage when we've already clobbered
> a bunch of things sounds like an "interesting" idea. I don't think we've
> given the error paths any real though beyond the "ci+error injection
> seems to not explode too badly" approach.
> 
>> 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.
> 
> Yeah, I guess something like that could be the safest option
> for the moment.

Ack I will go with that then.

Regards,

Hans



More information about the dri-devel mailing list