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 | |
42 | #define FB_REG09 0xD0810900 | |
43 | #define FB_SKU_MASK 0x7000 | |
44 | #define FB_SKU_SHIFT 12 | |
45 | #define FB_SKU_100 0 | |
46 | #define FB_SKU_100L 1 | |
47 | #define FB_SKU_83 2 | |
0cecdd81 AC |
48 | if (pci_root == NULL) { |
49 | WARN_ON(1); | |
50 | return; | |
51 | } | |
52 | ||
53 | ||
f910b411 AC |
54 | pci_write_config_dword(pci_root, 0xD0, FB_REG06); |
55 | pci_read_config_dword(pci_root, 0xD4, &fuse_value); | |
56 | ||
57 | /* FB_MIPI_DISABLE doesn't mean LVDS on with Medfield */ | |
58 | if (IS_MRST(dev)) | |
59 | dev_priv->iLVDS_enable = fuse_value & FB_MIPI_DISABLE; | |
60 | ||
61 | DRM_INFO("internal display is %s\n", | |
62 | dev_priv->iLVDS_enable ? "LVDS display" : "MIPI display"); | |
63 | ||
64 | /* Prevent runtime suspend at start*/ | |
65 | if (dev_priv->iLVDS_enable) { | |
66 | dev_priv->is_lvds_on = true; | |
67 | dev_priv->is_mipi_on = false; | |
68 | } else { | |
69 | dev_priv->is_mipi_on = true; | |
70 | dev_priv->is_lvds_on = false; | |
71 | } | |
72 | ||
73 | dev_priv->video_device_fuse = fuse_value; | |
74 | ||
75 | pci_write_config_dword(pci_root, 0xD0, FB_REG09); | |
76 | pci_read_config_dword(pci_root, 0xD4, &fuse_value); | |
77 | ||
78 | dev_dbg(dev->dev, "SKU values is 0x%x.\n", fuse_value); | |
79 | fuse_value_tmp = (fuse_value & FB_SKU_MASK) >> FB_SKU_SHIFT; | |
80 | ||
81 | dev_priv->fuse_reg_value = fuse_value; | |
82 | ||
83 | switch (fuse_value_tmp) { | |
84 | case FB_SKU_100: | |
85 | dev_priv->core_freq = 200; | |
86 | break; | |
87 | case FB_SKU_100L: | |
88 | dev_priv->core_freq = 100; | |
89 | break; | |
90 | case FB_SKU_83: | |
91 | dev_priv->core_freq = 166; | |
92 | break; | |
93 | default: | |
94 | dev_warn(dev->dev, "Invalid SKU values, SKU value = 0x%08x\n", | |
95 | fuse_value_tmp); | |
96 | dev_priv->core_freq = 0; | |
97 | } | |
98 | dev_dbg(dev->dev, "LNC core clk is %dMHz.\n", dev_priv->core_freq); | |
99 | pci_dev_put(pci_root); | |
100 | } | |
101 | ||
102 | /* | |
103 | * Get the revison ID, B0:D2:F0;0x08 | |
104 | */ | |
105 | static void mid_get_pci_revID(struct drm_psb_private *dev_priv) | |
106 | { | |
107 | uint32_t platform_rev_id = 0; | |
108 | struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); | |
109 | ||
0cecdd81 AC |
110 | if (pci_gfx_root == NULL) { |
111 | WARN_ON(1); | |
112 | return; | |
113 | } | |
f910b411 AC |
114 | pci_read_config_dword(pci_gfx_root, 0x08, &platform_rev_id); |
115 | dev_priv->platform_rev_id = (uint8_t) platform_rev_id; | |
116 | pci_dev_put(pci_gfx_root); | |
117 | dev_dbg(dev_priv->dev->dev, "platform_rev_id is %x\n", | |
118 | dev_priv->platform_rev_id); | |
119 | } | |
120 | ||
4086b1e2 KS |
121 | struct vbt_header { |
122 | u32 signature; | |
123 | u8 revision; | |
124 | } __packed; | |
125 | ||
126 | /* The same for r0 and r1 */ | |
127 | struct vbt_r0 { | |
128 | struct vbt_header vbt_header; | |
129 | u8 size; | |
130 | u8 checksum; | |
131 | } __packed; | |
132 | ||
133 | struct vbt_r10 { | |
134 | struct vbt_header vbt_header; | |
135 | u8 checksum; | |
136 | u16 size; | |
137 | u8 panel_count; | |
138 | u8 primary_panel_idx; | |
139 | u8 secondary_panel_idx; | |
140 | u8 __reserved[5]; | |
141 | } __packed; | |
142 | ||
143 | static int read_vbt_r0(u32 addr, struct vbt_r0 *vbt) | |
144 | { | |
145 | void __iomem *vbt_virtual; | |
146 | ||
147 | vbt_virtual = ioremap(addr, sizeof(*vbt)); | |
148 | if (vbt_virtual == NULL) | |
149 | return -1; | |
150 | ||
151 | memcpy_fromio(vbt, vbt_virtual, sizeof(*vbt)); | |
152 | iounmap(vbt_virtual); | |
153 | ||
154 | return 0; | |
155 | } | |
156 | ||
157 | static int read_vbt_r10(u32 addr, struct vbt_r10 *vbt) | |
158 | { | |
159 | void __iomem *vbt_virtual; | |
160 | ||
161 | vbt_virtual = ioremap(addr, sizeof(*vbt)); | |
162 | if (!vbt_virtual) | |
163 | return -1; | |
164 | ||
165 | memcpy_fromio(vbt, vbt_virtual, sizeof(*vbt)); | |
166 | iounmap(vbt_virtual); | |
167 | ||
168 | return 0; | |
169 | } | |
170 | ||
171 | static int mid_get_vbt_data_r0(struct drm_psb_private *dev_priv, u32 addr) | |
172 | { | |
173 | struct vbt_r0 vbt; | |
174 | void __iomem *gct_virtual; | |
175 | struct gct_r0 gct; | |
176 | u8 bpi; | |
177 | ||
178 | if (read_vbt_r0(addr, &vbt)) | |
179 | return -1; | |
180 | ||
181 | gct_virtual = ioremap(addr + sizeof(vbt), vbt.size - sizeof(vbt)); | |
182 | if (!gct_virtual) | |
183 | return -1; | |
184 | memcpy_fromio(&gct, gct_virtual, sizeof(gct)); | |
185 | iounmap(gct_virtual); | |
186 | ||
187 | bpi = gct.PD.BootPanelIndex; | |
188 | dev_priv->gct_data.bpi = bpi; | |
189 | dev_priv->gct_data.pt = gct.PD.PanelType; | |
190 | dev_priv->gct_data.DTD = gct.panel[bpi].DTD; | |
191 | dev_priv->gct_data.Panel_Port_Control = | |
192 | gct.panel[bpi].Panel_Port_Control; | |
193 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | |
194 | gct.panel[bpi].Panel_MIPI_Display_Descriptor; | |
195 | ||
196 | return 0; | |
197 | } | |
198 | ||
199 | static int mid_get_vbt_data_r1(struct drm_psb_private *dev_priv, u32 addr) | |
200 | { | |
201 | struct vbt_r0 vbt; | |
202 | void __iomem *gct_virtual; | |
203 | struct gct_r1 gct; | |
204 | u8 bpi; | |
205 | ||
206 | if (read_vbt_r0(addr, &vbt)) | |
207 | return -1; | |
208 | ||
209 | gct_virtual = ioremap(addr + sizeof(vbt), vbt.size - sizeof(vbt)); | |
210 | if (!gct_virtual) | |
211 | return -1; | |
212 | memcpy_fromio(&gct, gct_virtual, sizeof(gct)); | |
213 | iounmap(gct_virtual); | |
214 | ||
215 | bpi = gct.PD.BootPanelIndex; | |
216 | dev_priv->gct_data.bpi = bpi; | |
217 | dev_priv->gct_data.pt = gct.PD.PanelType; | |
218 | dev_priv->gct_data.DTD = gct.panel[bpi].DTD; | |
219 | dev_priv->gct_data.Panel_Port_Control = | |
220 | gct.panel[bpi].Panel_Port_Control; | |
221 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | |
222 | gct.panel[bpi].Panel_MIPI_Display_Descriptor; | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
227 | static int mid_get_vbt_data_r10(struct drm_psb_private *dev_priv, u32 addr) | |
228 | { | |
229 | struct vbt_r10 vbt; | |
230 | void __iomem *gct_virtual; | |
231 | struct gct_r10 *gct; | |
232 | struct oaktrail_timing_info *dp_ti = &dev_priv->gct_data.DTD; | |
233 | struct gct_r10_timing_info *ti; | |
234 | int ret = -1; | |
235 | ||
236 | if (read_vbt_r10(addr, &vbt)) | |
237 | return -1; | |
238 | ||
239 | gct = kmalloc(sizeof(*gct) * vbt.panel_count, GFP_KERNEL); | |
240 | if (!gct) | |
241 | return -1; | |
242 | ||
243 | gct_virtual = ioremap(addr + sizeof(vbt), | |
244 | sizeof(*gct) * vbt.panel_count); | |
245 | if (!gct_virtual) | |
246 | goto out; | |
247 | memcpy_fromio(gct, gct_virtual, sizeof(*gct)); | |
248 | iounmap(gct_virtual); | |
249 | ||
250 | dev_priv->gct_data.bpi = vbt.primary_panel_idx; | |
251 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | |
252 | gct[vbt.primary_panel_idx].Panel_MIPI_Display_Descriptor; | |
253 | ||
254 | ti = &gct[vbt.primary_panel_idx].DTD; | |
255 | dp_ti->pixel_clock = ti->pixel_clock; | |
256 | dp_ti->hactive_hi = ti->hactive_hi; | |
257 | dp_ti->hactive_lo = ti->hactive_lo; | |
258 | dp_ti->hblank_hi = ti->hblank_hi; | |
259 | dp_ti->hblank_lo = ti->hblank_lo; | |
260 | dp_ti->hsync_offset_hi = ti->hsync_offset_hi; | |
261 | dp_ti->hsync_offset_lo = ti->hsync_offset_lo; | |
262 | dp_ti->hsync_pulse_width_hi = ti->hsync_pulse_width_hi; | |
263 | dp_ti->hsync_pulse_width_lo = ti->hsync_pulse_width_lo; | |
264 | dp_ti->vactive_hi = ti->vactive_hi; | |
265 | dp_ti->vactive_lo = ti->vactive_lo; | |
266 | dp_ti->vblank_hi = ti->vblank_hi; | |
267 | dp_ti->vblank_lo = ti->vblank_lo; | |
268 | dp_ti->vsync_offset_hi = ti->vsync_offset_hi; | |
269 | dp_ti->vsync_offset_lo = ti->vsync_offset_lo; | |
270 | dp_ti->vsync_pulse_width_hi = ti->vsync_pulse_width_hi; | |
271 | dp_ti->vsync_pulse_width_lo = ti->vsync_pulse_width_lo; | |
272 | ||
273 | ret = 0; | |
274 | out: | |
275 | kfree(gct); | |
276 | return ret; | |
277 | } | |
278 | ||
f910b411 AC |
279 | static void mid_get_vbt_data(struct drm_psb_private *dev_priv) |
280 | { | |
281 | struct drm_device *dev = dev_priv->dev; | |
f910b411 | 282 | u32 addr; |
4086b1e2 KS |
283 | u8 __iomem *vbt_virtual; |
284 | struct vbt_header vbt_header; | |
f910b411 | 285 | struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); |
4086b1e2 | 286 | int ret = -1; |
f910b411 | 287 | |
4086b1e2 | 288 | /* Get the address of the platform config vbt */ |
f910b411 AC |
289 | pci_read_config_dword(pci_gfx_root, 0xFC, &addr); |
290 | pci_dev_put(pci_gfx_root); | |
291 | ||
292 | dev_dbg(dev->dev, "drm platform config address is %x\n", addr); | |
293 | ||
4086b1e2 KS |
294 | if (!addr) |
295 | goto out; | |
f910b411 AC |
296 | |
297 | /* get the virtual address of the vbt */ | |
4086b1e2 KS |
298 | vbt_virtual = ioremap(addr, sizeof(vbt_header)); |
299 | if (!vbt_virtual) | |
300 | goto out; | |
f910b411 | 301 | |
4086b1e2 KS |
302 | memcpy_fromio(&vbt_header, vbt_virtual, sizeof(vbt_header)); |
303 | iounmap(vbt_virtual); | |
f910b411 | 304 | |
4086b1e2 KS |
305 | if (memcmp(&vbt_header.signature, "$GCT", 4)) |
306 | goto out; | |
307 | ||
308 | dev_dbg(dev->dev, "GCT revision is %02x\n", vbt_header.revision); | |
aa0c45fd | 309 | |
4086b1e2 KS |
310 | switch (vbt_header.revision) { |
311 | case 0x00: | |
312 | ret = mid_get_vbt_data_r0(dev_priv, addr); | |
f910b411 | 313 | break; |
4086b1e2 KS |
314 | case 0x01: |
315 | ret = mid_get_vbt_data_r1(dev_priv, addr); | |
f910b411 AC |
316 | break; |
317 | case 0x10: | |
4086b1e2 | 318 | ret = mid_get_vbt_data_r10(dev_priv, addr); |
f910b411 AC |
319 | break; |
320 | default: | |
321 | dev_err(dev->dev, "Unknown revision of GCT!\n"); | |
f910b411 | 322 | } |
4086b1e2 KS |
323 | |
324 | out: | |
325 | if (ret) | |
326 | dev_err(dev->dev, "Unable to read GCT!"); | |
327 | else | |
328 | dev_priv->has_gct = true; | |
f910b411 AC |
329 | } |
330 | ||
331 | int mid_chip_setup(struct drm_device *dev) | |
332 | { | |
333 | struct drm_psb_private *dev_priv = dev->dev_private; | |
334 | mid_get_fuse_settings(dev); | |
335 | mid_get_vbt_data(dev_priv); | |
336 | mid_get_pci_revID(dev_priv); | |
337 | return 0; | |
338 | } |