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