On Mon, May 22, 2017 at 5:53 PM, Fabio Estevam <festevam@xxxxxxxxx> wrote: > From: Fabio Estevam <fabio.estevam@xxxxxxx> > > According to the eLCDIF initialization steps listed in the MX6SX > Reference Manual the eLCDIF block reset is mandatory. > > Without performing the eLCDIF reset the display shows garbage content > when the kernel boots. > > In earlier tests this issue has not been observed because the bootloader > was previously showing a splash screen and the bootloader display driver > does properly implement the eLCDIF reset. > > Add the eLCDIF reset to the driver, so that it can operate correctly > independently of the bootloader. > > Tested on a imx6sx-sdb board. > > Cc: <stable@xxxxxxxxxxxxxxx> #4.11.x > Signed-off-by: Fabio Estevam <fabio.estevam@xxxxxxx> > Reviewed-by: Marek Vasut <marex@xxxxxxx> > --- > Daniel, > > Marek suggested that this goes via drm-misc. Sean/Jani/Daniel, Any chance this could go via drm-misc? Without this change the mxsfb driver is unusable on some platforms. Thanks > > Thanks > > drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 42 ++++++++++++++++++++++++++++++++++++++ > 1 file changed, 42 insertions(+) > > diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c > index 1144e0c..0abe776 100644 > --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c > +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c > @@ -35,6 +35,13 @@ > #include "mxsfb_drv.h" > #include "mxsfb_regs.h" > > +#define MXS_SET_ADDR 0x4 > +#define MXS_CLR_ADDR 0x8 > +#define MODULE_CLKGATE BIT(30) > +#define MODULE_SFTRST BIT(31) > +/* 1 second delay should be plenty of time for block reset */ > +#define RESET_TIMEOUT 1000000 > + > static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) > { > return (val & mxsfb->devdata->hs_wdth_mask) << > @@ -159,6 +166,36 @@ static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb) > clk_disable_unprepare(mxsfb->clk_disp_axi); > } > > +/* > + * Clear the bit and poll it cleared. This is usually called with > + * a reset address and mask being either SFTRST(bit 31) or CLKGATE > + * (bit 30). > + */ > +static int clear_poll_bit(void __iomem *addr, u32 mask) > +{ > + u32 reg; > + > + writel(mask, addr + MXS_CLR_ADDR); > + return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT); > +} > + > +static int mxsfb_reset_block(void __iomem *reset_addr) > +{ > + int ret; > + > + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); > + if (ret) > + return ret; > + > + writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); > + > + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); > + if (ret) > + return ret; > + > + return clear_poll_bit(reset_addr, MODULE_CLKGATE); > +} > + > static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) > { > struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; > @@ -173,6 +210,11 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) > */ > mxsfb_enable_axi_clk(mxsfb); > > + /* Mandatory eLCDIF reset as per the Reference Manual */ > + err = mxsfb_reset_block(mxsfb->base); > + if (err) > + return; > + > /* Clear the FIFOs */ > writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); > > -- > 2.7.4 >