Commit | Line | Data |
---|---|---|
f910b411 AC |
1 | /************************************************************************** |
2 | * Copyright (c) 2011, Intel Corporation. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along with | |
15 | * this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
17 | * | |
18 | **************************************************************************/ | |
19 | ||
20 | /* TODO | |
21 | * - Split functions by vbt type | |
22 | * - Make them all take drm_device | |
23 | * - Check ioremap failures | |
24 | */ | |
25 | ||
26 | #include <drm/drmP.h> | |
27 | #include <drm/drm.h> | |
760285e7 | 28 | #include <drm/gma_drm.h> |
f910b411 AC |
29 | #include "psb_drv.h" |
30 | #include "mid_bios.h" | |
31 | ||
32 | static void mid_get_fuse_settings(struct drm_device *dev) | |
33 | { | |
34 | struct drm_psb_private *dev_priv = dev->dev_private; | |
35 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | |
36 | uint32_t fuse_value = 0; | |
37 | uint32_t fuse_value_tmp = 0; | |
38 | ||
39 | #define FB_REG06 0xD0810600 | |
40 | #define FB_MIPI_DISABLE (1 << 11) | |
41 | #define FB_REG09 0xD0810900 | |
f910b411 AC |
42 | #define FB_SKU_MASK 0x7000 |
43 | #define FB_SKU_SHIFT 12 | |
44 | #define FB_SKU_100 0 | |
45 | #define FB_SKU_100L 1 | |
46 | #define FB_SKU_83 2 | |
0cecdd81 AC |
47 | if (pci_root == NULL) { |
48 | WARN_ON(1); | |
49 | return; | |
50 | } | |
51 | ||
52 | ||
f910b411 AC |
53 | pci_write_config_dword(pci_root, 0xD0, FB_REG06); |
54 | pci_read_config_dword(pci_root, 0xD4, &fuse_value); | |
55 | ||
56 | /* FB_MIPI_DISABLE doesn't mean LVDS on with Medfield */ | |
57 | if (IS_MRST(dev)) | |
58 | dev_priv->iLVDS_enable = fuse_value & FB_MIPI_DISABLE; | |
59 | ||
60 | DRM_INFO("internal display is %s\n", | |
61 | dev_priv->iLVDS_enable ? "LVDS display" : "MIPI display"); | |
62 | ||
63 | /* Prevent runtime suspend at start*/ | |
64 | if (dev_priv->iLVDS_enable) { | |
65 | dev_priv->is_lvds_on = true; | |
66 | dev_priv->is_mipi_on = false; | |
67 | } else { | |
68 | dev_priv->is_mipi_on = true; | |
69 | dev_priv->is_lvds_on = false; | |
70 | } | |
71 | ||
72 | dev_priv->video_device_fuse = fuse_value; | |
73 | ||
74 | pci_write_config_dword(pci_root, 0xD0, FB_REG09); | |
75 | pci_read_config_dword(pci_root, 0xD4, &fuse_value); | |
76 | ||
77 | dev_dbg(dev->dev, "SKU values is 0x%x.\n", fuse_value); | |
78 | fuse_value_tmp = (fuse_value & FB_SKU_MASK) >> FB_SKU_SHIFT; | |
79 | ||
80 | dev_priv->fuse_reg_value = fuse_value; | |
81 | ||
82 | switch (fuse_value_tmp) { | |
83 | case FB_SKU_100: | |
84 | dev_priv->core_freq = 200; | |
85 | break; | |
86 | case FB_SKU_100L: | |
87 | dev_priv->core_freq = 100; | |
88 | break; | |
89 | case FB_SKU_83: | |
90 | dev_priv->core_freq = 166; | |
91 | break; | |
92 | default: | |
93 | dev_warn(dev->dev, "Invalid SKU values, SKU value = 0x%08x\n", | |
94 | fuse_value_tmp); | |
95 | dev_priv->core_freq = 0; | |
96 | } | |
97 | dev_dbg(dev->dev, "LNC core clk is %dMHz.\n", dev_priv->core_freq); | |
98 | pci_dev_put(pci_root); | |
99 | } | |
100 | ||
101 | /* | |
102 | * Get the revison ID, B0:D2:F0;0x08 | |
103 | */ | |
104 | static void mid_get_pci_revID(struct drm_psb_private *dev_priv) | |
105 | { | |
106 | uint32_t platform_rev_id = 0; | |
107 | struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); | |
108 | ||
0cecdd81 AC |
109 | if (pci_gfx_root == NULL) { |
110 | WARN_ON(1); | |
111 | return; | |
112 | } | |
f910b411 AC |
113 | pci_read_config_dword(pci_gfx_root, 0x08, &platform_rev_id); |
114 | dev_priv->platform_rev_id = (uint8_t) platform_rev_id; | |
115 | pci_dev_put(pci_gfx_root); | |
116 | dev_dbg(dev_priv->dev->dev, "platform_rev_id is %x\n", | |
117 | dev_priv->platform_rev_id); | |
118 | } | |
119 | ||
d112a816 | 120 | struct mid_vbt_header { |
4086b1e2 KS |
121 | u32 signature; |
122 | u8 revision; | |
123 | } __packed; | |
124 | ||
125 | /* The same for r0 and r1 */ | |
126 | struct vbt_r0 { | |
d112a816 | 127 | struct mid_vbt_header vbt_header; |
4086b1e2 KS |
128 | u8 size; |
129 | u8 checksum; | |
130 | } __packed; | |
131 | ||
132 | struct vbt_r10 { | |
d112a816 | 133 | struct mid_vbt_header vbt_header; |
4086b1e2 KS |
134 | u8 checksum; |
135 | u16 size; | |
136 | u8 panel_count; | |
137 | u8 primary_panel_idx; | |
138 | u8 secondary_panel_idx; | |
139 | u8 __reserved[5]; | |
140 | } __packed; | |
141 | ||
142 | static int read_vbt_r0(u32 addr, struct vbt_r0 *vbt) | |
143 | { | |
144 | void __iomem *vbt_virtual; | |
145 | ||
146 | vbt_virtual = ioremap(addr, sizeof(*vbt)); | |
147 | if (vbt_virtual == NULL) | |
148 | return -1; | |
149 | ||
150 | memcpy_fromio(vbt, vbt_virtual, sizeof(*vbt)); | |
151 | iounmap(vbt_virtual); | |
152 | ||
153 | return 0; | |
154 | } | |
155 | ||
156 | static int read_vbt_r10(u32 addr, struct vbt_r10 *vbt) | |
157 | { | |
158 | void __iomem *vbt_virtual; | |
159 | ||
160 | vbt_virtual = ioremap(addr, sizeof(*vbt)); | |
161 | if (!vbt_virtual) | |
162 | return -1; | |
163 | ||
164 | memcpy_fromio(vbt, vbt_virtual, sizeof(*vbt)); | |
165 | iounmap(vbt_virtual); | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | static int mid_get_vbt_data_r0(struct drm_psb_private *dev_priv, u32 addr) | |
171 | { | |
172 | struct vbt_r0 vbt; | |
173 | void __iomem *gct_virtual; | |
174 | struct gct_r0 gct; | |
175 | u8 bpi; | |
176 | ||
177 | if (read_vbt_r0(addr, &vbt)) | |
178 | return -1; | |
179 | ||
180 | gct_virtual = ioremap(addr + sizeof(vbt), vbt.size - sizeof(vbt)); | |
181 | if (!gct_virtual) | |
182 | return -1; | |
183 | memcpy_fromio(&gct, gct_virtual, sizeof(gct)); | |
184 | iounmap(gct_virtual); | |
185 | ||
186 | bpi = gct.PD.BootPanelIndex; | |
187 | dev_priv->gct_data.bpi = bpi; | |
188 | dev_priv->gct_data.pt = gct.PD.PanelType; | |
189 | dev_priv->gct_data.DTD = gct.panel[bpi].DTD; | |
190 | dev_priv->gct_data.Panel_Port_Control = | |
191 | gct.panel[bpi].Panel_Port_Control; | |
192 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | |
193 | gct.panel[bpi].Panel_MIPI_Display_Descriptor; | |
194 | ||
195 | return 0; | |
196 | } | |
197 | ||
198 | static int mid_get_vbt_data_r1(struct drm_psb_private *dev_priv, u32 addr) | |
199 | { | |
200 | struct vbt_r0 vbt; | |
201 | void __iomem *gct_virtual; | |
202 | struct gct_r1 gct; | |
203 | u8 bpi; | |
204 | ||
205 | if (read_vbt_r0(addr, &vbt)) | |
206 | return -1; | |
207 | ||
208 | gct_virtual = ioremap(addr + sizeof(vbt), vbt.size - sizeof(vbt)); | |
209 | if (!gct_virtual) | |
210 | return -1; | |
211 | memcpy_fromio(&gct, gct_virtual, sizeof(gct)); | |
212 | iounmap(gct_virtual); | |
213 | ||
214 | bpi = gct.PD.BootPanelIndex; | |
215 | dev_priv->gct_data.bpi = bpi; | |
216 | dev_priv->gct_data.pt = gct.PD.PanelType; | |
217 | dev_priv->gct_data.DTD = gct.panel[bpi].DTD; | |
218 | dev_priv->gct_data.Panel_Port_Control = | |
219 | gct.panel[bpi].Panel_Port_Control; | |
220 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | |
221 | gct.panel[bpi].Panel_MIPI_Display_Descriptor; | |
222 | ||
223 | return 0; | |
224 | } | |
225 | ||
226 | static int mid_get_vbt_data_r10(struct drm_psb_private *dev_priv, u32 addr) | |
227 | { | |
228 | struct vbt_r10 vbt; | |
229 | void __iomem *gct_virtual; | |
230 | struct gct_r10 *gct; | |
231 | struct oaktrail_timing_info *dp_ti = &dev_priv->gct_data.DTD; | |
232 | struct gct_r10_timing_info *ti; | |
233 | int ret = -1; | |
234 | ||
235 | if (read_vbt_r10(addr, &vbt)) | |
236 | return -1; | |
237 | ||
238 | gct = kmalloc(sizeof(*gct) * vbt.panel_count, GFP_KERNEL); | |
239 | if (!gct) | |
240 | return -1; | |
241 | ||
242 | gct_virtual = ioremap(addr + sizeof(vbt), | |
243 | sizeof(*gct) * vbt.panel_count); | |
244 | if (!gct_virtual) | |
245 | goto out; | |
246 | memcpy_fromio(gct, gct_virtual, sizeof(*gct)); | |
247 | iounmap(gct_virtual); | |
248 | ||
249 | dev_priv->gct_data.bpi = vbt.primary_panel_idx; | |
250 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | |
251 | gct[vbt.primary_panel_idx].Panel_MIPI_Display_Descriptor; | |
252 | ||
253 | ti = &gct[vbt.primary_panel_idx].DTD; | |
254 | dp_ti->pixel_clock = ti->pixel_clock; | |
255 | dp_ti->hactive_hi = ti->hactive_hi; | |
256 | dp_ti->hactive_lo = ti->hactive_lo; | |
257 | dp_ti->hblank_hi = ti->hblank_hi; | |
258 | dp_ti->hblank_lo = ti->hblank_lo; | |
259 | dp_ti->hsync_offset_hi = ti->hsync_offset_hi; | |
260 | dp_ti->hsync_offset_lo = ti->hsync_offset_lo; | |
261 | dp_ti->hsync_pulse_width_hi = ti->hsync_pulse_width_hi; | |
262 | dp_ti->hsync_pulse_width_lo = ti->hsync_pulse_width_lo; | |
263 | dp_ti->vactive_hi = ti->vactive_hi; | |
264 | dp_ti->vactive_lo = ti->vactive_lo; | |
265 | dp_ti->vblank_hi = ti->vblank_hi; | |
266 | dp_ti->vblank_lo = ti->vblank_lo; | |
267 | dp_ti->vsync_offset_hi = ti->vsync_offset_hi; | |
268 | dp_ti->vsync_offset_lo = ti->vsync_offset_lo; | |
269 | dp_ti->vsync_pulse_width_hi = ti->vsync_pulse_width_hi; | |
270 | dp_ti->vsync_pulse_width_lo = ti->vsync_pulse_width_lo; | |
271 | ||
272 | ret = 0; | |
273 | out: | |
274 | kfree(gct); | |
275 | return ret; | |
276 | } | |
277 | ||
f910b411 AC |
278 | static void mid_get_vbt_data(struct drm_psb_private *dev_priv) |
279 | { | |
280 | struct drm_device *dev = dev_priv->dev; | |
f910b411 | 281 | u32 addr; |
4086b1e2 | 282 | u8 __iomem *vbt_virtual; |
d112a816 | 283 | struct mid_vbt_header vbt_header; |
f910b411 | 284 | struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); |
4086b1e2 | 285 | int ret = -1; |
f910b411 | 286 | |
4086b1e2 | 287 | /* Get the address of the platform config vbt */ |
f910b411 AC |
288 | pci_read_config_dword(pci_gfx_root, 0xFC, &addr); |
289 | pci_dev_put(pci_gfx_root); | |
290 | ||
291 | dev_dbg(dev->dev, "drm platform config address is %x\n", addr); | |
292 | ||
4086b1e2 KS |
293 | if (!addr) |
294 | goto out; | |
f910b411 AC |
295 | |
296 | /* get the virtual address of the vbt */ | |
4086b1e2 KS |
297 | vbt_virtual = ioremap(addr, sizeof(vbt_header)); |
298 | if (!vbt_virtual) | |
299 | goto out; | |
f910b411 | 300 | |
4086b1e2 KS |
301 | memcpy_fromio(&vbt_header, vbt_virtual, sizeof(vbt_header)); |
302 | iounmap(vbt_virtual); | |
f910b411 | 303 | |
4086b1e2 KS |
304 | if (memcmp(&vbt_header.signature, "$GCT", 4)) |
305 | goto out; | |
306 | ||
307 | dev_dbg(dev->dev, "GCT revision is %02x\n", vbt_header.revision); | |
aa0c45fd | 308 | |
4086b1e2 KS |
309 | switch (vbt_header.revision) { |
310 | case 0x00: | |
311 | ret = mid_get_vbt_data_r0(dev_priv, addr); | |
f910b411 | 312 | break; |
4086b1e2 KS |
313 | case 0x01: |
314 | ret = mid_get_vbt_data_r1(dev_priv, addr); | |
f910b411 AC |
315 | break; |
316 | case 0x10: | |
4086b1e2 | 317 | ret = mid_get_vbt_data_r10(dev_priv, addr); |
f910b411 AC |
318 | break; |
319 | default: | |
320 | dev_err(dev->dev, "Unknown revision of GCT!\n"); | |
f910b411 | 321 | } |
4086b1e2 KS |
322 | |
323 | out: | |
324 | if (ret) | |
325 | dev_err(dev->dev, "Unable to read GCT!"); | |
326 | else | |
327 | dev_priv->has_gct = true; | |
f910b411 AC |
328 | } |
329 | ||
330 | int mid_chip_setup(struct drm_device *dev) | |
331 | { | |
332 | struct drm_psb_private *dev_priv = dev->dev_private; | |
333 | mid_get_fuse_settings(dev); | |
334 | mid_get_vbt_data(dev_priv); | |
335 | mid_get_pci_revID(dev_priv); | |
336 | return 0; | |
337 | } |