1 From 9e0e59993df0601cddb95c4f6c61aa3d5e753c00 Mon Sep 17 00:00:00 2001
2 From: Yifeng Li <tomli@tomli.me>
3 Date: Mon, 1 Apr 2019 17:46:59 +0200
4 Subject: fbdev: sm712fb: fix crashes during framebuffer writes by correctly mapping VRAM
6 From: Yifeng Li <tomli@tomli.me>
8 commit 9e0e59993df0601cddb95c4f6c61aa3d5e753c00 upstream.
10 On a Thinkpad s30 (Pentium III / i440MX, Lynx3DM), running fbtest or X
11 will crash the machine instantly, because the VRAM/framebuffer is not
14 On SM712, the framebuffer starts at the beginning of address space, but
15 SM720's framebuffer starts at the 1 MiB offset from the beginning. However,
16 sm712fb fails to take this into account, as a result, writing to the
17 framebuffer will destroy all the registers and kill the system immediately.
18 Another problem is the driver assumes 8 MiB of VRAM for SM720, but some
19 SM720 system, such as this IBM Thinkpad, only has 4 MiB of VRAM.
21 Fix this problem by removing the hardcoded VRAM size, adding a function to
22 query the amount of VRAM from register MCR76 on SM720, and adding proper
25 Please note that the memory map may have additional problems on Big-Endian
26 system, which is not available for testing by myself. But I highly suspect
27 that the original code is also broken on Big-Endian machines for SM720, so
28 at least we are not making the problem worse. More, the driver also assumed
29 SM710/SM712 has 4 MiB of VRAM, but it has a 2 MiB version as well, and used
30 in earlier laptops, such as IBM Thinkpad 240X, the driver would probably
31 crash on them. I've never seen one of those machines and cannot fix it, but
32 I have documented these problems in the comments.
34 Signed-off-by: Yifeng Li <tomli@tomli.me>
35 Tested-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
36 Cc: Teddy Wang <teddy.wang@siliconmotion.com>
37 Cc: <stable@vger.kernel.org> # v4.4+
38 Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
39 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
42 drivers/video/fbdev/sm712.h | 5 ----
43 drivers/video/fbdev/sm712fb.c | 48 ++++++++++++++++++++++++++++++++++++++----
44 2 files changed, 44 insertions(+), 9 deletions(-)
46 --- a/drivers/video/fbdev/sm712.h
47 +++ b/drivers/video/fbdev/sm712.h
49 #define SCREEN_Y_RES 600
52 -/*Assume SM712 graphics chip has 4MB VRAM */
53 -#define SM712_VIDEOMEMORYSIZE 0x00400000
54 -/*Assume SM722 graphics chip has 8MB VRAM */
55 -#define SM722_VIDEOMEMORYSIZE 0x00800000
57 #define dac_reg (0x3c8)
58 #define dac_val (0x3c9)
60 --- a/drivers/video/fbdev/sm712fb.c
61 +++ b/drivers/video/fbdev/sm712fb.c
62 @@ -1329,6 +1329,11 @@ static int smtc_map_smem(struct smtcfb_i
64 sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
66 + if (sfb->chip_id == 0x720)
67 + /* on SM720, the framebuffer starts at the 1 MB offset */
68 + sfb->fb->fix.smem_start += 0x00200000;
70 + /* XXX: is it safe for SM720 on Big-Endian? */
71 if (sfb->fb->var.bits_per_pixel == 32)
72 sfb->fb->fix.smem_start += big_addr;
74 @@ -1366,12 +1371,45 @@ static inline void sm7xx_init_hw(void)
78 +static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
82 + switch (sfb->chip_id) {
86 + * Assume SM712 graphics chip has 4MB VRAM.
88 + * FIXME: SM712 can have 2MB VRAM, which is used on earlier
89 + * laptops, such as IBM Thinkpad 240X. This driver would
90 + * probably crash on those machines. If anyone gets one of
91 + * those and is willing to help, run "git blame" and send me
96 + outb_p(0x76, 0x3c4);
97 + vram = inb_p(0x3c5) >> 6;
100 + return 0x00800000; /* 8 MB */
101 + else if (vram == 0x01)
102 + return 0x01000000; /* 16 MB */
103 + else if (vram == 0x02)
104 + return 0x00400000; /* illegal, fallback to 4 MB */
105 + else if (vram == 0x03)
106 + return 0x00400000; /* 4 MB */
108 + return 0; /* unknown hardware */
111 static int smtcfb_pci_probe(struct pci_dev *pdev,
112 const struct pci_device_id *ent)
114 struct smtcfb_info *sfb;
115 struct fb_info *info;
116 - u_long smem_size = 0x00800000; /* default 8MB */
119 unsigned long mmio_base;
121 @@ -1428,12 +1466,15 @@ static int smtcfb_pci_probe(struct pci_d
122 mmio_base = pci_resource_start(pdev, 0);
123 pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
125 + smem_size = sm7xx_vram_probe(sfb);
126 + dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
127 + smem_size / 1048576);
129 switch (sfb->chip_id) {
132 sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
133 sfb->fb->fix.mmio_len = 0x00400000;
134 - smem_size = SM712_VIDEOMEMORYSIZE;
135 sfb->lfb = ioremap(mmio_base, mmio_addr);
138 @@ -1465,8 +1506,7 @@ static int smtcfb_pci_probe(struct pci_d
140 sfb->fb->fix.mmio_start = mmio_base;
141 sfb->fb->fix.mmio_len = 0x00200000;
142 - smem_size = SM722_VIDEOMEMORYSIZE;
143 - sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
144 + sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
145 sfb->lfb = sfb->dp_regs + 0x00200000;
146 sfb->mmio = (smtc_regbaseaddress =
147 sfb->dp_regs + 0x000c0000);