On 05/05/2017 04:07 PM, Fabio Estevam wrote: > 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> > Signed-off-by: Fabio Estevam <fabio.estevam@xxxxxxx> > --- > drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 53 ++++++++++++++++++++++++++++++++++++++ > 1 file changed, 53 insertions(+) > > diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c > index 1144e0c..47e0941 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_MAX_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,48 @@ 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) > +{ > + unsigned int timeout = RESET_MAX_TIMEOUT; > + > + /* clear the bit */ > + writel(mask, addr + MXS_CLR_ADDR); > + > + udelay(1); > + > + /* poll the bit becoming clear */ > + while ((readl(addr) & mask) && --timeout) > + ; Is that like readl_poll_timeout() ? :) > + return !timeout; > +} > + > +static int mxsfb_reset_block(void __iomem *reset_addr) > +{ > + int ret; > + > + /* clear and poll SFTRST */ > + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); > + if (ret) > + return ret; > + > + /* clear CLKGATE */ > + writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); > + > + /* clear and poll SFTRST */ > + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); > + if (ret) > + return ret; > + > + /* clear and poll CLKGATE */ > + 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 +222,10 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) > */ > mxsfb_enable_axi_clk(mxsfb); > > + err = mxsfb_reset_block(mxsfb->base); Is this the right place ? Or should this be in the probe() function ? > + if (err) > + return; > + > /* Clear the FIFOs */ > writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); > > -- Best regards, Marek Vasut