diff options
| -rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c index 1144e0c9e894..0abe77675b76 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c | |||
| @@ -35,6 +35,13 @@ | |||
| 35 | #include "mxsfb_drv.h" | 35 | #include "mxsfb_drv.h" |
| 36 | #include "mxsfb_regs.h" | 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 | static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) | 45 | static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) |
| 39 | { | 46 | { |
| 40 | return (val & mxsfb->devdata->hs_wdth_mask) << | 47 | return (val & mxsfb->devdata->hs_wdth_mask) << |
| @@ -159,6 +166,36 @@ static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb) | |||
| 159 | clk_disable_unprepare(mxsfb->clk_disp_axi); | 166 | clk_disable_unprepare(mxsfb->clk_disp_axi); |
| 160 | } | 167 | } |
| 161 | 168 | ||
| 169 | /* | ||
| 170 | * Clear the bit and poll it cleared. This is usually called with | ||
| 171 | * a reset address and mask being either SFTRST(bit 31) or CLKGATE | ||
| 172 | * (bit 30). | ||
| 173 | */ | ||
| 174 | static int clear_poll_bit(void __iomem *addr, u32 mask) | ||
| 175 | { | ||
| 176 | u32 reg; | ||
| 177 | |||
| 178 | writel(mask, addr + MXS_CLR_ADDR); | ||
| 179 | return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT); | ||
| 180 | } | ||
| 181 | |||
| 182 | static int mxsfb_reset_block(void __iomem *reset_addr) | ||
| 183 | { | ||
| 184 | int ret; | ||
| 185 | |||
| 186 | ret = clear_poll_bit(reset_addr, MODULE_SFTRST); | ||
| 187 | if (ret) | ||
| 188 | return ret; | ||
| 189 | |||
| 190 | writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); | ||
| 191 | |||
| 192 | ret = clear_poll_bit(reset_addr, MODULE_SFTRST); | ||
| 193 | if (ret) | ||
| 194 | return ret; | ||
| 195 | |||
| 196 | return clear_poll_bit(reset_addr, MODULE_CLKGATE); | ||
| 197 | } | ||
| 198 | |||
| 162 | static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) | 199 | static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) |
| 163 | { | 200 | { |
| 164 | struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; | 201 | 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) | |||
| 173 | */ | 210 | */ |
| 174 | mxsfb_enable_axi_clk(mxsfb); | 211 | mxsfb_enable_axi_clk(mxsfb); |
| 175 | 212 | ||
| 213 | /* Mandatory eLCDIF reset as per the Reference Manual */ | ||
| 214 | err = mxsfb_reset_block(mxsfb->base); | ||
| 215 | if (err) | ||
| 216 | return; | ||
| 217 | |||
| 176 | /* Clear the FIFOs */ | 218 | /* Clear the FIFOs */ |
| 177 | writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); | 219 | writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); |
| 178 | 220 | ||
