Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: mxsfb_crtc: Reset the eLCDIF controller

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@vger.kernel.org>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
Reviewed-by: Marek Vasut <marex@denx.de>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Link: http://patchwork.freedesktop.org/patch/msgid/1494007301-14535-1-git-send-email-fabio.estevam@nxp.com

authored by

Fabio Estevam and committed by
Sean Paul
ae9d0421 d35fb617

+42
+42
drivers/gpu/drm/mxsfb/mxsfb_crtc.c
··· 35 35 #include "mxsfb_drv.h" 36 36 #include "mxsfb_regs.h" 37 37 38 + #define MXS_SET_ADDR 0x4 39 + #define MXS_CLR_ADDR 0x8 40 + #define MODULE_CLKGATE BIT(30) 41 + #define MODULE_SFTRST BIT(31) 42 + /* 1 second delay should be plenty of time for block reset */ 43 + #define RESET_TIMEOUT 1000000 44 + 38 45 static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) 39 46 { 40 47 return (val & mxsfb->devdata->hs_wdth_mask) << ··· 166 159 clk_disable_unprepare(mxsfb->clk_disp_axi); 167 160 } 168 161 162 + /* 163 + * Clear the bit and poll it cleared. This is usually called with 164 + * a reset address and mask being either SFTRST(bit 31) or CLKGATE 165 + * (bit 30). 166 + */ 167 + static int clear_poll_bit(void __iomem *addr, u32 mask) 168 + { 169 + u32 reg; 170 + 171 + writel(mask, addr + MXS_CLR_ADDR); 172 + return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT); 173 + } 174 + 175 + static int mxsfb_reset_block(void __iomem *reset_addr) 176 + { 177 + int ret; 178 + 179 + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); 180 + if (ret) 181 + return ret; 182 + 183 + writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); 184 + 185 + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); 186 + if (ret) 187 + return ret; 188 + 189 + return clear_poll_bit(reset_addr, MODULE_CLKGATE); 190 + } 191 + 169 192 static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) 170 193 { 171 194 struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; ··· 209 172 * first stop the controller and drain its FIFOs. 210 173 */ 211 174 mxsfb_enable_axi_clk(mxsfb); 175 + 176 + /* Mandatory eLCDIF reset as per the Reference Manual */ 177 + err = mxsfb_reset_block(mxsfb->base); 178 + if (err) 179 + return; 212 180 213 181 /* Clear the FIFOs */ 214 182 writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);