| From f627caf55b8e735dcec8fa6538e9668632b55276 Mon Sep 17 00:00:00 2001 |
| From: Yifeng Li <tomli@tomli.me> |
| Date: Mon, 1 Apr 2019 17:46:59 +0200 |
| Subject: fbdev: sm712fb: fix crashes and garbled display during DPMS modesetting |
| |
| From: Yifeng Li <tomli@tomli.me> |
| |
| commit f627caf55b8e735dcec8fa6538e9668632b55276 upstream. |
| |
| On a Thinkpad s30 (Pentium III / i440MX, Lynx3DM), blanking the display |
| or starting the X server will crash and freeze the system, or garble the |
| display. |
| |
| Experiments showed this problem can mostly be solved by adjusting the |
| order of register writes. Also, sm712fb failed to consider the difference |
| of clock frequency when unblanking the display, and programs the clock for |
| SM712 to SM720. |
| |
| Fix them by adjusting the order of register writes, and adding an |
| additional check for SM720 for programming the clock frequency. |
| |
| Signed-off-by: Yifeng Li <tomli@tomli.me> |
| Tested-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com> |
| Cc: Teddy Wang <teddy.wang@siliconmotion.com> |
| Cc: <stable@vger.kernel.org> # v4.4+ |
| Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/video/fbdev/sm712fb.c | 64 ++++++++++++++++++++++++------------------ |
| 1 file changed, 38 insertions(+), 26 deletions(-) |
| |
| --- a/drivers/video/fbdev/sm712fb.c |
| +++ b/drivers/video/fbdev/sm712fb.c |
| @@ -886,67 +886,79 @@ static inline unsigned int chan_to_field |
| |
| static int smtc_blank(int blank_mode, struct fb_info *info) |
| { |
| + struct smtcfb_info *sfb = info->par; |
| + |
| /* clear DPMS setting */ |
| switch (blank_mode) { |
| case FB_BLANK_UNBLANK: |
| /* Screen On: HSync: On, VSync : On */ |
| + |
| + switch (sfb->chip_id) { |
| + case 0x710: |
| + case 0x712: |
| + smtc_seqw(0x6a, 0x16); |
| + smtc_seqw(0x6b, 0x02); |
| + case 0x720: |
| + smtc_seqw(0x6a, 0x0d); |
| + smtc_seqw(0x6b, 0x02); |
| + break; |
| + } |
| + |
| + smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); |
| smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); |
| - smtc_seqw(0x6a, 0x16); |
| - smtc_seqw(0x6b, 0x02); |
| smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77)); |
| smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); |
| - smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); |
| - smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); |
| smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03)); |
| + smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); |
| break; |
| case FB_BLANK_NORMAL: |
| /* Screen Off: HSync: On, VSync : On Soft blank */ |
| + smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); |
| + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); |
| + smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); |
| smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); |
| + smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); |
| smtc_seqw(0x6a, 0x16); |
| smtc_seqw(0x6b, 0x02); |
| - smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); |
| - smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); |
| - smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); |
| - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); |
| break; |
| case FB_BLANK_VSYNC_SUSPEND: |
| /* Screen On: HSync: On, VSync : Off */ |
| + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); |
| + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); |
| + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20)); |
| smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); |
| - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); |
| - smtc_seqw(0x6a, 0x0c); |
| - smtc_seqw(0x6b, 0x02); |
| smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); |
| + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); |
| smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20)); |
| - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20)); |
| - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); |
| - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); |
| smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); |
| + smtc_seqw(0x6a, 0x0c); |
| + smtc_seqw(0x6b, 0x02); |
| break; |
| case FB_BLANK_HSYNC_SUSPEND: |
| /* Screen On: HSync: Off, VSync : On */ |
| + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); |
| + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); |
| + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); |
| smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); |
| - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); |
| - smtc_seqw(0x6a, 0x0c); |
| - smtc_seqw(0x6b, 0x02); |
| smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); |
| + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); |
| smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10)); |
| - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); |
| - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); |
| - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); |
| smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); |
| + smtc_seqw(0x6a, 0x0c); |
| + smtc_seqw(0x6b, 0x02); |
| break; |
| case FB_BLANK_POWERDOWN: |
| /* Screen On: HSync: Off, VSync : Off */ |
| + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); |
| + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); |
| + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); |
| smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); |
| - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); |
| - smtc_seqw(0x6a, 0x0c); |
| - smtc_seqw(0x6b, 0x02); |
| smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); |
| + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); |
| smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30)); |
| - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); |
| - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); |
| - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); |
| smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); |
| + smtc_seqw(0x6a, 0x0c); |
| + smtc_seqw(0x6b, 0x02); |
| break; |
| default: |
| return -EINVAL; |