Re: [Intel-gfx] [PATCH v9 5/5] drm/i915: Enable support for integrated privacy screen

2020-07-06 Thread Hans de Goede

Hi,

On 3/12/20 7:56 PM, Rajat Jain wrote:

Add support for an ACPI based integrated privacy screen that is
available on some systems.

Signed-off-by: Rajat Jain 


So as discussed a while ago I'm working on adding support for the
privacy-screen on Lenovo Thinkpads, introducing a small new
subsystem / helper-class as intermediary for when the privacy-screen
is controlled by e.g. some random drivers/platform/x86 driver rather
then directly by the GPU driver.

I'm almost ready to send out v1. I was working on hooking things
up in the i915 code and I was wondering what you were doing when
the property is actually changed and we need to commit the new
privacy-screen state to the hardware.

This made me look at this patch, some comments inline:


---
v9: same as v8
v8: - separate the APCI privacy screen into a separate patch.
 - Don't destroy the property if there is no privacy screen (because
   drm core doesn't like destroying property in late_register()).
 - The setting change needs to be committed in ->update_pipe() for
   ddi.c as well as dp.c and both of them call intel_dp_add_properties()
v7: Look for ACPI node in ->late_register() hook.
 Do the scan only once per drm_device (instead of 1 per drm_connector)
v6: Addressed minor comments from Jani at
 https://lkml.org/lkml/2020/1/24/1143
  - local variable renamed.
  - used drm_dbg_kms()
  - used acpi_device_handle()
  - Used opaque type acpi_handle instead of void*
v5: same as v4
v4: Same as v3
v3: fold the code into existing acpi_device_id_update() function
v2: formed by splitting the original patch into ACPI lookup, and privacy
 screen property. Also move it into i915 now that I found existing code
 in i915 that can be re-used.

  drivers/gpu/drm/i915/display/intel_atomic.c |  2 ++
  drivers/gpu/drm/i915/display/intel_ddi.c|  1 +
  drivers/gpu/drm/i915/display/intel_dp.c | 34 -
  drivers/gpu/drm/i915/display/intel_dp.h |  5 +++
  4 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c 
b/drivers/gpu/drm/i915/display/intel_atomic.c
index d043057d2fa03..9898d8980e7ce 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -150,6 +150,8 @@ int intel_digital_connector_atomic_check(struct 
drm_connector *conn,
new_conn_state->base.picture_aspect_ratio != 
old_conn_state->base.picture_aspect_ratio ||
new_conn_state->base.content_type != 
old_conn_state->base.content_type ||
new_conn_state->base.scaling_mode != 
old_conn_state->base.scaling_mode ||
+   new_conn_state->base.privacy_screen_status !=
+   old_conn_state->base.privacy_screen_status ||
!blob_equal(new_conn_state->base.hdr_output_metadata,
old_conn_state->base.hdr_output_metadata))
crtc_state->mode_changed = true;


Right I was planning on doing this to.


diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c 
b/drivers/gpu/drm/i915/display/intel_ddi.c
index 73d0f4648c06a..69a5423216dc5 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3708,6 +3708,7 @@ static void intel_ddi_update_pipe(struct intel_encoder 
*encoder,
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
intel_ddi_update_pipe_dp(encoder, crtc_state, conn_state);
  
+	intel_dp_update_privacy_screen(encoder, crtc_state, conn_state);

intel_hdcp_update_pipe(encoder, crtc_state, conn_state);
  }
  


And this too.


diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
b/drivers/gpu/drm/i915/display/intel_dp.c
index 3ddc424b028c1..5f33ebb466135 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -62,6 +62,7 @@
  #include "intel_lspcon.h"
  #include "intel_lvds.h"
  #include "intel_panel.h"
+#include "intel_privacy_screen.h"
  #include "intel_psr.h"
  #include "intel_sideband.h"
  #include "intel_tc.h"
@@ -5886,6 +5887,10 @@ intel_dp_connector_register(struct drm_connector 
*connector)
dev_priv->acpi_scan_done = true;
}
  
+	/* Check for integrated Privacy screen support */

+   if (intel_privacy_screen_present(to_intel_connector(connector)))
+   drm_connector_attach_privacy_screen_property(connector);
+
DRM_DEBUG_KMS("registering %s bus for %s\n",
  intel_dp->aux.name, connector->kdev->kobj.name);
  
@@ -6883,6 +6888,33 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect

connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
  
  	}

+
+   /*
+* Created here, but depending on result of probing for privacy-screen
+* in intel_dp_connector_register(), gets attached in that function.
+* Need to create here because the drm core doesn't like creating
+* properties 

Re: [RFC][PATCH 0/9] drm: Support simple-framebuffer devices and firmware fbs

2020-07-03 Thread Hans de Goede

Hi,

On 7/3/20 2:58 PM, Daniel Vetter wrote:

On Fri, Jul 3, 2020 at 12:55 PM Hans de Goede  wrote:


Hi,

On 7/1/20 4:10 PM, Thomas Zimmermann wrote:

Hi Daniel,

thanks for reviewing most of the patchset.

Am 30.06.20 um 11:06 schrieb Daniel Vetter:

On Mon, Jun 29, 2020 at 11:39 AM Hans de Goede  wrote:


Hi,

On 6/25/20 2:00 PM, Thomas Zimmermann wrote:

This patchset adds support for simple-framebuffer platform devices and
a handover mechanism for native drivers to take-over control of the
hardware.

The new driver, called simplekms, binds to a simple-frambuffer platform
device. The kernel's boot code creates such devices for firmware-provided
framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
loader sets up the framebuffers. Description via device tree is also an
option.

Simplekms is small enough to be linked into the kernel. The driver's main
purpose is to provide graphical output during the early phases of the boot
process, before the native DRM drivers are available. Native drivers are
typically loaded from an initrd ram disk. Occationally simplekms can also
serve as interim solution on graphics hardware without native DRM driver.


Cool, thank you for doing this, this is a very welcome change,
but ... (see below).


So far distributions rely on fbdev drivers, such as efifb, vesafb or
simplefb, for early-boot graphical output. However fbdev is deprecated and
the drivers do not provide DRM interfaces for modern userspace.

Patches 1 and 2 prepare the DRM format helpers for simplekms.

Patches 3 to 7 add the simplekms driver. It's build on simple DRM helpers
and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
pageflips, SHMEM buffers are copied into the framebuffer memory, similar
to cirrus or mgag200. The code in patches 6 and 7 handles clocks and
regulators. It's based on the simplefb drivers, but has been modified for
DRM.

Patches 8 and 9 add a hand-over mechanism. Simplekms acquires it's
framebuffer's I/O-memory range and provides a callback function to be
removed by a native driver. The native driver will remove simplekms before
taking over the hardware. The removal is integrated into existing helpers,
so drivers use it automatically.

I tested simplekms with x86 EFI and VESA framebuffers, which both work
reliably. The fbdev console and Weston work automatically. Xorg requires
manual configuration of the device. Xorgs current modesetting driver does
not work with both, platform and PCI device, for the same physical
hardware. Once configured, X11 works.


Ugh, Xorg not working OOTB is a bit of a showstopper, we cannot just go
around and break userspace. OTOH this does seem like an userspace issue
and not something which we can (or should try to) fix in the kernel.

I guess the solution will have to be to have this default to N for now
in Kconfig and clearly mention in the Kconfig help text that this needs
a fixed Xorg modesetting driver before it can be enabled.

Any chance you have time to work on fixing the Xorg modesetting driver
so that this will just work with the standard Xorg autoconfiguration
stuff?


Hm, why do we even have both platform and pci drivers visible at the
same time? I thought the point of this is that simplekms is built-in,
then initrd loads the real drm driver, and by the time Xorg is
running, simplekms should be long gone.

Maybe a few more details of what's going wrong and why to help unconfuse me?


I tested simplekms with PCI graphics cards.

Xorg does it's own scanning of the busses. It supports a platform bus,
where it finds the simple-framebuffer device that is driven by
simplekms. Xorg also scans the PCI bus, where is finds the native PCI
device; usually driven by the native driver. It's the same hardware, but
on different busses.

For each device, Xorg tries to configure a screen, the Xorg modeset
driver tried to open the DRM device file and acquire DRM master status
on it. This works for the first screen, but DRM master status can only
be acquired once, so it fails for the second screen. Xorg then aborts
and asks for manual configuration of the display device.

This can be solved by setting the platform device's bus id in the
xorg.conf device section. It just doesn't happen automatically.

I found it hard to find a solution to this. Weston just opens a DRM
device file and uses whatever it gets. Ideally, Xorg would do the same.
That whole bus-scanning exercise gives it a wrong idea on which graphics
devices are available.

One idea for a fix is to compare the device I/O-memory ranges and filter
out duplicates on the Xorg modeset driver. I don't know how reliable
this works in practice or if their are false positives.


I think that this should work nicely, although I wonder how Xorg will
get the memory-range for the simplefb platform device, it looks like
it will need to parse /dev/iomem for this, or we need to add a
new sysfs attr to the simplefb device for this. Adding the new sysfs
attr has the added bonus that we

Re: [RFC][PATCH 0/9] drm: Support simple-framebuffer devices and firmware fbs

2020-07-03 Thread Hans de Goede

Hi,

On 7/1/20 4:10 PM, Thomas Zimmermann wrote:

Hi Daniel,

thanks for reviewing most of the patchset.

Am 30.06.20 um 11:06 schrieb Daniel Vetter:

On Mon, Jun 29, 2020 at 11:39 AM Hans de Goede  wrote:


Hi,

On 6/25/20 2:00 PM, Thomas Zimmermann wrote:

This patchset adds support for simple-framebuffer platform devices and
a handover mechanism for native drivers to take-over control of the
hardware.

The new driver, called simplekms, binds to a simple-frambuffer platform
device. The kernel's boot code creates such devices for firmware-provided
framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
loader sets up the framebuffers. Description via device tree is also an
option.

Simplekms is small enough to be linked into the kernel. The driver's main
purpose is to provide graphical output during the early phases of the boot
process, before the native DRM drivers are available. Native drivers are
typically loaded from an initrd ram disk. Occationally simplekms can also
serve as interim solution on graphics hardware without native DRM driver.


Cool, thank you for doing this, this is a very welcome change,
but ... (see below).


So far distributions rely on fbdev drivers, such as efifb, vesafb or
simplefb, for early-boot graphical output. However fbdev is deprecated and
the drivers do not provide DRM interfaces for modern userspace.

Patches 1 and 2 prepare the DRM format helpers for simplekms.

Patches 3 to 7 add the simplekms driver. It's build on simple DRM helpers
and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
pageflips, SHMEM buffers are copied into the framebuffer memory, similar
to cirrus or mgag200. The code in patches 6 and 7 handles clocks and
regulators. It's based on the simplefb drivers, but has been modified for
DRM.

Patches 8 and 9 add a hand-over mechanism. Simplekms acquires it's
framebuffer's I/O-memory range and provides a callback function to be
removed by a native driver. The native driver will remove simplekms before
taking over the hardware. The removal is integrated into existing helpers,
so drivers use it automatically.

I tested simplekms with x86 EFI and VESA framebuffers, which both work
reliably. The fbdev console and Weston work automatically. Xorg requires
manual configuration of the device. Xorgs current modesetting driver does
not work with both, platform and PCI device, for the same physical
hardware. Once configured, X11 works.


Ugh, Xorg not working OOTB is a bit of a showstopper, we cannot just go
around and break userspace. OTOH this does seem like an userspace issue
and not something which we can (or should try to) fix in the kernel.

I guess the solution will have to be to have this default to N for now
in Kconfig and clearly mention in the Kconfig help text that this needs
a fixed Xorg modesetting driver before it can be enabled.

Any chance you have time to work on fixing the Xorg modesetting driver
so that this will just work with the standard Xorg autoconfiguration
stuff?


Hm, why do we even have both platform and pci drivers visible at the
same time? I thought the point of this is that simplekms is built-in,
then initrd loads the real drm driver, and by the time Xorg is
running, simplekms should be long gone.

Maybe a few more details of what's going wrong and why to help unconfuse me?


I tested simplekms with PCI graphics cards.

Xorg does it's own scanning of the busses. It supports a platform bus,
where it finds the simple-framebuffer device that is driven by
simplekms. Xorg also scans the PCI bus, where is finds the native PCI
device; usually driven by the native driver. It's the same hardware, but
on different busses.

For each device, Xorg tries to configure a screen, the Xorg modeset
driver tried to open the DRM device file and acquire DRM master status
on it. This works for the first screen, but DRM master status can only
be acquired once, so it fails for the second screen. Xorg then aborts
and asks for manual configuration of the display device.

This can be solved by setting the platform device's bus id in the
xorg.conf device section. It just doesn't happen automatically.

I found it hard to find a solution to this. Weston just opens a DRM
device file and uses whatever it gets. Ideally, Xorg would do the same.
That whole bus-scanning exercise gives it a wrong idea on which graphics
devices are available.

One idea for a fix is to compare the device I/O-memory ranges and filter
out duplicates on the Xorg modeset driver. I don't know how reliable
this works in practice or if their are false positives.


I think that this should work nicely, although I wonder how Xorg will
get the memory-range for the simplefb platform device, it looks like
it will need to parse /dev/iomem for this, or we need to add a
new sysfs attr to the simplefb device for this. Adding the new sysfs
attr has the added bonus that we only enable the duplicate based
resource check for simplefb devices.

Hmm, I think we can actually fix

Re: [RFC][PATCH 0/9] drm: Support simple-framebuffer devices and firmware fbs

2020-07-03 Thread Hans de Goede

Hi,

On 7/1/20 3:48 PM, Thomas Zimmermann wrote:

Hi Hans

Am 29.06.20 um 11:38 schrieb Hans de Goede:

Hi,

On 6/25/20 2:00 PM, Thomas Zimmermann wrote:

This patchset adds support for simple-framebuffer platform devices and
a handover mechanism for native drivers to take-over control of the
hardware.

The new driver, called simplekms, binds to a simple-frambuffer platform
device. The kernel's boot code creates such devices for firmware-provided
framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
loader sets up the framebuffers. Description via device tree is also an
option.

Simplekms is small enough to be linked into the kernel. The driver's main
purpose is to provide graphical output during the early phases of the
boot
process, before the native DRM drivers are available. Native drivers are
typically loaded from an initrd ram disk. Occationally simplekms can also
serve as interim solution on graphics hardware without native DRM driver.


Cool, thank you for doing this, this is a very welcome change,
but ... (see below).


So far distributions rely on fbdev drivers, such as efifb, vesafb or
simplefb, for early-boot graphical output. However fbdev is deprecated
and
the drivers do not provide DRM interfaces for modern userspace.

Patches 1 and 2 prepare the DRM format helpers for simplekms.

Patches 3 to 7 add the simplekms driver. It's build on simple DRM helpers
and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
pageflips, SHMEM buffers are copied into the framebuffer memory, similar
to cirrus or mgag200. The code in patches 6 and 7 handles clocks and
regulators. It's based on the simplefb drivers, but has been modified for
DRM.

Patches 8 and 9 add a hand-over mechanism. Simplekms acquires it's
framebuffer's I/O-memory range and provides a callback function to be
removed by a native driver. The native driver will remove simplekms
before
taking over the hardware. The removal is integrated into existing
helpers,
so drivers use it automatically.

I tested simplekms with x86 EFI and VESA framebuffers, which both work
reliably. The fbdev console and Weston work automatically. Xorg requires
manual configuration of the device. Xorgs current modesetting driver does
not work with both, platform and PCI device, for the same physical
hardware. Once configured, X11 works.


Ugh, Xorg not working OOTB is a bit of a showstopper, we cannot just go
around and break userspace. OTOH this does seem like an userspace issue
and not something which we can (or should try to) fix in the kernel.


Xorg is an important use case, but simplekms does not "break userspace."
If you're not using simplekms, nothing changes; if simplekms is replaced
by the native driver, nothing changes. Simplekms works with Xorg of the
device is auto-configured. Xorg is not able to auto-configure simplekms
devices ATM.


As I already mentioned in my replay to Daniel: If there is no native driver,
or the native driver fails to load (e.g. nvidia binary driver dkms build
fails with a nwer kernel) then having simplekms enables changes the user,
experience from Xorg on fbdev, slow but usable to search for a solution
to no GUI. I agree that we cannot solve this on the kernel side, but it
is a real problem which we need to keep in mind.


I guess the solution will have to be to have this default to N for now
in Kconfig and clearly mention in the Kconfig help text that this needs
a fixed Xorg modesetting driver before it can be enabled.


Sure, but simplekms is just a driver. Shouldn't it default to N anyway?


I guess so.


Any chance you have time to work on fixing the Xorg modesetting driver
so that this will just work with the standard Xorg autoconfiguration
stuff?


I'll do if somehow possible. See my reply to Daniel for a description of
the problem.


Great.


One cosmetical issue is that simplekms's device file is card0 and the
native driver's device file is card1. After simplekms has been kicked
out,
only card1 is left. This does not seem to be a practical problem however.

TODO/IDEAS:

 * provide deferred takeover


I assume you mean akin to CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER ?
I don't think you need to do anything for that, as long as you just
leave the fb contents intact until requested to change it.


Great. If it's that easy; even better.



Right now with flickerfree boot we have fbcon on top of efifb and
efifb does not do anything special wrt
CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
ATM it does draw/restore the ACPI BGRT logo since since some firmwares
don't draw that themselves, but that is not necessary in most cases
and other then that all the deferred takeover magic is in the fbcon
code, it does not bind to the fbdev (and thus does not draw to it)
until the first time the kernel tries to output text to the console,
together with the "quiet" kernel commandline argument that ensures
that the fb is kept unmodified until e.g. a panic happens.

With simplekms we 

Re: [RFC][PATCH 0/9] drm: Support simple-framebuffer devices and firmware fbs

2020-06-30 Thread Hans de Goede

Hi,

On 6/30/20 11:06 AM, Daniel Vetter wrote:

On Mon, Jun 29, 2020 at 11:39 AM Hans de Goede  wrote:


Hi,

On 6/25/20 2:00 PM, Thomas Zimmermann wrote:

This patchset adds support for simple-framebuffer platform devices and
a handover mechanism for native drivers to take-over control of the
hardware.

The new driver, called simplekms, binds to a simple-frambuffer platform
device. The kernel's boot code creates such devices for firmware-provided
framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
loader sets up the framebuffers. Description via device tree is also an
option.

Simplekms is small enough to be linked into the kernel. The driver's main
purpose is to provide graphical output during the early phases of the boot
process, before the native DRM drivers are available. Native drivers are
typically loaded from an initrd ram disk. Occationally simplekms can also
serve as interim solution on graphics hardware without native DRM driver.


Cool, thank you for doing this, this is a very welcome change,
but ... (see below).


So far distributions rely on fbdev drivers, such as efifb, vesafb or
simplefb, for early-boot graphical output. However fbdev is deprecated and
the drivers do not provide DRM interfaces for modern userspace.

Patches 1 and 2 prepare the DRM format helpers for simplekms.

Patches 3 to 7 add the simplekms driver. It's build on simple DRM helpers
and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
pageflips, SHMEM buffers are copied into the framebuffer memory, similar
to cirrus or mgag200. The code in patches 6 and 7 handles clocks and
regulators. It's based on the simplefb drivers, but has been modified for
DRM.

Patches 8 and 9 add a hand-over mechanism. Simplekms acquires it's
framebuffer's I/O-memory range and provides a callback function to be
removed by a native driver. The native driver will remove simplekms before
taking over the hardware. The removal is integrated into existing helpers,
so drivers use it automatically.

I tested simplekms with x86 EFI and VESA framebuffers, which both work
reliably. The fbdev console and Weston work automatically. Xorg requires
manual configuration of the device. Xorgs current modesetting driver does
not work with both, platform and PCI device, for the same physical
hardware. Once configured, X11 works.


Ugh, Xorg not working OOTB is a bit of a showstopper, we cannot just go
around and break userspace. OTOH this does seem like an userspace issue
and not something which we can (or should try to) fix in the kernel.

I guess the solution will have to be to have this default to N for now
in Kconfig and clearly mention in the Kconfig help text that this needs
a fixed Xorg modesetting driver before it can be enabled.

Any chance you have time to work on fixing the Xorg modesetting driver
so that this will just work with the standard Xorg autoconfiguration
stuff?


Hm, why do we even have both platform and pci drivers visible at the
same time? I thought the point of this is that simplekms is built-in,
then initrd loads the real drm driver, and by the time Xorg is
running, simplekms should be long gone.

Maybe a few more details of what's going wrong and why to help unconfuse me?


I guess that Thomas deliberately disabled the normal kms driver to test this.

Still we should make sure that this (Xorg on simpledrm) works, a user might
see this because of running an older kernel with a newer GPU, or when
using the nvidia binary and thus having nouveau disabled and then installing
a newer kernel which breaks the dkms nvidia module building because of API
changes.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC][PATCH 0/9] drm: Support simple-framebuffer devices and firmware fbs

2020-06-29 Thread Hans de Goede

Hi,

On 6/25/20 2:00 PM, Thomas Zimmermann wrote:

This patchset adds support for simple-framebuffer platform devices and
a handover mechanism for native drivers to take-over control of the
hardware.

The new driver, called simplekms, binds to a simple-frambuffer platform
device. The kernel's boot code creates such devices for firmware-provided
framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
loader sets up the framebuffers. Description via device tree is also an
option.

Simplekms is small enough to be linked into the kernel. The driver's main
purpose is to provide graphical output during the early phases of the boot
process, before the native DRM drivers are available. Native drivers are
typically loaded from an initrd ram disk. Occationally simplekms can also
serve as interim solution on graphics hardware without native DRM driver.


Cool, thank you for doing this, this is a very welcome change,
but ... (see below).


So far distributions rely on fbdev drivers, such as efifb, vesafb or
simplefb, for early-boot graphical output. However fbdev is deprecated and
the drivers do not provide DRM interfaces for modern userspace.

Patches 1 and 2 prepare the DRM format helpers for simplekms.

Patches 3 to 7 add the simplekms driver. It's build on simple DRM helpers
and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
pageflips, SHMEM buffers are copied into the framebuffer memory, similar
to cirrus or mgag200. The code in patches 6 and 7 handles clocks and
regulators. It's based on the simplefb drivers, but has been modified for
DRM.

Patches 8 and 9 add a hand-over mechanism. Simplekms acquires it's
framebuffer's I/O-memory range and provides a callback function to be
removed by a native driver. The native driver will remove simplekms before
taking over the hardware. The removal is integrated into existing helpers,
so drivers use it automatically.

I tested simplekms with x86 EFI and VESA framebuffers, which both work
reliably. The fbdev console and Weston work automatically. Xorg requires
manual configuration of the device. Xorgs current modesetting driver does
not work with both, platform and PCI device, for the same physical
hardware. Once configured, X11 works.


Ugh, Xorg not working OOTB is a bit of a showstopper, we cannot just go
around and break userspace. OTOH this does seem like an userspace issue
and not something which we can (or should try to) fix in the kernel.

I guess the solution will have to be to have this default to N for now
in Kconfig and clearly mention in the Kconfig help text that this needs
a fixed Xorg modesetting driver before it can be enabled.

Any chance you have time to work on fixing the Xorg modesetting driver
so that this will just work with the standard Xorg autoconfiguration
stuff?


One cosmetical issue is that simplekms's device file is card0 and the
native driver's device file is card1. After simplekms has been kicked out,
only card1 is left. This does not seem to be a practical problem however.

TODO/IDEAS:

* provide deferred takeover


I assume you mean akin to CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER ?
I don't think you need to do anything for that, as long as you just
leave the fb contents intact until requested to change it.

Right now with flickerfree boot we have fbcon on top of efifb and
efifb does not do anything special wrt
CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
ATM it does draw/restore the ACPI BGRT logo since since some firmwares
don't draw that themselves, but that is not necessary in most cases
and other then that all the deferred takeover magic is in the fbcon
code, it does not bind to the fbdev (and thus does not draw to it)
until the first time the kernel tries to output text to the console,
together with the "quiet" kernel commandline argument that ensures
that the fb is kept unmodified until e.g. a panic happens.

With simplekms we would replace "fbcon on top of efifb" with
"fbcon on top of emulated-fbdev on top of simplekms" so as long
as the emulated-fbdev and simplekms code defer from say clearing
the screen to black, but keep it as is. Then the fb contents
should be preserved until fbcon decides to takeover the fbdev
and draw to it.


* provide bootsplash DRM client


Hmm, I guess this might be interesting for simple cases, but
although I would love to kill plymouth (I've become one of the
upstream maintainers for it) I'm afraid it is not that easy,
it does a bunch of stuff which will be tricky to do in the kernel:

1) Ask the user for diskcrypt passwords:
https://ic.pics.livejournal.com/hansdegoede/13347631/1496/1496_900.png

2) Show a nice splash + progressbar when installing updates in
offline updates mode:
https://ic.pics.livejournal.com/hansdegoede/13347631/899/899_900.png

Still this would be nice for the non diskcrypt case I guess, then
we could not use plymouth during normal boot and only use it
for offline updates and it would also be nice for various embedded
cases.

Re: [PATCH 1/2] drm: panel-orientation-quirks: Add quirk for Asus T101HA panel

2020-06-23 Thread Hans de Goede

Hi,

On 5/31/20 7:25 PM, Emil Velikov wrote:

On Sun, 31 May 2020 at 10:30, Hans de Goede  wrote:


Like the Asus T100HA the Asus T101HA also uses a panel which has been
mounted 90 degrees rotated, add a quirk for this.


Reading the commit message, made me wonder: If it's similar why it
doesn't use the same quirk?
Something like the following helps:

... 90 degrees rotated, albeit in the opposite direction. Add a quirk for this.

With that the series is:
Reviewed-by: Emil Velikov 


Thank you, I've ammended the commit msg with your suggestion
and pushed the 2 patches to drm-misc-fixes.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 05/15] pwm: lpss: Use pwm_lpss_apply() when restoring state on resume

2020-06-20 Thread Hans de Goede
Before this commit a suspend + resume of the LPSS PWM controller
would result in the controller being reset to its defaults of
output-freq = clock/256, duty-cycle=100%, until someone changes
to the output-freq and/or duty-cycle are made.

This problem has been masked so far because the main consumer
(the i915 driver) was always making duty-cycle changes on resume.
With the conversion of the i915 driver to the atomic PWM API the
driver now only disables/enables the PWM on suspend/resume leaving
the output-freq and duty as is, triggering this problem.

The LPSS PWM controller has a mechanism where the ctrl register value
and the actual base-unit and on-time-div values used are latched. When
software sets the SW_UPDATE bit then at the end of the current PWM cycle,
the new values from the ctrl-register will be latched into the actual
registers, and the SW_UPDATE bit will be cleared.

The problem is that before this commit our suspend/resume handling
consisted of simply saving the PWM ctrl register on suspend and
restoring it on resume, without setting the PWM_SW_UPDATE bit.
When the controller has lost its state over a suspend/resume and thus
has been reset to the defaults, just restoring the register is not
enough. We must also set the SW_UPDATE bit to tell the controller to
latch the restored values into the actual registers.

Fixing this problem is not as simple as just or-ing in the value which
is being restored with SW_UPDATE. If the PWM was enabled before we must
write the new settings + PWM_SW_UPDATE before setting PWM_ENABLE.
We must also wait for PWM_SW_UPDATE to become 0 again and depending on the
model we must do this either before or after the setting of PWM_ENABLE.

All the necessary logic for doing this is already present inside
pwm_lpss_apply(), so instead of duplicating this inside the resume
handler, this commit makes the resume handler use pwm_lpss_apply() to
restore the settings when necessary. This fixes the output-freq and
duty-cycle being reset to their defaults on resume.

Signed-off-by: Hans de Goede 
---
Changes in v3:
- This replaces the "pwm: lpss: Set SW_UPDATE bit when enabling the PWM"
  patch from previous versions of this patch-set, which really was a hack
  working around the resume issue which this patch fixes properly.
---
 drivers/pwm/pwm-lpss.c | 62 --
 1 file changed, 53 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 80d0f9c64f9d..4f3d60ce9929 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -123,25 +123,31 @@ static inline void pwm_lpss_cond_enable(struct pwm_device 
*pwm, bool cond)
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
 }
 
-static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
- const struct pwm_state *state)
+static int __pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+   const struct pwm_state *state, bool from_resume)
 {
struct pwm_lpss_chip *lpwm = to_lpwm(chip);
int ret;
 
if (state->enabled) {
if (!pwm_is_enabled(pwm)) {
-   pm_runtime_get_sync(chip->dev);
+   if (!from_resume)
+   pm_runtime_get_sync(chip->dev);
+
ret = pwm_lpss_is_updating(pwm);
if (ret) {
-   pm_runtime_put(chip->dev);
+   if (!from_resume)
+   pm_runtime_put(chip->dev);
+
return ret;
}
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, 
state->period);
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
ret = pwm_lpss_wait_for_update(pwm);
if (ret) {
-   pm_runtime_put(chip->dev);
+   if (!from_resume)
+   pm_runtime_put(chip->dev);
+
return ret;
}
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true);
@@ -154,12 +160,20 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
}
} else if (pwm_is_enabled(pwm)) {
pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
-   pm_runtime_put(chip->dev);
+
+   if (!from_resume)
+   pm_runtime_put(chip->dev);
}
 
return 0;
 }
 
+static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+   return __pwm_lpss_apply(chip, pwm, state, false);
+}
+
 static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *

[PATCH v3 06/15] pwm: crc: Fix period / duty_cycle times being off by a factor of 256

2020-06-20 Thread Hans de Goede
While looking into adding atomic-pwm support to the pwm-crc driver I
noticed something odd, there is a PWM_BASE_CLK define of 6 MHz and
there is a clock-divider which divides this with a value between 1-128,
and there are 256 duty-cycle steps.

The pwm-crc code before this commit assumed that a clock-divider
setting of 1 means that the PWM output is running at 6 MHZ, if that
is true, where do these 256 duty-cycle steps come from?

This would require an internal frequency of 256 * 6 MHz = 1.5 GHz, that
seems unlikely for a PMIC which is using a silicon process optimized for
power-switching transistors. It is way more likely that there is an 8
bit counter for the duty cycle which acts as an extra fixed divider
wrt the PWM output frequency.

The main user of the pwm-crc driver is the i915 GPU driver which uses it
for backlight control. Lets compare the PWM register values set by the
video-BIOS (the GOP), assuming the extra fixed divider is present versus
the PWM frequency specified in the Video-BIOS-Tables:

Device: PWM Hz set by BIOS  PWM Hz specified in VBT
Asus T100TA 200 200
Asus T100HA 200 200
Lenovo Miix 2 8 23437   2
Toshiba WT8-A   23437   2

So as we can see if we assume the extra division by 256 then the register
values set by the GOP are an exact match for the VBT values, where as
otherwise the values would be of by a factor of 256.

This commit fixes the period / duty_cycle calculations to take the
extra division by 256 into account.

Signed-off-by: Hans de Goede 
---
Changes in v3:
- Use NSEC_PER_USEC instead of adding a new (non-sensical) NSEC_PER_MHZ define
---
 drivers/pwm/pwm-crc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 272eeb071147..c056eb9b858c 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -21,8 +21,8 @@
 
 #define PWM_MAX_LEVEL  0xFF
 
-#define PWM_BASE_CLK   600  /* 6 MHz */
-#define PWM_MAX_PERIOD_NS  21333/* 46.875KHz */
+#define PWM_BASE_CLK_MHZ   6   /* 6 MHz */
+#define PWM_MAX_PERIOD_NS  5461333 /* 183 Hz */
 
 /**
  * struct crystalcove_pwm - Crystal Cove PWM controller
@@ -72,7 +72,7 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
 
/* changing the clk divisor, need to disable fisrt */
crc_pwm_disable(c, pwm);
-   clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC;
+   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_USEC);
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 01/15] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase

2020-06-20 Thread Hans de Goede
The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets poked from the _PS0 method of the graphics-card device:

Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
If (((Local0 & 0x03) == 0x03))
{
PSAT &= 0xFFFC
Local1 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
RSTA = Zero
RSTF = Zero
RSTA = One
RSTF = One
PWMB |= 0xC000
PWMC = PWMB /* \_SB_.PCI0.GFX0.PWMB */
}

Where PSAT is the power-status register of the PWM controller, so if it
is in D3 when the GFX0 device's PS0 method runs then it will turn it on
and restore the PWM ctrl register value it saved from its PS3 handler.
Note not only does it restore it, it ors it with 0xC000 turning it
on at a time where we may not want it to get turned on at all.

The pwm_get call which the i915 driver does to get a reference to the
PWM controller, already adds a device-link making the GFX0 device a
consumer of the PWM device. So it should already have been resumed when
the above AML runs and the AML should thus not do its undesirable poking
of the PWM controller register.

But the PCI core powers on PCI devices in the no-irq resume phase and
thus calls the troublesome PS0 method in the no-irq resume phase.
Where as LPSS devices by default are resumed in the early resume phase.

This commit sets the resume_from_noirq flag in the bsw_pwm_dev_desc
struct, so that Cherry Trail PWM controllers will be resumed in the
no-irq phase. Together with the device-link added by the pwm-get this
ensures that the PWM controller will be on when the troublesome PS0
method runs, which stops it from poking the PWM controller.

Signed-off-by: Hans de Goede 
---
 drivers/acpi/acpi_lpss.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index c5a5a179f49d..446e666b3466 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -257,6 +257,7 @@ static const struct lpss_device_desc bsw_pwm_dev_desc = {
.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
.prv_offset = 0x800,
.setup = bsw_pwm_setup,
+   .resume_from_noirq = true,
 };
 
 static const struct lpss_device_desc byt_uart_dev_desc = {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 03/15] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare()

2020-06-20 Thread Hans de Goede
According to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency.

So assuming e.g. a 16 bit counter this means that if base_unit is set to 1,
after 65535 input clock-cycles the counter has been increased from 0 to
65535 and it will overflow on the next cycle, so it will overflow after
every 65536 clock cycles and thus the calculations done in
pwm_lpss_prepare() should use 65536 and not 65535.

This commit fixes this. Note this also aligns the calculations in
pwm_lpss_prepare() with those in pwm_lpss_get_state().

Note this effectively reverts commit 684309e5043e ("pwm: lpss: Avoid
potential overflow of base_unit"). The next patch in this series really
fixes the potential overflow of the base_unit value.

Fixes: 684309e5043e ("pwm: lpss: Avoid potential overflow of base_unit")
Reviewed-by: Andy Shevchenko 
Signed-off-by: Hans de Goede 
---
Changes in v3:
- Add Fixes tag
- Add Reviewed-by: Andy Shevchenko tag
---
 drivers/pwm/pwm-lpss.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 9d965ffe66d1..43b1fc634af1 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -93,7 +93,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 * The equation is:
 * base_unit = round(base_unit_range * freq / c)
 */
-   base_unit_range = BIT(lpwm->info->base_unit_bits) - 1;
+   base_unit_range = BIT(lpwm->info->base_unit_bits);
freq *= base_unit_range;
 
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
@@ -104,8 +104,8 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 
orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
-   ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
-   base_unit &= base_unit_range;
+   ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
+   base_unit &= (base_unit_range - 1);
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 10/15] pwm: crc: Implement apply() method to support the new atomic PWM API

2020-06-20 Thread Hans de Goede
Replace the enable, disable and config pwm_ops with an apply op,
to support the new atomic PWM API.

Signed-off-by: Hans de Goede 
---
Changes in v3:
- Keep crc_pwm_calc_clk_div() helper to avoid needless churn
---
 drivers/pwm/pwm-crc.c | 89 ++-
 1 file changed, 53 insertions(+), 36 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index b72008c9b072..8a7f4707279c 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -51,59 +51,76 @@ static int crc_pwm_calc_clk_div(int period_ns)
return clk_div;
 }
 
-static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
+static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+const struct pwm_state *state)
 {
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
-   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
-
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div | PWM_OUTPUT_ENABLE);
-   regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
-
-   return 0;
-}
-
-static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
-   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
-
-   regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div);
-}
-
-static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
- int duty_ns, int period_ns)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
struct device *dev = crc_pwm->chip.dev;
-   int level;
+   int err;
 
-   if (period_ns > PWM_MAX_PERIOD_NS) {
+   if (state->period > PWM_MAX_PERIOD_NS) {
dev_err(dev, "un-supported period_ns\n");
return -EINVAL;
}
 
-   if (pwm_get_period(pwm) != period_ns) {
-   int clk_div = crc_pwm_calc_clk_div(period_ns);
+   if (state->polarity != PWM_POLARITY_NORMAL)
+   return -EOPNOTSUPP;
+
+   if (pwm_is_enabled(pwm) && !state->enabled) {
+   err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
+   if (err) {
+   dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
+   return err;
+   }
+   }
+
+   if (pwm_get_duty_cycle(pwm) != state->duty_cycle ||
+   pwm_get_period(pwm) != state->period) {
+   int level = state->duty_cycle * PWM_MAX_LEVEL / state->period;
 
+   err = regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_DUTY_CYCLE %d\n", err);
+   return err;
+   }
+   }
+
+   if (pwm_is_enabled(pwm) && state->enabled &&
+   pwm_get_period(pwm) != state->period) {
/* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
+   err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
+   return err;
+   }
+   }
 
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
-   clk_div | PWM_OUTPUT_ENABLE);
+   if (pwm_get_period(pwm) != state->period ||
+   pwm_is_enabled(pwm) != state->enabled) {
+   int clk_div = crc_pwm_calc_clk_div(state->period);
+   int pwm_output_enable = state->enabled ? PWM_OUTPUT_ENABLE : 0;
+
+   err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
+  clk_div | pwm_output_enable);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
+   return err;
+   }
}
 
-   /* change the pwm duty cycle */
-   level = duty_ns * PWM_MAX_LEVEL / period_ns;
-   regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
+   if (!pwm_is_enabled(pwm) && state->enabled) {
+   err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
+   if (err) {
+   dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
+   return err;
+   }
+   }
 
return 0;
 }
 
 static const struct pwm_ops crc_pwm_ops = {
-   .config = crc_pwm_config,
-   .enable = crc_pwm_enable,
-   .disable = crc_pwm_disable,
+   .apply = crc_pwm_apply,
 };
 
 static int crystalcove_pwm_probe(struct platform_device *pdev)
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 08/15] pwm: crc: Fix period changes not having any effect

2020-06-20 Thread Hans de Goede
The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

I strongly suspect that the BACKLIGHT_EN register at address 0x51 really
controls a separate output-only GPIO which is connected to the LCD panels
backlight-enable input. Like how the PANEL_EN register at address 0x52
controls an output-only GPIO which is earmarked for the LCD panel's
enable pin. If this is correct then this GPIO should really be added to
the gpio-crystalcove.c driver and the PWM driver should stop poking it.
But I've been unable to come up with a definitive answer here, so I'm
keeping this as is for now.

As the comment in the old code already indicates we must disable the PWM
before we can change the clock divider. But the crc_pwm_disable() and
crc_pwm_enable() calls the old code make for this only change the
BACKLIGHT_EN register; and the value of that register does not matter for
changing the period / the divider. What does matter is that the
PWM_OUTPUT_ENABLE bit must be cleared before a new value can be written.

This commit modifies crc_pwm_config() to clear PWM_OUTPUT_ENABLE instead
when changing the period, so that period changes actually work.

Note this fix will cause a significant behavior change on some devices
using the CRC PWM output to drive their backlight. Before the PWM would
always run with the output frequency configured by the BIOS at boot, now
the period time specified by the i915 driver will actually be honored.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 7 ++-
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 44ec7d5b63e1..81232da0c767 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -82,14 +82,11 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
if (pwm_get_period(pwm) != period_ns) {
int clk_div = crc_pwm_calc_clk_div(period_ns);
 
-   /* changing the clk divisor, need to disable fisrt */
-   crc_pwm_disable(c, pwm);
+   /* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-
-   /* enable back */
-   crc_pwm_enable(c, pwm);
}
 
/* change the pwm duty cycle */
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 14/15] drm/i915: panel: Honor the VBT PWM min setting for devs with an external PWM controller

2020-06-20 Thread Hans de Goede
So far for devices using an external PWM controller (devices using
pwm_setup_backlight()), we have been hardcoding the minimum allowed
PWM level to 0. But several of these devices specify a non 0 minimum
setting in their VBT.

Change pwm_setup_backlight() to use get_backlight_min_vbt() to get
the minimum level.

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/display/intel_panel.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 14e611c92194..cb28b9908ca4 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1925,8 +1925,8 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
 */
pwm_apply_args(panel->backlight.pwm);
 
-   panel->backlight.min = 0; /* 0% */
panel->backlight.max = 100; /* 100% */
+   panel->backlight.min = get_backlight_min_vbt(connector);
level = intel_panel_compute_brightness(connector, 100);
ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
@@ -1941,8 +1941,9 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
 
level = DIV_ROUND_UP(pwm_get_duty_cycle(panel->backlight.pwm) * 100,
 panel->backlight.pwm_period_ns);
-   panel->backlight.level =
-   intel_panel_compute_brightness(connector, level);
+   level = intel_panel_compute_brightness(connector, level);
+   panel->backlight.level = clamp(level, panel->backlight.min,
+  panel->backlight.max);
panel->backlight.enabled = panel->backlight.level != 0;
 
drm_info(_priv->drm, "Using %s PWM for LCD backlight control\n",
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 07/15] pwm: crc: Fix off-by-one error in the clock-divider calculations

2020-06-20 Thread Hans de Goede
The CRC PWM controller has a clock-divider which divides the clock with
a value between 1-128. But as can seen from the PWM_DIV_CLK_xxx
defines, this range maps to a register value of 0-127.

So after calculating the clock-divider we must subtract 1 to get the
register value, unless the requested frequency was so high that the
calculation has already resulted in a (rounded) divider value of 0.

Note that before this fix, setting a period of PWM_MAX_PERIOD_NS which
corresponds to the max. divider value of 128 could have resulted in a
bug where the code would use 128 as divider-register value which would
have resulted in an actual divider value of 0 (and the enable bit being
set). A rounding error stopped this bug from actually happen. This
same rounding error means that after the subtraction of 1 it is impossible
to set the divider to 128. Also bump PWM_MAX_PERIOD_NS by 1 ns to allow
setting a divider of 128 (register-value 127).

Signed-off-by: Hans de Goede 
---
Changes in v3:
- Introduce crc_pwm_calc_clk_div() here instead of later in the patch-set
  to reduce the amount of churn in the patch-set a bit
---
 drivers/pwm/pwm-crc.c | 17 ++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index c056eb9b858c..44ec7d5b63e1 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -22,7 +22,7 @@
 #define PWM_MAX_LEVEL  0xFF
 
 #define PWM_BASE_CLK_MHZ   6   /* 6 MHz */
-#define PWM_MAX_PERIOD_NS  5461333 /* 183 Hz */
+#define PWM_MAX_PERIOD_NS  5461334 /* 183 Hz */
 
 /**
  * struct crystalcove_pwm - Crystal Cove PWM controller
@@ -39,6 +39,18 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct 
pwm_chip *pc)
return container_of(pc, struct crystalcove_pwm, chip);
 }
 
+static int crc_pwm_calc_clk_div(int period_ns)
+{
+   int clk_div;
+
+   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_USEC);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
+
+   return clk_div;
+}
+
 static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
@@ -68,11 +80,10 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
}
 
if (pwm_get_period(pwm) != period_ns) {
-   int clk_div;
+   int clk_div = crc_pwm_calc_clk_div(period_ns);
 
/* changing the clk divisor, need to disable fisrt */
crc_pwm_disable(c, pwm);
-   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_USEC);
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 09/15] pwm: crc: Enable/disable PWM output on enable/disable

2020-06-20 Thread Hans de Goede
The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

So far we've kept the PWM_OUTPUT_ENABLE bit set when disabling the PWM,
this commit makes crc_pwm_disable() clear it on disable and makes
crc_pwm_enable() set it again on re-enable.

Signed-off-by: Hans de Goede 
---
Changes in v3:
- Remove paragraph about tri-stating the output from the commit message,
  we don't have a datasheet so this was just an unfounded guess
---
 drivers/pwm/pwm-crc.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 81232da0c767..b72008c9b072 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -54,7 +54,9 @@ static int crc_pwm_calc_clk_div(int period_ns)
 static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
 
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div | PWM_OUTPUT_ENABLE);
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
 
return 0;
@@ -63,8 +65,10 @@ static int crc_pwm_enable(struct pwm_chip *c, struct 
pwm_device *pwm)
 static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
 
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div);
 }
 
 static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 15/15] drm/i915: panel: Use atomic PWM API for devs with an external PWM controller

2020-06-20 Thread Hans de Goede
Now that the PWM drivers which we use have been converted to the atomic
PWM API, we can move the i915 panel code over to using the atomic PWM API.

The removes a long standing FIXME and this removes a flicker where
the backlight brightness would jump to 100% when i915 loads even if
using the fastset path.

Signed-off-by: Hans de Goede 
---
 .../drm/i915/display/intel_display_types.h|  3 +-
 drivers/gpu/drm/i915/display/intel_panel.c| 73 +--
 2 files changed, 37 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index de32f9efb120..4bd9981e70a1 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -28,6 +28,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -223,7 +224,7 @@ struct intel_panel {
bool util_pin_active_low;   /* bxt+ */
u8 controller;  /* bxt+ only */
struct pwm_device *pwm;
-   int pwm_period_ns;
+   struct pwm_state pwm_state;
 
/* DPCD backlight */
u8 pwmgen_bit_count;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index cb28b9908ca4..a0f76343f381 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -592,10 +592,11 @@ static u32 bxt_get_backlight(struct intel_connector 
*connector)
 static u32 pwm_get_backlight(struct intel_connector *connector)
 {
struct intel_panel *panel = >panel;
-   int duty_ns;
+   int duty_ns, period_ns;
 
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-   return DIV_ROUND_UP(duty_ns * 100, panel->backlight.pwm_period_ns);
+   period_ns = pwm_get_period(panel->backlight.pwm);
+   return DIV_ROUND_UP(duty_ns * 100, period_ns);
 }
 
 static void lpt_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
@@ -669,10 +670,10 @@ static void bxt_set_backlight(const struct 
drm_connector_state *conn_state, u32
 static void pwm_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
 {
struct intel_panel *panel = 
_intel_connector(conn_state->connector)->panel;
-   int duty_ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   pwm_config(panel->backlight.pwm, duty_ns,
-  panel->backlight.pwm_period_ns);
+   panel->backlight.pwm_state.duty_cycle =
+   DIV_ROUND_UP(level * panel->backlight.pwm_state.period, 100);
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 static void
@@ -841,10 +842,8 @@ static void pwm_disable_backlight(const struct 
drm_connector_state *old_conn_sta
struct intel_connector *connector = 
to_intel_connector(old_conn_state->connector);
struct intel_panel *panel = >panel;
 
-   /* Disable the backlight */
-   intel_panel_actually_set_backlight(old_conn_state, 0);
-   usleep_range(2000, 3000);
-   pwm_disable(panel->backlight.pwm);
+   panel->backlight.pwm_state.enabled = false;
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 void intel_panel_disable_backlight(const struct drm_connector_state 
*old_conn_state)
@@ -1176,9 +1175,14 @@ static void pwm_enable_backlight(const struct 
intel_crtc_state *crtc_state,
 {
struct intel_connector *connector = 
to_intel_connector(conn_state->connector);
struct intel_panel *panel = >panel;
+   int level = panel->backlight.level;
 
-   pwm_enable(panel->backlight.pwm);
-   intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+   level = intel_panel_compute_brightness(connector, level);
+
+   panel->backlight.pwm_state.duty_cycle =
+   DIV_ROUND_UP(level * panel->backlight.pwm_state.period, 100);
+   panel->backlight.pwm_state.enabled = true;
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 static void __intel_panel_enable_backlight(const struct intel_crtc_state 
*crtc_state,
@@ -1897,8 +1901,7 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_panel *panel = >panel;
const char *desc;
-   u32 level, ns;
-   int retval;
+   u32 level;
 
/* Get the right PWM chip for DSI backlight according to VBT */
if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
@@ -1916,36 +1919,30 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
return -ENODEV;
}
 
-   panel->backlight.pwm_period_ns = NSEC_PER_SEC /
-get_vbt_pwm_freq(dev_priv);
-
-   /*
-

[PATCH v3 04/15] pwm: lpss: Add range limit check for the base_unit register value

2020-06-20 Thread Hans de Goede
When the user requests a high enough period ns value, then the
calculations in pwm_lpss_prepare() might result in a base_unit value of 0.

But according to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency. Adding 0
to the counter is a no-op. The data-sheet even explicitly states that
writing 0 to the base_unit bits will result in the PWM outputting a
continuous 0 signal.

When the user requestes a low enough period ns value, then the
calculations in pwm_lpss_prepare() might result in a base_unit value
which is bigger then base_unit_range - 1. Currently the codes for this
deals with this by applying a mask:

base_unit &= (base_unit_range - 1);

But this means that we let the value overflow the range, we throw away the
higher bits and store whatever value is left in the lower bits into the
register leading to a random output frequency, rather then clamping the
output frequency to the highest frequency which the hardware can do.

This commit fixes both issues by clamping the base_unit value to be
between 1 and (base_unit_range - 1).

Fixes: 684309e5043e ("pwm: lpss: Avoid potential overflow of base_unit")
Signed-off-by: Hans de Goede 
---
Changes in v3:
- Change upper limit of clamp to (base_unit_range - 1)
- Add Fixes tag
---
 drivers/pwm/pwm-lpss.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 43b1fc634af1..80d0f9c64f9d 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -97,6 +97,9 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
freq *= base_unit_range;
 
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
+   /* base_unit must not be 0 and we also want to avoid overflowing it */
+   base_unit = clamp_t(unsigned long long, base_unit, 1,
+   base_unit_range - 1);
 
on_time_div = 255ULL * duty_ns;
do_div(on_time_div, period_ns);
@@ -105,7 +108,6 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
-   base_unit &= (base_unit_range - 1);
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 13/15] drm/i915: panel: Honor the VBT PWM frequency for devs with an external PWM controller

2020-06-20 Thread Hans de Goede
So far for devices using an external PWM controller (devices using
pwm_setup_backlight()), we have been hardcoding the period-time passed to
pwm_config() to 21333 ns.

I suspect this was done because many VBTs set the PWM frequency to 200
which corresponds to a period-time of 500 ns, which greatly exceeds
the PWM_MAX_PERIOD_NS define in the Crystal Cove PMIC PWM driver, which
used to be 21333.

This PWM_MAX_PERIOD_NS define was actually based on a bug in the PWM
driver where its period and duty-cycle times where off by a factor of 256.

Due to this bug the hardcoded CRC_PMIC_PWM_PERIOD_NS value of 21333 would
result in the PWM driver using its divider of 128, which would result in
a PWM output frequency of 600 Hz / 256 / 128 = 183 Hz. So actually
pretty close to the default VBT value of 200 Hz.

Now that this bug in the pwm-crc driver is fixed, we can actually use
the VBT defined frequency.

This is important because:

a) With the pwm-crc driver fixed it will now translate the hardcoded
CRC_PMIC_PWM_PERIOD_NS value of 21333 ns / 46 Khz to a PWM output
frequency of 23 KHz (the max it can do).

b) The pwm-lpss driver used on many models has always honored the
21333 ns / 46 Khz request

Some panels do not like such high output frequencies. E.g. on a Terra
Pad 1061 tablet, using the LPSS PWM controller, the backlight would go
from off to max, when changing the sysfs backlight brightness value from
90-100%, anything under aprox. 90% would turn the backlight fully off.

Honoring the VBT specified PWM frequency will also hopefully fix the
various bug reports which we have received about users perceiving the
backlight to flicker after a suspend/resume cycle.

Signed-off-by: Hans de Goede 
---
 .../drm/i915/display/intel_display_types.h|  1 +
 drivers/gpu/drm/i915/display/intel_panel.c| 19 +++
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index 2bf3d4cb4ea9..de32f9efb120 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -223,6 +223,7 @@ struct intel_panel {
bool util_pin_active_low;   /* bxt+ */
u8 controller;  /* bxt+ only */
struct pwm_device *pwm;
+   int pwm_period_ns;
 
/* DPCD backlight */
u8 pwmgen_bit_count;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 8efdd9f08a08..14e611c92194 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -40,8 +40,6 @@
 #include "intel_dsi_dcs_backlight.h"
 #include "intel_panel.h"
 
-#define CRC_PMIC_PWM_PERIOD_NS 21333
-
 void
 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
   struct drm_display_mode *adjusted_mode)
@@ -597,7 +595,7 @@ static u32 pwm_get_backlight(struct intel_connector 
*connector)
int duty_ns;
 
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-   return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
+   return DIV_ROUND_UP(duty_ns * 100, panel->backlight.pwm_period_ns);
 }
 
 static void lpt_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
@@ -671,9 +669,10 @@ static void bxt_set_backlight(const struct 
drm_connector_state *conn_state, u32
 static void pwm_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
 {
struct intel_panel *panel = 
_intel_connector(conn_state->connector)->panel;
-   int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+   int duty_ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
+   pwm_config(panel->backlight.pwm, duty_ns,
+  panel->backlight.pwm_period_ns);
 }
 
 static void
@@ -1917,6 +1916,9 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
return -ENODEV;
}
 
+   panel->backlight.pwm_period_ns = NSEC_PER_SEC /
+get_vbt_pwm_freq(dev_priv);
+
/*
 * FIXME: pwm_apply_args() should be removed when switching to
 * the atomic PWM API.
@@ -1926,9 +1928,10 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
panel->backlight.min = 0; /* 0% */
panel->backlight.max = 100; /* 100% */
level = intel_panel_compute_brightness(connector, 100);
-   ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+   ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   retval = pwm_config(panel->backlight.pwm, ns, CRC_PMIC_PWM_PERIOD_NS);
+   retval = pwm_config(panel->backlight.pwm, ns,
+

[PATCH v3 02/15] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)

2020-06-20 Thread Hans de Goede
The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets turned off from the _PS3 method of the graphics-card dev:

Method (_PS3, 0, Serialized)  // _PS3: Power State 3
{
...
PWMB = PWMC /* \_SB_.PCI0.GFX0.PWMC */
PSAT |= 0x03
Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
...
}

Where PSAT is the power-status register of the PWM controller.

Since the i915 driver will do a pwm_get on the pwm device as it uses it to
control the LCD panel backlight, there is a device-link marking the i915
device as a consumer of the pwm device. So that the PWM controller will
always be suspended after the i915 driver suspends (which is the right
thing to do). This causes the above GFX0 PS3 AML code to run before
acpi_lpss.c calls acpi_lpss_save_ctx().

So on these devices the PWM controller will already be off when
acpi_lpss_save_ctx() runs. This causes it to read/save all 1-s (0x)
as ctx register values.

When these bogus values get restored on resume the PWM controller actually
keeps working, since most bits are reserved, but this does set bit 3 of
the LPSS General purpose register, which for the PWM controller has the
following function: "This bit is re-used to support 32kHz slow mode.
Default is 19.2MHz as PWM source clock".

This causes the clock of the PWM controller to switch from 19.2MHz to
32KHz, which is a slow-down of a factor 600. Surprisingly enough so far
there have been few bug reports about this. This is likely because the
i915 driver was hardcoding the PWM frequency to 46 KHz, which divided
by 600 would result in a PWM frequency of approx. 78 Hz, which mostly
still works fine. There are some bug reports about the LCD backlight
flickering after suspend/resume which are likely caused by this issue.

But with the upcoming patch-series to finally switch the i915 drivers
code for external PWM controllers to use the atomic API and to honor
the PWM frequency specified in the video BIOS (VBT), this becomes a much
bigger problem. On most cases the VBT specifies either 200 Hz or 20
KHz as PWM frequency, which with the mentioned issue ends up being either
1/3 Hz, where the backlight actually visible blinks on and off every 3s,
or in 33 Hz and horrible flickering of the backlight.

There are a number of possible solutions to this problem:

1. Make acpi_lpss_save_ctx() run before GFX0._PS3
 Pro: Clean solution from pov of not medling with save/restore ctx code
 Con: As mentioned the current ordering is the right thing to do
 Con: Requires assymmetry in at what suspend/resume phase we do the save vs
  restore, requiring more suspend/resume ordering hacks in already
  convoluted acpi_lpss.c suspend/resume code.
2. Do some sort of save once mode for the LPSS ctx
 Pro: Reasonably clean
 Con: Needs a new LPSS flag + code changes to handle the flag
3. Detect we have failed to save the ctx registers and do not restore them
 Pro: Not PWM specific, might help with issues on other LPSS devices too
 Con: If we can get away with not restoring the ctx why bother with it at
  all?
4. Do not save the ctx for CHT PWM controllers
 Pro: Clean, as simple as dropping a flag?
 Con: Not so simple as dropping a flag, needs a new flag to ensure that
  we still do lpss_deassert_reset() on device activation.
5. Make the pwm-lpss code fixup the LPSS-context registers
 Pro: Keeps acpi_lpss.c code clean
 Con: Moves knowledge of LPSS-context into the pwm-lpss.c code

1 and 5 both do not seem to be a desirable way forward.

3 and 4 seem ok, but they both assume that restoring the LPSS-context
registers is not necessary. I have done a couple of test and those do
show that restoring the LPSS-context indeed does not seem to be necessary
on devices using s2idle suspend (and successfully reaching S0i3). But I
have no hardware to test deep / S3 suspend. So I'm not sure that not
restoring the context is safe.

That leaves solution 2, which is about as simple / clean as 3 and 4,
so this commit fixes the described problem by implementing a new
LPSS_SAVE_CTX_ONCE flag and setting that for the CHT PWM controllers.

Signed-off-by: Hans de Goede 
---
Changes in v2:
- Move #define LPSS_SAVE_CTX_ONCE define to group it with LPSS_SAVE_CTX
---
 drivers/acpi/acpi_lpss.c | 21 +
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 446e666b3466..7e6db0f1d9ee 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -67,7 +67,15 @@ ACPI_MODULE_NAME("acpi_lpss");
 #define LPSS_CLK_DIVIDER   BIT(2)
 #define LPSS_LTR   BIT(3)
 #define LPSS_SAVE_CTX  BIT(4)
-#define LPSS_NO_D3_DELAY   BIT(5)
+/*
+ * For some devices the DSDT AML code for another device turns off the device
+ * before our suspend h

[PATCH v3 11/15] pwm: crc: Implement get_state() method

2020-06-20 Thread Hans de Goede
Implement the pwm_ops.get_state() method to complete the support for the
new atomic PWM API.

Reviewed-by: Andy Shevchenko 
Signed-off-by: Hans de Goede 
---
Changes in v3:
- Add Andy's Reviewed-by tag
- Remove extra whitespace to align some code after assignments (requested by
  Uwe Kleine-König)
---
 drivers/pwm/pwm-crc.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 8a7f4707279c..b311354d40a3 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -119,8 +119,37 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+  struct pwm_state *state)
+{
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
+   struct device *dev = crc_pwm->chip.dev;
+   unsigned int clk_div, clk_div_reg, duty_cycle_reg;
+   int error;
+
+   error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, _div_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error);
+   return;
+   }
+
+   error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, _cycle_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error);
+   return;
+   }
+
+   clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1;
+
+   state->period = clk_div * NSEC_PER_USEC * 256 / PWM_BASE_CLK_MHZ;
+   state->duty_cycle = duty_cycle_reg * state->period / PWM_MAX_LEVEL;
+   state->polarity = PWM_POLARITY_NORMAL;
+   state->enabled = !!(clk_div_reg & PWM_OUTPUT_ENABLE);
+}
+
 static const struct pwm_ops crc_pwm_ops = {
.apply = crc_pwm_apply,
+   .get_state = crc_pwm_get_state,
 };
 
 static int crystalcove_pwm_probe(struct platform_device *pdev)
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 12/15] drm/i915: panel: Add get_vbt_pwm_freq() helper

2020-06-20 Thread Hans de Goede
Factor the code which checks and drm_dbg_kms-s the VBT PWM frequency
out of get_backlight_max_vbt().

This is a preparation patch for honering the VBT PWM frequency for
devices which use an external PWM controller (devices using
pwm_setup_backlight()).

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/display/intel_panel.c | 27 ++
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 3c5056dbf607..8efdd9f08a08 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1543,18 +1543,9 @@ static u32 vlv_hz_to_pwm(struct intel_connector 
*connector, u32 pwm_freq_hz)
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
 }
 
-static u32 get_backlight_max_vbt(struct intel_connector *connector)
+static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv)
 {
-   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-   struct intel_panel *panel = >panel;
u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
-   u32 pwm;
-
-   if (!panel->backlight.hz_to_pwm) {
-   drm_dbg_kms(_priv->drm,
-   "backlight frequency conversion not supported\n");
-   return 0;
-   }
 
if (pwm_freq_hz) {
drm_dbg_kms(_priv->drm,
@@ -1567,6 +1558,22 @@ static u32 get_backlight_max_vbt(struct intel_connector 
*connector)
pwm_freq_hz);
}
 
+   return pwm_freq_hz;
+}
+
+static u32 get_backlight_max_vbt(struct intel_connector *connector)
+{
+   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+   struct intel_panel *panel = >panel;
+   u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
+   u32 pwm;
+
+   if (!panel->backlight.hz_to_pwm) {
+   drm_dbg_kms(_priv->drm,
+   "backlight frequency conversion not supported\n");
+   return 0;
+   }
+
pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
if (!pwm) {
drm_dbg_kms(_priv->drm,
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 00/15] acpi/pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API

2020-06-20 Thread Hans de Goede
Hi All,

Here is v3 of my patch series converting the i915 driver's code for
controlling the panel's backlight with an external PWM controller to
use the atomic PWM API. See below for the changelog.

Initially the plan was for this series to consist of 2 parts:
1. convert the pwm-crc driver to support the atomic PWM API and
2. convert the i915 driver's PWM code to use the atomic PWM API.

But during testing I've found a number of bugs in the pwm-lpss and I
found that the acpi_lpss code needs some special handling because of
some ugliness found in most Cherry Trail DSDTs.

So now this series has grown somewhat large and consists of 4 parts:

1. acpi_lpss fixes workarounds for Cherry Trail DSTD nastiness
2. various fixes to the pwm-lpss driver
3. convert the pwm-crc driver to support the atomic PWM API and
4. convert the i915 driver's PWM code to use the atomic PWM API

So we need to discuss how to merge this (once it passes review).
Although the inter-dependencies are only runtime I still think we should
make sure that 1-3 are in the drm-intel-next-queued (dinq) tree before
merging the i915 changes. Both to make sure that the intel-gfx CI system
does not become unhappy and for bisecting reasons.

The involved acpi_lpss and pwm drivers do not see a whole lot of churn, so
it likely is the easiest to just merge everything through dinq.

Rafael and Thierry, can I get your Acked-by for directly merging this into
dinq?

This series has been tested (and re-tested after adding various bug-fixes)
extensively. It has been tested on the following devices:

-Asus T100TA  BYT + CRC-PMIC PWM
-Toshiba WT8-A  BYT + CRC-PMIC PWM
-Thundersoft TS178 BYT + CRC-PMIC PWM, inverse PWM
-Asus T100HA  CHT + CRC-PMIC PWM
-Terra Pad 1061  BYT + LPSS PWM
-Trekstor Twin 10.1 BYT + LPSS PWM
-Asus T101HA  CHT + CRC-PMIC PWM
-GPD Pocket  CHT + CRC-PMIC PWM

Changelog:

Changes in v2:
- Fix coverletter subject
- Drop accidentally included debugging patch
- "[PATCH v3 02/15] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (
  - Move #define LPSS_SAVE_CTX_ONCE define to group it with LPSS_SAVE_CTX

Changes in v3:
- "[PATCH v3 04/15] pwm: lpss: Add range limit check for the base_unit register 
value"
  - Use base_unit_range - 1 as maximum value for the clamp()
- "[PATCH v3 05/15] pwm: lpss: Use pwm_lpss_apply() when restoring state on 
resume"
  - This replaces the "pwm: lpss: Set SW_UPDATE bit when enabling the PWM"
patch from previous versions of this patch-set, which really was a hack
working around the resume issue which this patch fixes properly.
- PATCH v3 6 - 11 pwm-crc changes:
  - Various small changes resulting from the reviews by Andy and Uwe,
including some refactoring of the patches to reduce the amount of churn
in the patch-set

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API

2020-06-12 Thread Hans de Goede

Hi,

On 6/11/20 11:21 PM, Uwe Kleine-König wrote:

Hello,

On Mon, Jun 08, 2020 at 04:35:00PM +0200, Daniel Vetter wrote:

On Sat, Jun 06, 2020 at 10:25:45PM +0200, Hans de Goede wrote:

Hi All,

This patch series converts the i915 driver's cpde for controlling the
panel's backlight with an external PWM controller to use the atomic PWM API.

Initially the plan was for this series to consist of 2 parts:
1. convert the pwm-crc driver to support the atomic PWM API and
2. convert the i915 driver's PWM code to use the atomic PWM API.

But during testing I've found a number of bugs in the pwm-lpss and I
found that the acpi_lpss code needs some special handling because of
some ugliness found in most Cherry Trail DSDTs.

So now this series has grown somewhat large and consists of 4 parts:

1. acpi_lpss fixes workarounds for Cherry Trail DSTD nastiness
2. various fixes to the pwm-lpss driver
3. convert the pwm-crc driver to support the atomic PWM API and
4. convert the i915 driver's PWM code to use the atomic PWM API

So we need to discuss how to merge this (once it passes review).
Although the inter-dependencies are only runtime I still think we should
make sure that 1-3 are in the drm-intel-next-queued (dinq) tree before
merging the i915 changes. Both to make sure that the intel-gfx CI system
does not become unhappy and for bisecting reasons.


Simplest is if acpi acks the acpi patches for merging through
drm-intel.git. Second simplest is topic branch (drm-intel maintainers can
do that) with the entire pile, which then acpi and drm-intel can both pull
in.

Up to the two maintainer teams to figure this one out.


I'm unclear about the dependencies


There is a runtime dependency of the i915 changes on the PWM changes
and since the intel-gfx folks use a lot of CI, we this need to get the
PWM changes into the drm-intel tree before the i915 changes can land.


, but the changes to drivers/pwm need
an ack (or processing) by the PWM team.


Of course, I asked for an Acked-by from the PWM team
(once this passes review) for merging this through
the drm-intel tree, as the i915 driver is the main
(only AFAIK) consumer of the PWMs controlled by these
2 drivers.  Daniel -ed that bit when he replied.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2 11/15] pwm: crc: Implement get_state() method

2020-06-12 Thread Hans de Goede

Hi,

On 6/11/20 11:37 PM, Uwe Kleine-König wrote:

Hello,

On Sun, Jun 07, 2020 at 08:18:36PM +0200, Hans de Goede wrote:

Implement the pwm_ops.get_state() method to complete the support for the
new atomic PWM API.

Signed-off-by: Hans de Goede 
---
  drivers/pwm/pwm-crc.c | 29 +
  1 file changed, 29 insertions(+)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 58c7e9ef7278..6c75a3470bc8 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -114,8 +114,37 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
  }
  
+static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,

+  struct pwm_state *state)
+{
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
+   struct device *dev = crc_pwm->chip.dev;
+   unsigned int clk_div, clk_div_reg, duty_cycle_reg;
+   int error;
+
+   error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, _div_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error);
+   return;
+   }
+
+   error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, _cycle_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error);
+   return;
+   }


I assume that duty_cycle_reg cannot be bigger than 0xff? Would it make
sense to mask the value accordingly to get more robust code?


+   clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1;
+
+   state->period = clk_div * NSEC_PER_MHZ * 256 / PWM_BASE_CLK_MHZ;
+   state->duty_cycle = duty_cycle_reg * state->period / PWM_MAX_LEVEL;
+   state->polarity   = PWM_POLARITY_NORMAL;
+   state->enabled= !!(clk_div_reg & PWM_OUTPUT_ENABLE);


These aligned = look strange (IMHO). If you don't feel strong here I'd
like to see a single space before a =.


Ok, will change for the next version.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2 09/15] pwm: crc: Enable/disable PWM output on enable/disable

2020-06-12 Thread Hans de Goede

Hi,

On 6/12/20 12:20 AM, Uwe Kleine-König wrote:

On Sun, Jun 07, 2020 at 08:18:34PM +0200, Hans de Goede wrote:

The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

So far we've kept the PWM_OUTPUT_ENABLE bit set when disabling the PWM,
this commit makes crc_pwm_disable() clear it on disable and makes
crc_pwm_enable() set it again on re-enable.

This should disable the internal (divided) PWM clock and tri-state the
PWM output pin when disabled, saving some power.


It would be great if you could also document that disabling the PWM
makes the output tri-state. There are a few drivers that have a
"Limitations" section at their top. Describing that there (in the same
format) would be the right place.

Also note that according to Thierry's conception getting a (driven)
inactive output is the right thing for a disabled PWM.


Hmm, the tri-state thing is an assumption from my side and we
don't have any docs for this PWM controller, so I'm not sure at
all if that is true. So I think it will be better to just drop
the tri-state bit from the commit msg for the next version.

Regards,

Hans


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2 06/15] pwm: crc: Fix period / duty_cycle times being off by a factor of 256

2020-06-09 Thread Hans de Goede

Hi,

On 6/9/20 1:29 PM, Andy Shevchenko wrote:

On Sun, Jun 07, 2020 at 08:18:31PM +0200, Hans de Goede wrote:

While looking into adding atomic-pwm support to the pwm-crc driver I
noticed something odd, there is a PWM_BASE_CLK define of 6 MHz and
there is a clock-divider which divides this with a value between 1-128,
and there are 256 duty-cycle steps.

The pwm-crc code before this commit assumed that a clock-divider
setting of 1 means that the PWM output is running at 6 MHZ, if that
is true, where do these 256 duty-cycle steps come from?

This would require an internal frequency of 256 * 6 MHz = 1.5 GHz, that
seems unlikely for a PMIC which is using a silicon process optimized for
power-switching transistors. It is way more likely that there is an 8
bit counter for the duty cycle which acts as an extra fixed divider
wrt the PWM output frequency.

The main user of the pwm-crc driver is the i915 GPU driver which uses it
for backlight control. Lets compare the PWM register values set by the
video-BIOS (the GOP), assuming the extra fixed divider is present versus
the PWM frequency specified in the Video-BIOS-Tables:

Device: PWM Hz set by BIOS  PWM Hz specified in VBT
Asus T100TA 200 200
Asus T100HA 200 200
Lenovo Miix 2 8 23437   2
Toshiba WT8-A   23437   2

So as we can see if we assume the extra division by 256 then the register
values set by the GOP are an exact match for the VBT values, where as
otherwise the values would be of by a factor of 256.

This commit fixes the period / duty_cycle calculations to take the
extra division by 256 into account.


...


+#define NSEC_PER_MHZ   1000


This is against physics. What this cryptic name means actually?
Existing NSEC_PER_USEC ?


Yes, using existing NSEC_PER_USEC is better I will use that for the
next version.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2 10/15] pwm: crc: Implement apply() method to support the new atomic PWM API

2020-06-09 Thread Hans de Goede

Hi,

On 6/9/20 1:32 PM, Andy Shevchenko wrote:

On Sun, Jun 07, 2020 at 08:18:35PM +0200, Hans de Goede wrote:

Replace the enable, disable and config pwm_ops with an apply op,
to support the new atomic PWM API.


...


-static int crc_pwm_calc_clk_div(int period_ns)
+static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+const struct pwm_state *state)
  {
-   int clk_div;
-
-   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
-   /* clk_div 1 - 128, maps to register values 0-127 */
-   if (clk_div > 0)
-   clk_div--;
-
-   return clk_div;
-}


...


+   clk_div = PWM_BASE_CLK_MHZ * state->period /
+ (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;


And again... :-(


Well yes I cannot help it that the original code, as submitted by Intel,
was of very questionable quality, so instead of just converting it to the
atomic PWM API I had to do a ton of bugfixes first...   I tried to do
this all in small bits rather then in a single big rewrite the buggy
 commit to make life easier for reviewers.

I can introduce the crc_pwm_calc_clk_div helper earlier as you suggested
in an earlier mail. I guess I could also keep the helper here, and then
fold it into the function in a later commit (*).

Would that work for you ?

Regards,

Hans



*) Because having a helper for 3 lines of code when it is used only
once is not helpful IMHO, it only makes it harder to figure out what
the code is exactly doing when readin the code.

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2 03/15] pwm: lpss: Add range limit check for the base_unit register value

2020-06-08 Thread Hans de Goede

Hi,

On 6/8/20 2:51 PM, Andy Shevchenko wrote:

On Mon, Jun 08, 2020 at 01:07:12PM +0200, Hans de Goede wrote:

On 6/8/20 5:50 AM, Andy Shevchenko wrote:

On Sun, Jun 07, 2020 at 08:18:28PM +0200, Hans de Goede wrote:

When the user requests a high enough period ns value, then the
calculations in pwm_lpss_prepare() might result in a base_unit value of 0.

But according to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency. Adding 0
to the counter is a no-op. The data-sheet even explicitly states that
writing 0 to the base_unit bits will result in the PWM outputting a
continuous 0 signal.


So, and why it's a problem?


Lets sya the user requests a PWM output frequency of 100Hz on Cherry Trail
which has a 1920 Hz clock this will result in 100 * 65536 / 1920 =
0.3 -> 0 as base-unit value. So instead of getting 100 Hz the user will
now get a pin which is always outputting low.

OTOH if we clamp to 1 as lowest value, the user will get 19200 / 65536
= 292 Hz as output frequency which is as close to the requested value as
we can get while actually still working as a PWM controller.


So, we should basically divide and round up, no?


Yes, that will work for the low limit of base_unit but it will make
all the other requested period values less accurate.


At least for 0 we will get 0.


We're dealing with frequency here, but the API is dealing with period,
so to get 0 HZ the API user would have to request a period of > 1s e.g.
request 2s / 0.5 Hz but then the user is still not really requesting 0Hz
(that would correspond with a period of infinity which integers cannot
represent.


base_unit values > (base_unit_range / 256), or iow base_unit values using
the 8 most significant bits, cause loss of resolution of the duty-cycle.
E.g. assuming a base_unit_range of 65536 steps, then a base_unit value of
768 (256 * 3), limits the duty-cycle resolution to 65536 / 768 = 85 steps.
Clamp the max base_unit value to base_unit_range / 32 to ensure a
duty-cycle resolution of at least 32 steps. This limits the maximum
output frequency to 600 KHz / 780 KHz depending on the base clock.


This part I don't understand. Why we limiting base unit? I seems like a
deliberate regression.


The way the PWM controller works is that the base-unit gets added to
say a 16 bit (on CHT) counter each input clock and then the highest 8
bits of that counter get compared to the value programmed into the
ON_TIME_DIV bits.

Lets say we do not clamp and allow any value and lets say the user
selects an output frequency of half the input clock, so base-unit
value is 32768, then the counter will only have 2 values:
0 and 32768 after that it will wrap around again. So any on time-div
value < 128 will result in the output being always high and any
value > 128 will result in the output being high/low 50% of the time
and a value of 255 will make the output always low.

So in essence we now only have 3 duty cycle levels, which seems like
a bad idea to me / not what a pwm controller is supposed to do.


It's exactly what is written in the documentation. I can't buy base unit clamp.
Though, I can buy, perhaps, on time divisor granularity, i.e.
   1/   0% - 25%-1 (0%)
   2/   25% - 50% - 75% (50%)
   3/   75%+1 - 100% (100%)
And so on till we got a maximum resolution (8 bits).


Note that the PWM API does not expose the granularity to the API user,
which is why I went with just putting a minimum on it of 32 steps.

Anyways I don't have a strong opinion on this, so I'm fine with not clamping
the base-unit to preserve granularity. We should still clamp it to avoid
overflow if the user us requesting a really high frequency though!

The old code had:

base_unit &= base_unit_range;

Which means that if the user requests a too high value, then we first
overflow base_unit and then truncate it to fit leading to a random
frequency.

So if we forget my minimal granularity argument, then at a minimum
we need to replace the above line with:

base_unit = clamp_t(unsigned long long, base_unit, 1, base_unit_range - 
1);

And since we need the clamp anyways we can then keep the current round-closest
behavior.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2 04/15] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare()

2020-06-08 Thread Hans de Goede

Hi,

On 6/8/20 5:55 AM, Andy Shevchenko wrote:

On Sun, Jun 07, 2020 at 08:18:29PM +0200, Hans de Goede wrote:

According to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency.

So assuming e.g. a 16 bit counter this means that if base_unit is set to 1,
after 65535 input clock-cycles the counter has been increased from 0 to
65535 and it will overflow on the next cycle, so it will overflow after
every 65536 clock cycles and thus the calculations done in
pwm_lpss_prepare() should use 65536 and not 65535.

This commit fixes this. Note this also aligns the calculations in
pwm_lpss_prepare() with those in pwm_lpss_get_state().


This one sounds like a bug which I have noticed on Broxton (but thought as a
hardware issue). In any case it has to be tested on various platforms to see
how it affects on them.


If you like at the datasheet / read my commit description then it
becomes obvious that because of the way the PWM controller works that
it takes the full 2^(base-unit-bits) for the counter to overflow,
not 2^(base-unit-bits) - 1. This will make a difference of a factor
65535/65536 in the output frequency which will be tricky to measure.

IOW I'm not sure we can really test if this helps, but it is
obviously the right thing to do and it aligns the pwm_apply code
with the pwm_get_state code which already does not have the - 1.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2 03/15] pwm: lpss: Add range limit check for the base_unit register value

2020-06-08 Thread Hans de Goede

Hi,

On 6/8/20 5:50 AM, Andy Shevchenko wrote:

On Sun, Jun 07, 2020 at 08:18:28PM +0200, Hans de Goede wrote:

When the user requests a high enough period ns value, then the
calculations in pwm_lpss_prepare() might result in a base_unit value of 0.

But according to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency. Adding 0
to the counter is a no-op. The data-sheet even explicitly states that
writing 0 to the base_unit bits will result in the PWM outputting a
continuous 0 signal.


So, and why it's a problem?


Lets sya the user requests a PWM output frequency of 100Hz on Cherry Trail
which has a 1920 Hz clock this will result in 100 * 65536 / 1920 =
0.3 -> 0 as base-unit value. So instead of getting 100 Hz the user will
now get a pin which is always outputting low.

OTOH if we clamp to 1 as lowest value, the user will get 19200 / 65536
= 292 Hz as output frequency which is as close to the requested value as
we can get while actually still working as a PWM controller.


base_unit values > (base_unit_range / 256), or iow base_unit values using
the 8 most significant bits, cause loss of resolution of the duty-cycle.
E.g. assuming a base_unit_range of 65536 steps, then a base_unit value of
768 (256 * 3), limits the duty-cycle resolution to 65536 / 768 = 85 steps.
Clamp the max base_unit value to base_unit_range / 32 to ensure a
duty-cycle resolution of at least 32 steps. This limits the maximum
output frequency to 600 KHz / 780 KHz depending on the base clock.


This part I don't understand. Why we limiting base unit? I seems like a
deliberate regression.


The way the PWM controller works is that the base-unit gets added to
say a 16 bit (on CHT) counter each input clock and then the highest 8
bits of that counter get compared to the value programmed into the
ON_TIME_DIV bits.

Lets say we do not clamp and allow any value and lets say the user
selects an output frequency of half the input clock, so base-unit
value is 32768, then the counter will only have 2 values:
0 and 32768 after that it will wrap around again. So any on time-div
value < 128 will result in the output being always high and any
value > 128 will result in the output being high/low 50% of the time
and a value of 255 will make the output always low.

So in essence we now only have 3 duty cycle levels, which seems like
a bad idea to me / not what a pwm controller is supposed to do.

So I decided to put a cut of at having at least 32 steps.

The mean reason I wrote this patch though is to avoid a base-unit
value of 0 which really results in a completely non working PWM
output. I personally believe clamping on the high side is a good
idea too. But if you are against that I can drop that part.

Note that the clamping on the high side will not affect the
primary user of the LPSS-pwm driver which is the i915 backlight
code, that never asks for such high frequencies.  But it could
help to avoid an user shooting themselves in the foot when using
the PWM on a dev board through the sysfs interface.

Regards,

Hans


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 09/15] pwm: crc: Enable/disable PWM output on enable/disable

2020-06-07 Thread Hans de Goede
The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

So far we've kept the PWM_OUTPUT_ENABLE bit set when disabling the PWM,
this commit makes crc_pwm_disable() clear it on disable and makes
crc_pwm_enable() set it again on re-enable.

This should disable the internal (divided) PWM clock and tri-state the
PWM output pin when disabled, saving some power.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 24 +---
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index ef49a6e3c4d6..53734bcf67e1 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -41,10 +41,24 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct 
pwm_chip *pc)
return container_of(pc, struct crystalcove_pwm, chip);
 }
 
+static int crc_pwm_calc_clk_div(int period_ns)
+{
+   int clk_div;
+
+   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
+
+   return clk_div;
+}
+
 static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
 
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div | PWM_OUTPUT_ENABLE);
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
 
return 0;
@@ -53,8 +67,10 @@ static int crc_pwm_enable(struct pwm_chip *c, struct 
pwm_device *pwm)
 static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
 
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div);
 }
 
 static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
@@ -70,16 +86,10 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
}
 
if (pwm_get_period(pwm) != period_ns) {
-   int clk_div;
+   int clk_div = crc_pwm_calc_clk_div(period_ns);
 
/* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
-
-   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
-   /* clk_div 1 - 128, maps to register values 0-127 */
-   if (clk_div > 0)
-   clk_div--;
-
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
}
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 12/15] drm/i915: panel: Add get_vbt_pwm_freq() helper

2020-06-07 Thread Hans de Goede
Factor the code which checks and drm_dbg_kms-s the VBT PWM frequency
out of get_backlight_max_vbt().

This is a preparation patch for honering the VBT PWM frequency for
devices which use an external PWM controller (devices using
pwm_setup_backlight()).

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/display/intel_panel.c | 27 ++
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 3c5056dbf607..8efdd9f08a08 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1543,18 +1543,9 @@ static u32 vlv_hz_to_pwm(struct intel_connector 
*connector, u32 pwm_freq_hz)
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
 }
 
-static u32 get_backlight_max_vbt(struct intel_connector *connector)
+static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv)
 {
-   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-   struct intel_panel *panel = >panel;
u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
-   u32 pwm;
-
-   if (!panel->backlight.hz_to_pwm) {
-   drm_dbg_kms(_priv->drm,
-   "backlight frequency conversion not supported\n");
-   return 0;
-   }
 
if (pwm_freq_hz) {
drm_dbg_kms(_priv->drm,
@@ -1567,6 +1558,22 @@ static u32 get_backlight_max_vbt(struct intel_connector 
*connector)
pwm_freq_hz);
}
 
+   return pwm_freq_hz;
+}
+
+static u32 get_backlight_max_vbt(struct intel_connector *connector)
+{
+   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+   struct intel_panel *panel = >panel;
+   u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
+   u32 pwm;
+
+   if (!panel->backlight.hz_to_pwm) {
+   drm_dbg_kms(_priv->drm,
+   "backlight frequency conversion not supported\n");
+   return 0;
+   }
+
pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
if (!pwm) {
drm_dbg_kms(_priv->drm,
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 11/15] pwm: crc: Implement get_state() method

2020-06-07 Thread Hans de Goede
Implement the pwm_ops.get_state() method to complete the support for the
new atomic PWM API.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 58c7e9ef7278..6c75a3470bc8 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -114,8 +114,37 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+  struct pwm_state *state)
+{
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
+   struct device *dev = crc_pwm->chip.dev;
+   unsigned int clk_div, clk_div_reg, duty_cycle_reg;
+   int error;
+
+   error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, _div_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error);
+   return;
+   }
+
+   error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, _cycle_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error);
+   return;
+   }
+
+   clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1;
+
+   state->period = clk_div * NSEC_PER_MHZ * 256 / PWM_BASE_CLK_MHZ;
+   state->duty_cycle = duty_cycle_reg * state->period / PWM_MAX_LEVEL;
+   state->polarity   = PWM_POLARITY_NORMAL;
+   state->enabled= !!(clk_div_reg & PWM_OUTPUT_ENABLE);
+}
+
 static const struct pwm_ops crc_pwm_ops = {
.apply = crc_pwm_apply,
+   .get_state = crc_pwm_get_state,
 };
 
 static int crystalcove_pwm_probe(struct platform_device *pdev)
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 10/15] pwm: crc: Implement apply() method to support the new atomic PWM API

2020-06-07 Thread Hans de Goede
Replace the enable, disable and config pwm_ops with an apply op,
to support the new atomic PWM API.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 107 +++---
 1 file changed, 59 insertions(+), 48 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 53734bcf67e1..58c7e9ef7278 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -41,70 +41,81 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct 
pwm_chip *pc)
return container_of(pc, struct crystalcove_pwm, chip);
 }
 
-static int crc_pwm_calc_clk_div(int period_ns)
+static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+const struct pwm_state *state)
 {
-   int clk_div;
-
-   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
-   /* clk_div 1 - 128, maps to register values 0-127 */
-   if (clk_div > 0)
-   clk_div--;
-
-   return clk_div;
-}
-
-static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
-   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
-
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div | PWM_OUTPUT_ENABLE);
-   regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
-
-   return 0;
-}
-
-static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
-   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
-
-   regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div);
-}
-
-static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
- int duty_ns, int period_ns)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
+   int err, clk_div, level, pwm_output_enable;
struct device *dev = crc_pwm->chip.dev;
-   int level;
 
-   if (period_ns > PWM_MAX_PERIOD_NS) {
+   if (state->period > PWM_MAX_PERIOD_NS) {
dev_err(dev, "un-supported period_ns\n");
return -EINVAL;
}
 
-   if (pwm_get_period(pwm) != period_ns) {
-   int clk_div = crc_pwm_calc_clk_div(period_ns);
+   if (state->polarity != PWM_POLARITY_NORMAL)
+   return -ENOTSUPP;
+
+   if (pwm_is_enabled(pwm) && !state->enabled) {
+   err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
+   if (err) {
+   dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
+   return err;
+   }
+   }
+
+   if (pwm_get_duty_cycle(pwm) != state->duty_cycle ||
+   pwm_get_period(pwm) != state->period) {
+   level = state->duty_cycle * PWM_MAX_LEVEL / state->period;
 
+   err = regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_DUTY_CYCLE %d\n", err);
+   return err;
+   }
+   }
+
+   if (pwm_is_enabled(pwm) && state->enabled &&
+   pwm_get_period(pwm) != state->period) {
/* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
-   clk_div | PWM_OUTPUT_ENABLE);
+   err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
+   return err;
+   }
}
 
-   /* change the pwm duty cycle */
-   level = duty_ns * PWM_MAX_LEVEL / period_ns;
-   regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
+   if (pwm_get_period(pwm) != state->period ||
+   pwm_is_enabled(pwm) != state->enabled) {
+   clk_div = PWM_BASE_CLK_MHZ * state->period /
+ (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
+
+   pwm_output_enable = state->enabled ? PWM_OUTPUT_ENABLE : 0;
+
+   err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
+  clk_div | pwm_output_enable);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
+   return err;
+   }
+   }
+
+   if (!pwm_is_enabled(pwm) && state->enabled) {
+   err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
+   if (err) {
+

[PATCH v2 05/15] pwm: lpss: Set SW_UPDATE bit when enabling the PWM

2020-06-07 Thread Hans de Goede
On the LPSS PWM controller found on Bay Trail (BYT) and Cherry Trail (CHT)
platforms, the following sequence results in an output duty-cycle of 100%
independent of what the duty-cycle requested in the ctrl-reg is:

1. Clear ENABLE bit in ctrl register
2. Let the machine reach a S0i3 low power state
3. Set the ENABLE bit in the ctrl register

The LPSS PWM controller has a mechanism where the ctrl register value
and the actual base-unit and on-time-div values used are latched. When
software sets the SW_UPDATE bit then at the end of the current PWM cycle,
the new values from the ctrl-register will be latched into the actual
registers, and the SW_UPDATE bit will be cleared.  Note on BYT and CHT
the ENABLE bit must be set before waiting for the SW_UPDATE bit to clear,
otherwise the SW_UPDATE bit will never clear (this is indicated in the
pwm-lpss.c code by lpwm->info->bypass being false).

My theory about why this is happening is that when we hit S0i3 the part
which holds the latched values gets turned off and when its turned back on
again at least the on-time-div value has been lost and gets reset to 0
which corresponds to an output duty-cycle of 100%. Testing has shown that
setting the SW_UPDATE bit to request latching the ctrl-register values into
the actual registers (again) fixes this, confirming this theory.

In the past there have been issues where setting the SW_UPDATE bit when
nothing has changed would lead to the next ctrl register changing being
ignored, see commit 2153bbc12f77 ("pwm: lpss: Only set update bit if we are
actually changing the settings"), so we should only set the SW_UPDATE bit
when actually changing the ENABLE bit from 0 to 1.

When looking into how to fix this I noticed that on platforms where
lpwm->info->bypass == false we unnecessarily do 2 read-modify-write cycles
of the ctrl register, one to set the base-unit and on-time-div, immediately
followed by another to set the ENABLE bit.

This commit fixes the 100% duty cycle issue by folding the setting of the
ENABLE bit into pwm_lpss_prepare(), which already checks if any bits in
the ctrl-register have actually changed and if that is the case then sets
the SW_UPDATE bit.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index a764e062103b..2cb0e2a9c08c 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -80,7 +80,7 @@ static inline int pwm_lpss_is_updating(struct pwm_device *pwm)
 }
 
 static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device 
*pwm,
-int duty_ns, int period_ns)
+int duty_ns, int period_ns, bool enable)
 {
unsigned long long on_time_div;
unsigned long c = lpwm->info->clk_rate, base_unit_range;
@@ -115,6 +115,8 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
+   if (enable)
+   ctrl |= PWM_ENABLE;
 
if (orig_ctrl != ctrl) {
pwm_lpss_write(pwm, ctrl);
@@ -142,8 +144,9 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
pm_runtime_put(chip->dev);
return ret;
}
-   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, 
state->period);
-   pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
+   pwm_lpss_prepare(lpwm, pwm,
+state->duty_cycle, state->period,
+lpwm->info->bypass == false);
ret = pwm_lpss_wait_for_update(pwm);
if (ret) {
pm_runtime_put(chip->dev);
@@ -154,7 +157,8 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
ret = pwm_lpss_is_updating(pwm);
if (ret)
return ret;
-   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, 
state->period);
+   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle,
+state->period, false);
return pwm_lpss_wait_for_update(pwm);
}
} else if (pwm_is_enabled(pwm)) {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 15/15] drm/i915: panel: Use atomic PWM API for devs with an external PWM controller

2020-06-07 Thread Hans de Goede
Now that the PWM drivers which we use have been converted to the atomic
PWM API, we can move the i915 panel code over to using the atomic PWM API.

The removes a long standing FIXME and this removes a flicker where
the backlight brightness would jump to 100% when i915 loads even if
using the fastset path.

Signed-off-by: Hans de Goede 
---
 .../drm/i915/display/intel_display_types.h|  3 +-
 drivers/gpu/drm/i915/display/intel_panel.c| 73 +--
 2 files changed, 37 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index 24ea4a7b6dde..48afb2925271 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -28,6 +28,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -223,7 +224,7 @@ struct intel_panel {
bool util_pin_active_low;   /* bxt+ */
u8 controller;  /* bxt+ only */
struct pwm_device *pwm;
-   int pwm_period_ns;
+   struct pwm_state pwm_state;
 
/* DPCD backlight */
u8 pwmgen_bit_count;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index cb28b9908ca4..a0f76343f381 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -592,10 +592,11 @@ static u32 bxt_get_backlight(struct intel_connector 
*connector)
 static u32 pwm_get_backlight(struct intel_connector *connector)
 {
struct intel_panel *panel = >panel;
-   int duty_ns;
+   int duty_ns, period_ns;
 
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-   return DIV_ROUND_UP(duty_ns * 100, panel->backlight.pwm_period_ns);
+   period_ns = pwm_get_period(panel->backlight.pwm);
+   return DIV_ROUND_UP(duty_ns * 100, period_ns);
 }
 
 static void lpt_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
@@ -669,10 +670,10 @@ static void bxt_set_backlight(const struct 
drm_connector_state *conn_state, u32
 static void pwm_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
 {
struct intel_panel *panel = 
_intel_connector(conn_state->connector)->panel;
-   int duty_ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   pwm_config(panel->backlight.pwm, duty_ns,
-  panel->backlight.pwm_period_ns);
+   panel->backlight.pwm_state.duty_cycle =
+   DIV_ROUND_UP(level * panel->backlight.pwm_state.period, 100);
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 static void
@@ -841,10 +842,8 @@ static void pwm_disable_backlight(const struct 
drm_connector_state *old_conn_sta
struct intel_connector *connector = 
to_intel_connector(old_conn_state->connector);
struct intel_panel *panel = >panel;
 
-   /* Disable the backlight */
-   intel_panel_actually_set_backlight(old_conn_state, 0);
-   usleep_range(2000, 3000);
-   pwm_disable(panel->backlight.pwm);
+   panel->backlight.pwm_state.enabled = false;
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 void intel_panel_disable_backlight(const struct drm_connector_state 
*old_conn_state)
@@ -1176,9 +1175,14 @@ static void pwm_enable_backlight(const struct 
intel_crtc_state *crtc_state,
 {
struct intel_connector *connector = 
to_intel_connector(conn_state->connector);
struct intel_panel *panel = >panel;
+   int level = panel->backlight.level;
 
-   pwm_enable(panel->backlight.pwm);
-   intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+   level = intel_panel_compute_brightness(connector, level);
+
+   panel->backlight.pwm_state.duty_cycle =
+   DIV_ROUND_UP(level * panel->backlight.pwm_state.period, 100);
+   panel->backlight.pwm_state.enabled = true;
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 static void __intel_panel_enable_backlight(const struct intel_crtc_state 
*crtc_state,
@@ -1897,8 +1901,7 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_panel *panel = >panel;
const char *desc;
-   u32 level, ns;
-   int retval;
+   u32 level;
 
/* Get the right PWM chip for DSI backlight according to VBT */
if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
@@ -1916,36 +1919,30 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
return -ENODEV;
}
 
-   panel->backlight.pwm_period_ns = NSEC_PER_SEC /
-get_vbt_pwm_freq(dev_priv);
-
-   /*
-

[PATCH v2 13/15] drm/i915: panel: Honor the VBT PWM frequency for devs with an external PWM controller

2020-06-07 Thread Hans de Goede
So far for devices using an external PWM controller (devices using
pwm_setup_backlight()), we have been hardcoding the period-time passed to
pwm_config() to 21333 ns.

I suspect this was done because many VBTs set the PWM frequency to 200
which corresponds to a period-time of 500 ns, which greatly exceeds
the PWM_MAX_PERIOD_NS define in the Crystal Cove PMIC PWM driver, which
used to be 21333.

This PWM_MAX_PERIOD_NS define was actually based on a bug in the PWM
driver where its period and duty-cycle times where off by a factor of 256.

Due to this bug the hardcoded CRC_PMIC_PWM_PERIOD_NS value of 21333 would
result in the PWM driver using its divider of 128, which would result in
a PWM output frequency of 600 Hz / 256 / 128 = 183 Hz. So actually
pretty close to the default VBT value of 200 Hz.

Now that this bug in the pwm-crc driver is fixed, we can actually use
the VBT defined frequency.

This is important because:

a) With the pwm-crc driver fixed it will now translate the hardcoded
CRC_PMIC_PWM_PERIOD_NS value of 21333 ns / 46 Khz to a PWM output
frequency of 23 KHz (the max it can do).

b) The pwm-lpss driver used on many models has always honored the
21333 ns / 46 Khz request

Some panels do not like such high output frequencies. E.g. on a Terra
Pad 1061 tablet, using the LPSS PWM controller, the backlight would go
from off to max, when changing the sysfs backlight brightness value from
90-100%, anything under aprox. 90% would turn the backlight fully off.

Honoring the VBT specified PWM frequency will also hopefully fix the
various bug reports which we have received about users perceiving the
backlight to flicker after a suspend/resume cycle.

Signed-off-by: Hans de Goede 
---
 .../drm/i915/display/intel_display_types.h|  1 +
 drivers/gpu/drm/i915/display/intel_panel.c| 19 +++
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index b24266c624fa..24ea4a7b6dde 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -223,6 +223,7 @@ struct intel_panel {
bool util_pin_active_low;   /* bxt+ */
u8 controller;  /* bxt+ only */
struct pwm_device *pwm;
+   int pwm_period_ns;
 
/* DPCD backlight */
u8 pwmgen_bit_count;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 8efdd9f08a08..14e611c92194 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -40,8 +40,6 @@
 #include "intel_dsi_dcs_backlight.h"
 #include "intel_panel.h"
 
-#define CRC_PMIC_PWM_PERIOD_NS 21333
-
 void
 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
   struct drm_display_mode *adjusted_mode)
@@ -597,7 +595,7 @@ static u32 pwm_get_backlight(struct intel_connector 
*connector)
int duty_ns;
 
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-   return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
+   return DIV_ROUND_UP(duty_ns * 100, panel->backlight.pwm_period_ns);
 }
 
 static void lpt_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
@@ -671,9 +669,10 @@ static void bxt_set_backlight(const struct 
drm_connector_state *conn_state, u32
 static void pwm_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
 {
struct intel_panel *panel = 
_intel_connector(conn_state->connector)->panel;
-   int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+   int duty_ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
+   pwm_config(panel->backlight.pwm, duty_ns,
+  panel->backlight.pwm_period_ns);
 }
 
 static void
@@ -1917,6 +1916,9 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
return -ENODEV;
}
 
+   panel->backlight.pwm_period_ns = NSEC_PER_SEC /
+get_vbt_pwm_freq(dev_priv);
+
/*
 * FIXME: pwm_apply_args() should be removed when switching to
 * the atomic PWM API.
@@ -1926,9 +1928,10 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
panel->backlight.min = 0; /* 0% */
panel->backlight.max = 100; /* 100% */
level = intel_panel_compute_brightness(connector, 100);
-   ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+   ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   retval = pwm_config(panel->backlight.pwm, ns, CRC_PMIC_PWM_PERIOD_NS);
+   retval = pwm_config(panel->backlight.pwm, ns,
+

[PATCH v2 06/15] pwm: crc: Fix period / duty_cycle times being off by a factor of 256

2020-06-07 Thread Hans de Goede
While looking into adding atomic-pwm support to the pwm-crc driver I
noticed something odd, there is a PWM_BASE_CLK define of 6 MHz and
there is a clock-divider which divides this with a value between 1-128,
and there are 256 duty-cycle steps.

The pwm-crc code before this commit assumed that a clock-divider
setting of 1 means that the PWM output is running at 6 MHZ, if that
is true, where do these 256 duty-cycle steps come from?

This would require an internal frequency of 256 * 6 MHz = 1.5 GHz, that
seems unlikely for a PMIC which is using a silicon process optimized for
power-switching transistors. It is way more likely that there is an 8
bit counter for the duty cycle which acts as an extra fixed divider
wrt the PWM output frequency.

The main user of the pwm-crc driver is the i915 GPU driver which uses it
for backlight control. Lets compare the PWM register values set by the
video-BIOS (the GOP), assuming the extra fixed divider is present versus
the PWM frequency specified in the Video-BIOS-Tables:

Device: PWM Hz set by BIOS  PWM Hz specified in VBT
Asus T100TA 200 200
Asus T100HA 200 200
Lenovo Miix 2 8 23437   2
Toshiba WT8-A   23437   2

So as we can see if we assume the extra division by 256 then the register
values set by the GOP are an exact match for the VBT values, where as
otherwise the values would be of by a factor of 256.

This commit fixes the period / duty_cycle calculations to take the
extra division by 256 into account.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 272eeb071147..43fc912c1fe9 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -21,8 +21,10 @@
 
 #define PWM_MAX_LEVEL  0xFF
 
-#define PWM_BASE_CLK   600  /* 6 MHz */
-#define PWM_MAX_PERIOD_NS  21333/* 46.875KHz */
+#define PWM_BASE_CLK_MHZ   6   /* 6 MHz */
+#define PWM_MAX_PERIOD_NS  5461333 /* 183 Hz */
+
+#define NSEC_PER_MHZ   1000
 
 /**
  * struct crystalcove_pwm - Crystal Cove PWM controller
@@ -72,7 +74,7 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
 
/* changing the clk divisor, need to disable fisrt */
crc_pwm_disable(c, pwm);
-   clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC;
+   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 14/15] drm/i915: panel: Honor the VBT PWM min setting for devs with an external PWM controller

2020-06-07 Thread Hans de Goede
So far for devices using an external PWM controller (devices using
pwm_setup_backlight()), we have been hardcoding the minimum allowed
PWM level to 0. But several of these devices specify a non 0 minimum
setting in their VBT.

Change pwm_setup_backlight() to use get_backlight_min_vbt() to get
the minimum level.

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/display/intel_panel.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 14e611c92194..cb28b9908ca4 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1925,8 +1925,8 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
 */
pwm_apply_args(panel->backlight.pwm);
 
-   panel->backlight.min = 0; /* 0% */
panel->backlight.max = 100; /* 100% */
+   panel->backlight.min = get_backlight_min_vbt(connector);
level = intel_panel_compute_brightness(connector, 100);
ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
@@ -1941,8 +1941,9 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
 
level = DIV_ROUND_UP(pwm_get_duty_cycle(panel->backlight.pwm) * 100,
 panel->backlight.pwm_period_ns);
-   panel->backlight.level =
-   intel_panel_compute_brightness(connector, level);
+   level = intel_panel_compute_brightness(connector, level);
+   panel->backlight.level = clamp(level, panel->backlight.min,
+  panel->backlight.max);
panel->backlight.enabled = panel->backlight.level != 0;
 
drm_info(_priv->drm, "Using %s PWM for LCD backlight control\n",
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 08/15] pwm: crc: Fix period changes not having any effect

2020-06-07 Thread Hans de Goede
The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

I strongly suspect that the BACKLIGHT_EN register at address 0x51 really
controls a separate output-only GPIO which is connected to the LCD panels
backlight-enable input. Like how the PANEL_EN register at address 0x52
controls an output-only GPIO which is earmarked for the LCD panel's
enable pin. If this is correct then this GPIO should really be added to
the gpio-crystalcove.c driver and the PWM driver should stop poking it.
But I've been unable to come up with a definitive answer here, so I'm
keeping this as is for now.

As the comment in the old code already indicates we must disable the PWM
before we can change the clock divider. But the crc_pwm_disable() and
crc_pwm_enable() calls the old code make for this only change the
BACKLIGHT_EN register; and the value of that register does not matter for
changing the period / the divider. What does matter is that the
PWM_OUTPUT_ENABLE bit must be cleared before a new value can be written.

This commit modifies crc_pwm_config() to clear PWM_OUTPUT_ENABLE instead
when changing the period, so that period changes actually work.

Note this fix will cause a significant behavior change on some devices
using the CRC PWM output to drive their backlight. Before the PWM would
always run with the output frequency configured by the BIOS at boot, now
the period time specified by the i915 driver will actually be honored.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 5ba2a65c524c..ef49a6e3c4d6 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -72,8 +72,9 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
if (pwm_get_period(pwm) != period_ns) {
int clk_div;
 
-   /* changing the clk divisor, need to disable fisrt */
-   crc_pwm_disable(c, pwm);
+   /* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
+
clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
/* clk_div 1 - 128, maps to register values 0-127 */
if (clk_div > 0)
@@ -81,9 +82,6 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-
-   /* enable back */
-   crc_pwm_enable(c, pwm);
}
 
/* change the pwm duty cycle */
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 07/15] pwm: crc: Fix off-by-one error in the clock-divider calculations

2020-06-07 Thread Hans de Goede
The CRC PWM controller has a clock-divider which divides the clock with
a value between 1-128. But as can seen from the PWM_DIV_CLK_xxx
defines, this range maps to a register value of 0-127.

So after calculating the clock-divider we must subtract 1 to get the
register value, unless the requested frequency was so high that the
calculation has already resulted in a (rounded) divider value of 0.

Note that before this fix, setting a period of PWM_MAX_PERIOD_NS which
corresponds to the max. divider value of 128 could have resulted in a
bug where the code would use 128 as divider-register value which would
have resulted in an actual divider value of 0 (and the enable bit being
set). A rounding error stopped this bug from actually happen. This
same rounding error means that after the subtraction of 1 it is impossible
to set the divider to 128. Also bump PWM_MAX_PERIOD_NS by 1 ns to allow
setting a divider of 128 (register-value 127).

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 43fc912c1fe9..5ba2a65c524c 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -22,7 +22,7 @@
 #define PWM_MAX_LEVEL  0xFF
 
 #define PWM_BASE_CLK_MHZ   6   /* 6 MHz */
-#define PWM_MAX_PERIOD_NS  5461333 /* 183 Hz */
+#define PWM_MAX_PERIOD_NS  5461334 /* 183 Hz */
 
 #define NSEC_PER_MHZ   1000
 
@@ -75,6 +75,9 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
/* changing the clk divisor, need to disable fisrt */
crc_pwm_disable(c, pwm);
clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 04/15] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare()

2020-06-07 Thread Hans de Goede
According to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency.

So assuming e.g. a 16 bit counter this means that if base_unit is set to 1,
after 65535 input clock-cycles the counter has been increased from 0 to
65535 and it will overflow on the next cycle, so it will overflow after
every 65536 clock cycles and thus the calculations done in
pwm_lpss_prepare() should use 65536 and not 65535.

This commit fixes this. Note this also aligns the calculations in
pwm_lpss_prepare() with those in pwm_lpss_get_state().

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index cae74ce61654..a764e062103b 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -93,7 +93,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 * The equation is:
 * base_unit = round(base_unit_range * freq / c)
 */
-   base_unit_range = BIT(lpwm->info->base_unit_bits) - 1;
+   base_unit_range = BIT(lpwm->info->base_unit_bits);
freq *= base_unit_range;
 
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
@@ -112,7 +112,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 
orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
-   ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
+   ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 01/15] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase

2020-06-07 Thread Hans de Goede
The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets poked from the _PS0 method of the graphics-card device:

Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
If (((Local0 & 0x03) == 0x03))
{
PSAT &= 0xFFFC
Local1 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
RSTA = Zero
RSTF = Zero
RSTA = One
RSTF = One
PWMB |= 0xC000
PWMC = PWMB /* \_SB_.PCI0.GFX0.PWMB */
}

Where PSAT is the power-status register of the PWM controller, so if it
is in D3 when the GFX0 device's PS0 method runs then it will turn it on
and restore the PWM ctrl register value it saved from its PS3 handler.
Note not only does it restore it, it ors it with 0xC000 turning it
on at a time where we may not want it to get turned on at all.

The pwm_get call which the i915 driver does to get a reference to the
PWM controller, already adds a device-link making the GFX0 device a
consumer of the PWM device. So it should already have been resumed when
the above AML runs and the AML should thus not do its undesirable poking
of the PWM controller register.

But the PCI core powers on PCI devices in the no-irq resume phase and
thus calls the troublesome PS0 method in the no-irq resume phase.
Where as LPSS devices by default are resumed in the early resume phase.

This commit sets the resume_from_noirq flag in the bsw_pwm_dev_desc
struct, so that Cherry Trail PWM controllers will be resumed in the
no-irq phase. Together with the device-link added by the pwm-get this
ensures that the PWM controller will be on when the troublesome PS0
method runs, which stops it from poking the PWM controller.

Signed-off-by: Hans de Goede 
---
 drivers/acpi/acpi_lpss.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 5e2bfbcf526f..67892fc0b822 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -257,6 +257,7 @@ static const struct lpss_device_desc bsw_pwm_dev_desc = {
.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
.prv_offset = 0x800,
.setup = bsw_pwm_setup,
+   .resume_from_noirq = true,
 };
 
 static const struct lpss_device_desc byt_uart_dev_desc = {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 02/15] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)

2020-06-07 Thread Hans de Goede
The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets turned off from the _PS3 method of the graphics-card dev:

Method (_PS3, 0, Serialized)  // _PS3: Power State 3
{
...
PWMB = PWMC /* \_SB_.PCI0.GFX0.PWMC */
PSAT |= 0x03
Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
...
}

Where PSAT is the power-status register of the PWM controller.

Since the i915 driver will do a pwm_get on the pwm device as it uses it to
control the LCD panel backlight, there is a device-link marking the i915
device as a consumer of the pwm device. So that the PWM controller will
always be suspended after the i915 driver suspends (which is the right
thing to do). This causes the above GFX0 PS3 AML code to run before
acpi_lpss.c calls acpi_lpss_save_ctx().

So on these devices the PWM controller will already be off when
acpi_lpss_save_ctx() runs. This causes it to read/save all 1-s (0x)
as ctx register values.

When these bogus values get restored on resume the PWM controller actually
keeps working, since most bits are reserved, but this does set bit 3 of
the LPSS General purpose register, which for the PWM controller has the
following function: "This bit is re-used to support 32kHz slow mode.
Default is 19.2MHz as PWM source clock".

This causes the clock of the PWM controller to switch from 19.2MHz to
32KHz, which is a slow-down of a factor 600. Surprisingly enough so far
there have been few bug reports about this. This is likely because the
i915 driver was hardcoding the PWM frequency to 46 KHz, which divided
by 600 would result in a PWM frequency of approx. 78 Hz, which mostly
still works fine. There are some bug reports about the LCD backlight
flickering after suspend/resume which are likely caused by this issue.

But with the upcoming patch-series to finally switch the i915 drivers
code for external PWM controllers to use the atomic API and to honor
the PWM frequency specified in the video BIOS (VBT), this becomes a much
bigger problem. On most cases the VBT specifies either 200 Hz or 20
KHz as PWM frequency, which with the mentioned issue ends up being either
1/3 Hz, where the backlight actually visible blinks on and off every 3s,
or in 33 Hz and horrible flickering of the backlight.

There are a number of possible solutions to this problem:

1. Make acpi_lpss_save_ctx() run before GFX0._PS3
 Pro: Clean solution from pov of not medling with save/restore ctx code
 Con: As mentioned the current ordering is the right thing to do
 Con: Requires assymmetry in at what suspend/resume phase we do the save vs
  restore, requiring more suspend/resume ordering hacks in already
  convoluted acpi_lpss.c suspend/resume code.
2. Do some sort of save once mode for the LPSS ctx
 Pro: Reasonably clean
 Con: Needs a new LPSS flag + code changes to handle the flag
3. Detect we have failed to save the ctx registers and do not restore them
 Pro: Not PWM specific, might help with issues on other LPSS devices too
 Con: If we can get away with not restoring the ctx why bother with it at
  all?
4. Do not save the ctx for CHT PWM controllers
 Pro: Clean, as simple as dropping a flag?
 Con: Not so simple as dropping a flag, needs a new flag to ensure that
  we still do lpss_deassert_reset() on device activation.
5. Make the pwm-lpss code fixup the LPSS-context registers
 Pro: Keeps acpi_lpss.c code clean
 Con: Moves knowledge of LPSS-context into the pwm-lpss.c code

1 and 5 both do not seem to be a desirable way forward.

3 and 4 seem ok, but they both assume that restoring the LPSS-context
registers is not necessary. I have done a couple of test and those do
show that restoring the LPSS-context indeed does not seem to be necessary
on devices using s2idle suspend (and successfully reaching S0i3). But I
have no hardware to test deep / S3 suspend. So I'm not sure that not
restoring the context is safe.

That leaves solution 2, which is about as simple / clean as 3 and 4,
so this commit fixes the described problem by implementing a new
LPSS_SAVE_CTX_ONCE flag and setting that for the CHT PWM controllers.

Signed-off-by: Hans de Goede 
---
Changes in v2:
- Move #define LPSS_SAVE_CTX_ONCE define to group it with LPSS_SAVE_CTX
---
 drivers/acpi/acpi_lpss.c | 21 +
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 67892fc0b822..a8d7d83ac761 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -67,7 +67,15 @@ ACPI_MODULE_NAME("acpi_lpss");
 #define LPSS_CLK_DIVIDER   BIT(2)
 #define LPSS_LTR   BIT(3)
 #define LPSS_SAVE_CTX  BIT(4)
-#define LPSS_NO_D3_DELAY   BIT(5)
+/*
+ * For some devices the DSDT AML code for another device turns off the device
+ * before our suspend h

[PATCH v2 00/15] pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API

2020-06-07 Thread Hans de Goede
Hi All,

Here is v2 dropping a debugging-patch which I accidentally kept for v1
and addressing a minor review remark from Andy for the 2nd patch.

This patch series converts the i915 driver's code for controlling the
panel's backlight with an external PWM controller to use the atomic PWM API.

Initially the plan was for this series to consist of 2 parts:
1. convert the pwm-crc driver to support the atomic PWM API and
2. convert the i915 driver's PWM code to use the atomic PWM API.

But during testing I've found a number of bugs in the pwm-lpss and I
found that the acpi_lpss code needs some special handling because of
some ugliness found in most Cherry Trail DSDTs.

So now this series has grown somewhat large and consists of 4 parts:

1. acpi_lpss fixes workarounds for Cherry Trail DSTD nastiness
2. various fixes to the pwm-lpss driver
3. convert the pwm-crc driver to support the atomic PWM API and
4. convert the i915 driver's PWM code to use the atomic PWM API

So we need to discuss how to merge this (once it passes review).
Although the inter-dependencies are only runtime I still think we should
make sure that 1-3 are in the drm-intel-next-queued (dinq) tree before
merging the i915 changes. Both to make sure that the intel-gfx CI system
does not become unhappy and for bisecting reasons.

The involved acpi_lpss and pwm drivers do not see a whole lot of churn,
so we could just merge everything through dinq, or we could use immutable
branch and merge those into dinq.

So Rafael and Thierry, can I either get your Acked-by for directly merging
this into dinq, or can you provide an immutable branch with these patches?

This series has been tested (and re-tested after adding various bug-fixes)
extensively. It has been tested on the following devices:

-Asus T100TA  BYT + CRC-PMIC PWM
-Toshiba WT8-A  BYT + CRC-PMIC PWM
-Thundersoft TS178 BYT + CRC-PMIC PWM, inverse PWM
-Asus T100HA  CHT + CRC-PMIC PWM
-Terra Pad 1061  BYT + LPSS PWM
-Trekstor Twin 10.1 BYT + LPSS PWM
-Asus T101HA  CHT + CRC-PMIC PWM
-GPD Pocket  CHT + CRC-PMIC PWM

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 03/15] pwm: lpss: Add range limit check for the base_unit register value

2020-06-07 Thread Hans de Goede
When the user requests a high enough period ns value, then the
calculations in pwm_lpss_prepare() might result in a base_unit value of 0.

But according to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency. Adding 0
to the counter is a no-op. The data-sheet even explicitly states that
writing 0 to the base_unit bits will result in the PWM outputting a
continuous 0 signal.

base_unit values > (base_unit_range / 256), or iow base_unit values using
the 8 most significant bits, cause loss of resolution of the duty-cycle.
E.g. assuming a base_unit_range of 65536 steps, then a base_unit value of
768 (256 * 3), limits the duty-cycle resolution to 65536 / 768 = 85 steps.
Clamp the max base_unit value to base_unit_range / 32 to ensure a
duty-cycle resolution of at least 32 steps. This limits the maximum
output frequency to 600 KHz / 780 KHz depending on the base clock.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 9d965ffe66d1..cae74ce61654 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -97,6 +97,14 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
freq *= base_unit_range;
 
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
+   /*
+* base_unit must not be 0 and for values > (base_unit_range / 256)
+* (values using the 8 most significant bits) the duty-cycle resolution
+* degrades. Clamp the maximum value to base_unit_range / 32 which
+* leaves a duty-cycle resolution of 32 steps.
+*/
+   base_unit = clamp_t(unsigned long long, base_unit, 1,
+   base_unit_range / 32);
 
on_time_div = 255ULL * duty_ns;
do_div(on_time_div, period_ns);
@@ -105,7 +113,6 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
-   base_unit &= base_unit_range;
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API

2020-06-07 Thread Hans de Goede

Hi All,

I forgot the [PATCH 0/16] part of the subject here and I accidentally
left a patch adding some debugging printk-s in the series. I will
send out a v2 addressing this.

Regards,

Hans

On 6/6/20 10:25 PM, Hans de Goede wrote:

Hi All,

This patch series converts the i915 driver's cpde for controlling the
panel's backlight with an external PWM controller to use the atomic PWM API.

Initially the plan was for this series to consist of 2 parts:
1. convert the pwm-crc driver to support the atomic PWM API and
2. convert the i915 driver's PWM code to use the atomic PWM API.

But during testing I've found a number of bugs in the pwm-lpss and I
found that the acpi_lpss code needs some special handling because of
some ugliness found in most Cherry Trail DSDTs.

So now this series has grown somewhat large and consists of 4 parts:

1. acpi_lpss fixes workarounds for Cherry Trail DSTD nastiness
2. various fixes to the pwm-lpss driver
3. convert the pwm-crc driver to support the atomic PWM API and
4. convert the i915 driver's PWM code to use the atomic PWM API

So we need to discuss how to merge this (once it passes review).
Although the inter-dependencies are only runtime I still think we should
make sure that 1-3 are in the drm-intel-next-queued (dinq) tree before
merging the i915 changes. Both to make sure that the intel-gfx CI system
does not become unhappy and for bisecting reasons.

The involved acpi_lpss and pwm drivers do not see a whole lot of churn,
so we could just merge everything through dinq, or we could use immutable
branch and merge those into dinq.

So Rafael and Thierry, can I either get your Acked-by for directly merging
this into dinq, or can you provide an immutable branch with these patches?

This series has been tested (and re-tested after adding various bug-fixes)
extensively. It has been tested on the following devices:

-Asus T100TABYT + CRC-PMIC PWM
-Toshiba WT8-A  BYT + CRC-PMIC PWM
-Thundersoft TS178  BYT + CRC-PMIC PWM, inverse PWM
-Asus T100HACHT + CRC-PMIC PWM
-Terra Pad 1061 BYT + LPSS PWM
-Trekstor Twin 10.1 BYT + LPSS PWM
-Asus T101HACHT + CRC-PMIC PWM
-GPD Pocket CHT + CRC-PMIC PWM

Regards,

Hans



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)

2020-06-07 Thread Hans de Goede

Hi,

On 6/7/20 7:03 PM, Andy Shevchenko wrote:

On Sat, Jun 06, 2020 at 10:25:47PM +0200, Hans de Goede wrote:

The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets turned off from the _PS3 method of the graphics-card dev:

 Method (_PS3, 0, Serialized)  // _PS3: Power State 3
 {
 ...
 PWMB = PWMC /* \_SB_.PCI0.GFX0.PWMC */
 PSAT |= 0x03
 Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
 ...
 }

Where PSAT is the power-status register of the PWM controller.

Since the i915 driver will do a pwm_get on the pwm device as it uses it to
control the LCD panel backlight, there is a device-link marking the i915
device as a consumer of the pwm device. So that the PWM controller will
always be suspended after the i915 driver suspends (which is the right
thing to do). This causes the above GFX0 PS3 AML code to run before
acpi_lpss.c calls acpi_lpss_save_ctx().

So on these devices the PWM controller will already be off when
acpi_lpss_save_ctx() runs. This causes it to read/save all 1-s (0x)
as ctx register values.

When these bogus values get restored on resume the PWM controller actually
keeps working, since most bits are reserved, but this does set bit 3 of
the LPSS General purpose register, which for the PWM controller has the
following function: "This bit is re-used to support 32kHz slow mode.
Default is 19.2MHz as PWM source clock".

This causes the clock of the PWM controller to switch from 19.2MHz to
32KHz, which is a slow-down of a factor 600. Suprisingly enough so far
there have been few bug reports about this. This is likely because the
i915 driver was hardcoding the PWM frequency to 46 KHz, which divided
by 600 would result in a PWM frequency of approx. 78 Hz, which mostly
still works fine. There are some bug reports about the LCD backlight
flickering after suspend/resume which are likely caused by this issue.

But with the upcoming patch-series to finally switch the i915 drivers
code for external PWM controllers to use the atomic API and to honor
the PWM frequency specified in the video BIOS (VBT), this becomes a much
bigger problem. On most cases the VBT specifies either 200 Hz or 20
KHz as PWM frequency, which with the mentioned issue ends up being either
1/3 Hz, where the backlight actually visible blinks on and off every 3s,
or in 33 Hz and horrible flickering of the backlight.

There are a number of possible solutions to this problem:

1. Make acpi_lpss_save_ctx() run before GFX0._PS3
  Pro: Clean solution from pov of not medling with save/restore ctx code
  Con: As mentioned the current ordering is the right thing to do
  Con: Requires assymmetry in at what suspend/resume phase we do the save vs
   restore, requiring more suspend/resume ordering hacks in already
   convoluted acpi_lpss.c suspend/resume code.
2. Do some sort of save once mode for the LPSS ctx
  Pro: Reasonably clean
  Con: Needs a new LPSS flag + code changes to handle the flag
3. Detect we have failed to save the ctx registers and do not restore them
  Pro: Not PWM specific, might help with issues on other LPSS devices too
  Con: If we can get away with not restoring the ctx why bother with it at
   all?
4. Do not save the ctx for CHT PWM controllers
  Pro: Clean, as simple as dropping a flag?
  Con: Not so simple as dropping a flag, needs a new flag to ensure that
   we still do lpss_deassert_reset() on device activation.
5. Make the pwm-lpss code fixup the LPSS-context registers
  Pro: Keeps acpi_lpss.c code clean
  Con: Moves knowledge of LPSS-context into the pwm-lpss.c code

1 and 5 both do not seem to be a desirable way forward.

3 and 4 seem ok, but they both assume that restoring the LPSS-context
registers is not necessary. I have done a couple of test and those do
show that restoring the LPSS-context indeed does not seem to be necessary
on devices using s2idle suspend (and successfully reaching S0i3). But I
have no hardware to test deep / S3 suspend. So I'm not sure that not
restoring the context is safe.

That leaves solution 2, which is about as simple / clean as 3 and 4,
so this commit fixes the described problem by implementing a new
LPSS_SAVE_CTX_ONCE flag and setting that for the CHT PWM controllers.

Signed-off-by: Hans de Goede 
---
  drivers/acpi/acpi_lpss.c | 19 ---
  1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 67892fc0b822..26933e6b7b8c 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -68,6 +68,14 @@ ACPI_MODULE_NAME("acpi_lpss");
  #define LPSS_LTR  BIT(3)
  #define LPSS_SAVE_CTX BIT(4)
  #define LPSS_NO_D3_DELAY  BIT(5)
+/*
+ * For some devices the DSDT AML code for another device turns off the device
+ * before our suspend hand

[PATCH 15/16] drm/i915: panel: Honor the VBT PWM min setting for devs with an external PWM controller

2020-06-06 Thread Hans de Goede
So far for devices using an external PWM controller (devices using
pwm_setup_backlight()), we have been hardcoding the minimum allowed
PWM level to 0. But several of these devices specify a non 0 minimum
setting in their VBT.

Change pwm_setup_backlight() to use get_backlight_min_vbt() to get
the minimum level.

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/display/intel_panel.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 14e611c92194..cb28b9908ca4 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1925,8 +1925,8 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
 */
pwm_apply_args(panel->backlight.pwm);
 
-   panel->backlight.min = 0; /* 0% */
panel->backlight.max = 100; /* 100% */
+   panel->backlight.min = get_backlight_min_vbt(connector);
level = intel_panel_compute_brightness(connector, 100);
ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
@@ -1941,8 +1941,9 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
 
level = DIV_ROUND_UP(pwm_get_duty_cycle(panel->backlight.pwm) * 100,
 panel->backlight.pwm_period_ns);
-   panel->backlight.level =
-   intel_panel_compute_brightness(connector, level);
+   level = intel_panel_compute_brightness(connector, level);
+   panel->backlight.level = clamp(level, panel->backlight.min,
+  panel->backlight.max);
panel->backlight.enabled = panel->backlight.level != 0;
 
drm_info(_priv->drm, "Using %s PWM for LCD backlight control\n",
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 13/16] drm/i915: panel: Add get_vbt_pwm_freq() helper

2020-06-06 Thread Hans de Goede
Factor the code which checks and drm_dbg_kms-s the VBT PWM frequency
out of get_backlight_max_vbt().

This is a preparation patch for honering the VBT PWM frequency for
devices which use an external PWM controller (devices using
pwm_setup_backlight()).

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/display/intel_panel.c | 27 ++
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 3c5056dbf607..8efdd9f08a08 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1543,18 +1543,9 @@ static u32 vlv_hz_to_pwm(struct intel_connector 
*connector, u32 pwm_freq_hz)
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
 }
 
-static u32 get_backlight_max_vbt(struct intel_connector *connector)
+static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv)
 {
-   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-   struct intel_panel *panel = >panel;
u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
-   u32 pwm;
-
-   if (!panel->backlight.hz_to_pwm) {
-   drm_dbg_kms(_priv->drm,
-   "backlight frequency conversion not supported\n");
-   return 0;
-   }
 
if (pwm_freq_hz) {
drm_dbg_kms(_priv->drm,
@@ -1567,6 +1558,22 @@ static u32 get_backlight_max_vbt(struct intel_connector 
*connector)
pwm_freq_hz);
}
 
+   return pwm_freq_hz;
+}
+
+static u32 get_backlight_max_vbt(struct intel_connector *connector)
+{
+   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+   struct intel_panel *panel = >panel;
+   u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
+   u32 pwm;
+
+   if (!panel->backlight.hz_to_pwm) {
+   drm_dbg_kms(_priv->drm,
+   "backlight frequency conversion not supported\n");
+   return 0;
+   }
+
pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
if (!pwm) {
drm_dbg_kms(_priv->drm,
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 04/16] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare()

2020-06-06 Thread Hans de Goede
According to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency.

So assuming e.g. a 16 bit counter this means that if base_unit is set to 1,
after 65535 input clock-cycles the counter has been increased from 0 to
65535 and it will overflow on the next cycle, so it will overflow after
every 65536 clock cycles and thus the calculations done in
pwm_lpss_prepare() should use 65536 and not 65535.

This commit fixes this. Note this also aligns the calculations in
pwm_lpss_prepare() with those in pwm_lpss_get_state().

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index cae74ce61654..a764e062103b 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -93,7 +93,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 * The equation is:
 * base_unit = round(base_unit_range * freq / c)
 */
-   base_unit_range = BIT(lpwm->info->base_unit_bits) - 1;
+   base_unit_range = BIT(lpwm->info->base_unit_bits);
freq *= base_unit_range;
 
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
@@ -112,7 +112,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 
orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
-   ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
+   ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 01/16] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase

2020-06-06 Thread Hans de Goede
The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets poked from the _PS0 method of the graphics-card device:

Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
If (((Local0 & 0x03) == 0x03))
{
PSAT &= 0xFFFC
Local1 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
RSTA = Zero
RSTF = Zero
RSTA = One
RSTF = One
PWMB |= 0xC000
PWMC = PWMB /* \_SB_.PCI0.GFX0.PWMB */
}

Where PSAT is the power-status register of the PWM controller, so if it
is in D3 when the GFX0 device's PS0 method runs then it will turn it on
and restore the PWM ctrl register value it saved from its PS3 handler.
Note not only does it restore it, it ors it with 0xC000 turning it
on at a time where we may not want it to get turned on at all.

The pwm_get call which the i915 driver does to get a reference to the
PWM controller, already adds a device-link making the GFX0 device a
consumer of the PWM device. So it should already have been resumed when
the above AML runs and the AML should thus not do its undesirable poking
of the PWM controller register.

But the PCI core powers on PCI devices in the no-irq resume phase and
thus calls the troublesome PS0 method in the no-irq resume phase.
Where as LPSS devices by default are resumed in the early resume phase.

This commit sets the resume_from_noirq flag in the bsw_pwm_dev_desc
struct, so that Cherry Trail PWM controllers will be resumed in the
no-irq phase. Together with the device-link added by the pwm-get this
ensures that the PWM controller will be on when the troublesome PS0
method runs, which stops it from poking the PWM controller.

Signed-off-by: Hans de Goede 
---
 drivers/acpi/acpi_lpss.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 5e2bfbcf526f..67892fc0b822 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -257,6 +257,7 @@ static const struct lpss_device_desc bsw_pwm_dev_desc = {
.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
.prv_offset = 0x800,
.setup = bsw_pwm_setup,
+   .resume_from_noirq = true,
 };
 
 static const struct lpss_device_desc byt_uart_dev_desc = {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 06/16] pwm: lpss: Add debug prints, test patch for moving i915 to atomic PWM

2020-06-06 Thread Hans de Goede
Add debug prints, test patch for moving i915 to atomic PWM.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 2cb0e2a9c08c..c1f8e6da0cd7 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -119,6 +119,8 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
ctrl |= PWM_ENABLE;
 
if (orig_ctrl != ctrl) {
+   dev_err(pwm->chip->dev, "prepare 0x%08x -> 0x%08lx\n",
+   orig_ctrl, ctrl | PWM_SW_UPDATE);
pwm_lpss_write(pwm, ctrl);
pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE);
}
@@ -126,8 +128,15 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 
 static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond)
 {
-   if (cond)
-   pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
+   if (cond) {
+   u32 orig_ctrl, ctrl;
+
+   orig_ctrl = ctrl = pwm_lpss_read(pwm);
+   ctrl |= PWM_ENABLE;
+   dev_err(pwm->chip->dev, "enable 0x%08x -> 0x%08x\n",
+   orig_ctrl, ctrl);
+   pwm_lpss_write(pwm, ctrl);
+   }
 }
 
 static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -200,6 +209,9 @@ static void pwm_lpss_get_state(struct pwm_chip *chip, 
struct pwm_device *pwm,
state->enabled = !!(ctrl & PWM_ENABLE);
 
pm_runtime_put(chip->dev);
+
+   dev_err(pwm->chip->dev, "initial state 0x%08x period %d duty_cycle %d 
enabled %d\n",
+   ctrl, state->period, state->duty_cycle, state->enabled);
 }
 
 static const struct pwm_ops pwm_lpss_ops = {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 11/16] pwm: crc: Implement apply() method to support the new atomic PWM API

2020-06-06 Thread Hans de Goede
Replace the enable, disable and config pwm_ops with an apply op,
to support the new atomic PWM API.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 107 +++---
 1 file changed, 59 insertions(+), 48 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 53734bcf67e1..58c7e9ef7278 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -41,70 +41,81 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct 
pwm_chip *pc)
return container_of(pc, struct crystalcove_pwm, chip);
 }
 
-static int crc_pwm_calc_clk_div(int period_ns)
+static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+const struct pwm_state *state)
 {
-   int clk_div;
-
-   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
-   /* clk_div 1 - 128, maps to register values 0-127 */
-   if (clk_div > 0)
-   clk_div--;
-
-   return clk_div;
-}
-
-static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
-   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
-
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div | PWM_OUTPUT_ENABLE);
-   regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
-
-   return 0;
-}
-
-static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
-   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
-
-   regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div);
-}
-
-static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
- int duty_ns, int period_ns)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
+   int err, clk_div, level, pwm_output_enable;
struct device *dev = crc_pwm->chip.dev;
-   int level;
 
-   if (period_ns > PWM_MAX_PERIOD_NS) {
+   if (state->period > PWM_MAX_PERIOD_NS) {
dev_err(dev, "un-supported period_ns\n");
return -EINVAL;
}
 
-   if (pwm_get_period(pwm) != period_ns) {
-   int clk_div = crc_pwm_calc_clk_div(period_ns);
+   if (state->polarity != PWM_POLARITY_NORMAL)
+   return -ENOTSUPP;
+
+   if (pwm_is_enabled(pwm) && !state->enabled) {
+   err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
+   if (err) {
+   dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
+   return err;
+   }
+   }
+
+   if (pwm_get_duty_cycle(pwm) != state->duty_cycle ||
+   pwm_get_period(pwm) != state->period) {
+   level = state->duty_cycle * PWM_MAX_LEVEL / state->period;
 
+   err = regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_DUTY_CYCLE %d\n", err);
+   return err;
+   }
+   }
+
+   if (pwm_is_enabled(pwm) && state->enabled &&
+   pwm_get_period(pwm) != state->period) {
/* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
-   clk_div | PWM_OUTPUT_ENABLE);
+   err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
+   return err;
+   }
}
 
-   /* change the pwm duty cycle */
-   level = duty_ns * PWM_MAX_LEVEL / period_ns;
-   regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
+   if (pwm_get_period(pwm) != state->period ||
+   pwm_is_enabled(pwm) != state->enabled) {
+   clk_div = PWM_BASE_CLK_MHZ * state->period /
+ (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
+
+   pwm_output_enable = state->enabled ? PWM_OUTPUT_ENABLE : 0;
+
+   err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
+  clk_div | pwm_output_enable);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
+   return err;
+   }
+   }
+
+   if (!pwm_is_enabled(pwm) && state->enabled) {
+   err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
+   if (err) {
+

[PATCH 05/16] pwm: lpss: Set SW_UPDATE bit when enabling the PWM

2020-06-06 Thread Hans de Goede
On the LPSS PWM controller found on Bay Trail (BYT) and Cherry Trail (CHT)
platforms, the following sequence results in an output duty-cycle of 100%
independent of what the duty-cycle requested in the ctrl-reg is:

1. Clear ENABLE bit in ctrl register
2. Let the machine reach a S0i3 low power state
3. Set the ENABLE bit in the ctrl register

The LPSS PWM controller has a mechanism where the ctrl register value
and the actual base-unit and on-time-div values used are latched. When
software sets the SW_UPDATE bit then at the end of the current PWM cycle,
the new values from the ctrl-register will be latched into the actual
registers, and the SW_UPDATE bit will be cleared.  Note on BYT and CHT
the ENABLE bit must be set before waiting for the SW_UPDATE bit to clear,
otherwise the SW_UPDATE bit will never clear (this is indicated in the
pwm-lpss.c code by lpwm->info->bypass being false).

My theory about why this is happening is that when we hit S0i3 the part
which holds the latched values gets turned off and when its turned back on
again at least the on-time-div value has been lost and gets reset to 0
which corresponds to an output duty-cycle of 100%. Testing has shown that
setting the SW_UPDATE bit to request latching the ctrl-register values into
the actual registers (again) fixes this, confirming this theory.

In the past there have been issues where setting the SW_UPDATE bit when
nothing has changed would lead to the next ctrl register changing being
ignored, see commit 2153bbc12f77 ("pwm: lpss: Only set update bit if we are
actually changing the settings"), so we should only set the SW_UPDATE bit
when actually changing the ENABLE bit from 0 to 1.

When looking into how to fix this I noticed that on platforms where
lpwm->info->bypass == false we unnecessarily do 2 read-modify-write cycles
of the ctrl register, one to set the base-unit and on-time-div, immediately
followed by another to set the ENABLE bit.

This commit fixes the 100% duty cycle issue by folding the setting of the
ENABLE bit into pwm_lpss_prepare(), which already checks if any bits in
the ctrl-register have actually changed and if that is the case then sets
the SW_UPDATE bit.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index a764e062103b..2cb0e2a9c08c 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -80,7 +80,7 @@ static inline int pwm_lpss_is_updating(struct pwm_device *pwm)
 }
 
 static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device 
*pwm,
-int duty_ns, int period_ns)
+int duty_ns, int period_ns, bool enable)
 {
unsigned long long on_time_div;
unsigned long c = lpwm->info->clk_rate, base_unit_range;
@@ -115,6 +115,8 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
+   if (enable)
+   ctrl |= PWM_ENABLE;
 
if (orig_ctrl != ctrl) {
pwm_lpss_write(pwm, ctrl);
@@ -142,8 +144,9 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
pm_runtime_put(chip->dev);
return ret;
}
-   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, 
state->period);
-   pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
+   pwm_lpss_prepare(lpwm, pwm,
+state->duty_cycle, state->period,
+lpwm->info->bypass == false);
ret = pwm_lpss_wait_for_update(pwm);
if (ret) {
pm_runtime_put(chip->dev);
@@ -154,7 +157,8 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
ret = pwm_lpss_is_updating(pwm);
if (ret)
return ret;
-   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, 
state->period);
+   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle,
+state->period, false);
return pwm_lpss_wait_for_update(pwm);
}
} else if (pwm_is_enabled(pwm)) {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 07/16] pwm: crc: Fix period / duty_cycle times being off by a factor of 256

2020-06-06 Thread Hans de Goede
While looking into adding atomic-pwm support to the pwm-crc driver I
noticed something odd, there is a PWM_BASE_CLK define of 6 MHz and
there is a clock-divider which divides this with a value between 1-128,
and there are 256 duty-cycle steps.

The pwm-crc code before this commit assumed that a clock-divider
setting of 1 means that the PWM output is running at 6 MHZ, if that
is true, where do these 256 duty-cycle steps come from?

This would require an internal frequency of 256 * 6 MHz = 1.5 GHz, that
seems unlikely for a PMIC which is using a silicon process optimized for
power-switching transistors. It is way more likely that there is an 8
bit counter for the duty cycle which acts as an extra fixed divider
wrt the PWM output frequency.

The main user of the pwm-crc driver is the i915 GPU driver which uses it
for backlight control. Lets compare the PWM register values set by the
video-BIOS (the GOP), assuming the extra fixed divider is present versus
the PWM frequency specified in the Video-BIOS-Tables:

Device: PWM Hz set by BIOS  PWM Hz specified in VBT
Asus T100TA 200 200
Asus T100HA 200 200
Lenovo Miix 2 8 23437   2
Toshiba WT8-A   23437   2

So as we can see if we assume the extra division by 256 then the register
values set by the GOP are an exact match for the VBT values, where as
otherwise the values would be of by a factor of 256.

This commit fixes the period / duty_cycle calculations to take the
extra division by 256 into account.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 272eeb071147..43fc912c1fe9 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -21,8 +21,10 @@
 
 #define PWM_MAX_LEVEL  0xFF
 
-#define PWM_BASE_CLK   600  /* 6 MHz */
-#define PWM_MAX_PERIOD_NS  21333/* 46.875KHz */
+#define PWM_BASE_CLK_MHZ   6   /* 6 MHz */
+#define PWM_MAX_PERIOD_NS  5461333 /* 183 Hz */
+
+#define NSEC_PER_MHZ   1000
 
 /**
  * struct crystalcove_pwm - Crystal Cove PWM controller
@@ -72,7 +74,7 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
 
/* changing the clk divisor, need to disable fisrt */
crc_pwm_disable(c, pwm);
-   clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC;
+   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 03/16] pwm: lpss: Add range limit check for the base_unit register value

2020-06-06 Thread Hans de Goede
When the user requests a high enough period ns value, then the
calculations in pwm_lpss_prepare() might result in a base_unit value of 0.

But according to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency. Adding 0
to the counter is a no-op. The data-sheet even explicitly states that
writing 0 to the base_unit bits will result in the PWM outputting a
continuous 0 signal.

base_unit values > (base_unit_range / 256), or iow base_unit values using
the 8 most significant bits, cause loss of resolution of the duty-cycle.
E.g. assuming a base_unit_range of 65536 steps, then a base_unit value of
768 (256 * 3), limits the duty-cycle resolution to 65536 / 768 = 85 steps.
Clamp the max base_unit value to base_unit_range / 32 to ensure a
duty-cycle resolution of at least 32 steps. This limits the maximum
output frequency to 600 KHz / 780 KHz depending on the base clock.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 9d965ffe66d1..cae74ce61654 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -97,6 +97,14 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
freq *= base_unit_range;
 
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
+   /*
+* base_unit must not be 0 and for values > (base_unit_range / 256)
+* (values using the 8 most significant bits) the duty-cycle resolution
+* degrades. Clamp the maximum value to base_unit_range / 32 which
+* leaves a duty-cycle resolution of 32 steps.
+*/
+   base_unit = clamp_t(unsigned long long, base_unit, 1,
+   base_unit_range / 32);
 
on_time_div = 255ULL * duty_ns;
do_div(on_time_div, period_ns);
@@ -105,7 +113,6 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
-   base_unit &= base_unit_range;
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 09/16] pwm: crc: Fix period changes not having any effect

2020-06-06 Thread Hans de Goede
The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

I strongly suspect that the BACKLIGHT_EN register at address 0x51 really
controls a separate output-only GPIO which is connected to the LCD panels
backlight-enable input. Like how the PANEL_EN register at address 0x52
controls an output-only GPIO which is earmarked for the LCD panel's
enable pin. If this is correct then this GPIO should really be added to
the gpio-crystalcove.c driver and the PWM driver should stop poking it.
But I've been unable to come up with a definitive answer here, so I'm
keeping this as is for now.

As the comment in the old code already indicates we must disable the PWM
before we can change the clock divider. But the crc_pwm_disable() and
crc_pwm_enable() calls the old code make for this only change the
BACKLIGHT_EN register; and the value of that register does not matter for
changing the period / the divider. What does matter is that the
PWM_OUTPUT_ENABLE bit must be cleared before a new value can be written.

This commit modifies crc_pwm_config() to clear PWM_OUTPUT_ENABLE instead
when changing the period, so that period changes actually work.

Note this fix will cause a significant behavior change on some devices
using the CRC PWM output to drive their backlight. Before the PWM would
always run with the output frequency configured by the BIOS at boot, now
the period time specified by the i915 driver will actually be honored.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 5ba2a65c524c..ef49a6e3c4d6 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -72,8 +72,9 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
if (pwm_get_period(pwm) != period_ns) {
int clk_div;
 
-   /* changing the clk divisor, need to disable fisrt */
-   crc_pwm_disable(c, pwm);
+   /* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
+
clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
/* clk_div 1 - 128, maps to register values 0-127 */
if (clk_div > 0)
@@ -81,9 +82,6 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-
-   /* enable back */
-   crc_pwm_enable(c, pwm);
}
 
/* change the pwm duty cycle */
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 14/16] drm/i915: panel: Honor the VBT PWM frequency for devs with an external PWM controller

2020-06-06 Thread Hans de Goede
So far for devices using an external PWM controller (devices using
pwm_setup_backlight()), we have been hardcoding the period-time passed to
pwm_config() to 21333 ns.

I suspect this was done because many VBTs set the PWM frequency to 200
which corresponds to a period-time of 500 ns, which greatly exceeds
the PWM_MAX_PERIOD_NS define in the Crystal Cove PMIC PWM driver, which
used to be 21333.

This PWM_MAX_PERIOD_NS define was actually based on a bug in the PWM
driver where its period and duty-cycle times where off by a factor of 256.

Due to this bug the hardcoded CRC_PMIC_PWM_PERIOD_NS value of 21333 would
result in the PWM driver using its divider of 128, which would result in
a PWM output frequency of 600 Hz / 256 / 128 = 183 Hz. So actually
pretty close to the default VBT value of 200 Hz.

Now that this bug in the pwm-crc driver is fixed, we can actually use
the VBT defined frequency.

This is important because:

a) With the pwm-crc driver fixed it will now translate the hardcoded
CRC_PMIC_PWM_PERIOD_NS value of 21333 ns / 46 Khz to a PWM output
frequency of 23 KHz (the max it can do).

b) The pwm-lpss driver used on many models has always honored the
21333 ns / 46 Khz request

Some panels do not like such high output frequencies. E.g. on a Terra
Pad 1061 tablet, using the LPSS PWM controller, the backlight would go
from off to max, when changing the sysfs backlight brightness value from
90-100%, anything under aprox. 90% would turn the backlight fully off.

Honoring the VBT specified PWM frequency will also hopefully fix the
various bug reports which we have received about users perceiving the
backlight to flicker after a suspend/resume cycle.

Signed-off-by: Hans de Goede 
---
 .../drm/i915/display/intel_display_types.h|  1 +
 drivers/gpu/drm/i915/display/intel_panel.c| 19 +++
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index b24266c624fa..24ea4a7b6dde 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -223,6 +223,7 @@ struct intel_panel {
bool util_pin_active_low;   /* bxt+ */
u8 controller;  /* bxt+ only */
struct pwm_device *pwm;
+   int pwm_period_ns;
 
/* DPCD backlight */
u8 pwmgen_bit_count;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 8efdd9f08a08..14e611c92194 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -40,8 +40,6 @@
 #include "intel_dsi_dcs_backlight.h"
 #include "intel_panel.h"
 
-#define CRC_PMIC_PWM_PERIOD_NS 21333
-
 void
 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
   struct drm_display_mode *adjusted_mode)
@@ -597,7 +595,7 @@ static u32 pwm_get_backlight(struct intel_connector 
*connector)
int duty_ns;
 
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-   return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
+   return DIV_ROUND_UP(duty_ns * 100, panel->backlight.pwm_period_ns);
 }
 
 static void lpt_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
@@ -671,9 +669,10 @@ static void bxt_set_backlight(const struct 
drm_connector_state *conn_state, u32
 static void pwm_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
 {
struct intel_panel *panel = 
_intel_connector(conn_state->connector)->panel;
-   int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+   int duty_ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
+   pwm_config(panel->backlight.pwm, duty_ns,
+  panel->backlight.pwm_period_ns);
 }
 
 static void
@@ -1917,6 +1916,9 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
return -ENODEV;
}
 
+   panel->backlight.pwm_period_ns = NSEC_PER_SEC /
+get_vbt_pwm_freq(dev_priv);
+
/*
 * FIXME: pwm_apply_args() should be removed when switching to
 * the atomic PWM API.
@@ -1926,9 +1928,10 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
panel->backlight.min = 0; /* 0% */
panel->backlight.max = 100; /* 100% */
level = intel_panel_compute_brightness(connector, 100);
-   ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+   ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   retval = pwm_config(panel->backlight.pwm, ns, CRC_PMIC_PWM_PERIOD_NS);
+   retval = pwm_config(panel->backlight.pwm, ns,
+

[PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)

2020-06-06 Thread Hans de Goede
The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets turned off from the _PS3 method of the graphics-card dev:

Method (_PS3, 0, Serialized)  // _PS3: Power State 3
{
...
PWMB = PWMC /* \_SB_.PCI0.GFX0.PWMC */
PSAT |= 0x03
Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
...
}

Where PSAT is the power-status register of the PWM controller.

Since the i915 driver will do a pwm_get on the pwm device as it uses it to
control the LCD panel backlight, there is a device-link marking the i915
device as a consumer of the pwm device. So that the PWM controller will
always be suspended after the i915 driver suspends (which is the right
thing to do). This causes the above GFX0 PS3 AML code to run before
acpi_lpss.c calls acpi_lpss_save_ctx().

So on these devices the PWM controller will already be off when
acpi_lpss_save_ctx() runs. This causes it to read/save all 1-s (0x)
as ctx register values.

When these bogus values get restored on resume the PWM controller actually
keeps working, since most bits are reserved, but this does set bit 3 of
the LPSS General purpose register, which for the PWM controller has the
following function: "This bit is re-used to support 32kHz slow mode.
Default is 19.2MHz as PWM source clock".

This causes the clock of the PWM controller to switch from 19.2MHz to
32KHz, which is a slow-down of a factor 600. Suprisingly enough so far
there have been few bug reports about this. This is likely because the
i915 driver was hardcoding the PWM frequency to 46 KHz, which divided
by 600 would result in a PWM frequency of aprox. 78 Hz, which mostly
still works fine. There are some bug reports about the LCD backlight
flickering after suspend/resume which are likely caused by this issue.

But with the upcoming patch-series to finally switch the i915 drivers
code for external PWM controllers to use the atomic API and to honor
the PWM frequency specified in the video BIOS (VBT), this becomes a much
bigger problem. On most cases the VBT specifies either 200 Hz or 20
KHz as PWM frequency, which with the mentioned issue ends up being either
1/3 Hz, where the backlight actually visible blinks on and off every 3s,
or in 33 Hz and horrible flickering of the backlight.

There are a number of possible solutions to this problem:

1. Make acpi_lpss_save_ctx() run before GFX0._PS3
 Pro: Clean solution from pov of not medling with save/restore ctx code
 Con: As mentioned the current ordering is the right thing to do
 Con: Requires assymmetry in at what suspend/resume phase we do the save vs
  restore, requiring more suspend/resume ordering hacks in already
  convoluted acpi_lpss.c suspend/resume code.
2. Do some sort of save once mode for the LPSS ctx
 Pro: Reasonably clean
 Con: Needs a new LPSS flag + code changes to handle the flag
3. Detect we have failed to save the ctx registers and do not restore them
 Pro: Not PWM specific, might help with issues on other LPSS devices too
 Con: If we can get away with not restoring the ctx why bother with it at
  all?
4. Do not save the ctx for CHT PWM controllers
 Pro: Clean, as simple as dropping a flag?
 Con: Not so simple as dropping a flag, needs a new flag to ensure that
  we still do lpss_deassert_reset() on device activation.
5. Make the pwm-lpss code fixup the LPSS-context registers
 Pro: Keeps acpi_lpss.c code clean
 Con: Moves knowledge of LPSS-context into the pwm-lpss.c code

1 and 5 both do not seem to be a desirable way forward.

3 and 4 seem ok, but they both assume that restoring the LPSS-context
registers is not necessary. I have done a couple of test and those do
show that restoring the LPSS-context indeed does not seem to be necessary
on devices using s2idle suspend (and successfully reaching S0i3). But I
have no hardware to test deep / S3 suspend. So I'm not sure that not
restoring the context is safe.

That leaves solution 2, which is about as simple / clean as 3 and 4,
so this commit fixes the described problem by implementing a new
LPSS_SAVE_CTX_ONCE flag and setting that for the CHT PWM controllers.

Signed-off-by: Hans de Goede 
---
 drivers/acpi/acpi_lpss.c | 19 ---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 67892fc0b822..26933e6b7b8c 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -68,6 +68,14 @@ ACPI_MODULE_NAME("acpi_lpss");
 #define LPSS_LTR   BIT(3)
 #define LPSS_SAVE_CTX  BIT(4)
 #define LPSS_NO_D3_DELAY   BIT(5)
+/*
+ * For some devices the DSDT AML code for another device turns off the device
+ * before our suspend handler runs, causing us to read/save all 1-s 
(0x)
+ * as ctx register values.
+ * Luckily these devices always use the same ctx re

pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API

2020-06-06 Thread Hans de Goede
Hi All,

This patch series converts the i915 driver's cpde for controlling the
panel's backlight with an external PWM controller to use the atomic PWM API.

Initially the plan was for this series to consist of 2 parts:
1. convert the pwm-crc driver to support the atomic PWM API and
2. convert the i915 driver's PWM code to use the atomic PWM API.

But during testing I've found a number of bugs in the pwm-lpss and I
found that the acpi_lpss code needs some special handling because of
some ugliness found in most Cherry Trail DSDTs.

So now this series has grown somewhat large and consists of 4 parts:

1. acpi_lpss fixes workarounds for Cherry Trail DSTD nastiness
2. various fixes to the pwm-lpss driver
3. convert the pwm-crc driver to support the atomic PWM API and
4. convert the i915 driver's PWM code to use the atomic PWM API

So we need to discuss how to merge this (once it passes review).
Although the inter-dependencies are only runtime I still think we should
make sure that 1-3 are in the drm-intel-next-queued (dinq) tree before
merging the i915 changes. Both to make sure that the intel-gfx CI system
does not become unhappy and for bisecting reasons.

The involved acpi_lpss and pwm drivers do not see a whole lot of churn,
so we could just merge everything through dinq, or we could use immutable
branch and merge those into dinq.

So Rafael and Thierry, can I either get your Acked-by for directly merging
this into dinq, or can you provide an immutable branch with these patches?

This series has been tested (and re-tested after adding various bug-fixes)
extensively. It has been tested on the following devices:

-Asus T100TABYT + CRC-PMIC PWM
-Toshiba WT8-A  BYT + CRC-PMIC PWM
-Thundersoft TS178  BYT + CRC-PMIC PWM, inverse PWM
-Asus T100HACHT + CRC-PMIC PWM
-Terra Pad 1061 BYT + LPSS PWM
-Trekstor Twin 10.1 BYT + LPSS PWM
-Asus T101HACHT + CRC-PMIC PWM
-GPD Pocket CHT + CRC-PMIC PWM

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 08/16] pwm: crc: Fix off-by-one error in the clock-divider calculations

2020-06-06 Thread Hans de Goede
The CRC PWM controller has a clock-divider which divides the clock with
a value between 1-128. But as can seen from the PWM_DIV_CLK_xxx
defines, this range maps to a register value of 0-127.

So after calculating the clock-divider we must subtract 1 to get the
register value, unless the requested frequency was so high that the
calculation has already resulted in a (rounded) divider value of 0.

Note that before this fix, setting a period of PWM_MAX_PERIOD_NS which
corresponds to the max. divider value of 128 could have resulted in a
bug where the code would use 128 as divider-register value which would
have resulted in an actual divider value of 0 (and the enable bit being
set). A rounding error stopped this bug from actually happen. This
same rounding error means that after the subtraction of 1 it is impossible
to set the divider to 128. Also bump PWM_MAX_PERIOD_NS by 1 ns to allow
setting a divider of 128 (register-value 127).

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 43fc912c1fe9..5ba2a65c524c 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -22,7 +22,7 @@
 #define PWM_MAX_LEVEL  0xFF
 
 #define PWM_BASE_CLK_MHZ   6   /* 6 MHz */
-#define PWM_MAX_PERIOD_NS  5461333 /* 183 Hz */
+#define PWM_MAX_PERIOD_NS  5461334 /* 183 Hz */
 
 #define NSEC_PER_MHZ   1000
 
@@ -75,6 +75,9 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
/* changing the clk divisor, need to disable fisrt */
crc_pwm_disable(c, pwm);
clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 16/16] drm/i915: panel: Use atomic PWM API for devs with an external PWM controller

2020-06-06 Thread Hans de Goede
Now that the PWM drivers which we use have been converted to the atomic
PWM API, we can move the i915 panel code over to using the atomic PWM API.

The removes a long standing FIXME and this removes a flicker where
the backlight brightness would jump to 100% when i915 loads even if
using the fastset path.

Signed-off-by: Hans de Goede 
---
 .../drm/i915/display/intel_display_types.h|  3 +-
 drivers/gpu/drm/i915/display/intel_panel.c| 73 +--
 2 files changed, 37 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index 24ea4a7b6dde..48afb2925271 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -28,6 +28,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -223,7 +224,7 @@ struct intel_panel {
bool util_pin_active_low;   /* bxt+ */
u8 controller;  /* bxt+ only */
struct pwm_device *pwm;
-   int pwm_period_ns;
+   struct pwm_state pwm_state;
 
/* DPCD backlight */
u8 pwmgen_bit_count;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index cb28b9908ca4..a0f76343f381 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -592,10 +592,11 @@ static u32 bxt_get_backlight(struct intel_connector 
*connector)
 static u32 pwm_get_backlight(struct intel_connector *connector)
 {
struct intel_panel *panel = >panel;
-   int duty_ns;
+   int duty_ns, period_ns;
 
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-   return DIV_ROUND_UP(duty_ns * 100, panel->backlight.pwm_period_ns);
+   period_ns = pwm_get_period(panel->backlight.pwm);
+   return DIV_ROUND_UP(duty_ns * 100, period_ns);
 }
 
 static void lpt_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
@@ -669,10 +670,10 @@ static void bxt_set_backlight(const struct 
drm_connector_state *conn_state, u32
 static void pwm_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
 {
struct intel_panel *panel = 
_intel_connector(conn_state->connector)->panel;
-   int duty_ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   pwm_config(panel->backlight.pwm, duty_ns,
-  panel->backlight.pwm_period_ns);
+   panel->backlight.pwm_state.duty_cycle =
+   DIV_ROUND_UP(level * panel->backlight.pwm_state.period, 100);
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 static void
@@ -841,10 +842,8 @@ static void pwm_disable_backlight(const struct 
drm_connector_state *old_conn_sta
struct intel_connector *connector = 
to_intel_connector(old_conn_state->connector);
struct intel_panel *panel = >panel;
 
-   /* Disable the backlight */
-   intel_panel_actually_set_backlight(old_conn_state, 0);
-   usleep_range(2000, 3000);
-   pwm_disable(panel->backlight.pwm);
+   panel->backlight.pwm_state.enabled = false;
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 void intel_panel_disable_backlight(const struct drm_connector_state 
*old_conn_state)
@@ -1176,9 +1175,14 @@ static void pwm_enable_backlight(const struct 
intel_crtc_state *crtc_state,
 {
struct intel_connector *connector = 
to_intel_connector(conn_state->connector);
struct intel_panel *panel = >panel;
+   int level = panel->backlight.level;
 
-   pwm_enable(panel->backlight.pwm);
-   intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+   level = intel_panel_compute_brightness(connector, level);
+
+   panel->backlight.pwm_state.duty_cycle =
+   DIV_ROUND_UP(level * panel->backlight.pwm_state.period, 100);
+   panel->backlight.pwm_state.enabled = true;
+   pwm_apply_state(panel->backlight.pwm, >backlight.pwm_state);
 }
 
 static void __intel_panel_enable_backlight(const struct intel_crtc_state 
*crtc_state,
@@ -1897,8 +1901,7 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_panel *panel = >panel;
const char *desc;
-   u32 level, ns;
-   int retval;
+   u32 level;
 
/* Get the right PWM chip for DSI backlight according to VBT */
if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
@@ -1916,36 +1919,30 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
return -ENODEV;
}
 
-   panel->backlight.pwm_period_ns = NSEC_PER_SEC /
-get_vbt_pwm_freq(dev_priv);
-
-   /*
-

[PATCH 12/16] pwm: crc: Implement get_state() method

2020-06-06 Thread Hans de Goede
Implement the pwm_ops.get_state() method to complete the support for the
new atomic PWM API.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 58c7e9ef7278..6c75a3470bc8 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -114,8 +114,37 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+  struct pwm_state *state)
+{
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
+   struct device *dev = crc_pwm->chip.dev;
+   unsigned int clk_div, clk_div_reg, duty_cycle_reg;
+   int error;
+
+   error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, _div_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error);
+   return;
+   }
+
+   error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, _cycle_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error);
+   return;
+   }
+
+   clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1;
+
+   state->period = clk_div * NSEC_PER_MHZ * 256 / PWM_BASE_CLK_MHZ;
+   state->duty_cycle = duty_cycle_reg * state->period / PWM_MAX_LEVEL;
+   state->polarity   = PWM_POLARITY_NORMAL;
+   state->enabled= !!(clk_div_reg & PWM_OUTPUT_ENABLE);
+}
+
 static const struct pwm_ops crc_pwm_ops = {
.apply = crc_pwm_apply,
+   .get_state = crc_pwm_get_state,
 };
 
 static int crystalcove_pwm_probe(struct platform_device *pdev)
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 10/16] pwm: crc: Enable/disable PWM output on enable/disable

2020-06-06 Thread Hans de Goede
The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

So far we've kept the PWM_OUTPUT_ENABLE bit set when disabling the PWM,
this commit makes crc_pwm_disable() clear it on disable and makes
crc_pwm_enable() set it again on re-enable.

This should disable the internal (divided) PWM clock and tri-state the
PWM output pin when disabled, saving some power.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 24 +---
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index ef49a6e3c4d6..53734bcf67e1 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -41,10 +41,24 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct 
pwm_chip *pc)
return container_of(pc, struct crystalcove_pwm, chip);
 }
 
+static int crc_pwm_calc_clk_div(int period_ns)
+{
+   int clk_div;
+
+   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
+
+   return clk_div;
+}
+
 static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
 
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div | PWM_OUTPUT_ENABLE);
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
 
return 0;
@@ -53,8 +67,10 @@ static int crc_pwm_enable(struct pwm_chip *c, struct 
pwm_device *pwm)
 static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
 
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div);
 }
 
 static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
@@ -70,16 +86,10 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
}
 
if (pwm_get_period(pwm) != period_ns) {
-   int clk_div;
+   int clk_div = crc_pwm_calc_clk_div(period_ns);
 
/* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
-
-   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
-   /* clk_div 1 - 128, maps to register values 0-127 */
-   if (clk_div > 0)
-   clk_div--;
-
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
}
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 1/2] drm: panel-orientation-quirks: Add quirk for Asus T101HA panel

2020-05-31 Thread Hans de Goede
Like the Asus T100HA the Asus T101HA also uses a panel which has been
mounted 90 degrees rotated, add a quirk for this.

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/drm_panel_orientation_quirks.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c 
b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index ffd95bfeaa94..d11d83703931 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -121,6 +121,12 @@ static const struct dmi_system_id orientation_data[] = {
  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
},
.driver_data = (void *)_t100ha,
+   }, {/* Asus T101HA */
+   .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T101HA"),
+   },
+   .driver_data = (void *)_rightside_up,
}, {/* GPD MicroPC (generic strings, also match on bios date) */
.matches = {
  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 2/2] drm: panel-orientation-quirks: Use generic orientation-data for Acer S1003

2020-05-31 Thread Hans de Goede
The Acer S1003 has proper DMI strings for sys-vendor and product-name,
so we do not need to match by BIOS-date.

This means that the Acer S1003 can use the generic lcd800x1280_rightside_up
drm_dmi_panel_orientation_data struct which is also used by other quirks.

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/drm_panel_orientation_quirks.c | 8 +---
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c 
b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index d11d83703931..d00ea384dcbf 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -30,12 +30,6 @@ struct drm_dmi_panel_orientation_data {
int orientation;
 };
 
-static const struct drm_dmi_panel_orientation_data acer_s1003 = {
-   .width = 800,
-   .height = 1280,
-   .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
-};
-
 static const struct drm_dmi_panel_orientation_data asus_t100ha = {
.width = 800,
.height = 1280,
@@ -114,7 +108,7 @@ static const struct dmi_system_id orientation_data[] = {
  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"),
},
-   .driver_data = (void *)_s1003,
+   .driver_data = (void *)_rightside_up,
}, {/* Asus T100HA */
.matches = {
  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH resend] drm: Add DRM_MODE_TYPE_USERDEF flag to probed modes matching a video= argument

2020-05-14 Thread Hans de Goede

Hi,

On 5/14/20 11:53 AM, Emil Velikov wrote:

Hi Hans,

On Thu, 30 Apr 2020 at 15:55, Hans de Goede  wrote:


Hi,

On 4/30/20 4:52 PM, Ville Syrjälä wrote:

On Thu, Apr 30, 2020 at 02:47:00PM +0100, Emil Velikov wrote:

Hi Hans,

On Fri, 21 Feb 2020 at 17:33, Hans de Goede  wrote:


drm_helper_probe_add_cmdline_mode() prefers using a probed mode matching
a video= argument over calculating our own timings for the user specified
mode using CVT or GTF.

But userspace code which is auto-configuring the mode may want to know that
the user has specified that mode on the kernel commandline so that it can
pick that mode over the mode which is marked as DRM_MODE_TYPE_PREFERRED.

This commit sets the DRM_MODE_TYPE_USERDEF flag on the matching mode, just
as we would do on the user-specified mode when no matching probed mode is
found.

Signed-off-by: Hans de Goede 


I was skimming around wrt Ville's compact drm_display_mode series and
noticed that this never landed.

The commit brings extra consistency when dealing with user defined
modes, and is:
Reviewed-by: Emil Velikov 

Ville this may trivially conflict with your work. I suspect you can do
the honours, and apply on top of your series?
That is if you agree with the patch.


Quick glance at the original thread says maybe there were still some
userspace issues unresolved? Not sure.


IIRC the thread ended with Daniel agreeing on the userspace interface,
but asking for some docs and me pointing out that the patch already
updated/clarified the existing docs. After that things got quiet.

So I believe that this is (still) ready to go upstream.


Having read through the full discussion, couple of times, I believe
you're spot on.

Daniel requested documentation, which the patch provides. I'd say
let's poke him on IRC a few times, if he doesn't object let's push it?


Sounds good to me, I'm usually not on IRC (too distracting for me), canyou
ping Daniel about this on IRC?

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC v2] drm/connector: Add support for privacy-screen properties (v2)

2020-05-12 Thread Hans de Goede

Hi,

On 5/12/20 10:44 PM, mario.limoncie...@dell.com wrote:

-Original Message-
From: Hans de Goede 
Sent: Monday, May 11, 2020 12:47 PM
To: Maarten Lankhorst; Maxime Ripard; Thomas Zimmermann; Daniel Vetter; David
Airlie; Rajat Jain; Jani Nikula
Cc: Hans de Goede; Pekka Paalanen; Limonciello, Mario; Quintanilla, Sonny;
Jared Dominguez; Mark Pearson; dri-devel@lists.freedesktop.org
Subject: [RFC v2] drm/connector: Add support for privacy-screen properties
(v2)


[EXTERNAL EMAIL]

From: Rajat Jain 

Add support for generic electronic privacy screen properties, that
can be added by systems that have an integrated EPS.

Changes in v2 (Hans de Goede)
- Create 2 properties, "privacy-screen sw-state" and
   "privacy-screen hw-state", to deal with devices where the OS might be
   locked out of making state changes
- Write kerneldoc explaining how the 2 properties work together, what
   happens when changes to the state are made outside of the DRM code's
   control, etc.

Signed-off-by: Rajat Jain 
Co-authored-by: Hans de Goede 
Signed-off-by: Hans de Goede 
---
  Documentation/gpu/drm-kms.rst |   2 +
  drivers/gpu/drm/drm_atomic_uapi.c |   6 ++
  drivers/gpu/drm/drm_connector.c   | 100 ++
  include/drm/drm_connector.h   |  50 +++
  4 files changed, 158 insertions(+)

diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index 906771e03103..b72b1e0db343 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -445,6 +445,8 @@ Property Types and Blob Property Support
  .. kernel-doc:: drivers/gpu/drm/drm_property.c
 :export:

+.. _standard_connector_properties:
+
  Standard Connector Properties
  -

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c
b/drivers/gpu/drm/drm_atomic_uapi.c
index a1e5e262bae2..e56a11208515 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -766,6 +766,8 @@ static int drm_atomic_connector_set_property(struct
drm_connector *connector,
   fence_ptr);
} else if (property == connector->max_bpc_property) {
state->max_requested_bpc = val;
+   } else if (property == connector->privacy_screen_sw_state_property) {
+   state->privacy_screen_sw_state = val;
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
@@ -842,6 +844,10 @@ drm_atomic_connector_get_property(struct drm_connector
*connector,
*val = 0;
} else if (property == connector->max_bpc_property) {
*val = state->max_requested_bpc;
+   } else if (property == connector->privacy_screen_sw_state_property) {
+   *val = state->privacy_screen_sw_state;
+   } else if (property == connector->privacy_screen_hw_state_property) {
+   *val = state->privacy_screen_hw_state;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 644f0ad10671..01360edc2376 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1186,6 +1186,45 @@ static const struct drm_prop_enum_list dp_colorspaces[]
= {
   *can also expose this property to external outputs, in which case they
   *must support "None", which should be the default (since external screens
   *have a built-in scaler).
+ *
+ * privacy-screen sw-state, privacy-screen hw-state:
+ * These 2 optional properties can be used to query the state of the
+ * electronic privacy screen that is available on some displays; and in
+ * some cases also control the state. If a driver implements these
+ * properties then both properties must be present.
+ *
+ * "privacy-screen hw-state" is read-only and reflects the actual state
+ * of the privacy-screen, possible values: "Enabled", "Disabled,
+ * "Enabled, locked", "Disabled, locked". The locked states indicate
+ * that the state cannot be changed through the DRM API. E.g. there
+ * might be devices where the firmware-setup options, or a hardware
+ * slider-switch, offer always on / off modes.
+ *
+ * "privacy-screen sw-state" can be set to change the privacy-screen state
+ * when not locked. In this case the driver must update the hw-state
+ * property to reflect the new state on completion of the commit of the
+ * sw-state property. Setting the sw-state property when the hw-state is
+ * locked must be interpreted by the driver as a request to change the
+ *

Re: [RFC v2 0/1] drm/connector: Add support for privacy-screen properties

2020-05-12 Thread Hans de Goede

Hi,

On 5/12/20 4:20 PM, Pekka Paalanen wrote:

On Tue, 12 May 2020 10:18:31 +0200
Hans de Goede  wrote:


Hi,

On 5/11/20 9:55 PM, Rajat Jain wrote:

Hi Hans,

On Mon, May 11, 2020 at 10:47 AM Hans de Goede mailto:hdego...@redhat.com>> wrote:

 Hi All,

 This RFC takes Rajat's earlier patch for adding privacy-screen properties
 infra to drm_connector.c and then adds the results of the discussion from
 the "RFC: Drm-connector properties managed by another driver / privacy
 screen support" mail thread on top, hence the v2.


Thank you so much for doing this. I was following the said discussion and 
eventually it became quite complex for me to understand and follow :-)


I hope the new doc text makes things clear again?



 The most important thing here is big kernel-doc comment which gets added in
 the first patch-chunk modifying drm_connector.c, this summarizes, or at
 least tries to summarize, the conclusions of our previous discussion on
 the userspace API and lays down the ground rules for how the 2 new
 "privacy-screen sw-state" and  "privacy-screen hw-state" properties are
 to be used both from the driver side as well as from the userspace side.

 Other then that this modifies Rajat's patch to add 2 properties instead
 of one, without much other changes.

 Rajat, perhaps you can do a new version of your patch-set integration /
 using this version of the properties and then if everyone is ok with
 the proposed userspace API Jani can hopefully merge the whole set
 through the i915 tree sometime during the 5.9 cycle.


SGTM. I have actually moved to working on something else now, so I will most 
likely wait for this patch to get merged, before rebasing my other / remaining 
patches on top of that.


We have the rule that code like this will not be merged until it has at least
one in kernel user. I plan to eventually use this too, but that is still
a while away as I first need to write a lcdshadow subsystem which the
thinkpad_acpi code can then use to register a lcdshadow device; and when
that all is in place, then I can hook it up on the drm code.


Hi,

I believe this falls under "new UAPI" rules, because this is adding new
KMS properties. Hence an in-kernel user is not enough:

https://www.kernel.org/doc/html/latest/gpu/drm-uapi.html#open-source-userspace-requirements


Hmm, I believe that that mostly applies to new DRI (ioclt) interfaces for
submitting rendering commands to new GPUs and other complex new APIs and
not necessarily to introducing new properties.Also note that all
properties are exported under X through Xrandr, at least reading them,
not sure about setting them.

Anyways I do plan to write some mutter code to test my lcdshadow subsys <->
DRM driver integration when that is all more then just vaporware. But I
would prefer for Rajat's series to land before that so that I can build
on top of it.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC v2 0/1] drm/connector: Add support for privacy-screen properties

2020-05-12 Thread Hans de Goede

Hi,

On 5/11/20 9:55 PM, Rajat Jain wrote:

Hi Hans,

On Mon, May 11, 2020 at 10:47 AM Hans de Goede mailto:hdego...@redhat.com>> wrote:

Hi All,

This RFC takes Rajat's earlier patch for adding privacy-screen properties
infra to drm_connector.c and then adds the results of the discussion from
the "RFC: Drm-connector properties managed by another driver / privacy
screen support" mail thread on top, hence the v2.


Thank you so much for doing this. I was following the said discussion and 
eventually it became quite complex for me to understand and follow :-)


I hope the new doc text makes things clear again?



The most important thing here is big kernel-doc comment which gets added in
the first patch-chunk modifying drm_connector.c, this summarizes, or at
least tries to summarize, the conclusions of our previous discussion on
the userspace API and lays down the ground rules for how the 2 new
"privacy-screen sw-state" and  "privacy-screen hw-state" properties are
to be used both from the driver side as well as from the userspace side.

Other then that this modifies Rajat's patch to add 2 properties instead
of one, without much other changes.

Rajat, perhaps you can do a new version of your patch-set integration /
using this version of the properties and then if everyone is ok with
the proposed userspace API Jani can hopefully merge the whole set
through the i915 tree sometime during the 5.9 cycle.


SGTM. I have actually moved to working on something else now, so I will most 
likely wait for this patch to get merged, before rebasing my other / remaining 
patches on top of that.


We have the rule that code like this will not be merged until it has at least
one in kernel user. I plan to eventually use this too, but that is still
a while away as I first need to write a lcdshadow subsystem which the
thinkpad_acpi code can then use to register a lcdshadow device; and when
that all is in place, then I can hook it up on the drm code.

So since Jani said your patch-set was more or less ready I think it would
be best if you add my version of this to your patch-set and then post
a new version of your patch-set. But first let me do a v3 addressing
the remarks on doc text. Note I will wait a bit before sending out v3
to see if I get more feedback.

Regards,

Hans




Thanks & Best Regards,

Rajat

This RFC takes Rajat's earlier patch for adding privacy-screen properties
infra to drm_connector.c and then adds the results of the discussion from
the "RFC: Drm-connector properties managed by another driver / privacy
screen support" mail thread on top, hence the v2.

The most important thing here is big kernel-doc comment which gets added in
the first patch-chunk modifying drm_connector.c, this summarizes, or at
least tries to summarize, the conclusions of our previous discussion on
the userspace API and lays down the ground rules for how the 2 new
"privacy-screen sw-state" and  "privacy-screen hw-state" properties are
to be used both from the driver side as well as from the userspace side.

Other then that this modifies Rajat's patch to add 2 properties instead
of one, without much other changes.

Rajat, perhaps you can do a new version of your patch-set integration /
using this version of the properties and then if everyone is ok with
the proposed userspace API Jani can hopefully merge the whole set
through the i915 tree sometime during the 5.9 cycle.

Regards,

Hans

p.s.

I plan to start working on the lcdshadow subsystem next. As discussed the
plan for this subsystem is to allow drivers outside of the DRM subsys, such
as for example the thinkpad_acpi driver, to register a lcdshadow device,
which DRM drivers can then get a reference to and use to implement these
properties.



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC v2] drm/connector: Add support for privacy-screen properties (v2)

2020-05-12 Thread Hans de Goede

Hi,

On 5/11/20 10:04 PM, Rajat Jain wrote:

On Mon, May 11, 2020 at 10:47 AM Hans de Goede  wrote:


From: Rajat Jain 

Add support for generic electronic privacy screen properties, that
can be added by systems that have an integrated EPS.

Changes in v2 (Hans de Goede)
- Create 2 properties, "privacy-screen sw-state" and
   "privacy-screen hw-state", to deal with devices where the OS might be
   locked out of making state changes
- Write kerneldoc explaining how the 2 properties work together, what
   happens when changes to the state are made outside of the DRM code's
   control, etc.

Signed-off-by: Rajat Jain 
Co-authored-by: Hans de Goede 
Signed-off-by: Hans de Goede 



Ack, Thanks for doing this.



---
  Documentation/gpu/drm-kms.rst |   2 +
  drivers/gpu/drm/drm_atomic_uapi.c |   6 ++
  drivers/gpu/drm/drm_connector.c   | 100 ++
  include/drm/drm_connector.h   |  50 +++
  4 files changed, 158 insertions(+)

diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index 906771e03103..b72b1e0db343 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -445,6 +445,8 @@ Property Types and Blob Property Support
  .. kernel-doc:: drivers/gpu/drm/drm_property.c
 :export:

+.. _standard_connector_properties:
+
  Standard Connector Properties
  -

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index a1e5e262bae2..e56a11208515 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -766,6 +766,8 @@ static int drm_atomic_connector_set_property(struct 
drm_connector *connector,
fence_ptr);
 } else if (property == connector->max_bpc_property) {
 state->max_requested_bpc = val;
+   } else if (property == connector->privacy_screen_sw_state_property) {
+   state->privacy_screen_sw_state = val;
 } else if (connector->funcs->atomic_set_property) {
 return connector->funcs->atomic_set_property(connector,
 state, property, val);
@@ -842,6 +844,10 @@ drm_atomic_connector_get_property(struct drm_connector 
*connector,
 *val = 0;
 } else if (property == connector->max_bpc_property) {
 *val = state->max_requested_bpc;
+   } else if (property == connector->privacy_screen_sw_state_property) {
+   *val = state->privacy_screen_sw_state;
+   } else if (property == connector->privacy_screen_hw_state_property) {
+   *val = state->privacy_screen_hw_state;
 } else if (connector->funcs->atomic_get_property) {
 return connector->funcs->atomic_get_property(connector,
 state, property, val);
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 644f0ad10671..01360edc2376 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1186,6 +1186,45 @@ static const struct drm_prop_enum_list dp_colorspaces[] 
= {
   * can also expose this property to external outputs, in which case they
   * must support "None", which should be the default (since external 
screens
   * have a built-in scaler).
+ *
+ * privacy-screen sw-state, privacy-screen hw-state:
+ * These 2 optional properties can be used to query the state of the
+ * electronic privacy screen that is available on some displays; and in
+ * some cases also control the state. If a driver implements these
+ * properties then both properties must be present.
+ *
+ * "privacy-screen hw-state" is read-only and reflects the actual state
+ * of the privacy-screen, possible values: "Enabled", "Disabled,
+ * "Enabled, locked", "Disabled, locked". The locked states indicate
+ * that the state cannot be changed through the DRM API. E.g. there
+ * might be devices where the firmware-setup options, or a hardware
+ * slider-switch, offer always on / off modes.



May be add: "This is what the userspace tools must use to query and
report the actual status at the moment, if needed"


Thank you, suggestions for improving the doc are always very welcome, so I
have tried adding this, both as is and with slightly changed wording. But it
always feels like it is just repeating earlier info. To me the
"reflect the actual state" from the beginning of the paragraph makes it
abundantly clear that this indeed is what userspace should use to get,
well, the actual state.


+ *
+ * "privacy-screen sw-state" can be set to change the privacy-screen state
+ * when not locked. In this case the driver must update the hw-state
+ * property to reflect the new state on

Re: [RFC v2] drm/connector: Add support for privacy-screen properties (v2)

2020-05-12 Thread Hans de Goede

Hi,

On 5/12/20 9:49 AM, Pekka Paalanen wrote:

On Mon, 11 May 2020 19:47:24 +0200
Hans de Goede  wrote:


From: Rajat Jain 

Add support for generic electronic privacy screen properties, that
can be added by systems that have an integrated EPS.

Changes in v2 (Hans de Goede)
- Create 2 properties, "privacy-screen sw-state" and
   "privacy-screen hw-state", to deal with devices where the OS might be
   locked out of making state changes
- Write kerneldoc explaining how the 2 properties work together, what
   happens when changes to the state are made outside of the DRM code's
   control, etc.

Signed-off-by: Rajat Jain 
Co-authored-by: Hans de Goede 
Signed-off-by: Hans de Goede 
---
  Documentation/gpu/drm-kms.rst |   2 +
  drivers/gpu/drm/drm_atomic_uapi.c |   6 ++
  drivers/gpu/drm/drm_connector.c   | 100 ++
  include/drm/drm_connector.h   |  50 +++
  4 files changed, 158 insertions(+)


...


diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 644f0ad10671..01360edc2376 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1186,6 +1186,45 @@ static const struct drm_prop_enum_list dp_colorspaces[] 
= {
   *can also expose this property to external outputs, in which case they
   *must support "None", which should be the default (since external screens
   *have a built-in scaler).
+ *
+ * privacy-screen sw-state, privacy-screen hw-state:
+ * These 2 optional properties can be used to query the state of the
+ * electronic privacy screen that is available on some displays; and in
+ * some cases also control the state. If a driver implements these
+ * properties then both properties must be present.
+ *
+ * "privacy-screen hw-state" is read-only and reflects the actual state
+ * of the privacy-screen, possible values: "Enabled", "Disabled,
+ * "Enabled, locked", "Disabled, locked". The locked states indicate
+ * that the state cannot be changed through the DRM API. E.g. there
+ * might be devices where the firmware-setup options, or a hardware
+ * slider-switch, offer always on / off modes.
+ *
+ * "privacy-screen sw-state" can be set to change the privacy-screen state
+ * when not locked. In this case the driver must update the hw-state
+ * property to reflect the new state on completion of the commit of the
+ * sw-state property. Setting the sw-state property when the hw-state is
+ * locked must be interpreted by the driver as a request to change the
+ * state to the set state when the hw-state becomes unlocked. E.g. if
+ * "privacy-screen hw-state" is "Enabled, locked" and the sw-state
+ * gets set to "Disabled" followed by the user unlocking the state by
+ * changing the slider-switch position, then the driver must set the
+ * state to "Disabled" upon receiving the unlock event.
+ *
+ * In some cases the privacy-screen state might change outside of control
+ * of the DRM code. E.g. there might be a firmware handled hotkey which
+ * toggles the state, or the state might be changed through another


Hi,

in the above three lines, I'd use the term "hardware state" instead of
just "state" to be explicit. Or should it be "physical state" since
"hardware state" might be confused with "hw-state" property state?


Maybe "actual state"? That is what is used a few lines higher:

'"privacy-screen hw-state" is read-only and reflects the actual state'

And you use it yourself to describe what we want below:


I don't mind as long as it's unambiguous and distinguishes explicitly
between actual and the two property states.


So since you and I both naturally described it as "actual state" without
thinking too much what we where writing at the time (I guess that applies
to your use too), "actual state" seems a good fit ?



+ * userspace API such as writing /proc/acpi/ibm/lcdshadow. In this case
+ * the driver must update both the hw-state and the sw-state to reflect
+ * the new value, overwriting any pending state requests in the sw-state.
+ *
+ * Note that the ability for the state to change outside of control of
+ * the DRM master process means that userspace must not cache the value
+ * of the sw-state. Ccaching the sw-state value and including it in later


Extra 'c' in "Caching".


Ack, will fix.


+ * atomic commits may lead to overriding a state change done through e.g.
+ * a firmware handled hotkey. Therefor userspace must not include the
+ * privacy-screen sw-state in an atomic commit unless it wants to change
+ * its value.
   */


This documentation and intended behaviour looks perfect to me.


Great I'm glad you like it.


If y

[RFC v2 0/1] drm/connector: Add support for privacy-screen properties

2020-05-11 Thread Hans de Goede
Hi All,

This RFC takes Rajat's earlier patch for adding privacy-screen properties
infra to drm_connector.c and then adds the results of the discussion from
the "RFC: Drm-connector properties managed by another driver / privacy
screen support" mail thread on top, hence the v2.

The most important thing here is big kernel-doc comment which gets added in
the first patch-chunk modifying drm_connector.c, this summarizes, or at
least tries to summarize, the conclusions of our previous discussion on
the userspace API and lays down the ground rules for how the 2 new
"privacy-screen sw-state" and  "privacy-screen hw-state" properties are
to be used both from the driver side as well as from the userspace side.

Other then that this modifies Rajat's patch to add 2 properties instead
of one, without much other changes.

Rajat, perhaps you can do a new version of your patch-set integration /
using this version of the properties and then if everyone is ok with
the proposed userspace API Jani can hopefully merge the whole set
through the i915 tree sometime during the 5.9 cycle.

Regards,

Hans

p.s.

I plan to start working on the lcdshadow subsystem next. As discussed the
plan for this subsystem is to allow drivers outside of the DRM subsys, such
as for example the thinkpad_acpi driver, to register a lcdshadow device,
which DRM drivers can then get a reference to and use to implement these
properties.

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC v2] drm/connector: Add support for privacy-screen properties (v2)

2020-05-11 Thread Hans de Goede
From: Rajat Jain 

Add support for generic electronic privacy screen properties, that
can be added by systems that have an integrated EPS.

Changes in v2 (Hans de Goede)
- Create 2 properties, "privacy-screen sw-state" and
  "privacy-screen hw-state", to deal with devices where the OS might be
  locked out of making state changes
- Write kerneldoc explaining how the 2 properties work together, what
  happens when changes to the state are made outside of the DRM code's
  control, etc.

Signed-off-by: Rajat Jain 
Co-authored-by: Hans de Goede 
Signed-off-by: Hans de Goede 
---
 Documentation/gpu/drm-kms.rst |   2 +
 drivers/gpu/drm/drm_atomic_uapi.c |   6 ++
 drivers/gpu/drm/drm_connector.c   | 100 ++
 include/drm/drm_connector.h   |  50 +++
 4 files changed, 158 insertions(+)

diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index 906771e03103..b72b1e0db343 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -445,6 +445,8 @@ Property Types and Blob Property Support
 .. kernel-doc:: drivers/gpu/drm/drm_property.c
:export:
 
+.. _standard_connector_properties:
+
 Standard Connector Properties
 -
 
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index a1e5e262bae2..e56a11208515 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -766,6 +766,8 @@ static int drm_atomic_connector_set_property(struct 
drm_connector *connector,
   fence_ptr);
} else if (property == connector->max_bpc_property) {
state->max_requested_bpc = val;
+   } else if (property == connector->privacy_screen_sw_state_property) {
+   state->privacy_screen_sw_state = val;
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
@@ -842,6 +844,10 @@ drm_atomic_connector_get_property(struct drm_connector 
*connector,
*val = 0;
} else if (property == connector->max_bpc_property) {
*val = state->max_requested_bpc;
+   } else if (property == connector->privacy_screen_sw_state_property) {
+   *val = state->privacy_screen_sw_state;
+   } else if (property == connector->privacy_screen_hw_state_property) {
+   *val = state->privacy_screen_hw_state;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 644f0ad10671..01360edc2376 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1186,6 +1186,45 @@ static const struct drm_prop_enum_list dp_colorspaces[] 
= {
  * can also expose this property to external outputs, in which case they
  * must support "None", which should be the default (since external screens
  * have a built-in scaler).
+ *
+ * privacy-screen sw-state, privacy-screen hw-state:
+ * These 2 optional properties can be used to query the state of the
+ * electronic privacy screen that is available on some displays; and in
+ * some cases also control the state. If a driver implements these
+ * properties then both properties must be present.
+ *
+ * "privacy-screen hw-state" is read-only and reflects the actual state
+ * of the privacy-screen, possible values: "Enabled", "Disabled,
+ * "Enabled, locked", "Disabled, locked". The locked states indicate
+ * that the state cannot be changed through the DRM API. E.g. there
+ * might be devices where the firmware-setup options, or a hardware
+ * slider-switch, offer always on / off modes.
+ *
+ * "privacy-screen sw-state" can be set to change the privacy-screen state
+ * when not locked. In this case the driver must update the hw-state
+ * property to reflect the new state on completion of the commit of the
+ * sw-state property. Setting the sw-state property when the hw-state is
+ * locked must be interpreted by the driver as a request to change the
+ * state to the set state when the hw-state becomes unlocked. E.g. if
+ * "privacy-screen hw-state" is "Enabled, locked" and the sw-state
+ * gets set to "Disabled" followed by the user unlocking the state by
+ * changing the slider-switch position, then the driver must set the
+ * state to "Disabled" upon receiving the unlock event.
+ *
+ * In some cases the privacy-screen state might change outside of control
+ * of the DRM code. E.g. the

Re: Linux GOP initialization is wrong

2020-05-04 Thread Hans de Goede

Hi,

On 4/30/20 3:22 AM, David Santamaría Rogado wrote:

I'm thinking also about the i915 part. Could be something different
that Intel does in the Windows version of their driver? Seem very
strange that Microsoft could patch something because of this
particular hardwares.


On Windows devices often ship with vendor modified drivers,
for the graphics driver Intel even allowed the vendor to
ship its own driver and opt out of generic Intel driver
updates (this changes very recently).

Also chances are that this is all controlled by some registry
setting, so as long as the device ships with the registry
setting telling the driver to deal with this, then on upgrades
of the driver, the driver will still see the old registry setting
and behave accordingly. I've very carefully checked the VBT
(Video Bios Tables) and I see no hints there which the windows
driver could use. So I believe that this is taking care of
with device specific settings done by the device's vendor.

Regards,

Hans





El mar., 28 abr. 2020 a las 10:45, Hans de Goede
() escribió:


Hi David,

On 4/28/20 1:58 AM, David Santamaría Rogado wrote:

This is related to the issues at least on some devices for panel
orientation quirks where added.


Thank you for looking into this.


My tests have been done over a Lenovo ideapad D330.

This devices like the other ones that need panel orientation quirks,
shows the initramfs with wrong stride and x and y swapped. By applying
the panel orientation quirks this gets solved but many parts of the
systems components needs to be patched. Hans has done a great job with
plymouth, mutter... but always appears a new problem derived as for
example vnc desktop sharing with this devices doesn't work and the
output is send messed up.


When I first started adding support for devices which have their
screen mounted 90 degrees rotated my first attempts where aimed
at solving this transparently in the kernel.

Unfortunately this is not possible. On most affected devices
the hardware does not support 90 degrees rotation for the
primary display layer; or if it does this requires the framebuffer
being in a hardware-specific tiled format rather then being a
linear framebuffer. Using these tiled formats requires userspace
to be aware of this, which rules out transparently handling this
in the kernel.

Other layers (cursor layer, video overlay layers) have similar
issues which require userspace to be aware of what is happening,
so unfortunately there is no other way to deal with this then
fixing involved userspace components.

I'm a bit surprised that you sat that vnc desktop sharing does
not work, I guess that also depends on how the desktop sharing
works. If it pokes directly at the framebuffer somehow, then yes
it will be messed up. But if it goes through the display server
then things might work. I guess that it is possible that the
code doing this cannot deal with Xrandr output rotation ...


The strange thing is that bootloaders like GRUB or rEFInd seems to be
able to handle this and they paint themselves right, despite when
booting Windows directly Windows paints itself right and booted with
GRUB or rEFInd the first second also paint itself wrong. Haven't
tested this too much but the interesting thing is in the next
paragraph.


My experience with bootloaders showing themselves the right way
up is mixed. It seems that the firmware is doing some hacks for
this on some devices, at least for the EFI text console.

Funnily enough (for some definition of fun) on at least one of
the devices where the firmware is playing tricks (Asus T100HA IIRC)
the position of the carret for text-editing is off by one, which
is very annoying when editing the kernel commandline and which
clearly shows that things are being emulated in software here.


I decided to get the UEFI GOP video modes and found that the D330 have
these ones:
Mode 0: 1200x1920
Mode 1: 640x480
Mode 2: 800x600
Mode 3: 1024x768
Mode 4: 1920x1200 (this is the default one started by the firmware)
Mode 5: 480x640
Mode 6: 600x800
Mode 7: 768x1024

So I thought that Linux is taking the first mode despite is not the
active one and that's why the display is messed up.


Nope, Linux does not touch the mode at all (nor does grub by default).
Doing a EFI/GOP modeset has the risk of triggering all sort of firmware
bugs. So we stick with what we get. This has interesting side effects
where on some systems you get a different mode when turning on the
machine and letting it boot, vs turning it on, pressing e.g. F12 to get
the boot menu and then boot Linux.


Playing a little I could modify the GOP video mode before booting with
the UEFI Shell by simple using the mode 150 101. This causes GOP video
mode 5 to be switched to video mode 0, the first one. Booting now
makes initramfs messages to be correctly rendered but in the wrong
orientation.


Right, the rendering on the side thing is expected. As said the hardware
cannot do 90 degrees rotation with a linear framebuffer and the GOP

Re: [PATCH 02/10] drm: Add backlight helper

2020-04-30 Thread Hans de Goede

Hi,

On 4/29/20 8:40 PM, Noralf Trønnes wrote:



Den 29.04.2020 16.13, skrev Hans de Goede:

Hi Noralf,

On 4/29/20 2:48 PM, Noralf Trønnes wrote:

This adds a function that creates a backlight device for a connector.
It does not deal with the KMS backlight ABI proposition[1] to add a
connector property. It only takes the current best practise to
standardise
the creation of a backlight device for DRM drivers while we wait for the
property.

The brightness value is set using a connector state variable and an
atomic
commit.

I have looked through some of the backlight users and this is what
I've found:

GNOME [2]
-

Brightness range: 0-100
Scale: Assumes perceptual


I'm afraid that this is an incaccurate view of how GNOME handles the
brightness. gnome-settings-daemon (g-s-d) exports a DBUS property which has
a range of 0 - 100%.  But it also offers step-up and step-down DBUS methods
which are used for handling brightness hotkey presses.

This is important because g-s-d internally also keeps a step_size variable
which depends on the brightness_max value of the sysfs backlight interface,
like this:

BRIGHTNESS_STEP_AMOUNT(max) ((max) < 20 ? 1 : (max) / 20)

This is important because some older laptops where we depend on the
vendor specific ACPI method (from e.g. dell-laptop or thinkpad_acpi)
there are only 8 levels. So if g-s-d where to simply fake a 1-100
range and would leave the stepping up to the DBus API user and that
user would want 20 steps, so 5 % per step, then the user would get

Start  -> 100% -> level 8
Press down ->  95% -> level 7
Press down ->  90% -> level 7 *no change*
etc.

Somewhat related on some embedded ARM devices there are tricks where
when the entire scene being rendered does not use 100% white as color,
the entire scene has all its rgb values upscaled (too a curve) so that
the brightest colors do hit 100% of one of r/g/b, combined with dimming
the backlight a bit to save power. As you can imagine for tricks like
these you want as much backlight control precision as possible.

So any backlight infra we add must expose the true range of the
backlight control and not normalize it to a 0-100 range.

So sorry, but nack for the current version because of the hardcoding
of the range.


No problem, I just had to start from somewhere, and I started with: Give
the driver developer as few options as possible, no more than necessary,
but I didn't really know what was necessary :-)

The reason I chose a 0-100 range is because the backlight property ABI
proposal had this range and it maps so nicely to percent. And can the
ordinary human see brightness changes in more than 100 steps?

This helper is only to be used by drm drivers and I assumed that all the
current drivers registering a backlight device could at least do that range.

Looking through the drivers and their max_brightness values that
assumption isn't quite right:

amd: 255
gma500: 100
i915: 
nouveau/nv40: 31
nouveau/nv50: 100
radeon: 255
shmobile: 

panel-dsi-cm.c: 255
panel-jdi-lt070me05000.c: 255
panel-orisetech-otm8009a.c: 255
panel-raydium-rm67191.c: 255
panel-samsung-s6e63m0.c: 10
panel-sony-acx424akp.c: 1023
panel-samsung-s6e3ha2.c: 100
panel-samsung-s6e63j0x03.c: 100
panel-sony-acx565akm.c: 255
bridge/parade-ps8622.c: 255

I'll add max_brightness as an argument together with scale which you
commented on below.


Ok, sounds good.


Also the scale really should be specified by the driver, or be hardcoded
to BACKLIGHT_SCALE_UNKNOWN for now. In many cases we do not really know.
But for e.g. the acpi_video firmware backlight interface a good guess is
that it actually represents a perceptual scale rather then controlling
the wattage.

Where as the native i915 backlight interface really is controlling
the wattage without any perceptual correction.

Another problem with your proposal is that it seems to assume that
the backlight is controlled by the drm/kms driver. On x86 we have


Yes, this backlight device is just for drm drivers.


I was hoping you might have some clever ideas how to deal with /
prepare for the backlight driver outside of drm-driver case too.
But I completely understand that you want to limit your scope.


The reason I spend time on this is because I want to pass backlight
brightness changes through the atomic machinery like any other state change.


I understand.

Regards,

Hans












atleast 3 different drivers for the backlight:

1) The i915 (or amd/nouveau) native driver which more or less
directly pokes the PWM controller of the GPU.
2) The ACPI video standard backlight interface
3) Vendor specific ACPI interfaces from older laptops

ATM we always register 1. which could remain unchanged with
your code and then also register 2/3 if we (the kernel) think
that will work better (*) and then rely on userspace prefering
these (they have a different backlight_type) over 1.

Ideally any infra we add will also offer the option to tie
2. or 3. to the connector...

Reg

Re: [PATCH resend] drm: Add DRM_MODE_TYPE_USERDEF flag to probed modes matching a video= argument

2020-04-30 Thread Hans de Goede

Hi,

On 4/30/20 4:52 PM, Ville Syrjälä wrote:

On Thu, Apr 30, 2020 at 02:47:00PM +0100, Emil Velikov wrote:

Hi Hans,

On Fri, 21 Feb 2020 at 17:33, Hans de Goede  wrote:


drm_helper_probe_add_cmdline_mode() prefers using a probed mode matching
a video= argument over calculating our own timings for the user specified
mode using CVT or GTF.

But userspace code which is auto-configuring the mode may want to know that
the user has specified that mode on the kernel commandline so that it can
pick that mode over the mode which is marked as DRM_MODE_TYPE_PREFERRED.

This commit sets the DRM_MODE_TYPE_USERDEF flag on the matching mode, just
as we would do on the user-specified mode when no matching probed mode is
found.

Signed-off-by: Hans de Goede 


I was skimming around wrt Ville's compact drm_display_mode series and
noticed that this never landed.

The commit brings extra consistency when dealing with user defined
modes, and is:
Reviewed-by: Emil Velikov 

Ville this may trivially conflict with your work. I suspect you can do
the honours, and apply on top of your series?
That is if you agree with the patch.


Quick glance at the original thread says maybe there were still some
userspace issues unresolved? Not sure.


IIRC the thread ended with Daniel agreeing on the userspace interface,
but asking for some docs and me pointing out that the patch already
updated/clarified the existing docs. After that things got quiet.

So I believe that this is (still) ready to go upstream.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 02/10] drm: Add backlight helper

2020-04-29 Thread Hans de Goede

Hi Noralf,

On 4/29/20 2:48 PM, Noralf Trønnes wrote:

This adds a function that creates a backlight device for a connector.
It does not deal with the KMS backlight ABI proposition[1] to add a
connector property. It only takes the current best practise to standardise
the creation of a backlight device for DRM drivers while we wait for the
property.

The brightness value is set using a connector state variable and an atomic
commit.

I have looked through some of the backlight users and this is what I've found:

GNOME [2]
-

Brightness range: 0-100
Scale: Assumes perceptual


I'm afraid that this is an incaccurate view of how GNOME handles the
brightness. gnome-settings-daemon (g-s-d) exports a DBUS property which has
a range of 0 - 100%.  But it also offers step-up and step-down DBUS methods
which are used for handling brightness hotkey presses.

This is important because g-s-d internally also keeps a step_size variable
which depends on the brightness_max value of the sysfs backlight interface,
like this:

BRIGHTNESS_STEP_AMOUNT(max) ((max) < 20 ? 1 : (max) / 20)

This is important because some older laptops where we depend on the
vendor specific ACPI method (from e.g. dell-laptop or thinkpad_acpi)
there are only 8 levels. So if g-s-d where to simply fake a 1-100
range and would leave the stepping up to the DBus API user and that
user would want 20 steps, so 5 % per step, then the user would get

Start  -> 100% -> level 8
Press down ->  95% -> level 7
Press down ->  90% -> level 7 *no change*
etc.

Somewhat related on some embedded ARM devices there are tricks where
when the entire scene being rendered does not use 100% white as color,
the entire scene has all its rgb values upscaled (too a curve) so that
the brightest colors do hit 100% of one of r/g/b, combined with dimming
the backlight a bit to save power. As you can imagine for tricks like
these you want as much backlight control precision as possible.

So any backlight infra we add must expose the true range of the
backlight control and not normalize it to a 0-100 range.

So sorry, but nack for the current version because of the hardcoding
of the range.

Also the scale really should be specified by the driver, or be hardcoded
to BACKLIGHT_SCALE_UNKNOWN for now. In many cases we do not really know.
But for e.g. the acpi_video firmware backlight interface a good guess is
that it actually represents a perceptual scale rather then controlling
the wattage.

Where as the native i915 backlight interface really is controlling
the wattage without any perceptual correction.

Another problem with your proposal is that it seems to assume that
the backlight is controlled by the drm/kms driver. On x86 we have
atleast 3 different drivers for the backlight:

1) The i915 (or amd/nouveau) native driver which more or less
directly pokes the PWM controller of the GPU.
2) The ACPI video standard backlight interface
3) Vendor specific ACPI interfaces from older laptops

ATM we always register 1. which could remain unchanged with
your code and then also register 2/3 if we (the kernel) think
that will work better (*) and then rely on userspace prefering
these (they have a different backlight_type) over 1.

Ideally any infra we add will also offer the option to tie
2. or 3. to the connector...

Regards,

Hans



*) e.g. it will work while the others will not work at all






Avoids setting the sysfs brightness value to zero if max_brightness >= 99.
Can connect connector and backlight using the sysfs device.

KDE [3]
---

Brightness range: 0-100
Scale: Assumes perceptual

Weston [4]
--

Brightness range: 0-255
Scale: Assumes perceptual

Chromium OS [5]
---

Brightness range: 0-100
Scale: Depends on the sysfs file 'scale' which is a recent addition (2019)

xserver [6]
---

Brightness range: 0-x (driver specific) (1 is minimum, 0 is OFF)
Scale: Assumes perceptual

The builtin modesetting driver[7] does not support Backlight, Intel[8] does.

[1] 
https://lore.kernel.org/dri-devel/4b17ba08-39f3-57dd-5aad-d37d844b0...@linux.intel.com/
[2] 
https://gitlab.gnome.org/GNOME/gnome-settings-daemon/-/blob/master/plugins/power/gsd-backlight.c
[3] 
https://github.com/KDE/powerdevil/blob/master/daemon/backends/upower/backlighthelper.cpp
[4] 
https://gitlab.freedesktop.org/wayland/weston/-/blob/master/libweston/backend-drm/drm.c
[5] 
https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/master/power_manager/powerd/system/internal_backlight.cc
[6] https://github.com/freedesktop/xorg-randrproto/blob/master/randrproto.txt
[7] 
https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/hw/xfree86/drivers/modesetting/drmmode_display.c
[8] 
https://gitlab.freedesktop.org/xorg/driver/xf86-video-intel/-/blob/master/src/backlight.c

Cc: Hans de Goede 
Cc: Jani Nikula 
Cc: Martin Peres 
Cc: Daniel Thompson 
Signed-off-by: Noralf Trønnes 
---
  Documentation/gpu/drm-kms-helpers.rst  |   6 +
  drivers/gpu/drm/Kcon

Re: Linux GOP initialization is wrong

2020-04-28 Thread Hans de Goede

Hi David,

On 4/28/20 1:58 AM, David Santamaría Rogado wrote:

This is related to the issues at least on some devices for panel
orientation quirks where added.


Thank you for looking into this.


My tests have been done over a Lenovo ideapad D330.

This devices like the other ones that need panel orientation quirks,
shows the initramfs with wrong stride and x and y swapped. By applying
the panel orientation quirks this gets solved but many parts of the
systems components needs to be patched. Hans has done a great job with
plymouth, mutter... but always appears a new problem derived as for
example vnc desktop sharing with this devices doesn't work and the
output is send messed up.


When I first started adding support for devices which have their
screen mounted 90 degrees rotated my first attempts where aimed
at solving this transparently in the kernel.

Unfortunately this is not possible. On most affected devices
the hardware does not support 90 degrees rotation for the
primary display layer; or if it does this requires the framebuffer
being in a hardware-specific tiled format rather then being a
linear framebuffer. Using these tiled formats requires userspace
to be aware of this, which rules out transparently handling this
in the kernel.

Other layers (cursor layer, video overlay layers) have similar
issues which require userspace to be aware of what is happening,
so unfortunately there is no other way to deal with this then
fixing involved userspace components.

I'm a bit surprised that you sat that vnc desktop sharing does
not work, I guess that also depends on how the desktop sharing
works. If it pokes directly at the framebuffer somehow, then yes
it will be messed up. But if it goes through the display server
then things might work. I guess that it is possible that the
code doing this cannot deal with Xrandr output rotation ...


The strange thing is that bootloaders like GRUB or rEFInd seems to be
able to handle this and they paint themselves right, despite when
booting Windows directly Windows paints itself right and booted with
GRUB or rEFInd the first second also paint itself wrong. Haven't
tested this too much but the interesting thing is in the next
paragraph.


My experience with bootloaders showing themselves the right way
up is mixed. It seems that the firmware is doing some hacks for
this on some devices, at least for the EFI text console.

Funnily enough (for some definition of fun) on at least one of
the devices where the firmware is playing tricks (Asus T100HA IIRC)
the position of the carret for text-editing is off by one, which
is very annoying when editing the kernel commandline and which
clearly shows that things are being emulated in software here.


I decided to get the UEFI GOP video modes and found that the D330 have
these ones:
Mode 0: 1200x1920
Mode 1: 640x480
Mode 2: 800x600
Mode 3: 1024x768
Mode 4: 1920x1200 (this is the default one started by the firmware)
Mode 5: 480x640
Mode 6: 600x800
Mode 7: 768x1024

So I thought that Linux is taking the first mode despite is not the
active one and that's why the display is messed up.


Nope, Linux does not touch the mode at all (nor does grub by default).
Doing a EFI/GOP modeset has the risk of triggering all sort of firmware
bugs. So we stick with what we get. This has interesting side effects
where on some systems you get a different mode when turning on the
machine and letting it boot, vs turning it on, pressing e.g. F12 to get
the boot menu and then boot Linux.


Playing a little I could modify the GOP video mode before booting with
the UEFI Shell by simple using the mode 150 101. This causes GOP video
mode 5 to be switched to video mode 0, the first one. Booting now
makes initramfs messages to be correctly rendered but in the wrong
orientation.


Right, the rendering on the side thing is expected. As said the hardware
cannot do 90 degrees rotation with a linear framebuffer and the GOP
provided efifb is a linear framebuffer. So without telling the kernel
to software rotate its text console the text will always be on its side.

What your little EFI shell hack is doing is working around what seems to
be a bug on these Lenovo devices gives us the wrong stride and dimensions
for the EFI framebuffer.

Note that this very much is a Lenovo bug, all the other devices
with 90 degree rotated screens let us render the text console
on its side just fine. They correctly tells us the real size
and stride of the screen (so its portrait dimensions since it
is a portrait screen).

Even though this is a Lenovo bug we should probably still try to
find a way to deal with this though, so that the efifb works
correctly on these devices...


A look at drivers/firmware/efi/libstub/gop.c seems to be what is
happening, the first available video mode is used despite it could not
be the active one in GOP and the active mode is not switched to the
discovered one by Linux. Both GRUB and rEFInd are able to respect the
video mode that GOP has active so it's 

Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-24 Thread Hans de Goede

Hi all,

On 4/24/20 11:08 AM, Pekka Paalanen wrote:

On Fri, 24 Apr 2020 10:24:31 +0200
Hans de Goede  wrote:





Agree on the hw-state prop reflecting the actual hardware state at
all times, that one is easy.


However, when userspace sets "privacy-screen-sw-state", the driver
should attempt to change hardware state regardless of whether the
"privacy-screen-sw-state" value changes compared to its old value or
not. Otherwise userspace cannot intentionally override a hardware
hotkey setting if possible (or would need two atomic commits to do it).


Ack / agreed.


Mind, the above paragraph is only what I interpreted from this email
thread here. Previously I did not think that with atomic KMS, setting a
property to a value it already has could trigger anything. But I guess
it can?


In a way. My idea for the "privacy-screen-sw-state" is for it to reflect
the last requested value, where the request could come from either a
firmware controlled hotkey; or from userspace (this seems to be where
our ideas of how to handle this diverts).

So what can happen is (with both props being always in sync)
-userspace reads privacy screen being off
-user toggles privacy screen on through firmware controlled hotkey
-kernel gets notified about state toggle, updates both property
   states to on
-userspace commits its old knowledge of the property (off), thereby
   triggering the kernel to turn the privacy screen back off

So in this case from the kernel pov the property is actually set
to a new value, not to "a value it already has".


Hi,

that is an interesting point of view.

You are keeping the separation between "wanted" and "actual" state, but
counting firmware/hardware hotkeys as "want" instead of letting them
silently change hardware state.


Right, that seems more natural to me, as mentioned
already, this way the wanted and hw state only get out
of sync if the hw is locked to a certain state.


That seems ok.


Note there can be races here of course, but lets ignore those (for now).
Both the hotkey event as well as userspace changing the setting will be
end-user triggered events and will not happen at high frequency.
Also I see no way to completely eliminate racing here. Luckily the side
effects of the race or pretty harmless (annoying maybe, but not causing
crashes, etc).


This design is based on that it can.
   

What is not clear to me is if any change to"privacy-screen-hw-state"
shall be propagated to "privacy-screen-sw-state"?
   - If yes, then I think we are not solving any problems of single property.
   - If no, then why do we require userspace to write to sw state only
if something has changed?


No. As already written, the kernel must not change the value of
"privacy-screen-sw-state", only userspace can.


So this is where out view of how to handle this differs, I do
not see the hotkey changing the state as different from userspace
changing it. The reason for me to have both a sw- and a hw-state
is in case there is a physical switch (typically a slider style
switch) which forces the state to on / off. In this case userspace
could still set the "privacy-screen-sw-state" prop and then
the 2 could differ.


Yes, the locked switch case definitely makes sense to me.

If userspace has to avoid setting the sw property unless it actually
intends to change it, then the sw property being controlled from
multiple sources (firmware, hotkey, the /proc file below) could work.
It would even tell the KMS client when someone else changed the
"wanted" state.


Right, that is the idea and telling the KMS client definitely
is a feature we want, so that we can show an OSD notifcation
on the firmware handled hotkey presses, like we already do for volume
control/mute, (kbd) backlight changes, etc.


Lets add one more complication to this, which I think helps.
Currently the thinkpad_acpi driver exports the privacy screen as:

/proc/acpi/ibm/lcdshadow

Userspace can write this and then change the privacy-screen
setting, this is in shipped kernels and cannot be dropped
because it is part if the kernel's uABI now.
This means that another userspace process can change the
property underneath a kms client. I do not see how this is
different from the firmware changing the setting based on
a hotkey press. Yet if we stick with your "only userspace can"
change the sw-state setting, then does this count as userspace,
or do you mean only a kms client can ?  And then how is
another kms-client changing the setting different ?


To me that would be similar to firmware changing hardware state: it's
not the KMS client (the display server) doing it, but something else
behind its back while it thinks it's in full control.

Doing things behind the display server's back is what creates all the
mess here.


Right, unfortunately this is not something which we can change.
I have asked Lenovo if it will be possible to jus

Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-24 Thread Hans de Goede

Hi all,

Pekka, Rajat,

Thank you for your input in this.

On 4/24/20 9:40 AM, Pekka Paalanen wrote:

On Thu, 23 Apr 2020 11:21:47 -0700
Rajat Jain  wrote:


On Tue, Apr 21, 2020 at 7:46 AM Pekka Paalanen  wrote:


On Tue, 21 Apr 2020 14:37:41 +0200
Hans de Goede  wrote:
  

TL;DR: Yes there will be races, because of both userspace +
the firmware having; and potentially using r/w access to
the privacy-screen state. But in practice I expect these
to not really be an issue. Important here is that userspace
only commits the property in a transaction to commit if
it actually intends to change the property so as to not
needlessly create a situation where we might hit the race.

As for 1 vs 2 properties for this I guess that in preparation
for potential devices where the state is locked, having a
r/w sw-state + a ro hw-state property makes sense.

So I suggest that we replace the current "privacy-screen" property
from Rajat's patch-set with 2 props named:

"privacy-screen-sw-state" (r/w)
"privacy-screen-hw-state" (ro)

Where for current gen hardware the privacy-screen-hw-state is
just a mirror of the sw-state.


Just to make sure I understand the semantics correctly:

- The  "privacy-screen-hw-state" shall be read-only, and can be modified by:
   - Hardware (e.g. HW kill switch).
   - Firmware.
   - (Potentially) needs a notification/irq to the kernel when this
changes (or may be kernel can read it only when userspace queries for
it).

- The "privacy-screen-sw-state" shall be read-write, and can only be
modified by user space.
 - If user space toggles it, the kernel will attempt to
"request" the change to hardware.
 - Whether the request to hardware was successful or not, the
"privacy-screen-sw-state" will always reflect the latest value
userspace wrote.
 - If the request to hardware was successful, the
"privacy-screen-hw-state" will also change (probably via a separate
notification/irq from HW).
 - We expect the user space to write to
"privacy-screen-sw-state" only if it really wants to toggle the value.


Hi,

yes, to my understanding, that seems to be the correct idea from this
thread. The hw-state property must reflect the actual hardware state at
all times.


Agree on the hw-state prop reflecting the actual hardware state at
all times, that one is easy.


However, when userspace sets "privacy-screen-sw-state", the driver
should attempt to change hardware state regardless of whether the
"privacy-screen-sw-state" value changes compared to its old value or
not. Otherwise userspace cannot intentionally override a hardware
hotkey setting if possible (or would need two atomic commits to do it).


Ack / agreed.


Mind, the above paragraph is only what I interpreted from this email
thread here. Previously I did not think that with atomic KMS, setting a
property to a value it already has could trigger anything. But I guess
it can?


In a way. My idea for the "privacy-screen-sw-state" is for it to reflect
the last requested value, where the request could come from either a
firmware controlled hotkey; or from userspace (this seems to be where
our ideas of how to handle this diverts).

So what can happen is (with both props being always in sync)
-userspace reads privacy screen being off
-user toggles privacy screen on through firmware controlled hotkey
-kernel gets notified about state toggle, updates both property
 states to on
-userspace commits its old knowledge of the property (off), thereby
 triggering the kernel to turn the privacy screen back off

So in this case from the kernel pov the property is actually set
to a new value, not to "a value it already has".

Note there can be races here of course, but lets ignore those (for now).
Both the hotkey event as well as userspace changing the setting will be
end-user triggered events and will not happen at high frequency.
Also I see no way to completely eliminate racing here. Luckily the side
effects of the race or pretty harmless (annoying maybe, but not causing
crashes, etc).


This design is based on that it can.


What is not clear to me is if any change to"privacy-screen-hw-state"
shall be propagated to "privacy-screen-sw-state"?
  - If yes, then I think we are not solving any problems of single property.
  - If no, then why do we require userspace to write to sw state only
if something has changed?


No. As already written, the kernel must not change the value of
"privacy-screen-sw-state", only userspace can.


So this is where out view of how to handle this differs, I do
not see the hotkey changing the state as different from userspace
changing it. The reason for me to have both a sw- and a hw-state
is in case there is a physical switch (typically a slider style
switch) which forces the state to on / off. In this case userspace
could still set the &quo

Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-21 Thread Hans de Goede

Hi,

On 4/17/20 1:55 PM, Jani Nikula wrote:

On Fri, 17 Apr 2020, Pekka Paalanen  wrote:

On Wed, 15 Apr 2020 17:40:46 +0200
Hans de Goede  wrote:


Hi,

On 4/15/20 5:28 PM, Jani Nikula wrote:

On Wed, 15 Apr 2020, Hans de Goede  wrote:

ii. Currently the "privacy-screen" property added by Rajat's
patch-set is an enum with 2 possible values:
"Enabled"
"Disabled"

We could add a third value "Not Available", which would be the
default and then for internal panels always add the property
so that we avoid the problem that detecting if the laptop has
an internal privacy screen needs to be done before the connector
is registered. Then we can add some hooks which allow an
lcdshadow-driver to register itself against a connector later
(which is non trivial wrt probe order, but lets ignore that for now).


I regret dropping the ball on Rajat's series (sorry!).

I do think having the connector property for this is the way to go.


I 100% agree.


Even
if we couldn't necessarily figure out all the details on the kernel
internal connections, can we settle on the property though, so we could
move forward with Rajat's series?


Yes please, this will also allow us to move forward with userspace
support even if for testing that we do some hacks for the kernel's
internal connections for now.


Moreover, do we actually need two properties, one which could indicate
userspace's desire for the property, and another that tells the hardware
state?


No I do not think so. I would expect there to just be one property,
I guess that if the state is (partly) firmware controlled then there
might be a race, but we will need a notification mechanism (*) for
firmware triggered state changes anyways, so shortly after loosing
the race userspace will process the notification and it will know
about it.

One thing which might be useful is a way to signal that the property
is read-only in case we ever hit hw where that is the case.


I'd so very much like to have no in-kernel/in-firmware shortcuts
to enable/disable the privacy screen, and instead have any hardware
buttons just be events that the userspace could react to. However I
don't think that'll be the case unfortunately.


In my experience with keyboard-backlight support, we will (unfortunately)
see a mix and in some case we will get a notification that the firmware
has adjusted the state, rather then just getting a keypress and
dealing with that ourselves.  In some cases we may even be able to
choose, so the fw will deal with it by default but we can ask it
to just send a key-press.  But I do believe that we can *not* expect
that we will always just get a keypress for userspace to deal with.


Hi,

let's think about how userspace uses atomic KMS UAPI. The simplest way
to use atomic correctly is that userspace will for every update send the
full, complete set of all properties that exist, both known and unknown
to userspace (to recover from temporarily VT-switching to another KMS
program that changes unknown properties). Attempting to track which
properties already have their correct values in the kernel is extra
work for just extra bugs.

Assuming the property is userspace-writable: if kernel goes and
changes the property value on its own, it will very likely be just
overwritten by userspace right after if userspace does not manage to
process the uevent first. If that happens and userspace later
processes the uevent, userspace queries the kernel for the current
proprerty state which is now what userspace wrote, not what firmware
set.

Therefore you end up with the firmware hotkey working only randomly.

It would be much better to have the hotkey events delivered to
userspace so that userspace can control the privacy screen and
everything will be reliable, both the hotkeys and any GUI for it.


I'd like this too. However I fear this is out of our control, and OEMs
have and will anyway fiddle with the privacy screen directly no matter
what we say, and we can't prevent that. From their POV it's easier for
them to do their value-add in components they have total control over. I
emphatize with that view, even if it's counter-productive from the Linux
ecosystem POV.

So we'll just have to deal with it.


Ack, at least that is the case for the current generation Lenovo devices.


The other reliable option is that userspace must never be able to
change privacy screen state, only the hardware hotkeys can.


That, in turn, discourages anyone from doing the right thing, and blocks
us from adding any nice additional features for privacy screens that
only the userspace is capable of managing. For example, controlling
privacy screen based on content, which seems like an obvious feature.


Right.

So we have the case here were both the firmware and userspace may change
the privacyscreen state (on/off) at any time.

This means that the atomic API use described by Pekka for this, where
userspace keeps all properties in memory, updates the one which it
wants to ch

Re: [PATCH 05/59] drm/vboxvidoe: use managed pci functions

2020-04-20 Thread Hans de Goede

Hi,

On 4/15/20 7:44 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 05:03:55PM +0200, Hans de Goede wrote:

Hi,

On 4/15/20 9:39 AM, Daniel Vetter wrote:

Allows us to drop the cleanup code on the floor.

Sam noticed in his review:

With this change we avoid calling pci_disable_device()
twise in case vbox_mm_init() fails.
Once in vbox_hw_fini() and once in the error path.


v2: Include Sam's review remarks

Acked-by: Sam Ravnborg 
Signed-off-by: Daniel Vetter 
Cc: Hans de Goede 
---
   drivers/gpu/drm/vboxvideo/vbox_drv.c  | 6 ++
   drivers/gpu/drm/vboxvideo/vbox_main.c | 7 +--
   2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c 
b/drivers/gpu/drm/vboxvideo/vbox_drv.c
index cfa4639c5142..cf2e3e6a2388 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_drv.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c
@@ -55,13 +55,13 @@ static int vbox_pci_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
pci_set_drvdata(pdev, vbox);
mutex_init(>hw_mutex);
-   ret = pci_enable_device(pdev);
+   ret = pcim_enable_device(pdev);
if (ret)
return ret;
ret = vbox_hw_init(vbox);
if (ret)
-   goto err_pci_disable;
+   return ret;
ret = vbox_mm_init(vbox);
if (ret)
@@ -91,8 +91,6 @@ static int vbox_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
vbox_mm_fini(vbox);
   err_hw_fini:
vbox_hw_fini(vbox);
-err_pci_disable:
-   pci_disable_device(pdev);
return ret;
   }
diff --git a/drivers/gpu/drm/vboxvideo/vbox_main.c 
b/drivers/gpu/drm/vboxvideo/vbox_main.c
index 9dcab115a261..1336ab9795fc 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_main.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_main.c
@@ -71,8 +71,6 @@ static void vbox_accel_fini(struct vbox_private *vbox)
for (i = 0; i < vbox->num_crtcs; ++i)
vbva_disable(>vbva_info[i], vbox->guest_pool, i);
-
-   pci_iounmap(vbox->ddev.pdev, vbox->vbva_buffers);
   }
   /* Do we support the 4.3 plus mode hint reporting interface? */


This seems to be missing the conversion of the iomap_range call to
the devm equivalent ?   :

drivers/gpu/drm/vboxvideo/vbox_main.c
44: vbox->vbva_buffers = pci_iomap_range(vbox->ddev.pdev, 0, ...


pcim_enable_device is pure magic, it converts _all_ pci_ calls on that
device to the managed version. There's no other manged pci_ functions (ok
1-2 more, but they're rather special).


Ah I see, magic indeed.

Well with that explained, this is:

Reviewed-by: Hans de Goede 

Regards,

Hans




@@ -125,7 +123,7 @@ int vbox_hw_init(struct vbox_private *vbox)
/* Create guest-heap mem-pool use 2^4 = 16 byte chunks */
vbox->guest_pool = gen_pool_create(4, -1);
if (!vbox->guest_pool)
-   goto err_unmap_guest_heap;
+   return -ENOMEM;
ret = gen_pool_add_virt(vbox->guest_pool,
(unsigned long)vbox->guest_heap,
@@ -168,8 +166,6 @@ int vbox_hw_init(struct vbox_private *vbox)
   err_destroy_guest_pool:
gen_pool_destroy(vbox->guest_pool);
-err_unmap_guest_heap:
-   pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
return ret;
   }
@@ -177,5 +173,4 @@ void vbox_hw_fini(struct vbox_private *vbox)
   {
vbox_accel_fini(vbox);
gen_pool_destroy(vbox->guest_pool);
-   pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
   }







___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 11:10 PM, Jani Nikula wrote:

On Wed, 15 Apr 2020, Rajat Jain  wrote:

Hello,

On Wed, Apr 15, 2020 at 8:40 AM Hans de Goede  wrote:


Hi,

On 4/15/20 5:28 PM, Jani Nikula wrote:

On Wed, 15 Apr 2020, Hans de Goede  wrote:

ii. Currently the "privacy-screen" property added by Rajat's
patch-set is an enum with 2 possible values:
"Enabled"
"Disabled"

We could add a third value "Not Available", which would be the
default and then for internal panels always add the property
so that we avoid the problem that detecting if the laptop has
an internal privacy screen needs to be done before the connector
is registered. Then we can add some hooks which allow an
lcdshadow-driver to register itself against a connector later
(which is non trivial wrt probe order, but lets ignore that for now).


I regret dropping the ball on Rajat's series (sorry!).

I do think having the connector property for this is the way to go.


I 100% agree.


Even
if we couldn't necessarily figure out all the details on the kernel
internal connections, can we settle on the property though, so we could
move forward with Rajat's series?


Thanks, it would be great!.



Yes please, this will also allow us to move forward with userspace
support even if for testing that we do some hacks for the kernel's
internal connections for now.


Moreover, do we actually need two properties, one which could indicate
userspace's desire for the property, and another that tells the hardware
state?


No I do not think so. I would expect there to just be one property,
I guess that if the state is (partly) firmware controlled then there
might be a race, but we will need a notification mechanism (*) for
firmware triggered state changes anyways, so shortly after loosing
the race userspace will process the notification and it will know
about it.


I agree with Hans here that I think it would be better if we could do
it with one property.

  * I can imagine demand for laptops that have a "hardware kill switch"
for privacy screen (just like there are for camera etc today). So I
think in future we may have to deal with this case anyway. In such
devices it's the hardware (as opposite to firmware) that will change
the state. The HW will likely provide an interrupt to the software to
notify of the change. This is all imaginative at this point though.

* I think having 2 properties might be a confusing UAPI. Also, we have
existing properties like link-status that can be changed by both the
user and the hardware.


I think the consensus is that all properties that get changed by both
userspace and the kernel are mistakes, and the way to handle it is to
have two properties.


But the actual privacy screen has only 1 state, having two properties
for this will only be confusing. As I mentioned before we have a similar
case with e.g. keyboard backlighting and there the userspace API
also has a single sysfs attribute for the brightness, with change
notifications to userspace if the firmware changes the brightness
on its own and this works well.

What would the semantics of these 2 different properties be? And
what sort of extra functionality would these semantics offer which
the single property versions does not offer?

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 8:29 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 8:19 PM Hans de Goede  wrote:


Hi,

On 4/15/20 7:54 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 03:02:53PM +0200, Hans de Goede wrote:

Hi,

On 4/15/20 2:01 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 01:39:23PM +0200, Hans de Goede wrote:

Hi,

On 4/15/20 12:22 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 12:11 PM Hans de Goede  wrote:


Hi,

On 4/15/20 11:52 AM, Daniel Vetter wrote:





iv. What every SoC subsystem does:

- lcdshadow drivers register drivers
- drm drivers look them up
- if stuff isn't there yet, we delay loading with EPROBE_DEFER until
the entire thing is assembled.

That's what we're doing already for other standardized components like
drm_bridge or drm_panel, and I think that's also the right approach
for backlight and anything else like that. Hand-rolling our own
EPROBE_DEFER handling, or some other duct-tape monsters imo just leads
to real pain. Also, with EPROBE_DEFER we have one standard way of
building a driver from component, which spans subsystems and is also
the underlying magic that makes stuff like component.c work.


On the SoCs we have devicetree telling us what components there
are, so we can wait for them to show up. The only way to figure out
if the lcdshadow thing is there on a ThinkPad is asking thinkpad_acpi,
or duplicating a lot of code from thinkpad_acpi. Edit:
also see below for a possible solution.


Yup it sucks. I think all we can do is have a small acpi match
function (which yes will duplicate some of the thinkpad_acpi driver
logic) to re-create that information and give us a "should we have a
lcdshadow driver for this $pci_device" answer.


Ok, so questions about this solution:

1. Where should that match-function live ?

2. An acpi_thinkpad derived match-function will only be able to
  answer if there is an lcdshadow device/driver for the internal
  panel. It will not be able to tie this info to a certain PCI
  device. My plan is to pass NULL as dev_name when registering
  the lcdshadow-device and have lcdshadow_get(dev, )
  skip device-name matching (consider everything a match) for
  lcdshadow-devices registered with NULL as dev_name.

  So I guess in this case the mini match function should just
  ignore the passed in device?


Yeah I think we can't really avoid that. I also expect that we'll need
ACPI and dt versions of this, and driver needs to know which one to call.
Since at least in a dt world the driver knows exactly for which dt node it
needs a lcdshadow driver for (with the phandle stuff), so we can be a lot
more strict.

For the acpi version I'm not even sure we can do more than provide the
struct device * pointer of the gpu. I think if we ever get more than 1
lcdshadow driver on acpi systems we can add more stuff later on, for now
I'd just leave that out.

So maybe

acpi_lcdshadow_get(struct device *dev);

of_lcdshadow_get(struct device_node *np);

And with maybe a future plan to add some kind of enum or whatever to
acpi_lcdshadow_get(). Both would return either the lcdshadow pointer, or
an PTR_ERR() so that we could encode EPROBE_DEFER vs ENOENT.


Ok, note I plan to only implement the acpi version for now, I do
expect some non ACPI/x86 devices to show up with his feature
eventually but I believe it is best to implement this once
those actually show up. Esp. since this will also involve adding
some devicetree bindings for this.


ofc, just wanted to lay out the entire thing. The DT version needs some
good bikeshed on the dt schema first anyway (so that the helper can decode
that directly).


We might also want a low-level lcdshadow_get() which only returns ENOENT
when the driver isn't there, and which leaves "do we really need one?" to
higher levels to answer.


Right, so my latest idea on that is indeed a high-level lcdshadow_get()
which takes a struct device * and a connector-name and which never
returns EPROBE_DEFER.

As for leaving things to the higher levels to answer, as explained
in my other follow-up email I think that we should probably add a
lcdshadow_probe_defer() helper for this and call that early on
in the PCI-driver probe functions for the 3 major x86 GPU drivers.
Does that sound ok to you?


Uh ... not pretty. There's still a lifetime problem that strictly speaking
there's nothing stopping the other driver from getting unloaded between
your _probe_defer and the subsequent _get. I think fixing this properly
(and screaming a bit at the error code, oh well) is better.


I would really like to separate the discussion and the work
on getting the 3 major x86 GPU drivers ready to deal with EPROBE_DEFER
from the lcdshadow discussion and work.  I expect getting these
3 drivers ready for EPROBE_DEFER is going to be a major undertaking
and I would like avoid introducing this significant scope creep
to the lcdshadow discussion, because it simply is a too big undertaking
to undertake without us g

Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 7:54 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 03:02:53PM +0200, Hans de Goede wrote:

Hi,

On 4/15/20 2:01 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 01:39:23PM +0200, Hans de Goede wrote:

Hi,

On 4/15/20 12:22 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 12:11 PM Hans de Goede  wrote:


Hi,

On 4/15/20 11:52 AM, Daniel Vetter wrote:





iv. What every SoC subsystem does:

- lcdshadow drivers register drivers
- drm drivers look them up
- if stuff isn't there yet, we delay loading with EPROBE_DEFER until
the entire thing is assembled.

That's what we're doing already for other standardized components like
drm_bridge or drm_panel, and I think that's also the right approach
for backlight and anything else like that. Hand-rolling our own
EPROBE_DEFER handling, or some other duct-tape monsters imo just leads
to real pain. Also, with EPROBE_DEFER we have one standard way of
building a driver from component, which spans subsystems and is also
the underlying magic that makes stuff like component.c work.


On the SoCs we have devicetree telling us what components there
are, so we can wait for them to show up. The only way to figure out
if the lcdshadow thing is there on a ThinkPad is asking thinkpad_acpi,
or duplicating a lot of code from thinkpad_acpi. Edit:
also see below for a possible solution.


Yup it sucks. I think all we can do is have a small acpi match
function (which yes will duplicate some of the thinkpad_acpi driver
logic) to re-create that information and give us a "should we have a
lcdshadow driver for this $pci_device" answer.


Ok, so questions about this solution:

1. Where should that match-function live ?

2. An acpi_thinkpad derived match-function will only be able to
 answer if there is an lcdshadow device/driver for the internal
 panel. It will not be able to tie this info to a certain PCI
 device. My plan is to pass NULL as dev_name when registering
 the lcdshadow-device and have lcdshadow_get(dev, )
 skip device-name matching (consider everything a match) for
 lcdshadow-devices registered with NULL as dev_name.

 So I guess in this case the mini match function should just
 ignore the passed in device?


Yeah I think we can't really avoid that. I also expect that we'll need
ACPI and dt versions of this, and driver needs to know which one to call.
Since at least in a dt world the driver knows exactly for which dt node it
needs a lcdshadow driver for (with the phandle stuff), so we can be a lot
more strict.

For the acpi version I'm not even sure we can do more than provide the
struct device * pointer of the gpu. I think if we ever get more than 1
lcdshadow driver on acpi systems we can add more stuff later on, for now
I'd just leave that out.

So maybe

acpi_lcdshadow_get(struct device *dev);

of_lcdshadow_get(struct device_node *np);

And with maybe a future plan to add some kind of enum or whatever to
acpi_lcdshadow_get(). Both would return either the lcdshadow pointer, or
an PTR_ERR() so that we could encode EPROBE_DEFER vs ENOENT.


Ok, note I plan to only implement the acpi version for now, I do
expect some non ACPI/x86 devices to show up with his feature
eventually but I believe it is best to implement this once
those actually show up. Esp. since this will also involve adding
some devicetree bindings for this.


ofc, just wanted to lay out the entire thing. The DT version needs some
good bikeshed on the dt schema first anyway (so that the helper can decode
that directly).


We might also want a low-level lcdshadow_get() which only returns ENOENT
when the driver isn't there, and which leaves "do we really need one?" to
higher levels to answer.


Right, so my latest idea on that is indeed a high-level lcdshadow_get()
which takes a struct device * and a connector-name and which never
returns EPROBE_DEFER.

As for leaving things to the higher levels to answer, as explained
in my other follow-up email I think that we should probably add a
lcdshadow_probe_defer() helper for this and call that early on
in the PCI-driver probe functions for the 3 major x86 GPU drivers.
Does that sound ok to you?


Uh ... not pretty. There's still a lifetime problem that strictly speaking
there's nothing stopping the other driver from getting unloaded between
your _probe_defer and the subsequent _get. I think fixing this properly
(and screaming a bit at the error code, oh well) is better.


I would really like to separate the discussion and the work
on getting the 3 major x86 GPU drivers ready to deal with EPROBE_DEFER
from the lcdshadow discussion and work.  I expect getting these
3 drivers ready for EPROBE_DEFER is going to be a major undertaking
and I would like avoid introducing this significant scope creep
to the lcdshadow discussion, because it simply is a too big undertaking
to undertake without us getting a significant amount of manpower
specifically for this from somewhere.

Note I do agree with you that get

Re: [External] Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-15 Thread Hans de Goede

Hi Mark,

On 4/15/20 7:14 PM, Mark Pearson wrote:

Hi,


-Original Message-
From: Hans de Goede 
Sent: Wednesday, April 15, 2020 11:41 AM
On 4/15/20 5:28 PM, Jani Nikula wrote:

On Wed, 15 Apr 2020, Hans de Goede  wrote:
Moreover, do we actually need two properties, one which could indicate
userspace's desire for the property, and another that tells the hardware
state?


No I do not think so. I would expect there to just be one property,
I guess that if the state is (partly) firmware controlled then there
might be a race, but we will need a notification mechanism (*) for
firmware triggered state changes anyways, so shortly after loosing
the race userspace will process the notification and it will know
about it.

One thing which might be useful is a way to signal that the property
is read-only in case we ever hit hw where that is the case.


I'd so very much like to have no in-kernel/in-firmware shortcuts
to enable/disable the privacy screen, and instead have any hardware
buttons just be events that the userspace could react to. However I
don't think that'll be the case unfortunately.


In my experience with keyboard-backlight support, we will (unfortunately)
see a mix and in some case we will get a notification that the firmware
has adjusted the state, rather then just getting a keypress and
dealing with that ourselves.  In some cases we may even be able to
choose, so the fw will deal with it by default but we can ask it
to just send a key-press.  But I do believe that we can *not* expect
that we will always just get a keypress for userspace to deal with.


Afraid, the "hotkeys" control for ePrivacy (Fn+D I believe) is very unlikely
to change - Windows uses it as well...
We can do notification of any hotkey presses to update the DRM layer (and
userspace) if that helps


We are not asking for changing the hotkey, what we would like is
for the hotkey to only send a notification that it was pressed
and for it to not actually do anything with the ePrivacy screen
state.  This does not need to be it defaults behavior, but we would
like to be able to ask the firmware to not act on it itself,
just like we can already disable the firmware/embedded controller
responding to e.g. brightness up/down key presses itself.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 5:28 PM, Jani Nikula wrote:

On Wed, 15 Apr 2020, Hans de Goede  wrote:

ii. Currently the "privacy-screen" property added by Rajat's
patch-set is an enum with 2 possible values:
"Enabled"
"Disabled"

We could add a third value "Not Available", which would be the
default and then for internal panels always add the property
so that we avoid the problem that detecting if the laptop has
an internal privacy screen needs to be done before the connector
is registered. Then we can add some hooks which allow an
lcdshadow-driver to register itself against a connector later
(which is non trivial wrt probe order, but lets ignore that for now).


I regret dropping the ball on Rajat's series (sorry!).

I do think having the connector property for this is the way to go.


I 100% agree.


Even
if we couldn't necessarily figure out all the details on the kernel
internal connections, can we settle on the property though, so we could
move forward with Rajat's series?


Yes please, this will also allow us to move forward with userspace
support even if for testing that we do some hacks for the kernel's
internal connections for now.


Moreover, do we actually need two properties, one which could indicate
userspace's desire for the property, and another that tells the hardware
state?


No I do not think so. I would expect there to just be one property,
I guess that if the state is (partly) firmware controlled then there
might be a race, but we will need a notification mechanism (*) for
firmware triggered state changes anyways, so shortly after loosing
the race userspace will process the notification and it will know
about it.

One thing which might be useful is a way to signal that the property
is read-only in case we ever hit hw where that is the case.


I'd so very much like to have no in-kernel/in-firmware shortcuts
to enable/disable the privacy screen, and instead have any hardware
buttons just be events that the userspace could react to. However I
don't think that'll be the case unfortunately.


In my experience with keyboard-backlight support, we will (unfortunately)
see a mix and in some case we will get a notification that the firmware
has adjusted the state, rather then just getting a keypress and
dealing with that ourselves.  In some cases we may even be able to
choose, so the fw will deal with it by default but we can ask it
to just send a key-press.  But I do believe that we can *not* expect
that we will always just get a keypress for userspace to deal with.

Regards,

Hans


*) Some udev event I guess, I sorta assume there already is a
notification mechanism for property change notifications ?


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 22/59] drm/gm12u320: Don't use drm_device->dev_private

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 9:39 AM, Daniel Vetter wrote:

Upcasting using a container_of macro is more typesafe, faster and
easier for the compiler to optimize.

Acked-by: Sam Ravnborg 
Signed-off-by: Daniel Vetter 
Cc: Hans de Goede 


LGTM:

Reviewed-by: Hans de Goede 

Regards,

Hans




---
  drivers/gpu/drm/tiny/gm12u320.c | 11 ++-
  1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c
index 907739a67bf6..cc397671f689 100644
--- a/drivers/gpu/drm/tiny/gm12u320.c
+++ b/drivers/gpu/drm/tiny/gm12u320.c
@@ -98,6 +98,8 @@ struct gm12u320_device {
} fb_update;
  };
  
+#define to_gm12u320(__dev) container_of(__dev, struct gm12u320_device, dev)

+
  static const char cmd_data[CMD_SIZE] = {
0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
0x68, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff,
@@ -408,7 +410,7 @@ static void gm12u320_fb_update_work(struct work_struct 
*work)
  static void gm12u320_fb_mark_dirty(struct drm_framebuffer *fb,
   struct drm_rect *dirty)
  {
-   struct gm12u320_device *gm12u320 = fb->dev->dev_private;
+   struct gm12u320_device *gm12u320 = to_gm12u320(fb->dev);
struct drm_framebuffer *old_fb = NULL;
bool wakeup = false;
  
@@ -558,7 +560,7 @@ static void gm12u320_pipe_enable(struct drm_simple_display_pipe *pipe,

 struct drm_plane_state *plane_state)
  {
struct drm_rect rect = { 0, 0, GM12U320_USER_WIDTH, GM12U320_HEIGHT };
-   struct gm12u320_device *gm12u320 = pipe->crtc.dev->dev_private;
+   struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev);
  
  	gm12u320->fb_update.draw_status_timeout = FIRST_FRAME_TIMEOUT;

gm12u320_fb_mark_dirty(plane_state->fb, );
@@ -566,7 +568,7 @@ static void gm12u320_pipe_enable(struct 
drm_simple_display_pipe *pipe,
  
  static void gm12u320_pipe_disable(struct drm_simple_display_pipe *pipe)

  {
-   struct gm12u320_device *gm12u320 = pipe->crtc.dev->dev_private;
+   struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev);
  
  	gm12u320_stop_fb_update(gm12u320);

  }
@@ -641,7 +643,6 @@ static int gm12u320_usb_probe(struct usb_interface 
*interface,
mutex_init(>fb_update.lock);
  
  	dev = >dev;

-   dev->dev_private = gm12u320;
  
  	ret = drmm_mode_config_init(dev);

if (ret)
@@ -706,7 +707,7 @@ static __maybe_unused int gm12u320_suspend(struct 
usb_interface *interface,
  static __maybe_unused int gm12u320_resume(struct usb_interface *interface)
  {
struct drm_device *dev = usb_get_intfdata(interface);
-   struct gm12u320_device *gm12u320 = dev->dev_private;
+   struct gm12u320_device *gm12u320 = to_gm12u320(dev);
  
  	gm12u320_set_ecomode(gm12u320);
  



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 21/59] drm/gm12u320: Use devm_drm_dev_alloc

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 9:39 AM, Daniel Vetter wrote:

Already using devm_drm_dev_init, so very simple replacment.

Acked-by: Sam Ravnborg 
Signed-off-by: Daniel Vetter 
Cc: Hans de Goede 


LGTM:

Reviewed-by: Hans de Goede 

Regards,

Hans




---
  drivers/gpu/drm/tiny/gm12u320.c | 13 -
  1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c
index 6f0ea2827d62..907739a67bf6 100644
--- a/drivers/gpu/drm/tiny/gm12u320.c
+++ b/drivers/gpu/drm/tiny/gm12u320.c
@@ -631,22 +631,17 @@ static int gm12u320_usb_probe(struct usb_interface 
*interface,
if (interface->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
  
-	gm12u320 = kzalloc(sizeof(*gm12u320), GFP_KERNEL);

-   if (gm12u320 == NULL)
-   return -ENOMEM;
+   gm12u320 = devm_drm_dev_alloc(>dev, _drm_driver,
+ struct gm12u320_device, dev);
+   if (IS_ERR(gm12u320))
+   return PTR_ERR(gm12u320);
  
  	gm12u320->udev = interface_to_usbdev(interface);

INIT_DELAYED_WORK(>fb_update.work, gm12u320_fb_update_work);
mutex_init(>fb_update.lock);
  
  	dev = >dev;

-   ret = devm_drm_dev_init(>dev, dev, _drm_driver);
-   if (ret) {
-   kfree(gm12u320);
-   return ret;
-   }
dev->dev_private = gm12u320;
-   drmm_add_final_kfree(dev, gm12u320);
  
  	ret = drmm_mode_config_init(dev);

if (ret)



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 06/59] drm/vboxvideo: Use devm_gen_pool_create

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 9:39 AM, Daniel Vetter wrote:

Aside from deleting all the cleanup code we're now also setting a name
for the pool

Acked-by: Sam Ravnborg 
Signed-off-by: Daniel Vetter 
Cc: Hans de Goede 


LGTM:

Reviewed-by: Hans de Goede 

Regards,

Hans




---
  drivers/gpu/drm/vboxvideo/vbox_main.c | 22 --
  1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/vboxvideo/vbox_main.c 
b/drivers/gpu/drm/vboxvideo/vbox_main.c
index 1336ab9795fc..d68d9bad7674 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_main.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_main.c
@@ -121,7 +121,8 @@ int vbox_hw_init(struct vbox_private *vbox)
return -ENOMEM;
  
  	/* Create guest-heap mem-pool use 2^4 = 16 byte chunks */

-   vbox->guest_pool = gen_pool_create(4, -1);
+   vbox->guest_pool = devm_gen_pool_create(vbox->ddev.dev, 4, -1,
+   "vboxvideo-accel");
if (!vbox->guest_pool)
return -ENOMEM;
  
@@ -130,12 +131,12 @@ int vbox_hw_init(struct vbox_private *vbox)

GUEST_HEAP_OFFSET(vbox),
GUEST_HEAP_USABLE_SIZE, -1);
if (ret)
-   goto err_destroy_guest_pool;
+   return ret;
  
  	ret = hgsmi_test_query_conf(vbox->guest_pool);

if (ret) {
DRM_ERROR("vboxvideo: hgsmi_test_query_conf failed\n");
-   goto err_destroy_guest_pool;
+   return ret;
}
  
  	/* Reduce available VRAM size to reflect the guest heap. */

@@ -147,30 +148,23 @@ int vbox_hw_init(struct vbox_private *vbox)
  
  	if (!have_hgsmi_mode_hints(vbox)) {

ret = -ENOTSUPP;
-   goto err_destroy_guest_pool;
+   return ret;
}
  
  	vbox->last_mode_hints = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs,

 sizeof(struct vbva_modehint),
 GFP_KERNEL);
-   if (!vbox->last_mode_hints) {
-   ret = -ENOMEM;
-   goto err_destroy_guest_pool;
-   }
+   if (!vbox->last_mode_hints)
+   return -ENOMEM;
  
  	ret = vbox_accel_init(vbox);

if (ret)
-   goto err_destroy_guest_pool;
+   return ret;
  
  	return 0;

-
-err_destroy_guest_pool:
-   gen_pool_destroy(vbox->guest_pool);
-   return ret;
  }
  
  void vbox_hw_fini(struct vbox_private *vbox)

  {
vbox_accel_fini(vbox);
-   gen_pool_destroy(vbox->guest_pool);
  }



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 05/59] drm/vboxvidoe: use managed pci functions

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 9:39 AM, Daniel Vetter wrote:

Allows us to drop the cleanup code on the floor.

Sam noticed in his review:

With this change we avoid calling pci_disable_device()
twise in case vbox_mm_init() fails.
Once in vbox_hw_fini() and once in the error path.


v2: Include Sam's review remarks

Acked-by: Sam Ravnborg 
Signed-off-by: Daniel Vetter 
Cc: Hans de Goede 
---
  drivers/gpu/drm/vboxvideo/vbox_drv.c  | 6 ++
  drivers/gpu/drm/vboxvideo/vbox_main.c | 7 +--
  2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c 
b/drivers/gpu/drm/vboxvideo/vbox_drv.c
index cfa4639c5142..cf2e3e6a2388 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_drv.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c
@@ -55,13 +55,13 @@ static int vbox_pci_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
pci_set_drvdata(pdev, vbox);
mutex_init(>hw_mutex);
  
-	ret = pci_enable_device(pdev);

+   ret = pcim_enable_device(pdev);
if (ret)
return ret;
  
  	ret = vbox_hw_init(vbox);

if (ret)
-   goto err_pci_disable;
+   return ret;
  
  	ret = vbox_mm_init(vbox);

if (ret)
@@ -91,8 +91,6 @@ static int vbox_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
vbox_mm_fini(vbox);
  err_hw_fini:
vbox_hw_fini(vbox);
-err_pci_disable:
-   pci_disable_device(pdev);
return ret;
  }
  
diff --git a/drivers/gpu/drm/vboxvideo/vbox_main.c b/drivers/gpu/drm/vboxvideo/vbox_main.c

index 9dcab115a261..1336ab9795fc 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_main.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_main.c
@@ -71,8 +71,6 @@ static void vbox_accel_fini(struct vbox_private *vbox)
  
  	for (i = 0; i < vbox->num_crtcs; ++i)

vbva_disable(>vbva_info[i], vbox->guest_pool, i);
-
-   pci_iounmap(vbox->ddev.pdev, vbox->vbva_buffers);
  }
  
  /* Do we support the 4.3 plus mode hint reporting interface? */


This seems to be missing the conversion of the iomap_range call to
the devm equivalent ?   :

drivers/gpu/drm/vboxvideo/vbox_main.c
44: vbox->vbva_buffers = pci_iomap_range(vbox->ddev.pdev, 0, ...

Regards,

Hans






@@ -125,7 +123,7 @@ int vbox_hw_init(struct vbox_private *vbox)
/* Create guest-heap mem-pool use 2^4 = 16 byte chunks */
vbox->guest_pool = gen_pool_create(4, -1);
if (!vbox->guest_pool)
-   goto err_unmap_guest_heap;
+   return -ENOMEM;
  
  	ret = gen_pool_add_virt(vbox->guest_pool,

(unsigned long)vbox->guest_heap,
@@ -168,8 +166,6 @@ int vbox_hw_init(struct vbox_private *vbox)
  
  err_destroy_guest_pool:

gen_pool_destroy(vbox->guest_pool);
-err_unmap_guest_heap:
-   pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
return ret;
  }
  
@@ -177,5 +173,4 @@ void vbox_hw_fini(struct vbox_private *vbox)

  {
vbox_accel_fini(vbox);
gen_pool_destroy(vbox->guest_pool);
-   pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
  }



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 02/59] drm/vboxvideo: drop DRM_MTRR_WC #define

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 9:39 AM, Daniel Vetter wrote:

Doesn't apply to upstream kernels since a rather long time.

Acked-by: Sam Ravnborg 
Signed-off-by: Daniel Vetter 
Cc: Hans de Goede 


LGTM:

Reviewed-by: Hans de Goede 

Regards,

Hans



---
  drivers/gpu/drm/vboxvideo/vbox_ttm.c | 12 
  1 file changed, 12 deletions(-)

diff --git a/drivers/gpu/drm/vboxvideo/vbox_ttm.c 
b/drivers/gpu/drm/vboxvideo/vbox_ttm.c
index 976423d0c3cc..f5a06675da43 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_ttm.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_ttm.c
@@ -24,25 +24,13 @@ int vbox_mm_init(struct vbox_private *vbox)
return ret;
}
  
-#ifdef DRM_MTRR_WC

-   vbox->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
-pci_resource_len(dev->pdev, 0),
-DRM_MTRR_WC);
-#else
vbox->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
 pci_resource_len(dev->pdev, 0));
-#endif
return 0;
  }
  
  void vbox_mm_fini(struct vbox_private *vbox)

  {
-#ifdef DRM_MTRR_WC
-   drm_mtrr_del(vbox->fb_mtrr,
-pci_resource_start(vbox->ddev.pdev, 0),
-pci_resource_len(vbox->ddev.pdev, 0), DRM_MTRR_WC);
-#else
arch_phys_wc_del(vbox->fb_mtrr);
-#endif
drm_vram_helper_release_mm(>ddev);
  }



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 03/59] drm/vboxvideo: Use devm_drm_dev_alloc

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 9:39 AM, Daniel Vetter wrote:

Straightforward conversion.

Signed-off-by: Daniel Vetter 
Cc: Hans de Goede 


LGTM:

Reviewed-by: Hans de Goede 

Regards,

Hans




---
  drivers/gpu/drm/vboxvideo/vbox_drv.c | 19 +--
  1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c 
b/drivers/gpu/drm/vboxvideo/vbox_drv.c
index 282348e071fe..7dd25c7a3768 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_drv.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c
@@ -46,25 +46,19 @@ static int vbox_pci_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
if (ret)
return ret;
  
-	vbox = kzalloc(sizeof(*vbox), GFP_KERNEL);

-   if (!vbox)
-   return -ENOMEM;
-
-   ret = drm_dev_init(>ddev, , >dev);
-   if (ret) {
-   kfree(vbox);
-   return ret;
-   }
+   vbox = devm_drm_dev_alloc(>dev, ,
+ struct vbox_private, ddev);
+   if (IS_ERR(vbox))
+   return PTR_ERR(vbox);
  
  	vbox->ddev.pdev = pdev;

vbox->ddev.dev_private = vbox;
pci_set_drvdata(pdev, vbox);
-   drmm_add_final_kfree(>ddev, vbox);
mutex_init(>hw_mutex);
  
  	ret = pci_enable_device(pdev);

if (ret)
-   goto err_dev_put;
+   return ret;
  
  	ret = vbox_hw_init(vbox);

if (ret)
@@ -100,8 +94,6 @@ static int vbox_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
vbox_hw_fini(vbox);
  err_pci_disable:
pci_disable_device(pdev);
-err_dev_put:
-   drm_dev_put(>ddev);
return ret;
  }
  
@@ -114,7 +106,6 @@ static void vbox_pci_remove(struct pci_dev *pdev)

vbox_mode_fini(vbox);
vbox_mm_fini(vbox);
vbox_hw_fini(vbox);
-   drm_dev_put(>ddev);
  }
  
  #ifdef CONFIG_PM_SLEEP




___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 04/59] drm/vboxvideo: Stop using drm_device->dev_private

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 9:39 AM, Daniel Vetter wrote:

We use the baseclass pattern here, so lets to the proper (and more
typesafe) upcasting.

Acked-by: Sam Ravnborg 
Acked-by: Thomas Zimmermann 
Signed-off-by: Daniel Vetter 
Cc: Hans de Goede 


LGTM:

Reviewed-by: Hans de Goede 

Regards,

Hans




---
  drivers/gpu/drm/vboxvideo/vbox_drv.c  |  1 -
  drivers/gpu/drm/vboxvideo/vbox_drv.h  |  1 +
  drivers/gpu/drm/vboxvideo/vbox_irq.c  |  2 +-
  drivers/gpu/drm/vboxvideo/vbox_mode.c | 10 +-
  4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c 
b/drivers/gpu/drm/vboxvideo/vbox_drv.c
index 7dd25c7a3768..cfa4639c5142 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_drv.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c
@@ -52,7 +52,6 @@ static int vbox_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
return PTR_ERR(vbox);
  
  	vbox->ddev.pdev = pdev;

-   vbox->ddev.dev_private = vbox;
pci_set_drvdata(pdev, vbox);
mutex_init(>hw_mutex);
  
diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.h b/drivers/gpu/drm/vboxvideo/vbox_drv.h

index 87421903816c..ac7c2effc46f 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_drv.h
+++ b/drivers/gpu/drm/vboxvideo/vbox_drv.h
@@ -127,6 +127,7 @@ struct vbox_encoder {
  #define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base)
  #define to_vbox_connector(x) container_of(x, struct vbox_connector, base)
  #define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base)
+#define to_vbox_dev(x) container_of(x, struct vbox_private, ddev)
  
  bool vbox_check_supported(u16 id);

  int vbox_hw_init(struct vbox_private *vbox);
diff --git a/drivers/gpu/drm/vboxvideo/vbox_irq.c 
b/drivers/gpu/drm/vboxvideo/vbox_irq.c
index 16a1e29f5292..631657fa554f 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_irq.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_irq.c
@@ -34,7 +34,7 @@ void vbox_report_hotplug(struct vbox_private *vbox)
  irqreturn_t vbox_irq_handler(int irq, void *arg)
  {
struct drm_device *dev = (struct drm_device *)arg;
-   struct vbox_private *vbox = (struct vbox_private *)dev->dev_private;
+   struct vbox_private *vbox = to_vbox_dev(dev);
u32 host_flags = vbox_get_flags(vbox);
  
  	if (!(host_flags & HGSMIHOSTFLAGS_IRQ))

diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c 
b/drivers/gpu/drm/vboxvideo/vbox_mode.c
index 0883a435e62b..d9a5af62af89 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_mode.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c
@@ -36,7 +36,7 @@ static void vbox_do_modeset(struct drm_crtc *crtc)
u16 flags;
s32 x_offset, y_offset;
  
-	vbox = crtc->dev->dev_private;

+   vbox = to_vbox_dev(crtc->dev);
width = vbox_crtc->width ? vbox_crtc->width : 640;
height = vbox_crtc->height ? vbox_crtc->height : 480;
bpp = fb ? fb->format->cpp[0] * 8 : 32;
@@ -77,7 +77,7 @@ static void vbox_do_modeset(struct drm_crtc *crtc)
  static int vbox_set_view(struct drm_crtc *crtc)
  {
struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
-   struct vbox_private *vbox = crtc->dev->dev_private;
+   struct vbox_private *vbox = to_vbox_dev(crtc->dev);
struct vbva_infoview *p;
  
  	/*

@@ -174,7 +174,7 @@ static void vbox_crtc_set_base_and_mode(struct drm_crtc 
*crtc,
int x, int y)
  {
struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(fb->obj[0]);
-   struct vbox_private *vbox = crtc->dev->dev_private;
+   struct vbox_private *vbox = to_vbox_dev(crtc->dev);
struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
bool needs_modeset = drm_atomic_crtc_needs_modeset(crtc->state);
  
@@ -272,7 +272,7 @@ static void vbox_primary_atomic_update(struct drm_plane *plane,

  {
struct drm_crtc *crtc = plane->state->crtc;
struct drm_framebuffer *fb = plane->state->fb;
-   struct vbox_private *vbox = fb->dev->dev_private;
+   struct vbox_private *vbox = to_vbox_dev(fb->dev);
struct drm_mode_rect *clips;
uint32_t num_clips, i;
  
@@ -704,7 +704,7 @@ static int vbox_get_modes(struct drm_connector *connector)

int preferred_width, preferred_height;
  
  	vbox_connector = to_vbox_connector(connector);

-   vbox = connector->dev->dev_private;
+   vbox = to_vbox_dev(connector->dev);
  
  	hgsmi_report_flags_location(vbox->guest_pool, GUEST_HEAP_OFFSET(vbox) +

HOST_FLAGS_OFFSET);



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 2:01 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 01:39:23PM +0200, Hans de Goede wrote:

Hi,

On 4/15/20 12:22 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 12:11 PM Hans de Goede  wrote:


Hi,

On 4/15/20 11:52 AM, Daniel Vetter wrote:





iv. What every SoC subsystem does:

- lcdshadow drivers register drivers
- drm drivers look them up
- if stuff isn't there yet, we delay loading with EPROBE_DEFER until
the entire thing is assembled.

That's what we're doing already for other standardized components like
drm_bridge or drm_panel, and I think that's also the right approach
for backlight and anything else like that. Hand-rolling our own
EPROBE_DEFER handling, or some other duct-tape monsters imo just leads
to real pain. Also, with EPROBE_DEFER we have one standard way of
building a driver from component, which spans subsystems and is also
the underlying magic that makes stuff like component.c work.


On the SoCs we have devicetree telling us what components there
are, so we can wait for them to show up. The only way to figure out
if the lcdshadow thing is there on a ThinkPad is asking thinkpad_acpi,
or duplicating a lot of code from thinkpad_acpi. Edit:
also see below for a possible solution.


Yup it sucks. I think all we can do is have a small acpi match
function (which yes will duplicate some of the thinkpad_acpi driver
logic) to re-create that information and give us a "should we have a
lcdshadow driver for this $pci_device" answer.


Ok, so questions about this solution:

1. Where should that match-function live ?

2. An acpi_thinkpad derived match-function will only be able to
answer if there is an lcdshadow device/driver for the internal
panel. It will not be able to tie this info to a certain PCI
device. My plan is to pass NULL as dev_name when registering
the lcdshadow-device and have lcdshadow_get(dev, )
skip device-name matching (consider everything a match) for
lcdshadow-devices registered with NULL as dev_name.

So I guess in this case the mini match function should just
ignore the passed in device?


Yeah I think we can't really avoid that. I also expect that we'll need
ACPI and dt versions of this, and driver needs to know which one to call.
Since at least in a dt world the driver knows exactly for which dt node it
needs a lcdshadow driver for (with the phandle stuff), so we can be a lot
more strict.

For the acpi version I'm not even sure we can do more than provide the
struct device * pointer of the gpu. I think if we ever get more than 1
lcdshadow driver on acpi systems we can add more stuff later on, for now
I'd just leave that out.

So maybe

acpi_lcdshadow_get(struct device *dev);

of_lcdshadow_get(struct device_node *np);

And with maybe a future plan to add some kind of enum or whatever to
acpi_lcdshadow_get(). Both would return either the lcdshadow pointer, or
an PTR_ERR() so that we could encode EPROBE_DEFER vs ENOENT.


Ok, note I plan to only implement the acpi version for now, I do
expect some non ACPI/x86 devices to show up with his feature
eventually but I believe it is best to implement this once
those actually show up. Esp. since this will also involve adding
some devicetree bindings for this.


We might also want a low-level lcdshadow_get() which only returns ENOENT
when the driver isn't there, and which leaves "do we really need one?" to
higher levels to answer.


Right, so my latest idea on that is indeed a high-level lcdshadow_get()
which takes a struct device * and a connector-name and which never
returns EPROBE_DEFER.

As for leaving things to the higher levels to answer, as explained
in my other follow-up email I think that we should probably add a
lcdshadow_probe_defer() helper for this and call that early on
in the PCI-driver probe functions for the 3 major x86 GPU drivers.
Does that sound ok to you?


I'd also lean towards putting lcdshadow headers/interfaces into
drivers/gpu,


Ack, I think we should even make this drm specific and prefix it with
drm_ so that we get drm_lcdshadow_foo as functions, just to make
clear that this is maintained together with the other drm bits.

But my question about "where should this live" was mainly about
the light weight match helpers you suggested to use to figure out
if the device supports lcdshadow at all (and we thus should wait
for a driver) or not. E.g. I can see us adding a:

drivers/gpu/drm/drm_lcdshadow.c

file for the core bits and then maybe a:

drivers/gpu/drm/drm_lcdshadow_detect.c

file with the light weight match helpers, with each helper
wrapped in #if IS_ENABLED(CONFIG_THINKPAD_ACPI), etc. ?


with driver implementations all over.


Ack.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 1:39 PM, Hans de Goede wrote:



/* Add comment explaining why we need this messy stuff here */
const char * const shadow_providers[] = {
#ifdef CONFIG_THINKPAD_ACPI_MODULE
 "thinkpad_acpi",
#endif
#ifdef CONFIG_OTHER_MODULE
 "other",
#endif
 NULL
};

int module_init(void)
{
 /* do actual setup of the ?class? */

 for (i = 0; shadow_providers[i]; i++)
 request_module(shadow_providers[i]);

 return 0;
}


Hm I think explicitly loading drivers feels very much not device model
like. Don't these drivers auto-load, matching on acpi functions?


thinkpad_acpi does autoload based on a number of ACPI device-ids,
the idea behind the above request_module is to avoid the need
to have the acpi-match function you mentioned above.

Basically what would happen is e.g. :

1. i915 loads, calls lcdshadow_get(dev, "eDP-1");
2. if this is the first lcdshadow_get() call then
    the lcdshadow core will do the request_module calls,
    allowing any of these modules to get loaded + probed and
    call e.g. lcdshadow_register(, , 
"eDP-1");
3. After the request modules the lcdshadow_get() will walk over
    the list of registered devices, including the ones just registered
    by the request_module calls and then hopefully find a match

So by doing the request-module calls before checking for
a matching lcdshadow dev, we avoid the need of having some of
the knowledge currently abstracted away in the thinkpad_acpi driver
duplicated inside the drm code somewhere.


I guess if that doesn't exist, then we'd need to fix that one first :-/
In general no request_module please, that shouldn't be needed either.

The trouble with request_module is also that (afaiui) it doesn't
really work well with parallel module load and all that, for
EPROBE_DEFER to work we do need to be able to answer "should we have a
driver?" independently of whether that driver has loaded already or
not.


The idea here is to avoid using EPROBE_DEFER (on x86 at least)
and either directly return the lcdshadow_dev or ENOENT. Also
see below.





Assuming we are going to add some device/model specific
lcdshadow knowledge inside the lcdshadow core as you
suggested with your "small acpi match function" above,
we could do something similar to what the vga_switcheroo
code is doing for this and have a lcdshadow_defer_probe()
helper and call that really early in i915_pci_probe(),
which currently already has this for the vgaswitcheroo case:

     if (vga_switcheroo_client_probe_defer(pdev))
     return -EPROBE_DEFER;


So thinking more about this and given the total lack of
EPROBE_DEFER handling in the 3 major X86 GPU/kms drivers
I think that adding a lcdshadow_defer_probe() helper is
the way to go. This will also avoid the need for duplicating
the lcdshadow detect functionality in the small ACPI-match
functions you mentioned (although that might still be
interesting to speedup the boot).

When everything is builtin then each enabled "module"-s
module_init function will get called, we can call a
lcdshadow_probe_done("module-name") function from those
and the lcdshadow core can then track if all potential
lcdhadow providers have initialized before it stops
returning non 0 from lcdshadow_defer_probe().

Or if we still do the small match functions it could
be even smarter with this...

And for the modular case it can call request_module on
all (enabled as module) potential lcdhadow providers
(or again we could rely on the small match function
instead).

Then (on x86 at least) we can have lcdshadow_get never
return -EPROBE_DEFER and avoid the need to solve the
lack of EPROBE_DEFER support in the 3 major x86 drivers.

And this is all kernel internal, so if that lack of
EPROBE_DEFER support ever gets fixed then we can drop
the lcdshadow_defer_probe() hack and make
lcdshadow_get also return -EPROBE_DEFER on x86 in
some cases.

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: RFC: Drm-connector properties managed by another driver / privacy screen support

2020-04-15 Thread Hans de Goede

Hi,

On 4/15/20 12:22 PM, Daniel Vetter wrote:

On Wed, Apr 15, 2020 at 12:11 PM Hans de Goede  wrote:


Hi,

On 4/15/20 11:52 AM, Daniel Vetter wrote:





iv. What every SoC subsystem does:

- lcdshadow drivers register drivers
- drm drivers look them up
- if stuff isn't there yet, we delay loading with EPROBE_DEFER until
the entire thing is assembled.

That's what we're doing already for other standardized components like
drm_bridge or drm_panel, and I think that's also the right approach
for backlight and anything else like that. Hand-rolling our own
EPROBE_DEFER handling, or some other duct-tape monsters imo just leads
to real pain. Also, with EPROBE_DEFER we have one standard way of
building a driver from component, which spans subsystems and is also
the underlying magic that makes stuff like component.c work.


On the SoCs we have devicetree telling us what components there
are, so we can wait for them to show up. The only way to figure out
if the lcdshadow thing is there on a ThinkPad is asking thinkpad_acpi,
or duplicating a lot of code from thinkpad_acpi. Edit:
also see below for a possible solution.


Yup it sucks. I think all we can do is have a small acpi match
function (which yes will duplicate some of the thinkpad_acpi driver
logic) to re-create that information and give us a "should we have a
lcdshadow driver for this $pci_device" answer.


Ok, so questions about this solution:

1. Where should that match-function live ?

2. An acpi_thinkpad derived match-function will only be able to
   answer if there is an lcdshadow device/driver for the internal
   panel. It will not be able to tie this info to a certain PCI
   device. My plan is to pass NULL as dev_name when registering
   the lcdshadow-device and have lcdshadow_get(dev, )
   skip device-name matching (consider everything a match) for
   lcdshadow-devices registered with NULL as dev_name.

   So I guess in this case the mini match function should just
   ignore the passed in device?


This need for an in-kernel source of truth for "which backlight, if
any, do I need" is why the backlight stuff never got fixed. It's a
really hard problem, and doing the table flip and just letting
userspace deal with the mess at least avoids having to face the fact
that the kernel is totally failing here. It's made worse for backlight
because of 20 years of hacked up systems that "work", and we can't
regress any of them.


Right, as discussed during last plumbers Christian Kellner and I
have written a plan to slowly resolve this. Unfortunately Christian
has not found the time to work on this yet.


I really want to avoid that situation for anything new like lcdshadow.


Ack.


Wrt the actual userspace interface, I think the drm core should handle
this as much as possible. Same way we let drm core handle a lot of the
atomic property stuff, to make sure things are standardized.


Agreed.



So

- add an lcdshadow pointer to struct drm_connector
- implement the property glue code in drm core completely, at least
for the read side
- for the write side we might want to have some drm wrappers drivers
can call to at the appropriate times to e.g. restore privacy screen
settings when the panel gets enabled. In case that's needed.

Also one thing that the EPROBE_DEFER stuff forces us to handle
correctly is to track these depencies. That's the other nightmare in
backlight land, essentially you have no idea of knowing (in userspace)
whether the backlight driver you want is actually loaded, resulting in
lots of fun. The kernel is the only thing that can know, and for hw
that's built-in there's really no excuse to not know. So a model where
stuff gets assembled after drm_dev_register() is imo just plain buggy.

This means that the lcdshadow subsystem needs to have some idea of
whether it needs a driver, so that it can correctly differentiate
between EPROBE_DEFER and ENOENT error cases. In the latter the driver
should continue loading ofc.


Right, so how would the lcdshadow subsystem do this? The only way
would be for it to say try and modprobe thinkpad_acpi from its
core init function (if thinkpad_acpi is enabled).  IOW it is the usual
x86 mess.  I guess we could have something like this in a theoretical
to be added lcdshadow subsystem:

/* Add comment explaining why we need this messy stuff here */
const char * const shadow_providers[] = {
#ifdef CONFIG_THINKPAD_ACPI_MODULE
 "thinkpad_acpi",
#endif
#ifdef CONFIG_OTHER_MODULE
 "other",
#endif
 NULL
};

int module_init(void)
{
 /* do actual setup of the ?class? */

 for (i = 0; shadow_providers[i]; i++)
 request_module(shadow_providers[i]);

 return 0;
}


Hm I think explicitly loading drivers feels very much not device model
like. Don't these drivers auto-load, matching on acpi functions?


thinkpad_acpi does autoload based on a number of ACPI device-ids,
the idea behind the above request_module is to 

<    5   6   7   8   9   10   11   12   13   14   >