It's typical for the bootloader to configure CTL_0 for the boot splash
or EFIFB, but for non-DSI use cases the DPU driver tend to pick another
CTL and the system might end up with two configured data paths producing
data on the same INTF. In particular as the IOMMU configuration isn't
retained from the bootloader one of the data paths will push underflow
color, resulting in screen flickering.
Naturally the end goal would be to inherit the bootloader's
configuration and provide the user with a glitch-free handover from the
boot configuration to a running DPU.
But such effort will affect clocks, regulators, power-domains etc, and
will take time to implement. So in the meantime this patch simply
disables all the data paths, on platforms that has CTL_FETCH_ACTIVE, to
avoid the graphical artifacts.
Signed-off-by: Bjorn Andersson <[email protected]>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 13 +++++++++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 6 ++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 ++
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 17 +++++++++++++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 8 ++++++++
5 files changed, 46 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
index 02da9ecf71f1..69d4849484fa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -357,6 +357,18 @@ static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx)
DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0);
}
+static void dpu_hw_ctl_disable_boot_config(struct dpu_hw_ctl *ctx)
+{
+ if (ctx->caps->features & BIT(DPU_CTL_FETCH_ACTIVE)) {
+ /*
+ * Disable the pipe fetch and trigger a start, to disable the
+ * data path
+ */
+ DPU_REG_WRITE(&ctx->hw, CTL_FETCH_PIPE_ACTIVE, 0);
+ DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1);
+ }
+}
+
static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg)
{
@@ -590,6 +602,7 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
ops->trigger_pending = dpu_hw_ctl_trigger_pending;
ops->reset = dpu_hw_ctl_reset_control;
ops->wait_reset_status = dpu_hw_ctl_wait_reset_status;
+ ops->disable_boot_config = dpu_hw_ctl_disable_boot_config;
ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages;
ops->setup_blendstage = dpu_hw_ctl_setup_blendstage;
ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
index 806c171e5df2..c2734f6ab760 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -159,6 +159,12 @@ struct dpu_hw_ctl_ops {
*/
void (*clear_all_blendstages)(struct dpu_hw_ctl *ctx);
+ /**
+ * Disable the configuration setup by the bootloader
+ * @ctx : ctl path ctx pointer
+ */
+ void (*disable_boot_config)(struct dpu_hw_ctl *ctx);
+
/**
* Configure layer mixer to pipe configuration
* @ctx : ctl path ctx pointer
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index cedc631f8498..eef2f017031a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -1107,6 +1107,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
dpu_kms->rm_init = true;
+ dpu_rm_clear_boot_config(&dpu_kms->rm, dpu_kms->catalog);
+
dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio,
dpu_kms->catalog);
if (IS_ERR(dpu_kms->hw_mdp)) {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index f9c83d6e427a..3365c5e41e28 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -4,6 +4,7 @@
*/
#define pr_fmt(fmt) "[drm:%s] " fmt, __func__
+#include <linux/delay.h>
#include "dpu_kms.h"
#include "dpu_hw_lm.h"
#include "dpu_hw_ctl.h"
@@ -229,6 +230,22 @@ int dpu_rm_init(struct dpu_rm *rm,
return rc ? rc : -EFAULT;
}
+void dpu_rm_clear_boot_config(struct dpu_rm *rm, struct dpu_mdss_cfg *cat)
+{
+ struct dpu_hw_ctl *ctl;
+ int i;
+
+ for (i = CTL_0; i < CTL_MAX; i++) {
+ if (!rm->ctl_blks[i - CTL_0])
+ continue;
+
+ DPU_DEBUG("disabling ctl%d boot configuration\n", i - CTL_0);
+
+ ctl = to_dpu_hw_ctl(rm->ctl_blks[i - CTL_0]);
+ ctl->ops.disable_boot_config(ctl);
+ }
+}
+
static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top)
{
return top->num_intf > 1;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
index 1f12c8d5b8aa..d3e084541e67 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
@@ -88,5 +88,13 @@ void dpu_rm_release(struct dpu_global_state *global_state,
int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
struct dpu_global_state *global_state, uint32_t enc_id,
enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size);
+
+/**
+ * dpu_rm_clear_boot_config() - Tear down any data paths configured by boot
+ * @rm: DPU Resource Manager handle
+ * @cat: Pointer to hardware catalog
+ */
+void dpu_rm_clear_boot_config(struct dpu_rm *rm, struct dpu_mdss_cfg *cat);
+
#endif /* __DPU_RM_H__ */
--
2.33.1
On 15/02/2022 07:37, Bjorn Andersson wrote:
> It's typical for the bootloader to configure CTL_0 for the boot splash
> or EFIFB, but for non-DSI use cases the DPU driver tend to pick another
> CTL and the system might end up with two configured data paths producing
> data on the same INTF. In particular as the IOMMU configuration isn't
> retained from the bootloader one of the data paths will push underflow
> color, resulting in screen flickering.
>
> Naturally the end goal would be to inherit the bootloader's
> configuration and provide the user with a glitch-free handover from the
> boot configuration to a running DPU.
>
> But such effort will affect clocks, regulators, power-domains etc, and
> will take time to implement. So in the meantime this patch simply
> disables all the data paths, on platforms that has CTL_FETCH_ACTIVE, to
> avoid the graphical artifacts.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 13 +++++++++++++
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 6 ++++++
> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 ++
> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 17 +++++++++++++++++
> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 8 ++++++++
> 5 files changed, 46 insertions(+)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> index 02da9ecf71f1..69d4849484fa 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> @@ -357,6 +357,18 @@ static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx)
> DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0);
> }
>
> +static void dpu_hw_ctl_disable_boot_config(struct dpu_hw_ctl *ctx)
> +{
> + if (ctx->caps->features & BIT(DPU_CTL_FETCH_ACTIVE)) {
I see that you are changing only CTL_FETCH_PIPE_ACTIVE. However it still
seems like a hack.
What if instead we always disable boot config for all paths except CTL_0
(or CTL_0 and CTL_1)?
> + /*
> + * Disable the pipe fetch and trigger a start, to disable the
> + * data path
> + */
> + DPU_REG_WRITE(&ctx->hw, CTL_FETCH_PIPE_ACTIVE, 0);
> + DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1);
What about video vs cmd modes?
> + }
> +}
> +
> static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
> enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg)
> {
> @@ -590,6 +602,7 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
> ops->trigger_pending = dpu_hw_ctl_trigger_pending;
> ops->reset = dpu_hw_ctl_reset_control;
> ops->wait_reset_status = dpu_hw_ctl_wait_reset_status;
> + ops->disable_boot_config = dpu_hw_ctl_disable_boot_config;
> ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages;
> ops->setup_blendstage = dpu_hw_ctl_setup_blendstage;
> ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp;
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> index 806c171e5df2..c2734f6ab760 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> @@ -159,6 +159,12 @@ struct dpu_hw_ctl_ops {
> */
> void (*clear_all_blendstages)(struct dpu_hw_ctl *ctx);
>
> + /**
> + * Disable the configuration setup by the bootloader
> + * @ctx : ctl path ctx pointer
> + */
> + void (*disable_boot_config)(struct dpu_hw_ctl *ctx);
> +
> /**
> * Configure layer mixer to pipe configuration
> * @ctx : ctl path ctx pointer
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> index cedc631f8498..eef2f017031a 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> @@ -1107,6 +1107,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
>
> dpu_kms->rm_init = true;
>
> + dpu_rm_clear_boot_config(&dpu_kms->rm, dpu_kms->catalog);
> +
> dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio,
> dpu_kms->catalog);
> if (IS_ERR(dpu_kms->hw_mdp)) {
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> index f9c83d6e427a..3365c5e41e28 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> @@ -4,6 +4,7 @@
> */
>
> #define pr_fmt(fmt) "[drm:%s] " fmt, __func__
> +#include <linux/delay.h>
> #include "dpu_kms.h"
> #include "dpu_hw_lm.h"
> #include "dpu_hw_ctl.h"
> @@ -229,6 +230,22 @@ int dpu_rm_init(struct dpu_rm *rm,
> return rc ? rc : -EFAULT;
> }
>
> +void dpu_rm_clear_boot_config(struct dpu_rm *rm, struct dpu_mdss_cfg *cat)
> +{
> + struct dpu_hw_ctl *ctl;
> + int i;
> +
> + for (i = CTL_0; i < CTL_MAX; i++) {
> + if (!rm->ctl_blks[i - CTL_0])
> + continue;
> +
> + DPU_DEBUG("disabling ctl%d boot configuration\n", i - CTL_0);
> +
> + ctl = to_dpu_hw_ctl(rm->ctl_blks[i - CTL_0]);
> + ctl->ops.disable_boot_config(ctl);
> + }
> +}
> +
> static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top)
> {
> return top->num_intf > 1;
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> index 1f12c8d5b8aa..d3e084541e67 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> @@ -88,5 +88,13 @@ void dpu_rm_release(struct dpu_global_state *global_state,
> int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
> struct dpu_global_state *global_state, uint32_t enc_id,
> enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size);
> +
> +/**
> + * dpu_rm_clear_boot_config() - Tear down any data paths configured by boot
> + * @rm: DPU Resource Manager handle
> + * @cat: Pointer to hardware catalog
> + */
> +void dpu_rm_clear_boot_config(struct dpu_rm *rm, struct dpu_mdss_cfg *cat);
> +
> #endif /* __DPU_RM_H__ */
>
--
With best wishes
Dmitry
On Tue 15 Feb 08:44 CST 2022, Dmitry Baryshkov wrote:
> On 15/02/2022 07:37, Bjorn Andersson wrote:
> > It's typical for the bootloader to configure CTL_0 for the boot splash
> > or EFIFB, but for non-DSI use cases the DPU driver tend to pick another
> > CTL and the system might end up with two configured data paths producing
> > data on the same INTF. In particular as the IOMMU configuration isn't
> > retained from the bootloader one of the data paths will push underflow
> > color, resulting in screen flickering.
> >
> > Naturally the end goal would be to inherit the bootloader's
> > configuration and provide the user with a glitch-free handover from the
> > boot configuration to a running DPU.
> >
> > But such effort will affect clocks, regulators, power-domains etc, and
> > will take time to implement. So in the meantime this patch simply
> > disables all the data paths, on platforms that has CTL_FETCH_ACTIVE, to
> > avoid the graphical artifacts.
> >
> > Signed-off-by: Bjorn Andersson <[email protected]>
> > ---
> > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 13 +++++++++++++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 6 ++++++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 ++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 17 +++++++++++++++++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 8 ++++++++
> > 5 files changed, 46 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> > index 02da9ecf71f1..69d4849484fa 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> > @@ -357,6 +357,18 @@ static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx)
> > DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0);
> > }
> > +static void dpu_hw_ctl_disable_boot_config(struct dpu_hw_ctl *ctx)
> > +{
> > + if (ctx->caps->features & BIT(DPU_CTL_FETCH_ACTIVE)) {
>
> I see that you are changing only CTL_FETCH_PIPE_ACTIVE. However it still
> seems like a hack.
You're not wrong, it certainly seems a little bit hacky.
I think that it would be more appropriate to try to inherit the
bootloader configuration. So the proposal here is, in my view, a
stop-gap until we start to look at "continuous splash".
> What if instead we always disable boot config for all paths except CTL_0 (or
> CTL_0 and CTL_1)?
>
On my laptop the bootloader sets up efifb using CTL_0. When Linux brings
up the eDP interface it seems to skip DPU_CTL_SPLIT_DISPLAY ctls and
picks CTL_2.
As mentioned in the message, I now have both CTL_0 and CTL_2 pushing
data to the one interface; resulting in flickering.
> > + /*
> > + * Disable the pipe fetch and trigger a start, to disable the
> > + * data path
> > + */
> > + DPU_REG_WRITE(&ctx->hw, CTL_FETCH_PIPE_ACTIVE, 0);
> > + DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1);
>
> What about video vs cmd modes?
>
Initially I was resetting a whole bunch of properties in the CTL, but
all I want to do is stop the data flow. It's my expectation that the
steps to follow will reset the interfaces and configure the actual data
paths anew.
Perhaps I'm missing some steps here, the documentation is not clear and
this has the expected visual outcome...
Regards,
Bjorn
> > + }
> > +}
> > +
> > static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
> > enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg)
> > {
> > @@ -590,6 +602,7 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
> > ops->trigger_pending = dpu_hw_ctl_trigger_pending;
> > ops->reset = dpu_hw_ctl_reset_control;
> > ops->wait_reset_status = dpu_hw_ctl_wait_reset_status;
> > + ops->disable_boot_config = dpu_hw_ctl_disable_boot_config;
> > ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages;
> > ops->setup_blendstage = dpu_hw_ctl_setup_blendstage;
> > ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp;
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> > index 806c171e5df2..c2734f6ab760 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> > @@ -159,6 +159,12 @@ struct dpu_hw_ctl_ops {
> > */
> > void (*clear_all_blendstages)(struct dpu_hw_ctl *ctx);
> > + /**
> > + * Disable the configuration setup by the bootloader
> > + * @ctx : ctl path ctx pointer
> > + */
> > + void (*disable_boot_config)(struct dpu_hw_ctl *ctx);
> > +
> > /**
> > * Configure layer mixer to pipe configuration
> > * @ctx : ctl path ctx pointer
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > index cedc631f8498..eef2f017031a 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > @@ -1107,6 +1107,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
> > dpu_kms->rm_init = true;
> > + dpu_rm_clear_boot_config(&dpu_kms->rm, dpu_kms->catalog);
> > +
> > dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio,
> > dpu_kms->catalog);
> > if (IS_ERR(dpu_kms->hw_mdp)) {
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > index f9c83d6e427a..3365c5e41e28 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > @@ -4,6 +4,7 @@
> > */
> > #define pr_fmt(fmt) "[drm:%s] " fmt, __func__
> > +#include <linux/delay.h>
> > #include "dpu_kms.h"
> > #include "dpu_hw_lm.h"
> > #include "dpu_hw_ctl.h"
> > @@ -229,6 +230,22 @@ int dpu_rm_init(struct dpu_rm *rm,
> > return rc ? rc : -EFAULT;
> > }
> > +void dpu_rm_clear_boot_config(struct dpu_rm *rm, struct dpu_mdss_cfg *cat)
> > +{
> > + struct dpu_hw_ctl *ctl;
> > + int i;
> > +
> > + for (i = CTL_0; i < CTL_MAX; i++) {
> > + if (!rm->ctl_blks[i - CTL_0])
> > + continue;
> > +
> > + DPU_DEBUG("disabling ctl%d boot configuration\n", i - CTL_0);
> > +
> > + ctl = to_dpu_hw_ctl(rm->ctl_blks[i - CTL_0]);
> > + ctl->ops.disable_boot_config(ctl);
> > + }
> > +}
> > +
> > static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top)
> > {
> > return top->num_intf > 1;
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > index 1f12c8d5b8aa..d3e084541e67 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > @@ -88,5 +88,13 @@ void dpu_rm_release(struct dpu_global_state *global_state,
> > int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
> > struct dpu_global_state *global_state, uint32_t enc_id,
> > enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size);
> > +
> > +/**
> > + * dpu_rm_clear_boot_config() - Tear down any data paths configured by boot
> > + * @rm: DPU Resource Manager handle
> > + * @cat: Pointer to hardware catalog
> > + */
> > +void dpu_rm_clear_boot_config(struct dpu_rm *rm, struct dpu_mdss_cfg *cat);
> > +
> > #endif /* __DPU_RM_H__ */
>
>
> --
> With best wishes
> Dmitry
On 15/02/2022 18:15, Bjorn Andersson wrote:
> On Tue 15 Feb 08:44 CST 2022, Dmitry Baryshkov wrote:
>
>> On 15/02/2022 07:37, Bjorn Andersson wrote:
>>> It's typical for the bootloader to configure CTL_0 for the boot splash
>>> or EFIFB, but for non-DSI use cases the DPU driver tend to pick another
>>> CTL and the system might end up with two configured data paths producing
>>> data on the same INTF. In particular as the IOMMU configuration isn't
>>> retained from the bootloader one of the data paths will push underflow
>>> color, resulting in screen flickering.
>>>
>>> Naturally the end goal would be to inherit the bootloader's
>>> configuration and provide the user with a glitch-free handover from the
>>> boot configuration to a running DPU.
>>>
>>> But such effort will affect clocks, regulators, power-domains etc, and
>>> will take time to implement. So in the meantime this patch simply
>>> disables all the data paths, on platforms that has CTL_FETCH_ACTIVE, to
>>> avoid the graphical artifacts.
>>>
>>> Signed-off-by: Bjorn Andersson <[email protected]>
>>> ---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 13 +++++++++++++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 6 ++++++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 ++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 17 +++++++++++++++++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 8 ++++++++
>>> 5 files changed, 46 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
>>> index 02da9ecf71f1..69d4849484fa 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
>>> @@ -357,6 +357,18 @@ static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx)
>>> DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0);
>>> }
>>> +static void dpu_hw_ctl_disable_boot_config(struct dpu_hw_ctl *ctx)
>>> +{
>>> + if (ctx->caps->features & BIT(DPU_CTL_FETCH_ACTIVE)) {
>>
>> I see that you are changing only CTL_FETCH_PIPE_ACTIVE. However it still
>> seems like a hack.
>
> You're not wrong, it certainly seems a little bit hacky.
>
> I think that it would be more appropriate to try to inherit the
> bootloader configuration. So the proposal here is, in my view, a
> stop-gap until we start to look at "continuous splash".
>
>> What if instead we always disable boot config for all paths except CTL_0 (or
>> CTL_0 and CTL_1)?
>>
>
> On my laptop the bootloader sets up efifb using CTL_0. When Linux brings
> up the eDP interface it seems to skip DPU_CTL_SPLIT_DISPLAY ctls and
> picks CTL_2.
>
> As mentioned in the message, I now have both CTL_0 and CTL_2 pushing
> data to the one interface; resulting in flickering.
Ah, I thought, it's the other way.
Yep, the SPLIT_DISPLAY CTLs are precious, ideally they should be used
only when required.
>
>>> + /*
>>> + * Disable the pipe fetch and trigger a start, to disable the
>>> + * data path
>>> + */
>>> + DPU_REG_WRITE(&ctx->hw, CTL_FETCH_PIPE_ACTIVE, 0);
>>> + DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1);
>>
>> What about video vs cmd modes?
>>
>
> Initially I was resetting a whole bunch of properties in the CTL, but
> all I want to do is stop the data flow. It's my expectation that the
> steps to follow will reset the interfaces and configure the actual data
> paths anew.
>
> Perhaps I'm missing some steps here, the documentation is not clear and
> this has the expected visual outcome...
CTL_START is used only for WB and DSI command mode. Thus I'm surprised
that you need it for the eDP (which should be using video mode).
>
> Regards,
> Bjorn
>
>>> + }
>>> +}
>>> +
>>> static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
>>> enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg)
>>> {
>>> @@ -590,6 +602,7 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
>>> ops->trigger_pending = dpu_hw_ctl_trigger_pending;
>>> ops->reset = dpu_hw_ctl_reset_control;
>>> ops->wait_reset_status = dpu_hw_ctl_wait_reset_status;
>>> + ops->disable_boot_config = dpu_hw_ctl_disable_boot_config;
>>> ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages;
>>> ops->setup_blendstage = dpu_hw_ctl_setup_blendstage;
>>> ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp;
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
>>> index 806c171e5df2..c2734f6ab760 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
>>> @@ -159,6 +159,12 @@ struct dpu_hw_ctl_ops {
>>> */
>>> void (*clear_all_blendstages)(struct dpu_hw_ctl *ctx);
>>> + /**
>>> + * Disable the configuration setup by the bootloader
>>> + * @ctx : ctl path ctx pointer
>>> + */
>>> + void (*disable_boot_config)(struct dpu_hw_ctl *ctx);
>>> +
>>> /**
>>> * Configure layer mixer to pipe configuration
>>> * @ctx : ctl path ctx pointer
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>> index cedc631f8498..eef2f017031a 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>> @@ -1107,6 +1107,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
>>> dpu_kms->rm_init = true;
>>> + dpu_rm_clear_boot_config(&dpu_kms->rm, dpu_kms->catalog);
>>> +
>>> dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio,
>>> dpu_kms->catalog);
>>> if (IS_ERR(dpu_kms->hw_mdp)) {
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>> index f9c83d6e427a..3365c5e41e28 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>> @@ -4,6 +4,7 @@
>>> */
>>> #define pr_fmt(fmt) "[drm:%s] " fmt, __func__
>>> +#include <linux/delay.h>
>>> #include "dpu_kms.h"
>>> #include "dpu_hw_lm.h"
>>> #include "dpu_hw_ctl.h"
>>> @@ -229,6 +230,22 @@ int dpu_rm_init(struct dpu_rm *rm,
>>> return rc ? rc : -EFAULT;
>>> }
>>> +void dpu_rm_clear_boot_config(struct dpu_rm *rm, struct dpu_mdss_cfg *cat)
>>> +{
>>> + struct dpu_hw_ctl *ctl;
>>> + int i;
>>> +
>>> + for (i = CTL_0; i < CTL_MAX; i++) {
>>> + if (!rm->ctl_blks[i - CTL_0])
>>> + continue;
>>> +
>>> + DPU_DEBUG("disabling ctl%d boot configuration\n", i - CTL_0);
>>> +
>>> + ctl = to_dpu_hw_ctl(rm->ctl_blks[i - CTL_0]);
>>> + ctl->ops.disable_boot_config(ctl);
>>> + }
>>> +}
>>> +
>>> static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top)
>>> {
>>> return top->num_intf > 1;
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>> index 1f12c8d5b8aa..d3e084541e67 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>> @@ -88,5 +88,13 @@ void dpu_rm_release(struct dpu_global_state *global_state,
>>> int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
>>> struct dpu_global_state *global_state, uint32_t enc_id,
>>> enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size);
>>> +
>>> +/**
>>> + * dpu_rm_clear_boot_config() - Tear down any data paths configured by boot
>>> + * @rm: DPU Resource Manager handle
>>> + * @cat: Pointer to hardware catalog
>>> + */
>>> +void dpu_rm_clear_boot_config(struct dpu_rm *rm, struct dpu_mdss_cfg *cat);
>>> +
>>> #endif /* __DPU_RM_H__ */
>>
>>
>> --
>> With best wishes
>> Dmitry
--
With best wishes
Dmitry