[PATCH] drm: mxsfb_crtc: Reset the eLCDIF controller
Marek Vasut
marex at denx.de
Fri May 5 14:17:06 UTC 2017
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 at vger.kernel.org>
> Signed-off-by: Fabio Estevam <fabio.estevam at nxp.com>
> ---
> 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
More information about the dri-devel
mailing list