From: Daniel Thompson <hidden> Date: 2021-07-22 14:47:00
Currently there are (at least) two problems in the way pwm_bl starts
managing the enable_gpio pin. Both occur when the backlight is initially
off and the driver finds the pin not already in output mode and, as a
result, unconditionally switches it to output-mode and asserts the signal.
Problem 1: This could cause the backlight to flicker since, at this stage
in driver initialisation, we have no idea what the PWM and regulator are
doing (an unconfigured PWM could easily "rest" at 100% duty cycle).
Problem 2: This will cause us not to correctly honour the
post_pwm_on_delay (which also risks flickers).
Fix this by moving the code to configure the GPIO output mode until after
we have examines the handover state. That allows us to initialize
enable_gpio to off if the backlight is currently off and on if the
backlight is on.
Reported-by: Marek Vasut <marex@denx.de>
Signed-off-by: Daniel Thompson <redacted>
Cc: stable@vger.kernel.org
Acked-by: Marek Vasut <marex@denx.de>
Tested-by: Marek Vasut <marex@denx.de>
---
drivers/video/backlight/pwm_bl.c | 54 +++++++++++++++++---------------
1 file changed, 28 insertions(+), 26 deletions(-)
@@ -409,6 +409,33 @@ static bool pwm_backlight_is_linear(struct platform_pwm_backlight_data *data)staticintpwm_backlight_initial_power_state(conststructpwm_bl_data*pb){structdevice_node*node=pb->dev->of_node;+boolactive=true;++/*+*IftheenableGPIOispresent,observable(eitherasinput+*oroutput)andoffthenthebacklightisnotcurrentlyactive.+**/+if(pb->enable_gpio&&gpiod_get_value_cansleep(pb->enable_gpio)==0)+active=false;++if(!regulator_is_enabled(pb->power_supply))+active=false;++if(!pwm_is_enabled(pb->pwm))+active=false;++/*+*Synchronizetheenable_gpiowiththeobservedstateofthe+*hardware.+*/+if(pb->enable_gpio)+gpiod_direction_output(pb->enable_gpio,active);++/*+*Donotchangepb->enabledhere!pb->enabledessentially+*tellsusifweownoneoftheregulator'susecountsand+*rightnowwedonot.+*//* Not booted with device tree or no phandle link to the node */if(!node||!node->phandle)
@@ -420,20 +447,7 @@ static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)*assumethatanotherdriverwillenablethebacklightatthe*appropriatetime.Therefore,ifitisdisabled,keepitso.*/--/* if the enable GPIO is disabled, do not enable the backlight */-if(pb->enable_gpio&&gpiod_get_value_cansleep(pb->enable_gpio)==0)-returnFB_BLANK_POWERDOWN;--/* The regulator is disabled, do not enable the backlight */-if(!regulator_is_enabled(pb->power_supply))-returnFB_BLANK_POWERDOWN;--/* The PWM is disabled, keep it like this */-if(!pwm_is_enabled(pb->pwm))-returnFB_BLANK_POWERDOWN;--returnFB_BLANK_UNBLANK;+returnactive?FB_BLANK_UNBLANK:FB_BLANK_POWERDOWN;}staticintpwm_backlight_probe(structplatform_device*pdev)
@@ -486,18 +500,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)gotoerr_alloc;}-/*-*IftheGPIOisnotknowntobealreadyconfiguredasoutput,that-*is,ifgpiod_get_directionreturnseither1or-EINVAL,changethe-*directiontooutputandsettheGPIOasactive.-*DonotforcetheGPIOtoactivewhenitwasalreadyoutputasit-*couldcausebacklightflickeringorwewouldenablethebacklighttoo-*early.Leavethedecisionoftheinitialbacklightstateforlater.-*/-if(pb->enable_gpio&&-gpiod_get_direction(pb->enable_gpio)!=0)-gpiod_direction_output(pb->enable_gpio,1);-pb->power_supply=devm_regulator_get(&pdev->dev,"power");if(IS_ERR(pb->power_supply)){ret=PTR_ERR(pb->power_supply);
From: Daniel Thompson <hidden> Date: 2021-07-22 14:54:26
Currently there are (at least) two problems in the way pwm_bl starts
managing the enable_gpio pin. Both occur when the backlight is initially
off and the driver finds the pin not already in output mode and, as a
result, unconditionally switches it to output-mode and asserts the signal.
Problem 1: This could cause the backlight to flicker since, at this stage
in driver initialisation, we have no idea what the PWM and regulator are
doing (an unconfigured PWM could easily "rest" at 100% duty cycle).
Problem 2: This will cause us not to correctly honour the
post_pwm_on_delay (which also risks flickers).
Fix this by moving the code to configure the GPIO output mode until after
we have examines the handover state. That allows us to initialize
enable_gpio to off if the backlight is currently off and on if the
backlight is on.
Reported-by: Marek Vasut <marex@denx.de>
Signed-off-by: Daniel Thompson <redacted>
Cc: stable@vger.kernel.org
Fixes: 3698d7e7d221 ("backlight: pwm_bl: Avoid backlight flicker when probed from DT")
Acked-by: Marek Vasut <marex@denx.de>
Tested-by: Marek Vasut <marex@denx.de>
---
Notes:
v2: Added Fixes: tag (sorry for the noise)
drivers/video/backlight/pwm_bl.c | 54 +++++++++++++++++---------------
1 file changed, 28 insertions(+), 26 deletions(-)
@@ -409,6 +409,33 @@ static bool pwm_backlight_is_linear(struct platform_pwm_backlight_data *data)staticintpwm_backlight_initial_power_state(conststructpwm_bl_data*pb){structdevice_node*node=pb->dev->of_node;+boolactive=true;++/*+*IftheenableGPIOispresent,observable(eitherasinput+*oroutput)andoffthenthebacklightisnotcurrentlyactive.+**/+if(pb->enable_gpio&&gpiod_get_value_cansleep(pb->enable_gpio)==0)+active=false;++if(!regulator_is_enabled(pb->power_supply))+active=false;++if(!pwm_is_enabled(pb->pwm))+active=false;++/*+*Synchronizetheenable_gpiowiththeobservedstateofthe+*hardware.+*/+if(pb->enable_gpio)+gpiod_direction_output(pb->enable_gpio,active);++/*+*Donotchangepb->enabledhere!pb->enabledessentially+*tellsusifweownoneoftheregulator'susecountsand+*rightnowwedonot.+*//* Not booted with device tree or no phandle link to the node */if(!node||!node->phandle)
@@ -420,20 +447,7 @@ static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)*assumethatanotherdriverwillenablethebacklightatthe*appropriatetime.Therefore,ifitisdisabled,keepitso.*/--/* if the enable GPIO is disabled, do not enable the backlight */-if(pb->enable_gpio&&gpiod_get_value_cansleep(pb->enable_gpio)==0)-returnFB_BLANK_POWERDOWN;--/* The regulator is disabled, do not enable the backlight */-if(!regulator_is_enabled(pb->power_supply))-returnFB_BLANK_POWERDOWN;--/* The PWM is disabled, keep it like this */-if(!pwm_is_enabled(pb->pwm))-returnFB_BLANK_POWERDOWN;--returnFB_BLANK_UNBLANK;+returnactive?FB_BLANK_UNBLANK:FB_BLANK_POWERDOWN;}staticintpwm_backlight_probe(structplatform_device*pdev)
@@ -486,18 +500,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)gotoerr_alloc;}-/*-*IftheGPIOisnotknowntobealreadyconfiguredasoutput,that-*is,ifgpiod_get_directionreturnseither1or-EINVAL,changethe-*directiontooutputandsettheGPIOasactive.-*DonotforcetheGPIOtoactivewhenitwasalreadyoutputasit-*couldcausebacklightflickeringorwewouldenablethebacklighttoo-*early.Leavethedecisionoftheinitialbacklightstateforlater.-*/-if(pb->enable_gpio&&-gpiod_get_direction(pb->enable_gpio)!=0)-gpiod_direction_output(pb->enable_gpio,1);-pb->power_supply=devm_regulator_get(&pdev->dev,"power");if(IS_ERR(pb->power_supply)){ret=PTR_ERR(pb->power_supply);
From: Daniel Thompson <hidden> Date: 2021-07-23 11:04:05
Currently there are (at least) two problems in the way pwm_bl starts
managing the enable_gpio pin. Both occur when the backlight is initially
off and the driver finds the pin not already in output mode and, as a
result, unconditionally switches it to output-mode and asserts the signal.
Problem 1: This could cause the backlight to flicker since, at this stage
in driver initialisation, we have no idea what the PWM and regulator are
doing (an unconfigured PWM could easily "rest" at 100% duty cycle).
Problem 2: This will cause us not to correctly honour the
post_pwm_on_delay (which also risks flickers).
Fix this by moving the code to configure the GPIO output mode until after
we have examines the handover state. That allows us to initialize
enable_gpio to off if the backlight is currently off and on if the
backlight is on.
There has also been lots of discussion recently about how pwm_bl inherits
the initial state established by the bootloader (or by power-on reset if
the bootloader doesn't do anything to the backlight). Let's take this
chance to document the four handover cases.
Reported-by: Marek Vasut <marex@denx.de>
Signed-off-by: Daniel Thompson <redacted>
Cc: stable@vger.kernel.org
Fixes: 3698d7e7d221 ("backlight: pwm_bl: Avoid backlight flicker when probed from DT")
Acked-by: Marek Vasut <marex@denx.de>
Tested-by: Marek Vasut <marex@denx.de>
---
Notes:
v3: Added better documentation of the different handover cases (thanks
Marek)
v2: Added Fixes: tag (sorry for the noise)
drivers/video/backlight/pwm_bl.c | 110 +++++++++++++++++++++++--------
1 file changed, 83 insertions(+), 27 deletions(-)
@@ -406,9 +406,90 @@ static bool pwm_backlight_is_linear(struct platform_pwm_backlight_data *data)returntrue;}+/*+*Inherittheinitialpowerstatefromthehardware.+*+*Thisfunctionprovidesthefeaturesnecessarytoachieveaflicker-freeboot+*sequenceregardlessoftheinitialstateofthebacklight.+*+*Therearetwofactorsthataffectthebehaviourofthisfunction.+*+*1.Whetherthebacklightwasonoroffwhenthekernelwasbooted.We+*currentlydeterminethestateofthebacklightbycheckingifthePWMis+*enabled,whethertheregulator(ifthereisone)isenabledandwhether+*theenable_gpio(ifthereisone)isasserted.Allmustbeenabledfor+*thebacklighttobeon.+*+*2.Whetherthebacklightislinkedtoadisplaydevice.Thismattersbecause+*whenthereisalinkeddisplayiswillautomaticallyhandlethe+*backlightaspartofitsownblank/unblanking.+*+*Thisgivesusfourpossiblecases.+*+*Backlightinitiallyoff,displaylinked:+*+*Thebacklightmustremainoff(a.k.a.FB_BLANK_POWERDOWN)duringandafter+*thebacklightprobe.Thisallowsasplashscreentobedrawnbeforethe+*backlightisenabledbythedisplaydriver.Thisavoidsaflickerwhenthe+*backlightcomeson(whichtypicallychangestheblacklevelslightly)+*beforethesplashimagehasbeendrawn.+*+*Backlightinitiallyon,displaylinked:+*+*Thebacklightmustremainon(a.k.a.FB_BLANK_UNBLANK)duringandafter+*thebacklightprobe.Thisallowsabootloadertoshowasplashscreenand+*forthedisplaysystem(includingthebacklight)tocontinueshowingthe+*splashimageuntilthekernelisreadytotakeoverthedisplayanddraw+*somethingelse.+*+*Backlightinitiallyoff,nodisplay:+*+*Thebacklightmusttransitionfromofftoon(a.k.a.FB_BLANK_UNBLANK)+*duringthebacklightprobe.Thisislargelyalegacycase.Wemust+*unblankthebacklightatbootbecausesomeuserspacesarenot+*capableofchangingthepowerstateofafree-standingbacklight+*(theyonlyknowhowtosetthebrightnesslevel).+*+*Backlightinitiallyon,nodisplay:+*+*Identicaltotheinitiallyon,displaylinkedcase.+*+*Note:Inbothcaseswherebacklightisinitiallyoffthenwemust+*explicitlydeasserttheenable_gpioinordertoensurewe+*honourthepost_pwm_on_delaywhenthebacklightiseventually+*activated.Thisisrequiredregardlessofboththeinitialstateof+*theenablepinandwhetherweintendtoactivatethebacklightduring+*theprobe.+*/staticintpwm_backlight_initial_power_state(conststructpwm_bl_data*pb){-structdevice_node*node=pb->dev->of_node;+structdevice_node*node=pb->dev->of_node;boolactive=true;++/*+*IftheenableGPIOispresent,observable(eitherasinput+*oroutput)andoffthenthebacklightisnotcurrentlyactive.+*/+if(pb->enable_gpio&&gpiod_get_value_cansleep(pb->enable_gpio)==0)+active=false;++if(!regulator_is_enabled(pb->power_supply))+active=false;++if(!pwm_is_enabled(pb->pwm))+active=false;++/*+*Synchronizetheenable_gpiowiththeobservedstateofthe+*hardware.+*/+if(pb->enable_gpio)+gpiod_direction_output(pb->enable_gpio,active);++/*+*Donotchangepb->enabledhere!pb->enabledessentially+*tellsusifweownoneoftheregulator'susecountsand+*rightnowwedonot.+*//* Not booted with device tree or no phandle link to the node */if(!node||!node->phandle)
@@ -420,20 +501,7 @@ static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)*assumethatanotherdriverwillenablethebacklightatthe*appropriatetime.Therefore,ifitisdisabled,keepitso.*/--/* if the enable GPIO is disabled, do not enable the backlight */-if(pb->enable_gpio&&gpiod_get_value_cansleep(pb->enable_gpio)==0)-returnFB_BLANK_POWERDOWN;--/* The regulator is disabled, do not enable the backlight */-if(!regulator_is_enabled(pb->power_supply))-returnFB_BLANK_POWERDOWN;--/* The PWM is disabled, keep it like this */-if(!pwm_is_enabled(pb->pwm))-returnFB_BLANK_POWERDOWN;--returnFB_BLANK_UNBLANK;+returnactive?FB_BLANK_UNBLANK:FB_BLANK_POWERDOWN;}staticintpwm_backlight_probe(structplatform_device*pdev)
@@ -486,18 +554,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)gotoerr_alloc;}-/*-*IftheGPIOisnotknowntobealreadyconfiguredasoutput,that-*is,ifgpiod_get_directionreturnseither1or-EINVAL,changethe-*directiontooutputandsettheGPIOasactive.-*DonotforcetheGPIOtoactivewhenitwasalreadyoutputasit-*couldcausebacklightflickeringorwewouldenablethebacklighttoo-*early.Leavethedecisionoftheinitialbacklightstateforlater.-*/-if(pb->enable_gpio&&-gpiod_get_direction(pb->enable_gpio)!=0)-gpiod_direction_output(pb->enable_gpio,1);-pb->power_supply=devm_regulator_get(&pdev->dev,"power");if(IS_ERR(pb->power_supply)){ret=PTR_ERR(pb->power_supply);
From: Lee Jones <hidden> Date: 2021-08-19 09:59:37
On Thu, 22 Jul 2021, Daniel Thompson wrote:
Currently there are (at least) two problems in the way pwm_bl starts
managing the enable_gpio pin. Both occur when the backlight is initially
off and the driver finds the pin not already in output mode and, as a
result, unconditionally switches it to output-mode and asserts the signal.
Problem 1: This could cause the backlight to flicker since, at this stage
in driver initialisation, we have no idea what the PWM and regulator are
doing (an unconfigured PWM could easily "rest" at 100% duty cycle).
Problem 2: This will cause us not to correctly honour the
post_pwm_on_delay (which also risks flickers).
Fix this by moving the code to configure the GPIO output mode until after
we have examines the handover state. That allows us to initialize
enable_gpio to off if the backlight is currently off and on if the
backlight is on.
Reported-by: Marek Vasut <marex@denx.de>
Signed-off-by: Daniel Thompson <redacted>
Cc: stable@vger.kernel.org
Acked-by: Marek Vasut <marex@denx.de>
Tested-by: Marek Vasut <marex@denx.de>
---
drivers/video/backlight/pwm_bl.c | 54 +++++++++++++++++---------------
1 file changed, 28 insertions(+), 26 deletions(-)
Applied, thanks.
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog