linux-pwm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API
@ 2020-06-06 20:25 Hans de Goede
  2020-06-06 20:25 ` [PATCH 01/16] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase Hans de Goede
                   ` (17 more replies)
  0 siblings, 18 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 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

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 01/16] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation) Hans de Goede
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 &= 0xFFFFFFFC
	    Local1 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
	    RSTA = Zero
	    RSTF = Zero
	    RSTA = One
	    RSTF = One
	    PWMB |= 0xC0000000
	    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 0xC0000000 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 <hdegoede@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
  2020-06-06 20:25 ` [PATCH 01/16] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-07 17:03   ` Andy Shevchenko
  2020-06-06 20:25 ` [PATCH 03/16] pwm: lpss: Add range limit check for the base_unit register value Hans de Goede
                   ` (15 subsequent siblings)
  17 siblings, 1 reply; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 (0xffffffff)
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 <hdegoede@redhat.com>
---
 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 (0xffffffff)
+ * as ctx register values.
+ * Luckily these devices always use the same ctx register values, so we can
+ * work around this by saving the ctx registers once on activation.
+ */
+#define LPSS_SAVE_CTX_ONCE		BIT(6)
 
 struct lpss_private_data;
 
@@ -254,7 +262,7 @@ static const struct lpss_device_desc byt_pwm_dev_desc = {
 };
 
 static const struct lpss_device_desc bsw_pwm_dev_desc = {
-	.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
+	.flags = LPSS_SAVE_CTX_ONCE | LPSS_NO_D3_DELAY,
 	.prv_offset = 0x800,
 	.setup = bsw_pwm_setup,
 	.resume_from_noirq = true,
@@ -885,9 +893,14 @@ static int acpi_lpss_activate(struct device *dev)
 	 * we have to deassert reset line to be sure that ->probe() will
 	 * recognize the device.
 	 */
-	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+	if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
 		lpss_deassert_reset(pdata);
 
+#ifdef CONFIG_PM
+	if (pdata->dev_desc->flags & LPSS_SAVE_CTX_ONCE)
+		acpi_lpss_save_ctx(dev, pdata);
+#endif
+
 	return 0;
 }
 
@@ -1031,7 +1044,7 @@ static int acpi_lpss_resume(struct device *dev)
 
 	acpi_lpss_d3_to_d0_delay(pdata);
 
-	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+	if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
 		acpi_lpss_restore_ctx(dev, pdata);
 
 	return 0;
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 03/16] pwm: lpss: Add range limit check for the base_unit register value
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
  2020-06-06 20:25 ` [PATCH 01/16] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase Hans de Goede
  2020-06-06 20:25 ` [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation) Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 04/16] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare() Hans de Goede
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 04/16] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare()
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (2 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 03/16] pwm: lpss: Add range limit check for the base_unit register value Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 05/16] pwm: lpss: Set SW_UPDATE bit when enabling the PWM Hans de Goede
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 05/16] pwm: lpss: Set SW_UPDATE bit when enabling the PWM
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (3 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 04/16] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare() Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 06/16] pwm: lpss: Add debug prints, test patch for moving i915 to atomic PWM Hans de Goede
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 06/16] pwm: lpss: Add debug prints, test patch for moving i915 to atomic PWM
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (4 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 05/16] pwm: lpss: Set SW_UPDATE bit when enabling the PWM Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 07/16] pwm: crc: Fix period / duty_cycle times being off by a factor of 256 Hans de Goede
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

Add debug prints, test patch for moving i915 to atomic PWM.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 07/16] pwm: crc: Fix period / duty_cycle times being off by a factor of 256
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (5 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 06/16] pwm: lpss: Add debug prints, test patch for moving i915 to atomic PWM Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 08/16] pwm: crc: Fix off-by-one error in the clock-divider calculations Hans de Goede
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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			20000
Toshiba WT8-A	23437			20000

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 <hdegoede@redhat.com>
---
 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		6000000  /* 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 08/16] pwm: crc: Fix off-by-one error in the clock-divider calculations
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (6 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 07/16] pwm: crc: Fix period / duty_cycle times being off by a factor of 256 Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 09/16] pwm: crc: Fix period changes not having any effect Hans de Goede
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 09/16] pwm: crc: Fix period changes not having any effect
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (7 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 08/16] pwm: crc: Fix off-by-one error in the clock-divider calculations Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 10/16] pwm: crc: Enable/disable PWM output on enable/disable Hans de Goede
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 10/16] pwm: crc: Enable/disable PWM output on enable/disable
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (8 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 09/16] pwm: crc: Fix period changes not having any effect Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 11/16] pwm: crc: Implement apply() method to support the new atomic PWM API Hans de Goede
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 11/16] pwm: crc: Implement apply() method to support the new atomic PWM API
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (9 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 10/16] pwm: crc: Enable/disable PWM output on enable/disable Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 12/16] pwm: crc: Implement get_state() method Hans de Goede
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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) {
+			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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 12/16] pwm: crc: Implement get_state() method
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (10 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 11/16] pwm: crc: Implement apply() method to support the new atomic PWM API Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 13/16] drm/i915: panel: Add get_vbt_pwm_freq() helper Hans de Goede
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 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, &clk_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, &duty_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

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 13/16] drm/i915: panel: Add get_vbt_pwm_freq() helper
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (11 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 12/16] pwm: crc: Implement get_state() method Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:25 ` [PATCH 14/16] drm/i915: panel: Honor the VBT PWM frequency for devs with an external PWM controller Hans de Goede
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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 = &connector->panel;
 	u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
-	u32 pwm;
-
-	if (!panel->backlight.hz_to_pwm) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "backlight frequency conversion not supported\n");
-		return 0;
-	}
 
 	if (pwm_freq_hz) {
 		drm_dbg_kms(&dev_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 = &connector->panel;
+	u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
+	u32 pwm;
+
+	if (!panel->backlight.hz_to_pwm) {
+		drm_dbg_kms(&dev_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(&dev_priv->drm,
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 14/16] drm/i915: panel: Honor the VBT PWM frequency for devs with an external PWM controller
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (12 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 13/16] drm/i915: panel: Add get_vbt_pwm_freq() helper Hans de Goede
@ 2020-06-06 20:25 ` Hans de Goede
  2020-06-06 20:26 ` [PATCH 15/16] drm/i915: panel: Honor the VBT PWM min setting " Hans de Goede
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:25 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 5000000 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 6000000 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 <hdegoede@redhat.com>
---
 .../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 = &to_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,
+			    panel->backlight.pwm_period_ns);
 	if (retval < 0) {
 		drm_err(&dev_priv->drm, "Failed to configure the pwm chip\n");
 		pwm_put(panel->backlight.pwm);
@@ -1937,7 +1940,7 @@ static int pwm_setup_backlight(struct intel_connector *connector,
 	}
 
 	level = DIV_ROUND_UP(pwm_get_duty_cycle(panel->backlight.pwm) * 100,
-			     CRC_PMIC_PWM_PERIOD_NS);
+			     panel->backlight.pwm_period_ns);
 	panel->backlight.level =
 		intel_panel_compute_brightness(connector, level);
 	panel->backlight.enabled = panel->backlight.level != 0;
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 15/16] drm/i915: panel: Honor the VBT PWM min setting for devs with an external PWM controller
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (13 preceding siblings ...)
  2020-06-06 20:25 ` [PATCH 14/16] drm/i915: panel: Honor the VBT PWM frequency for devs with an external PWM controller Hans de Goede
@ 2020-06-06 20:26 ` Hans de Goede
  2020-06-06 20:26 ` [PATCH 16/16] drm/i915: panel: Use atomic PWM API " Hans de Goede
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:26 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 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(&dev_priv->drm, "Using %s PWM for LCD backlight control\n",
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 16/16] drm/i915: panel: Use atomic PWM API for devs with an external PWM controller
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (14 preceding siblings ...)
  2020-06-06 20:26 ` [PATCH 15/16] drm/i915: panel: Honor the VBT PWM min setting " Hans de Goede
@ 2020-06-06 20:26 ` Hans de Goede
  2020-06-07 18:15 ` pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
  2020-06-08 14:35 ` Daniel Vetter
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-06 20:26 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: Hans de Goede, linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 <hdegoede@redhat.com>
---
 .../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 <linux/async.h>
 #include <linux/i2c.h>
+#include <linux/pwm.h>
 #include <linux/sched/clock.h>
 
 #include <drm/drm_atomic.h>
@@ -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 = &connector->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 = &to_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, &panel->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 = &connector->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, &panel->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 = &connector->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, &panel->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 = &connector->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);
-
-	/*
-	 * FIXME: pwm_apply_args() should be removed when switching to
-	 * the atomic PWM API.
-	 */
-	pwm_apply_args(panel->backlight.pwm);
-
 	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);
 
-	retval = pwm_config(panel->backlight.pwm, ns,
-			    panel->backlight.pwm_period_ns);
-	if (retval < 0) {
-		drm_err(&dev_priv->drm, "Failed to configure the pwm chip\n");
-		pwm_put(panel->backlight.pwm);
-		panel->backlight.pwm = NULL;
-		return retval;
+	if (pwm_is_enabled(panel->backlight.pwm) &&
+	    pwm_get_period(panel->backlight.pwm)) {
+		/* PWM is already enabled, use existing settings */
+		pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state);
+
+		level = DIV_ROUND_UP(panel->backlight.pwm_state.duty_cycle *
+					100, panel->backlight.pwm_state.period);
+		level = intel_panel_compute_brightness(connector, level);
+		panel->backlight.level = clamp(level, panel->backlight.min,
+					       panel->backlight.max);
+		panel->backlight.enabled = true;
+
+		drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n",
+			    NSEC_PER_SEC / panel->backlight.pwm_state.period,
+			    get_vbt_pwm_freq(dev_priv), level);
+	} else {
+		/* Set period from VBT frequency, leave other setting at 0. */
+		panel->backlight.pwm_state.period =
+			NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv);
 	}
 
-	level = DIV_ROUND_UP(pwm_get_duty_cycle(panel->backlight.pwm) * 100,
-			     panel->backlight.pwm_period_ns);
-	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(&dev_priv->drm, "Using %s PWM for LCD backlight control\n",
 		 desc);
 	return 0;
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)
  2020-06-06 20:25 ` [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation) Hans de Goede
@ 2020-06-07 17:03   ` Andy Shevchenko
  2020-06-07 18:14     ` Hans de Goede
  0 siblings, 1 reply; 23+ messages in thread
From: Andy Shevchenko @ 2020-06-07 17:03 UTC (permalink / raw)
  To: Hans de Goede
  Cc: linux-pwm, intel-gfx, Rafael J . Wysocki, linux-acpi, dri-devel,
	Uwe Kleine-König, Mika Westerberg, Len Brown

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 (0xffffffff)
> 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 <hdegoede@redhat.com>
> ---
>  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 (0xffffffff)
> + * as ctx register values.
> + * Luckily these devices always use the same ctx register values, so we can
> + * work around this by saving the ctx registers once on activation.
> + */
> +#define LPSS_SAVE_CTX_ONCE		BIT(6)

A nit: I would group SAVE_CTX and CTX_ONCE in the list, i.e. make this BIT(5)
and move NO_D3_DELAY to BIT(6).

>  struct lpss_private_data;
>  
> @@ -254,7 +262,7 @@ static const struct lpss_device_desc byt_pwm_dev_desc = {
>  };
>  
>  static const struct lpss_device_desc bsw_pwm_dev_desc = {
> -	.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
> +	.flags = LPSS_SAVE_CTX_ONCE | LPSS_NO_D3_DELAY,
>  	.prv_offset = 0x800,
>  	.setup = bsw_pwm_setup,
>  	.resume_from_noirq = true,
> @@ -885,9 +893,14 @@ static int acpi_lpss_activate(struct device *dev)
>  	 * we have to deassert reset line to be sure that ->probe() will
>  	 * recognize the device.
>  	 */
> -	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
> +	if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
>  		lpss_deassert_reset(pdata);
>  
> +#ifdef CONFIG_PM
> +	if (pdata->dev_desc->flags & LPSS_SAVE_CTX_ONCE)
> +		acpi_lpss_save_ctx(dev, pdata);
> +#endif
> +
>  	return 0;
>  }
>  
> @@ -1031,7 +1044,7 @@ static int acpi_lpss_resume(struct device *dev)
>  
>  	acpi_lpss_d3_to_d0_delay(pdata);
>  
> -	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
> +	if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
>  		acpi_lpss_restore_ctx(dev, pdata);
>  
>  	return 0;
> -- 
> 2.26.2
> 

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)
  2020-06-07 17:03   ` Andy Shevchenko
@ 2020-06-07 18:14     ` Hans de Goede
  0 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-07 18:14 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown, linux-pwm, intel-gfx, dri-devel,
	Mika Westerberg, linux-acpi

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 (0xffffffff)
>> 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 <hdegoede@redhat.com>
>> ---
>>   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 (0xffffffff)
>> + * as ctx register values.
>> + * Luckily these devices always use the same ctx register values, so we can
>> + * work around this by saving the ctx registers once on activation.
>> + */
>> +#define LPSS_SAVE_CTX_ONCE		BIT(6)
> 
> A nit: I would group SAVE_CTX and CTX_ONCE in the list, i.e. make this BIT(5)
> and move NO_D3_DELAY to BIT(6).

Ok, I've fixed this for v2 which I will send out shortly, as I needed to do
a v2 anyways because I accidentally left a debugging patch in the v1 series.

Regards,

Hans



> 
>>   struct lpss_private_data;
>>   
>> @@ -254,7 +262,7 @@ static const struct lpss_device_desc byt_pwm_dev_desc = {
>>   };
>>   
>>   static const struct lpss_device_desc bsw_pwm_dev_desc = {
>> -	.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
>> +	.flags = LPSS_SAVE_CTX_ONCE | LPSS_NO_D3_DELAY,
>>   	.prv_offset = 0x800,
>>   	.setup = bsw_pwm_setup,
>>   	.resume_from_noirq = true,
>> @@ -885,9 +893,14 @@ static int acpi_lpss_activate(struct device *dev)
>>   	 * we have to deassert reset line to be sure that ->probe() will
>>   	 * recognize the device.
>>   	 */
>> -	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
>> +	if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
>>   		lpss_deassert_reset(pdata);
>>   
>> +#ifdef CONFIG_PM
>> +	if (pdata->dev_desc->flags & LPSS_SAVE_CTX_ONCE)
>> +		acpi_lpss_save_ctx(dev, pdata);
>> +#endif
>> +
>>   	return 0;
>>   }
>>   
>> @@ -1031,7 +1044,7 @@ static int acpi_lpss_resume(struct device *dev)
>>   
>>   	acpi_lpss_d3_to_d0_delay(pdata);
>>   
>> -	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
>> +	if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
>>   		acpi_lpss_restore_ctx(dev, pdata);
>>   
>>   	return 0;
>> -- 
>> 2.26.2
>>
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (15 preceding siblings ...)
  2020-06-06 20:26 ` [PATCH 16/16] drm/i915: panel: Use atomic PWM API " Hans de Goede
@ 2020-06-07 18:15 ` Hans de Goede
  2020-06-08 14:35 ` Daniel Vetter
  17 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-07 18:15 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown
  Cc: linux-pwm, intel-gfx, dri-devel, Andy Shevchenko,
	Mika Westerberg, linux-acpi

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 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
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API
  2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
                   ` (16 preceding siblings ...)
  2020-06-07 18:15 ` pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
@ 2020-06-08 14:35 ` Daniel Vetter
  2020-06-11 21:21   ` Uwe Kleine-König
  17 siblings, 1 reply; 23+ messages in thread
From: Daniel Vetter @ 2020-06-08 14:35 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Thierry Reding, Uwe Kleine-König, Jani Nikula,
	Joonas Lahtinen, Ville Syrjälä,
	Rafael J . Wysocki, Len Brown, linux-pwm, linux-acpi, intel-gfx,
	dri-devel, Andy Shevchenko, Mika Westerberg

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.

/me out

Cheers, Daniel

> 
> 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

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API
  2020-06-08 14:35 ` Daniel Vetter
@ 2020-06-11 21:21   ` Uwe Kleine-König
  2020-06-12 17:04     ` Hans de Goede
  0 siblings, 1 reply; 23+ messages in thread
From: Uwe Kleine-König @ 2020-06-11 21:21 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Hans de Goede, Thierry Reding, Jani Nikula, Joonas Lahtinen,
	Ville Syrjälä,
	Rafael J . Wysocki, Len Brown, linux-pwm, linux-acpi, intel-gfx,
	dri-devel, Andy Shevchenko, Mika Westerberg

[-- Attachment #1: Type: text/plain, Size: 2025 bytes --]

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, but the changes to drivers/pwm need
an ack (or processing) by the PWM team.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API
  2020-06-11 21:21   ` Uwe Kleine-König
@ 2020-06-12 17:04     ` Hans de Goede
  0 siblings, 0 replies; 23+ messages in thread
From: Hans de Goede @ 2020-06-12 17:04 UTC (permalink / raw)
  To: Uwe Kleine-König, Daniel Vetter
  Cc: Thierry Reding, Jani Nikula, Joonas Lahtinen,
	Ville Syrjälä,
	Rafael J . Wysocki, Len Brown, linux-pwm, linux-acpi, intel-gfx,
	dri-devel, Andy Shevchenko, Mika Westerberg

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 <snip>-ed that bit when he replied.

Regards,

Hans

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2020-06-12 17:05 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-06 20:25 pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
2020-06-06 20:25 ` [PATCH 01/16] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase Hans de Goede
2020-06-06 20:25 ` [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation) Hans de Goede
2020-06-07 17:03   ` Andy Shevchenko
2020-06-07 18:14     ` Hans de Goede
2020-06-06 20:25 ` [PATCH 03/16] pwm: lpss: Add range limit check for the base_unit register value Hans de Goede
2020-06-06 20:25 ` [PATCH 04/16] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare() Hans de Goede
2020-06-06 20:25 ` [PATCH 05/16] pwm: lpss: Set SW_UPDATE bit when enabling the PWM Hans de Goede
2020-06-06 20:25 ` [PATCH 06/16] pwm: lpss: Add debug prints, test patch for moving i915 to atomic PWM Hans de Goede
2020-06-06 20:25 ` [PATCH 07/16] pwm: crc: Fix period / duty_cycle times being off by a factor of 256 Hans de Goede
2020-06-06 20:25 ` [PATCH 08/16] pwm: crc: Fix off-by-one error in the clock-divider calculations Hans de Goede
2020-06-06 20:25 ` [PATCH 09/16] pwm: crc: Fix period changes not having any effect Hans de Goede
2020-06-06 20:25 ` [PATCH 10/16] pwm: crc: Enable/disable PWM output on enable/disable Hans de Goede
2020-06-06 20:25 ` [PATCH 11/16] pwm: crc: Implement apply() method to support the new atomic PWM API Hans de Goede
2020-06-06 20:25 ` [PATCH 12/16] pwm: crc: Implement get_state() method Hans de Goede
2020-06-06 20:25 ` [PATCH 13/16] drm/i915: panel: Add get_vbt_pwm_freq() helper Hans de Goede
2020-06-06 20:25 ` [PATCH 14/16] drm/i915: panel: Honor the VBT PWM frequency for devs with an external PWM controller Hans de Goede
2020-06-06 20:26 ` [PATCH 15/16] drm/i915: panel: Honor the VBT PWM min setting " Hans de Goede
2020-06-06 20:26 ` [PATCH 16/16] drm/i915: panel: Use atomic PWM API " Hans de Goede
2020-06-07 18:15 ` pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API Hans de Goede
2020-06-08 14:35 ` Daniel Vetter
2020-06-11 21:21   ` Uwe Kleine-König
2020-06-12 17:04     ` Hans de Goede

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).