]>
Commit | Line | Data |
---|---|---|
53722911 GKH |
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 | |
5 | ||
6 | From: Yifeng Li <tomli@tomli.me> | |
7 | ||
8 | commit 9e0e59993df0601cddb95c4f6c61aa3d5e753c00 upstream. | |
9 | ||
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 | |
12 | mapped correctly. | |
13 | ||
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. | |
20 | ||
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 | |
23 | framebuffer offset. | |
24 | ||
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. | |
33 | ||
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> | |
40 | ||
41 | --- | |
42 | drivers/video/fbdev/sm712.h | 5 ---- | |
43 | drivers/video/fbdev/sm712fb.c | 48 ++++++++++++++++++++++++++++++++++++++---- | |
44 | 2 files changed, 44 insertions(+), 9 deletions(-) | |
45 | ||
46 | --- a/drivers/video/fbdev/sm712.h | |
47 | +++ b/drivers/video/fbdev/sm712.h | |
48 | @@ -19,11 +19,6 @@ | |
49 | #define SCREEN_Y_RES 600 | |
50 | #define SCREEN_BPP 16 | |
51 | ||
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 | |
56 | - | |
57 | #define dac_reg (0x3c8) | |
58 | #define dac_val (0x3c9) | |
59 | ||
60 | --- a/drivers/video/fbdev/sm712fb.c | |
61 | +++ b/drivers/video/fbdev/sm712fb.c | |
62 | @@ -1328,6 +1328,11 @@ static int smtc_map_smem(struct smtcfb_i | |
63 | { | |
64 | sfb->fb->fix.smem_start = pci_resource_start(pdev, 0); | |
65 | ||
66 | + if (sfb->chip_id == 0x720) | |
67 | + /* on SM720, the framebuffer starts at the 1 MB offset */ | |
68 | + sfb->fb->fix.smem_start += 0x00200000; | |
69 | + | |
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; | |
73 | ||
74 | @@ -1365,12 +1370,45 @@ static inline void sm7xx_init_hw(void) | |
75 | outb_p(0x11, 0x3c5); | |
76 | } | |
77 | ||
78 | +static u_long sm7xx_vram_probe(struct smtcfb_info *sfb) | |
79 | +{ | |
80 | + u8 vram; | |
81 | + | |
82 | + switch (sfb->chip_id) { | |
83 | + case 0x710: | |
84 | + case 0x712: | |
85 | + /* | |
86 | + * Assume SM712 graphics chip has 4MB VRAM. | |
87 | + * | |
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 | |
92 | + * an E-mail. | |
93 | + */ | |
94 | + return 0x00400000; | |
95 | + case 0x720: | |
96 | + outb_p(0x76, 0x3c4); | |
97 | + vram = inb_p(0x3c5) >> 6; | |
98 | + | |
99 | + if (vram == 0x00) | |
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 */ | |
107 | + } | |
108 | + return 0; /* unknown hardware */ | |
109 | +} | |
110 | + | |
111 | static int smtcfb_pci_probe(struct pci_dev *pdev, | |
112 | const struct pci_device_id *ent) | |
113 | { | |
114 | struct smtcfb_info *sfb; | |
115 | struct fb_info *info; | |
116 | - u_long smem_size = 0x00800000; /* default 8MB */ | |
117 | + u_long smem_size; | |
118 | int err; | |
119 | unsigned long mmio_base; | |
120 | ||
121 | @@ -1427,12 +1465,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); | |
124 | ||
125 | + smem_size = sm7xx_vram_probe(sfb); | |
126 | + dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n", | |
127 | + smem_size / 1048576); | |
128 | + | |
129 | switch (sfb->chip_id) { | |
130 | case 0x710: | |
131 | case 0x712: | |
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); | |
136 | if (!sfb->lfb) { | |
137 | dev_err(&pdev->dev, | |
138 | @@ -1464,8 +1505,7 @@ static int smtcfb_pci_probe(struct pci_d | |
139 | case 0x720: | |
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); |