diff options
Diffstat (limited to 'drivers/gpu/drm/gma500')
48 files changed, 22338 insertions, 0 deletions
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig new file mode 100644 index 00000000000..754e14bdc80 --- /dev/null +++ b/drivers/gpu/drm/gma500/Kconfig | |||
@@ -0,0 +1,27 @@ | |||
1 | config DRM_GMA500 | ||
2 | tristate "Intel GMA5/600 KMS Framebuffer" | ||
3 | depends on DRM && PCI && X86 && EXPERIMENTAL | ||
4 | select FB_CFB_COPYAREA | ||
5 | select FB_CFB_FILLRECT | ||
6 | select FB_CFB_IMAGEBLIT | ||
7 | select DRM_KMS_HELPER | ||
8 | select DRM_TTM | ||
9 | help | ||
10 | Say yes for an experimental 2D KMS framebuffer driver for the | ||
11 | Intel GMA500 ('Poulsbo') and other Intel IMG based graphics | ||
12 | devices. | ||
13 | |||
14 | config DRM_GMA600 | ||
15 | bool "Intel GMA600 support (Experimental)" | ||
16 | depends on DRM_GMA500 | ||
17 | help | ||
18 | Say yes to include support for GMA600 (Intel Moorestown/Oaktrail) | ||
19 | platforms with LVDS ports. HDMI and MIPI are not currently | ||
20 | supported. | ||
21 | |||
22 | config DRM_GMA3600 | ||
23 | bool "Intel GMA3600/3650 support (Experimental)" | ||
24 | depends on DRM_GMA500 | ||
25 | help | ||
26 | Say yes to include basic support for Intel GMA3600/3650 (Intel | ||
27 | Cedar Trail) platforms. | ||
diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile new file mode 100644 index 00000000000..81c103be5e2 --- /dev/null +++ b/drivers/gpu/drm/gma500/Makefile | |||
@@ -0,0 +1,40 @@ | |||
1 | # | ||
2 | # KMS driver for the GMA500 | ||
3 | # | ||
4 | ccflags-y += -Iinclude/drm | ||
5 | |||
6 | gma500_gfx-y += gem_glue.o \ | ||
7 | accel_2d.o \ | ||
8 | backlight.o \ | ||
9 | framebuffer.o \ | ||
10 | gem.o \ | ||
11 | gtt.o \ | ||
12 | intel_bios.o \ | ||
13 | intel_i2c.o \ | ||
14 | intel_gmbus.o \ | ||
15 | intel_opregion.o \ | ||
16 | mmu.o \ | ||
17 | power.o \ | ||
18 | psb_drv.o \ | ||
19 | psb_intel_display.o \ | ||
20 | psb_intel_lvds.o \ | ||
21 | psb_intel_modes.o \ | ||
22 | psb_intel_sdvo.o \ | ||
23 | psb_lid.o \ | ||
24 | psb_irq.o \ | ||
25 | psb_device.o \ | ||
26 | mid_bios.o | ||
27 | |||
28 | gma500_gfx-$(CONFIG_DRM_GMA3600) += cdv_device.o \ | ||
29 | cdv_intel_crt.o \ | ||
30 | cdv_intel_display.o \ | ||
31 | cdv_intel_hdmi.o \ | ||
32 | cdv_intel_lvds.o | ||
33 | |||
34 | gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \ | ||
35 | oaktrail_crtc.o \ | ||
36 | oaktrail_lvds.o \ | ||
37 | oaktrail_hdmi.o \ | ||
38 | oaktrail_hdmi_i2c.o | ||
39 | |||
40 | obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o | ||
diff --git a/drivers/gpu/drm/gma500/accel_2d.c b/drivers/gpu/drm/gma500/accel_2d.c new file mode 100644 index 00000000000..d5ef1a5793c --- /dev/null +++ b/drivers/gpu/drm/gma500/accel_2d.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007-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 | * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to | ||
19 | * develop this driver. | ||
20 | * | ||
21 | **************************************************************************/ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/tty.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/fb.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/console.h> | ||
34 | |||
35 | #include <drm/drmP.h> | ||
36 | #include <drm/drm.h> | ||
37 | #include <drm/drm_crtc.h> | ||
38 | |||
39 | #include "psb_drv.h" | ||
40 | #include "psb_reg.h" | ||
41 | #include "framebuffer.h" | ||
42 | |||
43 | /** | ||
44 | * psb_spank - reset the 2D engine | ||
45 | * @dev_priv: our PSB DRM device | ||
46 | * | ||
47 | * Soft reset the graphics engine and then reload the necessary registers. | ||
48 | * We use this at initialisation time but it will become relevant for | ||
49 | * accelerated X later | ||
50 | */ | ||
51 | void psb_spank(struct drm_psb_private *dev_priv) | ||
52 | { | ||
53 | PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET | | ||
54 | _PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET | | ||
55 | _PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET | | ||
56 | _PSB_CS_RESET_TWOD_RESET, PSB_CR_SOFT_RESET); | ||
57 | PSB_RSGX32(PSB_CR_SOFT_RESET); | ||
58 | |||
59 | msleep(1); | ||
60 | |||
61 | PSB_WSGX32(0, PSB_CR_SOFT_RESET); | ||
62 | wmb(); | ||
63 | PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT, | ||
64 | PSB_CR_BIF_CTRL); | ||
65 | wmb(); | ||
66 | (void) PSB_RSGX32(PSB_CR_BIF_CTRL); | ||
67 | |||
68 | msleep(1); | ||
69 | PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_CB_CTRL_CLEAR_FAULT, | ||
70 | PSB_CR_BIF_CTRL); | ||
71 | (void) PSB_RSGX32(PSB_CR_BIF_CTRL); | ||
72 | PSB_WSGX32(dev_priv->gtt.gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * psb2_2d_wait_available - wait for FIFO room | ||
77 | * @dev_priv: our DRM device | ||
78 | * @size: size (in dwords) of the command we want to issue | ||
79 | * | ||
80 | * Wait until there is room to load the FIFO with our data. If the | ||
81 | * device is not responding then reset it | ||
82 | */ | ||
83 | static int psb_2d_wait_available(struct drm_psb_private *dev_priv, | ||
84 | unsigned size) | ||
85 | { | ||
86 | uint32_t avail = PSB_RSGX32(PSB_CR_2D_SOCIF); | ||
87 | unsigned long t = jiffies + HZ; | ||
88 | |||
89 | while (avail < size) { | ||
90 | avail = PSB_RSGX32(PSB_CR_2D_SOCIF); | ||
91 | if (time_after(jiffies, t)) { | ||
92 | psb_spank(dev_priv); | ||
93 | return -EIO; | ||
94 | } | ||
95 | } | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * psb_2d_submit - submit a 2D command | ||
101 | * @dev_priv: our DRM device | ||
102 | * @cmdbuf: command to issue | ||
103 | * @size: length (in dwords) | ||
104 | * | ||
105 | * Issue one or more 2D commands to the accelerator. This needs to be | ||
106 | * serialized later when we add the GEM interfaces for acceleration | ||
107 | */ | ||
108 | static int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf, | ||
109 | unsigned size) | ||
110 | { | ||
111 | int ret = 0; | ||
112 | int i; | ||
113 | unsigned submit_size; | ||
114 | unsigned long flags; | ||
115 | |||
116 | spin_lock_irqsave(&dev_priv->lock_2d, flags); | ||
117 | while (size > 0) { | ||
118 | submit_size = (size < 0x60) ? size : 0x60; | ||
119 | size -= submit_size; | ||
120 | ret = psb_2d_wait_available(dev_priv, submit_size); | ||
121 | if (ret) | ||
122 | break; | ||
123 | |||
124 | submit_size <<= 2; | ||
125 | |||
126 | for (i = 0; i < submit_size; i += 4) | ||
127 | PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i); | ||
128 | |||
129 | (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4); | ||
130 | } | ||
131 | spin_unlock_irqrestore(&dev_priv->lock_2d, flags); | ||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | |||
136 | /** | ||
137 | * psb_accel_2d_copy_direction - compute blit order | ||
138 | * @xdir: X direction of move | ||
139 | * @ydir: Y direction of move | ||
140 | * | ||
141 | * Compute the correct order setings to ensure that an overlapping blit | ||
142 | * correctly copies all the pixels. | ||
143 | */ | ||
144 | static u32 psb_accel_2d_copy_direction(int xdir, int ydir) | ||
145 | { | ||
146 | if (xdir < 0) | ||
147 | return (ydir < 0) ? PSB_2D_COPYORDER_BR2TL : | ||
148 | PSB_2D_COPYORDER_TR2BL; | ||
149 | else | ||
150 | return (ydir < 0) ? PSB_2D_COPYORDER_BL2TR : | ||
151 | PSB_2D_COPYORDER_TL2BR; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * psb_accel_2d_copy - accelerated 2D copy | ||
156 | * @dev_priv: our DRM device | ||
157 | * @src_offset in bytes | ||
158 | * @src_stride in bytes | ||
159 | * @src_format psb 2D format defines | ||
160 | * @dst_offset in bytes | ||
161 | * @dst_stride in bytes | ||
162 | * @dst_format psb 2D format defines | ||
163 | * @src_x offset in pixels | ||
164 | * @src_y offset in pixels | ||
165 | * @dst_x offset in pixels | ||
166 | * @dst_y offset in pixels | ||
167 | * @size_x of the copied area | ||
168 | * @size_y of the copied area | ||
169 | * | ||
170 | * Format and issue a 2D accelerated copy command. | ||
171 | */ | ||
172 | static int psb_accel_2d_copy(struct drm_psb_private *dev_priv, | ||
173 | uint32_t src_offset, uint32_t src_stride, | ||
174 | uint32_t src_format, uint32_t dst_offset, | ||
175 | uint32_t dst_stride, uint32_t dst_format, | ||
176 | uint16_t src_x, uint16_t src_y, | ||
177 | uint16_t dst_x, uint16_t dst_y, | ||
178 | uint16_t size_x, uint16_t size_y) | ||
179 | { | ||
180 | uint32_t blit_cmd; | ||
181 | uint32_t buffer[10]; | ||
182 | uint32_t *buf; | ||
183 | uint32_t direction; | ||
184 | |||
185 | buf = buffer; | ||
186 | |||
187 | direction = | ||
188 | psb_accel_2d_copy_direction(src_x - dst_x, src_y - dst_y); | ||
189 | |||
190 | if (direction == PSB_2D_COPYORDER_BR2TL || | ||
191 | direction == PSB_2D_COPYORDER_TR2BL) { | ||
192 | src_x += size_x - 1; | ||
193 | dst_x += size_x - 1; | ||
194 | } | ||
195 | if (direction == PSB_2D_COPYORDER_BR2TL || | ||
196 | direction == PSB_2D_COPYORDER_BL2TR) { | ||
197 | src_y += size_y - 1; | ||
198 | dst_y += size_y - 1; | ||
199 | } | ||
200 | |||
201 | blit_cmd = | ||
202 | PSB_2D_BLIT_BH | | ||
203 | PSB_2D_ROT_NONE | | ||
204 | PSB_2D_DSTCK_DISABLE | | ||
205 | PSB_2D_SRCCK_DISABLE | | ||
206 | PSB_2D_USE_PAT | PSB_2D_ROP3_SRCCOPY | direction; | ||
207 | |||
208 | *buf++ = PSB_2D_FENCE_BH; | ||
209 | *buf++ = | ||
210 | PSB_2D_DST_SURF_BH | dst_format | (dst_stride << | ||
211 | PSB_2D_DST_STRIDE_SHIFT); | ||
212 | *buf++ = dst_offset; | ||
213 | *buf++ = | ||
214 | PSB_2D_SRC_SURF_BH | src_format | (src_stride << | ||
215 | PSB_2D_SRC_STRIDE_SHIFT); | ||
216 | *buf++ = src_offset; | ||
217 | *buf++ = | ||
218 | PSB_2D_SRC_OFF_BH | (src_x << PSB_2D_SRCOFF_XSTART_SHIFT) | | ||
219 | (src_y << PSB_2D_SRCOFF_YSTART_SHIFT); | ||
220 | *buf++ = blit_cmd; | ||
221 | *buf++ = | ||
222 | (dst_x << PSB_2D_DST_XSTART_SHIFT) | (dst_y << | ||
223 | PSB_2D_DST_YSTART_SHIFT); | ||
224 | *buf++ = | ||
225 | (size_x << PSB_2D_DST_XSIZE_SHIFT) | (size_y << | ||
226 | PSB_2D_DST_YSIZE_SHIFT); | ||
227 | *buf++ = PSB_2D_FLUSH_BH; | ||
228 | |||
229 | return psbfb_2d_submit(dev_priv, buffer, buf - buffer); | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * psbfb_copyarea_accel - copyarea acceleration for /dev/fb | ||
234 | * @info: our framebuffer | ||
235 | * @a: copyarea parameters from the framebuffer core | ||
236 | * | ||
237 | * Perform a 2D copy via the accelerator | ||
238 | */ | ||
239 | static void psbfb_copyarea_accel(struct fb_info *info, | ||
240 | const struct fb_copyarea *a) | ||
241 | { | ||
242 | struct psb_fbdev *fbdev = info->par; | ||
243 | struct psb_framebuffer *psbfb = &fbdev->pfb; | ||
244 | struct drm_device *dev = psbfb->base.dev; | ||
245 | struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; | ||
246 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
247 | uint32_t offset; | ||
248 | uint32_t stride; | ||
249 | uint32_t src_format; | ||
250 | uint32_t dst_format; | ||
251 | |||
252 | if (!fb) | ||
253 | return; | ||
254 | |||
255 | offset = psbfb->gtt->offset; | ||
256 | stride = fb->pitches[0]; | ||
257 | |||
258 | switch (fb->depth) { | ||
259 | case 8: | ||
260 | src_format = PSB_2D_SRC_332RGB; | ||
261 | dst_format = PSB_2D_DST_332RGB; | ||
262 | break; | ||
263 | case 15: | ||
264 | src_format = PSB_2D_SRC_555RGB; | ||
265 | dst_format = PSB_2D_DST_555RGB; | ||
266 | break; | ||
267 | case 16: | ||
268 | src_format = PSB_2D_SRC_565RGB; | ||
269 | dst_format = PSB_2D_DST_565RGB; | ||
270 | break; | ||
271 | case 24: | ||
272 | case 32: | ||
273 | /* this is wrong but since we don't do blending its okay */ | ||
274 | src_format = PSB_2D_SRC_8888ARGB; | ||
275 | dst_format = PSB_2D_DST_8888ARGB; | ||
276 | break; | ||
277 | default: | ||
278 | /* software fallback */ | ||
279 | cfb_copyarea(info, a); | ||
280 | return; | ||
281 | } | ||
282 | |||
283 | if (!gma_power_begin(dev, false)) { | ||
284 | cfb_copyarea(info, a); | ||
285 | return; | ||
286 | } | ||
287 | psb_accel_2d_copy(dev_priv, | ||
288 | offset, stride, src_format, | ||
289 | offset, stride, dst_format, | ||
290 | a->sx, a->sy, a->dx, a->dy, a->width, a->height); | ||
291 | gma_power_end(dev); | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * psbfb_copyarea - 2D copy interface | ||
296 | * @info: our framebuffer | ||
297 | * @region: region to copy | ||
298 | * | ||
299 | * Copy an area of the framebuffer console either by the accelerator | ||
300 | * or directly using the cfb helpers according to the request | ||
301 | */ | ||
302 | void psbfb_copyarea(struct fb_info *info, | ||
303 | const struct fb_copyarea *region) | ||
304 | { | ||
305 | if (unlikely(info->state != FBINFO_STATE_RUNNING)) | ||
306 | return; | ||
307 | |||
308 | /* Avoid the 8 pixel erratum */ | ||
309 | if (region->width == 8 || region->height == 8 || | ||
310 | (info->flags & FBINFO_HWACCEL_DISABLED)) | ||
311 | return cfb_copyarea(info, region); | ||
312 | |||
313 | psbfb_copyarea_accel(info, region); | ||
314 | } | ||
315 | |||
316 | /** | ||
317 | * psbfb_sync - synchronize 2D | ||
318 | * @info: our framebuffer | ||
319 | * | ||
320 | * Wait for the 2D engine to quiesce so that we can do CPU | ||
321 | * access to the framebuffer again | ||
322 | */ | ||
323 | int psbfb_sync(struct fb_info *info) | ||
324 | { | ||
325 | struct psb_fbdev *fbdev = info->par; | ||
326 | struct psb_framebuffer *psbfb = &fbdev->pfb; | ||
327 | struct drm_device *dev = psbfb->base.dev; | ||
328 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
329 | unsigned long _end = jiffies + DRM_HZ; | ||
330 | int busy = 0; | ||
331 | unsigned long flags; | ||
332 | |||
333 | spin_lock_irqsave(&dev_priv->lock_2d, flags); | ||
334 | /* | ||
335 | * First idle the 2D engine. | ||
336 | */ | ||
337 | |||
338 | if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) && | ||
339 | ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0)) | ||
340 | goto out; | ||
341 | |||
342 | do { | ||
343 | busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); | ||
344 | cpu_relax(); | ||
345 | } while (busy && !time_after_eq(jiffies, _end)); | ||
346 | |||
347 | if (busy) | ||
348 | busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); | ||
349 | if (busy) | ||
350 | goto out; | ||
351 | |||
352 | do { | ||
353 | busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & | ||
354 | _PSB_C2B_STATUS_BUSY) != 0); | ||
355 | cpu_relax(); | ||
356 | } while (busy && !time_after_eq(jiffies, _end)); | ||
357 | if (busy) | ||
358 | busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & | ||
359 | _PSB_C2B_STATUS_BUSY) != 0); | ||
360 | |||
361 | out: | ||
362 | spin_unlock_irqrestore(&dev_priv->lock_2d, flags); | ||
363 | return (busy) ? -EBUSY : 0; | ||
364 | } | ||
diff --git a/drivers/gpu/drm/gma500/backlight.c b/drivers/gpu/drm/gma500/backlight.c new file mode 100644 index 00000000000..20793951fca --- /dev/null +++ b/drivers/gpu/drm/gma500/backlight.c | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * GMA500 Backlight Interface | ||
3 | * | ||
4 | * Copyright (c) 2009-2011, Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Authors: Eric Knopp | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include "psb_drv.h" | ||
24 | #include "psb_intel_reg.h" | ||
25 | #include "psb_intel_drv.h" | ||
26 | #include "intel_bios.h" | ||
27 | #include "power.h" | ||
28 | |||
29 | int gma_backlight_init(struct drm_device *dev) | ||
30 | { | ||
31 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
32 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
33 | return dev_priv->ops->backlight_init(dev); | ||
34 | #else | ||
35 | return 0; | ||
36 | #endif | ||
37 | } | ||
38 | |||
39 | void gma_backlight_exit(struct drm_device *dev) | ||
40 | { | ||
41 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
42 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
43 | if (dev_priv->backlight_device) { | ||
44 | dev_priv->backlight_device->props.brightness = 0; | ||
45 | backlight_update_status(dev_priv->backlight_device); | ||
46 | backlight_device_unregister(dev_priv->backlight_device); | ||
47 | } | ||
48 | #endif | ||
49 | } | ||
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c new file mode 100644 index 00000000000..4a5b099c3bc --- /dev/null +++ b/drivers/gpu/drm/gma500/cdv_device.c | |||
@@ -0,0 +1,351 @@ | |||
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 | #include <linux/backlight.h> | ||
21 | #include <drm/drmP.h> | ||
22 | #include <drm/drm.h> | ||
23 | #include "gma_drm.h" | ||
24 | #include "psb_drv.h" | ||
25 | #include "psb_reg.h" | ||
26 | #include "psb_intel_reg.h" | ||
27 | #include "intel_bios.h" | ||
28 | #include "cdv_device.h" | ||
29 | |||
30 | #define VGA_SR_INDEX 0x3c4 | ||
31 | #define VGA_SR_DATA 0x3c5 | ||
32 | |||
33 | static void cdv_disable_vga(struct drm_device *dev) | ||
34 | { | ||
35 | u8 sr1; | ||
36 | u32 vga_reg; | ||
37 | |||
38 | vga_reg = VGACNTRL; | ||
39 | |||
40 | outb(1, VGA_SR_INDEX); | ||
41 | sr1 = inb(VGA_SR_DATA); | ||
42 | outb(sr1 | 1<<5, VGA_SR_DATA); | ||
43 | udelay(300); | ||
44 | |||
45 | REG_WRITE(vga_reg, VGA_DISP_DISABLE); | ||
46 | REG_READ(vga_reg); | ||
47 | } | ||
48 | |||
49 | static int cdv_output_init(struct drm_device *dev) | ||
50 | { | ||
51 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
52 | cdv_disable_vga(dev); | ||
53 | |||
54 | cdv_intel_crt_init(dev, &dev_priv->mode_dev); | ||
55 | cdv_intel_lvds_init(dev, &dev_priv->mode_dev); | ||
56 | |||
57 | /* These bits indicate HDMI not SDVO on CDV, but we don't yet support | ||
58 | the HDMI interface */ | ||
59 | if (REG_READ(SDVOB) & SDVO_DETECTED) | ||
60 | cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOB); | ||
61 | if (REG_READ(SDVOC) & SDVO_DETECTED) | ||
62 | cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOC); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
67 | |||
68 | /* | ||
69 | * Poulsbo Backlight Interfaces | ||
70 | */ | ||
71 | |||
72 | #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ | ||
73 | #define BLC_PWM_FREQ_CALC_CONSTANT 32 | ||
74 | #define MHz 1000000 | ||
75 | |||
76 | #define PSB_BLC_PWM_PRECISION_FACTOR 10 | ||
77 | #define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE | ||
78 | #define PSB_BLC_MIN_PWM_REG_FREQ 0x2 | ||
79 | |||
80 | #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) | ||
81 | #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) | ||
82 | |||
83 | static int cdv_brightness; | ||
84 | static struct backlight_device *cdv_backlight_device; | ||
85 | |||
86 | static int cdv_get_brightness(struct backlight_device *bd) | ||
87 | { | ||
88 | /* return locally cached var instead of HW read (due to DPST etc.) */ | ||
89 | /* FIXME: ideally return actual value in case firmware fiddled with | ||
90 | it */ | ||
91 | return cdv_brightness; | ||
92 | } | ||
93 | |||
94 | |||
95 | static int cdv_backlight_setup(struct drm_device *dev) | ||
96 | { | ||
97 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
98 | unsigned long core_clock; | ||
99 | /* u32 bl_max_freq; */ | ||
100 | /* unsigned long value; */ | ||
101 | u16 bl_max_freq; | ||
102 | uint32_t value; | ||
103 | uint32_t blc_pwm_precision_factor; | ||
104 | |||
105 | /* get bl_max_freq and pol from dev_priv*/ | ||
106 | if (!dev_priv->lvds_bl) { | ||
107 | dev_err(dev->dev, "Has no valid LVDS backlight info\n"); | ||
108 | return -ENOENT; | ||
109 | } | ||
110 | bl_max_freq = dev_priv->lvds_bl->freq; | ||
111 | blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR; | ||
112 | |||
113 | core_clock = dev_priv->core_freq; | ||
114 | |||
115 | value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; | ||
116 | value *= blc_pwm_precision_factor; | ||
117 | value /= bl_max_freq; | ||
118 | value /= blc_pwm_precision_factor; | ||
119 | |||
120 | if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ || | ||
121 | value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ) | ||
122 | return -ERANGE; | ||
123 | else { | ||
124 | /* FIXME */ | ||
125 | } | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int cdv_set_brightness(struct backlight_device *bd) | ||
130 | { | ||
131 | int level = bd->props.brightness; | ||
132 | |||
133 | /* Percentage 1-100% being valid */ | ||
134 | if (level < 1) | ||
135 | level = 1; | ||
136 | |||
137 | /*cdv_intel_lvds_set_brightness(dev, level); FIXME */ | ||
138 | cdv_brightness = level; | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static const struct backlight_ops cdv_ops = { | ||
143 | .get_brightness = cdv_get_brightness, | ||
144 | .update_status = cdv_set_brightness, | ||
145 | }; | ||
146 | |||
147 | static int cdv_backlight_init(struct drm_device *dev) | ||
148 | { | ||
149 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
150 | int ret; | ||
151 | struct backlight_properties props; | ||
152 | |||
153 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
154 | props.max_brightness = 100; | ||
155 | props.type = BACKLIGHT_PLATFORM; | ||
156 | |||
157 | cdv_backlight_device = backlight_device_register("psb-bl", | ||
158 | NULL, (void *)dev, &cdv_ops, &props); | ||
159 | if (IS_ERR(cdv_backlight_device)) | ||
160 | return PTR_ERR(cdv_backlight_device); | ||
161 | |||
162 | ret = cdv_backlight_setup(dev); | ||
163 | if (ret < 0) { | ||
164 | backlight_device_unregister(cdv_backlight_device); | ||
165 | cdv_backlight_device = NULL; | ||
166 | return ret; | ||
167 | } | ||
168 | cdv_backlight_device->props.brightness = 100; | ||
169 | cdv_backlight_device->props.max_brightness = 100; | ||
170 | backlight_update_status(cdv_backlight_device); | ||
171 | dev_priv->backlight_device = cdv_backlight_device; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | #endif | ||
176 | |||
177 | /* | ||
178 | * Provide the Cedarview specific chip logic and low level methods | ||
179 | * for power management | ||
180 | * | ||
181 | * FIXME: we need to implement the apm/ospm base management bits | ||
182 | * for this and the MID devices. | ||
183 | */ | ||
184 | |||
185 | static inline u32 CDV_MSG_READ32(uint port, uint offset) | ||
186 | { | ||
187 | int mcr = (0x10<<24) | (port << 16) | (offset << 8); | ||
188 | uint32_t ret_val = 0; | ||
189 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | ||
190 | pci_write_config_dword(pci_root, 0xD0, mcr); | ||
191 | pci_read_config_dword(pci_root, 0xD4, &ret_val); | ||
192 | pci_dev_put(pci_root); | ||
193 | return ret_val; | ||
194 | } | ||
195 | |||
196 | static inline void CDV_MSG_WRITE32(uint port, uint offset, u32 value) | ||
197 | { | ||
198 | int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0; | ||
199 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | ||
200 | pci_write_config_dword(pci_root, 0xD4, value); | ||
201 | pci_write_config_dword(pci_root, 0xD0, mcr); | ||
202 | pci_dev_put(pci_root); | ||
203 | } | ||
204 | |||
205 | #define PSB_APM_CMD 0x0 | ||
206 | #define PSB_APM_STS 0x04 | ||
207 | #define PSB_PM_SSC 0x20 | ||
208 | #define PSB_PM_SSS 0x30 | ||
209 | #define PSB_PWRGT_GFX_MASK 0x3 | ||
210 | #define CDV_PWRGT_DISPLAY_CNTR 0x000fc00c | ||
211 | #define CDV_PWRGT_DISPLAY_STS 0x000fc00c | ||
212 | |||
213 | static void cdv_init_pm(struct drm_device *dev) | ||
214 | { | ||
215 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
216 | u32 pwr_cnt; | ||
217 | int i; | ||
218 | |||
219 | dev_priv->apm_base = CDV_MSG_READ32(PSB_PUNIT_PORT, | ||
220 | PSB_APMBA) & 0xFFFF; | ||
221 | dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT, | ||
222 | PSB_OSPMBA) & 0xFFFF; | ||
223 | |||
224 | /* Force power on for now */ | ||
225 | pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD); | ||
226 | pwr_cnt &= ~PSB_PWRGT_GFX_MASK; | ||
227 | |||
228 | outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD); | ||
229 | for (i = 0; i < 5; i++) { | ||
230 | u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS); | ||
231 | if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0) | ||
232 | break; | ||
233 | udelay(10); | ||
234 | } | ||
235 | pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC); | ||
236 | pwr_cnt &= ~CDV_PWRGT_DISPLAY_CNTR; | ||
237 | outl(pwr_cnt, dev_priv->ospm_base + PSB_PM_SSC); | ||
238 | for (i = 0; i < 5; i++) { | ||
239 | u32 pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS); | ||
240 | if ((pwr_sts & CDV_PWRGT_DISPLAY_STS) == 0) | ||
241 | break; | ||
242 | udelay(10); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /** | ||
247 | * cdv_save_display_registers - save registers lost on suspend | ||
248 | * @dev: our DRM device | ||
249 | * | ||
250 | * Save the state we need in order to be able to restore the interface | ||
251 | * upon resume from suspend | ||
252 | * | ||
253 | * FIXME: review | ||
254 | */ | ||
255 | static int cdv_save_display_registers(struct drm_device *dev) | ||
256 | { | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * cdv_restore_display_registers - restore lost register state | ||
262 | * @dev: our DRM device | ||
263 | * | ||
264 | * Restore register state that was lost during suspend and resume. | ||
265 | * | ||
266 | * FIXME: review | ||
267 | */ | ||
268 | static int cdv_restore_display_registers(struct drm_device *dev) | ||
269 | { | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int cdv_power_down(struct drm_device *dev) | ||
274 | { | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int cdv_power_up(struct drm_device *dev) | ||
279 | { | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /* FIXME ? - shared with Poulsbo */ | ||
284 | static void cdv_get_core_freq(struct drm_device *dev) | ||
285 | { | ||
286 | uint32_t clock; | ||
287 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | ||
288 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
289 | |||
290 | pci_write_config_dword(pci_root, 0xD0, 0xD0050300); | ||
291 | pci_read_config_dword(pci_root, 0xD4, &clock); | ||
292 | pci_dev_put(pci_root); | ||
293 | |||
294 | switch (clock & 0x07) { | ||
295 | case 0: | ||
296 | dev_priv->core_freq = 100; | ||
297 | break; | ||
298 | case 1: | ||
299 | dev_priv->core_freq = 133; | ||
300 | break; | ||
301 | case 2: | ||
302 | dev_priv->core_freq = 150; | ||
303 | break; | ||
304 | case 3: | ||
305 | dev_priv->core_freq = 178; | ||
306 | break; | ||
307 | case 4: | ||
308 | dev_priv->core_freq = 200; | ||
309 | break; | ||
310 | case 5: | ||
311 | case 6: | ||
312 | case 7: | ||
313 | dev_priv->core_freq = 266; | ||
314 | default: | ||
315 | dev_priv->core_freq = 0; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | static int cdv_chip_setup(struct drm_device *dev) | ||
320 | { | ||
321 | cdv_get_core_freq(dev); | ||
322 | gma_intel_opregion_init(dev); | ||
323 | psb_intel_init_bios(dev); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | /* CDV is much like Poulsbo but has MID like SGX offsets and PM */ | ||
328 | |||
329 | const struct psb_ops cdv_chip_ops = { | ||
330 | .name = "GMA3600/3650", | ||
331 | .accel_2d = 0, | ||
332 | .pipes = 2, | ||
333 | .crtcs = 2, | ||
334 | .sgx_offset = MRST_SGX_OFFSET, | ||
335 | .chip_setup = cdv_chip_setup, | ||
336 | |||
337 | .crtc_helper = &cdv_intel_helper_funcs, | ||
338 | .crtc_funcs = &cdv_intel_crtc_funcs, | ||
339 | |||
340 | .output_init = cdv_output_init, | ||
341 | |||
342 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
343 | .backlight_init = cdv_backlight_init, | ||
344 | #endif | ||
345 | |||
346 | .init_pm = cdv_init_pm, | ||
347 | .save_regs = cdv_save_display_registers, | ||
348 | .restore_regs = cdv_restore_display_registers, | ||
349 | .power_down = cdv_power_down, | ||
350 | .power_up = cdv_power_up, | ||
351 | }; | ||
diff --git a/drivers/gpu/drm/gma500/cdv_device.h b/drivers/gpu/drm/gma500/cdv_device.h new file mode 100644 index 00000000000..2a88b7beb55 --- /dev/null +++ b/drivers/gpu/drm/gma500/cdv_device.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright © 2011 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | */ | ||
17 | |||
18 | extern const struct drm_crtc_helper_funcs cdv_intel_helper_funcs; | ||
19 | extern const struct drm_crtc_funcs cdv_intel_crtc_funcs; | ||
20 | extern void cdv_intel_crt_init(struct drm_device *dev, | ||
21 | struct psb_intel_mode_device *mode_dev); | ||
22 | extern void cdv_intel_lvds_init(struct drm_device *dev, | ||
23 | struct psb_intel_mode_device *mode_dev); | ||
24 | extern void cdv_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, | ||
25 | int reg); | ||
26 | extern struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev, | ||
27 | struct drm_crtc *crtc); | ||
28 | |||
29 | extern inline void cdv_intel_wait_for_vblank(struct drm_device *dev) | ||
30 | { | ||
31 | /* Wait for 20ms, i.e. one cycle at 50hz. */ | ||
32 | /* FIXME: msleep ?? */ | ||
33 | mdelay(20); | ||
34 | } | ||
35 | |||
36 | |||
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c new file mode 100644 index 00000000000..6d0f10b7569 --- /dev/null +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c | |||
@@ -0,0 +1,333 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | */ | ||
26 | |||
27 | #include <linux/i2c.h> | ||
28 | #include <drm/drmP.h> | ||
29 | |||
30 | #include "intel_bios.h" | ||
31 | #include "psb_drv.h" | ||
32 | #include "psb_intel_drv.h" | ||
33 | #include "psb_intel_reg.h" | ||
34 | #include "power.h" | ||
35 | #include <linux/pm_runtime.h> | ||
36 | |||
37 | |||
38 | static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) | ||
39 | { | ||
40 | struct drm_device *dev = encoder->dev; | ||
41 | u32 temp, reg; | ||
42 | reg = ADPA; | ||
43 | |||
44 | temp = REG_READ(reg); | ||
45 | temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); | ||
46 | temp &= ~ADPA_DAC_ENABLE; | ||
47 | |||
48 | switch (mode) { | ||
49 | case DRM_MODE_DPMS_ON: | ||
50 | temp |= ADPA_DAC_ENABLE; | ||
51 | break; | ||
52 | case DRM_MODE_DPMS_STANDBY: | ||
53 | temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; | ||
54 | break; | ||
55 | case DRM_MODE_DPMS_SUSPEND: | ||
56 | temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; | ||
57 | break; | ||
58 | case DRM_MODE_DPMS_OFF: | ||
59 | temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; | ||
60 | break; | ||
61 | } | ||
62 | |||
63 | REG_WRITE(reg, temp); | ||
64 | } | ||
65 | |||
66 | static int cdv_intel_crt_mode_valid(struct drm_connector *connector, | ||
67 | struct drm_display_mode *mode) | ||
68 | { | ||
69 | int max_clock = 0; | ||
70 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
71 | return MODE_NO_DBLESCAN; | ||
72 | |||
73 | /* The lowest clock for CDV is 20000KHz */ | ||
74 | if (mode->clock < 20000) | ||
75 | return MODE_CLOCK_LOW; | ||
76 | |||
77 | /* The max clock for CDV is 355 instead of 400 */ | ||
78 | max_clock = 355000; | ||
79 | if (mode->clock > max_clock) | ||
80 | return MODE_CLOCK_HIGH; | ||
81 | |||
82 | if (mode->hdisplay > 1680 || mode->vdisplay > 1050) | ||
83 | return MODE_PANEL; | ||
84 | |||
85 | return MODE_OK; | ||
86 | } | ||
87 | |||
88 | static bool cdv_intel_crt_mode_fixup(struct drm_encoder *encoder, | ||
89 | struct drm_display_mode *mode, | ||
90 | struct drm_display_mode *adjusted_mode) | ||
91 | { | ||
92 | return true; | ||
93 | } | ||
94 | |||
95 | static void cdv_intel_crt_mode_set(struct drm_encoder *encoder, | ||
96 | struct drm_display_mode *mode, | ||
97 | struct drm_display_mode *adjusted_mode) | ||
98 | { | ||
99 | |||
100 | struct drm_device *dev = encoder->dev; | ||
101 | struct drm_crtc *crtc = encoder->crtc; | ||
102 | struct psb_intel_crtc *psb_intel_crtc = | ||
103 | to_psb_intel_crtc(crtc); | ||
104 | int dpll_md_reg; | ||
105 | u32 adpa, dpll_md; | ||
106 | u32 adpa_reg; | ||
107 | |||
108 | if (psb_intel_crtc->pipe == 0) | ||
109 | dpll_md_reg = DPLL_A_MD; | ||
110 | else | ||
111 | dpll_md_reg = DPLL_B_MD; | ||
112 | |||
113 | adpa_reg = ADPA; | ||
114 | |||
115 | /* | ||
116 | * Disable separate mode multiplier used when cloning SDVO to CRT | ||
117 | * XXX this needs to be adjusted when we really are cloning | ||
118 | */ | ||
119 | { | ||
120 | dpll_md = REG_READ(dpll_md_reg); | ||
121 | REG_WRITE(dpll_md_reg, | ||
122 | dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); | ||
123 | } | ||
124 | |||
125 | adpa = 0; | ||
126 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
127 | adpa |= ADPA_HSYNC_ACTIVE_HIGH; | ||
128 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
129 | adpa |= ADPA_VSYNC_ACTIVE_HIGH; | ||
130 | |||
131 | if (psb_intel_crtc->pipe == 0) | ||
132 | adpa |= ADPA_PIPE_A_SELECT; | ||
133 | else | ||
134 | adpa |= ADPA_PIPE_B_SELECT; | ||
135 | |||
136 | REG_WRITE(adpa_reg, adpa); | ||
137 | } | ||
138 | |||
139 | |||
140 | /** | ||
141 | * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. | ||
142 | * | ||
143 | * \return true if CRT is connected. | ||
144 | * \return false if CRT is disconnected. | ||
145 | */ | ||
146 | static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector, | ||
147 | bool force) | ||
148 | { | ||
149 | struct drm_device *dev = connector->dev; | ||
150 | u32 hotplug_en; | ||
151 | int i, tries = 0, ret = false; | ||
152 | u32 adpa_orig; | ||
153 | |||
154 | /* disable the DAC when doing the hotplug detection */ | ||
155 | |||
156 | adpa_orig = REG_READ(ADPA); | ||
157 | |||
158 | REG_WRITE(ADPA, adpa_orig & ~(ADPA_DAC_ENABLE)); | ||
159 | |||
160 | /* | ||
161 | * On a CDV thep, CRT detect sequence need to be done twice | ||
162 | * to get a reliable result. | ||
163 | */ | ||
164 | tries = 2; | ||
165 | |||
166 | hotplug_en = REG_READ(PORT_HOTPLUG_EN); | ||
167 | hotplug_en &= ~(CRT_HOTPLUG_DETECT_MASK); | ||
168 | hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; | ||
169 | |||
170 | hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; | ||
171 | hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; | ||
172 | |||
173 | for (i = 0; i < tries ; i++) { | ||
174 | unsigned long timeout; | ||
175 | /* turn on the FORCE_DETECT */ | ||
176 | REG_WRITE(PORT_HOTPLUG_EN, hotplug_en); | ||
177 | timeout = jiffies + msecs_to_jiffies(1000); | ||
178 | /* wait for FORCE_DETECT to go off */ | ||
179 | do { | ||
180 | if (!(REG_READ(PORT_HOTPLUG_EN) & | ||
181 | CRT_HOTPLUG_FORCE_DETECT)) | ||
182 | break; | ||
183 | msleep(1); | ||
184 | } while (time_after(timeout, jiffies)); | ||
185 | } | ||
186 | |||
187 | if ((REG_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) != | ||
188 | CRT_HOTPLUG_MONITOR_NONE) | ||
189 | ret = true; | ||
190 | |||
191 | /* Restore the saved ADPA */ | ||
192 | REG_WRITE(ADPA, adpa_orig); | ||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | static enum drm_connector_status cdv_intel_crt_detect( | ||
197 | struct drm_connector *connector, bool force) | ||
198 | { | ||
199 | if (cdv_intel_crt_detect_hotplug(connector, force)) | ||
200 | return connector_status_connected; | ||
201 | else | ||
202 | return connector_status_disconnected; | ||
203 | } | ||
204 | |||
205 | static void cdv_intel_crt_destroy(struct drm_connector *connector) | ||
206 | { | ||
207 | struct psb_intel_encoder *psb_intel_encoder = | ||
208 | psb_intel_attached_encoder(connector); | ||
209 | |||
210 | psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); | ||
211 | drm_sysfs_connector_remove(connector); | ||
212 | drm_connector_cleanup(connector); | ||
213 | kfree(connector); | ||
214 | } | ||
215 | |||
216 | static int cdv_intel_crt_get_modes(struct drm_connector *connector) | ||
217 | { | ||
218 | struct psb_intel_encoder *psb_intel_encoder = | ||
219 | psb_intel_attached_encoder(connector); | ||
220 | return psb_intel_ddc_get_modes(connector, &psb_intel_encoder->ddc_bus->adapter); | ||
221 | } | ||
222 | |||
223 | static int cdv_intel_crt_set_property(struct drm_connector *connector, | ||
224 | struct drm_property *property, | ||
225 | uint64_t value) | ||
226 | { | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Routines for controlling stuff on the analog port | ||
232 | */ | ||
233 | |||
234 | static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = { | ||
235 | .dpms = cdv_intel_crt_dpms, | ||
236 | .mode_fixup = cdv_intel_crt_mode_fixup, | ||
237 | .prepare = psb_intel_encoder_prepare, | ||
238 | .commit = psb_intel_encoder_commit, | ||
239 | .mode_set = cdv_intel_crt_mode_set, | ||
240 | }; | ||
241 | |||
242 | static const struct drm_connector_funcs cdv_intel_crt_connector_funcs = { | ||
243 | .dpms = drm_helper_connector_dpms, | ||
244 | .detect = cdv_intel_crt_detect, | ||
245 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
246 | .destroy = cdv_intel_crt_destroy, | ||
247 | .set_property = cdv_intel_crt_set_property, | ||
248 | }; | ||
249 | |||
250 | static const struct drm_connector_helper_funcs | ||
251 | cdv_intel_crt_connector_helper_funcs = { | ||
252 | .mode_valid = cdv_intel_crt_mode_valid, | ||
253 | .get_modes = cdv_intel_crt_get_modes, | ||
254 | .best_encoder = psb_intel_best_encoder, | ||
255 | }; | ||
256 | |||
257 | static void cdv_intel_crt_enc_destroy(struct drm_encoder *encoder) | ||
258 | { | ||
259 | drm_encoder_cleanup(encoder); | ||
260 | } | ||
261 | |||
262 | static const struct drm_encoder_funcs cdv_intel_crt_enc_funcs = { | ||
263 | .destroy = cdv_intel_crt_enc_destroy, | ||
264 | }; | ||
265 | |||
266 | void cdv_intel_crt_init(struct drm_device *dev, | ||
267 | struct psb_intel_mode_device *mode_dev) | ||
268 | { | ||
269 | |||
270 | struct psb_intel_connector *psb_intel_connector; | ||
271 | struct psb_intel_encoder *psb_intel_encoder; | ||
272 | struct drm_connector *connector; | ||
273 | struct drm_encoder *encoder; | ||
274 | |||
275 | u32 i2c_reg; | ||
276 | |||
277 | psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); | ||
278 | if (!psb_intel_encoder) | ||
279 | return; | ||
280 | |||
281 | psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); | ||
282 | if (!psb_intel_connector) | ||
283 | goto failed_connector; | ||
284 | |||
285 | connector = &psb_intel_connector->base; | ||
286 | drm_connector_init(dev, connector, | ||
287 | &cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||
288 | |||
289 | encoder = &psb_intel_encoder->base; | ||
290 | drm_encoder_init(dev, encoder, | ||
291 | &cdv_intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); | ||
292 | |||
293 | psb_intel_connector_attach_encoder(psb_intel_connector, | ||
294 | psb_intel_encoder); | ||
295 | |||
296 | /* Set up the DDC bus. */ | ||
297 | i2c_reg = GPIOA; | ||
298 | /* Remove the following code for CDV */ | ||
299 | /* | ||
300 | if (dev_priv->crt_ddc_bus != 0) | ||
301 | i2c_reg = dev_priv->crt_ddc_bus; | ||
302 | }*/ | ||
303 | psb_intel_encoder->ddc_bus = psb_intel_i2c_create(dev, | ||
304 | i2c_reg, "CRTDDC_A"); | ||
305 | if (!psb_intel_encoder->ddc_bus) { | ||
306 | dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " | ||
307 | "failed.\n"); | ||
308 | goto failed_ddc; | ||
309 | } | ||
310 | |||
311 | psb_intel_encoder->type = INTEL_OUTPUT_ANALOG; | ||
312 | /* | ||
313 | psb_intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT); | ||
314 | psb_intel_output->crtc_mask = (1 << 0) | (1 << 1); | ||
315 | */ | ||
316 | connector->interlace_allowed = 0; | ||
317 | connector->doublescan_allowed = 0; | ||
318 | |||
319 | drm_encoder_helper_add(encoder, &cdv_intel_crt_helper_funcs); | ||
320 | drm_connector_helper_add(connector, | ||
321 | &cdv_intel_crt_connector_helper_funcs); | ||
322 | |||
323 | drm_sysfs_connector_add(connector); | ||
324 | |||
325 | return; | ||
326 | failed_ddc: | ||
327 | drm_encoder_cleanup(&psb_intel_encoder->base); | ||
328 | drm_connector_cleanup(&psb_intel_connector->base); | ||
329 | kfree(psb_intel_connector); | ||
330 | failed_connector: | ||
331 | kfree(psb_intel_encoder); | ||
332 | return; | ||
333 | } | ||
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c new file mode 100644 index 00000000000..18d11525095 --- /dev/null +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c | |||
@@ -0,0 +1,1508 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2011 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | |||
24 | #include <drm/drmP.h> | ||
25 | #include "framebuffer.h" | ||
26 | #include "psb_drv.h" | ||
27 | #include "psb_intel_drv.h" | ||
28 | #include "psb_intel_reg.h" | ||
29 | #include "psb_intel_display.h" | ||
30 | #include "power.h" | ||
31 | #include "cdv_device.h" | ||
32 | |||
33 | |||
34 | struct cdv_intel_range_t { | ||
35 | int min, max; | ||
36 | }; | ||
37 | |||
38 | struct cdv_intel_p2_t { | ||
39 | int dot_limit; | ||
40 | int p2_slow, p2_fast; | ||
41 | }; | ||
42 | |||
43 | struct cdv_intel_clock_t { | ||
44 | /* given values */ | ||
45 | int n; | ||
46 | int m1, m2; | ||
47 | int p1, p2; | ||
48 | /* derived values */ | ||
49 | int dot; | ||
50 | int vco; | ||
51 | int m; | ||
52 | int p; | ||
53 | }; | ||
54 | |||
55 | #define INTEL_P2_NUM 2 | ||
56 | |||
57 | struct cdv_intel_limit_t { | ||
58 | struct cdv_intel_range_t dot, vco, n, m, m1, m2, p, p1; | ||
59 | struct cdv_intel_p2_t p2; | ||
60 | }; | ||
61 | |||
62 | #define CDV_LIMIT_SINGLE_LVDS_96 0 | ||
63 | #define CDV_LIMIT_SINGLE_LVDS_100 1 | ||
64 | #define CDV_LIMIT_DAC_HDMI_27 2 | ||
65 | #define CDV_LIMIT_DAC_HDMI_96 3 | ||
66 | |||
67 | static const struct cdv_intel_limit_t cdv_intel_limits[] = { | ||
68 | { /* CDV_SIGNLE_LVDS_96MHz */ | ||
69 | .dot = {.min = 20000, .max = 115500}, | ||
70 | .vco = {.min = 1800000, .max = 3600000}, | ||
71 | .n = {.min = 2, .max = 6}, | ||
72 | .m = {.min = 60, .max = 160}, | ||
73 | .m1 = {.min = 0, .max = 0}, | ||
74 | .m2 = {.min = 58, .max = 158}, | ||
75 | .p = {.min = 28, .max = 140}, | ||
76 | .p1 = {.min = 2, .max = 10}, | ||
77 | .p2 = {.dot_limit = 200000, | ||
78 | .p2_slow = 14, .p2_fast = 14}, | ||
79 | }, | ||
80 | { /* CDV_SINGLE_LVDS_100MHz */ | ||
81 | .dot = {.min = 20000, .max = 115500}, | ||
82 | .vco = {.min = 1800000, .max = 3600000}, | ||
83 | .n = {.min = 2, .max = 6}, | ||
84 | .m = {.min = 60, .max = 160}, | ||
85 | .m1 = {.min = 0, .max = 0}, | ||
86 | .m2 = {.min = 58, .max = 158}, | ||
87 | .p = {.min = 28, .max = 140}, | ||
88 | .p1 = {.min = 2, .max = 10}, | ||
89 | /* The single-channel range is 25-112Mhz, and dual-channel | ||
90 | * is 80-224Mhz. Prefer single channel as much as possible. | ||
91 | */ | ||
92 | .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14}, | ||
93 | }, | ||
94 | { /* CDV_DAC_HDMI_27MHz */ | ||
95 | .dot = {.min = 20000, .max = 400000}, | ||
96 | .vco = {.min = 1809000, .max = 3564000}, | ||
97 | .n = {.min = 1, .max = 1}, | ||
98 | .m = {.min = 67, .max = 132}, | ||
99 | .m1 = {.min = 0, .max = 0}, | ||
100 | .m2 = {.min = 65, .max = 130}, | ||
101 | .p = {.min = 5, .max = 90}, | ||
102 | .p1 = {.min = 1, .max = 9}, | ||
103 | .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, | ||
104 | }, | ||
105 | { /* CDV_DAC_HDMI_96MHz */ | ||
106 | .dot = {.min = 20000, .max = 400000}, | ||
107 | .vco = {.min = 1800000, .max = 3600000}, | ||
108 | .n = {.min = 2, .max = 6}, | ||
109 | .m = {.min = 60, .max = 160}, | ||
110 | .m1 = {.min = 0, .max = 0}, | ||
111 | .m2 = {.min = 58, .max = 158}, | ||
112 | .p = {.min = 5, .max = 100}, | ||
113 | .p1 = {.min = 1, .max = 10}, | ||
114 | .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, | ||
115 | }, | ||
116 | }; | ||
117 | |||
118 | #define _wait_for(COND, MS, W) ({ \ | ||
119 | unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ | ||
120 | int ret__ = 0; \ | ||
121 | while (!(COND)) { \ | ||
122 | if (time_after(jiffies, timeout__)) { \ | ||
123 | ret__ = -ETIMEDOUT; \ | ||
124 | break; \ | ||
125 | } \ | ||
126 | if (W && !in_dbg_master()) \ | ||
127 | msleep(W); \ | ||
128 | } \ | ||
129 | ret__; \ | ||
130 | }) | ||
131 | |||
132 | #define wait_for(COND, MS) _wait_for(COND, MS, 1) | ||
133 | |||
134 | |||
135 | static int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val) | ||
136 | { | ||
137 | int ret; | ||
138 | |||
139 | ret = wait_for((REG_READ(SB_PCKT) & SB_BUSY) == 0, 1000); | ||
140 | if (ret) { | ||
141 | DRM_ERROR("timeout waiting for SB to idle before read\n"); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | REG_WRITE(SB_ADDR, reg); | ||
146 | REG_WRITE(SB_PCKT, | ||
147 | SET_FIELD(SB_OPCODE_READ, SB_OPCODE) | | ||
148 | SET_FIELD(SB_DEST_DPLL, SB_DEST) | | ||
149 | SET_FIELD(0xf, SB_BYTE_ENABLE)); | ||
150 | |||
151 | ret = wait_for((REG_READ(SB_PCKT) & SB_BUSY) == 0, 1000); | ||
152 | if (ret) { | ||
153 | DRM_ERROR("timeout waiting for SB to idle after read\n"); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | *val = REG_READ(SB_DATA); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val) | ||
163 | { | ||
164 | int ret; | ||
165 | static bool dpio_debug = true; | ||
166 | u32 temp; | ||
167 | |||
168 | if (dpio_debug) { | ||
169 | if (cdv_sb_read(dev, reg, &temp) == 0) | ||
170 | DRM_DEBUG_KMS("0x%08x: 0x%08x (before)\n", reg, temp); | ||
171 | DRM_DEBUG_KMS("0x%08x: 0x%08x\n", reg, val); | ||
172 | } | ||
173 | |||
174 | ret = wait_for((REG_READ(SB_PCKT) & SB_BUSY) == 0, 1000); | ||
175 | if (ret) { | ||
176 | DRM_ERROR("timeout waiting for SB to idle before write\n"); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | REG_WRITE(SB_ADDR, reg); | ||
181 | REG_WRITE(SB_DATA, val); | ||
182 | REG_WRITE(SB_PCKT, | ||
183 | SET_FIELD(SB_OPCODE_WRITE, SB_OPCODE) | | ||
184 | SET_FIELD(SB_DEST_DPLL, SB_DEST) | | ||
185 | SET_FIELD(0xf, SB_BYTE_ENABLE)); | ||
186 | |||
187 | ret = wait_for((REG_READ(SB_PCKT) & SB_BUSY) == 0, 1000); | ||
188 | if (ret) { | ||
189 | DRM_ERROR("timeout waiting for SB to idle after write\n"); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | if (dpio_debug) { | ||
194 | if (cdv_sb_read(dev, reg, &temp) == 0) | ||
195 | DRM_DEBUG_KMS("0x%08x: 0x%08x (after)\n", reg, temp); | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | /* Reset the DPIO configuration register. The BIOS does this at every | ||
202 | * mode set. | ||
203 | */ | ||
204 | static void cdv_sb_reset(struct drm_device *dev) | ||
205 | { | ||
206 | |||
207 | REG_WRITE(DPIO_CFG, 0); | ||
208 | REG_READ(DPIO_CFG); | ||
209 | REG_WRITE(DPIO_CFG, DPIO_MODE_SELECT_0 | DPIO_CMN_RESET_N); | ||
210 | } | ||
211 | |||
212 | /* Unlike most Intel display engines, on Cedarview the DPLL registers | ||
213 | * are behind this sideband bus. They must be programmed while the | ||
214 | * DPLL reference clock is on in the DPLL control register, but before | ||
215 | * the DPLL is enabled in the DPLL control register. | ||
216 | */ | ||
217 | static int | ||
218 | cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, | ||
219 | struct cdv_intel_clock_t *clock) | ||
220 | { | ||
221 | struct psb_intel_crtc *psb_crtc = | ||
222 | to_psb_intel_crtc(crtc); | ||
223 | int pipe = psb_crtc->pipe; | ||
224 | u32 m, n_vco, p; | ||
225 | int ret = 0; | ||
226 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
227 | u32 ref_value; | ||
228 | |||
229 | cdv_sb_reset(dev); | ||
230 | |||
231 | if ((REG_READ(dpll_reg) & DPLL_SYNCLOCK_ENABLE) == 0) { | ||
232 | DRM_ERROR("Attempting to set DPLL with refclk disabled\n"); | ||
233 | return -EBUSY; | ||
234 | } | ||
235 | |||
236 | /* Follow the BIOS and write the REF/SFR Register. Hardcoded value */ | ||
237 | ref_value = 0x68A701; | ||
238 | |||
239 | cdv_sb_write(dev, SB_REF_SFR(pipe), ref_value); | ||
240 | |||
241 | /* We don't know what the other fields of these regs are, so | ||
242 | * leave them in place. | ||
243 | */ | ||
244 | ret = cdv_sb_read(dev, SB_M(pipe), &m); | ||
245 | if (ret) | ||
246 | return ret; | ||
247 | m &= ~SB_M_DIVIDER_MASK; | ||
248 | m |= ((clock->m2) << SB_M_DIVIDER_SHIFT); | ||
249 | ret = cdv_sb_write(dev, SB_M(pipe), m); | ||
250 | if (ret) | ||
251 | return ret; | ||
252 | |||
253 | ret = cdv_sb_read(dev, SB_N_VCO(pipe), &n_vco); | ||
254 | if (ret) | ||
255 | return ret; | ||
256 | |||
257 | /* Follow the BIOS to program the N_DIVIDER REG */ | ||
258 | n_vco &= 0xFFFF; | ||
259 | n_vco |= 0x107; | ||
260 | n_vco &= ~(SB_N_VCO_SEL_MASK | | ||
261 | SB_N_DIVIDER_MASK | | ||
262 | SB_N_CB_TUNE_MASK); | ||
263 | |||
264 | n_vco |= ((clock->n) << SB_N_DIVIDER_SHIFT); | ||
265 | |||
266 | if (clock->vco < 2250000) { | ||
267 | n_vco |= (2 << SB_N_CB_TUNE_SHIFT); | ||
268 | n_vco |= (0 << SB_N_VCO_SEL_SHIFT); | ||
269 | } else if (clock->vco < 2750000) { | ||
270 | n_vco |= (1 << SB_N_CB_TUNE_SHIFT); | ||
271 | n_vco |= (1 << SB_N_VCO_SEL_SHIFT); | ||
272 | } else if (clock->vco < 3300000) { | ||
273 | n_vco |= (0 << SB_N_CB_TUNE_SHIFT); | ||
274 | n_vco |= (2 << SB_N_VCO_SEL_SHIFT); | ||
275 | } else { | ||
276 | n_vco |= (0 << SB_N_CB_TUNE_SHIFT); | ||
277 | n_vco |= (3 << SB_N_VCO_SEL_SHIFT); | ||
278 | } | ||
279 | |||
280 | ret = cdv_sb_write(dev, SB_N_VCO(pipe), n_vco); | ||
281 | if (ret) | ||
282 | return ret; | ||
283 | |||
284 | ret = cdv_sb_read(dev, SB_P(pipe), &p); | ||
285 | if (ret) | ||
286 | return ret; | ||
287 | p &= ~(SB_P2_DIVIDER_MASK | SB_P1_DIVIDER_MASK); | ||
288 | p |= SET_FIELD(clock->p1, SB_P1_DIVIDER); | ||
289 | switch (clock->p2) { | ||
290 | case 5: | ||
291 | p |= SET_FIELD(SB_P2_5, SB_P2_DIVIDER); | ||
292 | break; | ||
293 | case 10: | ||
294 | p |= SET_FIELD(SB_P2_10, SB_P2_DIVIDER); | ||
295 | break; | ||
296 | case 14: | ||
297 | p |= SET_FIELD(SB_P2_14, SB_P2_DIVIDER); | ||
298 | break; | ||
299 | case 7: | ||
300 | p |= SET_FIELD(SB_P2_7, SB_P2_DIVIDER); | ||
301 | break; | ||
302 | default: | ||
303 | DRM_ERROR("Bad P2 clock: %d\n", clock->p2); | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | ret = cdv_sb_write(dev, SB_P(pipe), p); | ||
307 | if (ret) | ||
308 | return ret; | ||
309 | |||
310 | /* always Program the Lane Register for the Pipe A*/ | ||
311 | if (pipe == 0) { | ||
312 | /* Program the Lane0/1 for HDMI B */ | ||
313 | u32 lane_reg, lane_value; | ||
314 | |||
315 | lane_reg = PSB_LANE0; | ||
316 | cdv_sb_read(dev, lane_reg, &lane_value); | ||
317 | lane_value &= ~(LANE_PLL_MASK); | ||
318 | lane_value |= LANE_PLL_ENABLE; | ||
319 | cdv_sb_write(dev, lane_reg, lane_value); | ||
320 | |||
321 | lane_reg = PSB_LANE1; | ||
322 | cdv_sb_read(dev, lane_reg, &lane_value); | ||
323 | lane_value &= ~(LANE_PLL_MASK); | ||
324 | lane_value |= LANE_PLL_ENABLE; | ||
325 | cdv_sb_write(dev, lane_reg, lane_value); | ||
326 | |||
327 | /* Program the Lane2/3 for HDMI C */ | ||
328 | lane_reg = PSB_LANE2; | ||
329 | cdv_sb_read(dev, lane_reg, &lane_value); | ||
330 | lane_value &= ~(LANE_PLL_MASK); | ||
331 | lane_value |= LANE_PLL_ENABLE; | ||
332 | cdv_sb_write(dev, lane_reg, lane_value); | ||
333 | |||
334 | lane_reg = PSB_LANE3; | ||
335 | cdv_sb_read(dev, lane_reg, &lane_value); | ||
336 | lane_value &= ~(LANE_PLL_MASK); | ||
337 | lane_value |= LANE_PLL_ENABLE; | ||
338 | cdv_sb_write(dev, lane_reg, lane_value); | ||
339 | } | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * Returns whether any encoder on the specified pipe is of the specified type | ||
346 | */ | ||
347 | bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type) | ||
348 | { | ||
349 | struct drm_device *dev = crtc->dev; | ||
350 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
351 | struct drm_connector *l_entry; | ||
352 | |||
353 | list_for_each_entry(l_entry, &mode_config->connector_list, head) { | ||
354 | if (l_entry->encoder && l_entry->encoder->crtc == crtc) { | ||
355 | struct psb_intel_encoder *psb_intel_encoder = | ||
356 | psb_intel_attached_encoder(l_entry); | ||
357 | if (psb_intel_encoder->type == type) | ||
358 | return true; | ||
359 | } | ||
360 | } | ||
361 | return false; | ||
362 | } | ||
363 | |||
364 | static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc, | ||
365 | int refclk) | ||
366 | { | ||
367 | const struct cdv_intel_limit_t *limit; | ||
368 | if (cdv_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { | ||
369 | /* | ||
370 | * Now only single-channel LVDS is supported on CDV. If it is | ||
371 | * incorrect, please add the dual-channel LVDS. | ||
372 | */ | ||
373 | if (refclk == 96000) | ||
374 | limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_96]; | ||
375 | else | ||
376 | limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_100]; | ||
377 | } else { | ||
378 | if (refclk == 27000) | ||
379 | limit = &cdv_intel_limits[CDV_LIMIT_DAC_HDMI_27]; | ||
380 | else | ||
381 | limit = &cdv_intel_limits[CDV_LIMIT_DAC_HDMI_96]; | ||
382 | } | ||
383 | return limit; | ||
384 | } | ||
385 | |||
386 | /* m1 is reserved as 0 in CDV, n is a ring counter */ | ||
387 | static void cdv_intel_clock(struct drm_device *dev, | ||
388 | int refclk, struct cdv_intel_clock_t *clock) | ||
389 | { | ||
390 | clock->m = clock->m2 + 2; | ||
391 | clock->p = clock->p1 * clock->p2; | ||
392 | clock->vco = (refclk * clock->m) / clock->n; | ||
393 | clock->dot = clock->vco / clock->p; | ||
394 | } | ||
395 | |||
396 | |||
397 | #define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } | ||
398 | static bool cdv_intel_PLL_is_valid(struct drm_crtc *crtc, | ||
399 | const struct cdv_intel_limit_t *limit, | ||
400 | struct cdv_intel_clock_t *clock) | ||
401 | { | ||
402 | if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) | ||
403 | INTELPllInvalid("p1 out of range\n"); | ||
404 | if (clock->p < limit->p.min || limit->p.max < clock->p) | ||
405 | INTELPllInvalid("p out of range\n"); | ||
406 | /* unnecessary to check the range of m(m1/M2)/n again */ | ||
407 | if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) | ||
408 | INTELPllInvalid("vco out of range\n"); | ||
409 | /* XXX: We may need to be checking "Dot clock" | ||
410 | * depending on the multiplier, connector, etc., | ||
411 | * rather than just a single range. | ||
412 | */ | ||
413 | if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) | ||
414 | INTELPllInvalid("dot out of range\n"); | ||
415 | |||
416 | return true; | ||
417 | } | ||
418 | |||
419 | static bool cdv_intel_find_best_PLL(struct drm_crtc *crtc, int target, | ||
420 | int refclk, | ||
421 | struct cdv_intel_clock_t *best_clock) | ||
422 | { | ||
423 | struct drm_device *dev = crtc->dev; | ||
424 | struct cdv_intel_clock_t clock; | ||
425 | const struct cdv_intel_limit_t *limit = cdv_intel_limit(crtc, refclk); | ||
426 | int err = target; | ||
427 | |||
428 | |||
429 | if (cdv_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && | ||
430 | (REG_READ(LVDS) & LVDS_PORT_EN) != 0) { | ||
431 | /* | ||
432 | * For LVDS, if the panel is on, just rely on its current | ||
433 | * settings for dual-channel. We haven't figured out how to | ||
434 | * reliably set up different single/dual channel state, if we | ||
435 | * even can. | ||
436 | */ | ||
437 | if ((REG_READ(LVDS) & LVDS_CLKB_POWER_MASK) == | ||
438 | LVDS_CLKB_POWER_UP) | ||
439 | clock.p2 = limit->p2.p2_fast; | ||
440 | else | ||
441 | clock.p2 = limit->p2.p2_slow; | ||
442 | } else { | ||
443 | if (target < limit->p2.dot_limit) | ||
444 | clock.p2 = limit->p2.p2_slow; | ||
445 | else | ||
446 | clock.p2 = limit->p2.p2_fast; | ||
447 | } | ||
448 | |||
449 | memset(best_clock, 0, sizeof(*best_clock)); | ||
450 | clock.m1 = 0; | ||
451 | /* m1 is reserved as 0 in CDV, n is a ring counter. | ||
452 | So skip the m1 loop */ | ||
453 | for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) { | ||
454 | for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; | ||
455 | clock.m2++) { | ||
456 | for (clock.p1 = limit->p1.min; | ||
457 | clock.p1 <= limit->p1.max; | ||
458 | clock.p1++) { | ||
459 | int this_err; | ||
460 | |||
461 | cdv_intel_clock(dev, refclk, &clock); | ||
462 | |||
463 | if (!cdv_intel_PLL_is_valid(crtc, | ||
464 | limit, &clock)) | ||
465 | continue; | ||
466 | |||
467 | this_err = abs(clock.dot - target); | ||
468 | if (this_err < err) { | ||
469 | *best_clock = clock; | ||
470 | err = this_err; | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | |||
476 | return err != target; | ||
477 | } | ||
478 | |||
479 | int cdv_intel_pipe_set_base(struct drm_crtc *crtc, | ||
480 | int x, int y, struct drm_framebuffer *old_fb) | ||
481 | { | ||
482 | struct drm_device *dev = crtc->dev; | ||
483 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
484 | struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); | ||
485 | int pipe = psb_intel_crtc->pipe; | ||
486 | unsigned long start, offset; | ||
487 | int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); | ||
488 | int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); | ||
489 | int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; | ||
490 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
491 | u32 dspcntr; | ||
492 | int ret = 0; | ||
493 | |||
494 | if (!gma_power_begin(dev, true)) | ||
495 | return 0; | ||
496 | |||
497 | /* no fb bound */ | ||
498 | if (!crtc->fb) { | ||
499 | dev_err(dev->dev, "No FB bound\n"); | ||
500 | goto psb_intel_pipe_cleaner; | ||
501 | } | ||
502 | |||
503 | |||
504 | /* We are displaying this buffer, make sure it is actually loaded | ||
505 | into the GTT */ | ||
506 | ret = psb_gtt_pin(psbfb->gtt); | ||
507 | if (ret < 0) | ||
508 | goto psb_intel_pipe_set_base_exit; | ||
509 | start = psbfb->gtt->offset; | ||
510 | offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); | ||
511 | |||
512 | REG_WRITE(dspstride, crtc->fb->pitches[0]); | ||
513 | |||
514 | dspcntr = REG_READ(dspcntr_reg); | ||
515 | dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; | ||
516 | |||
517 | switch (crtc->fb->bits_per_pixel) { | ||
518 | case 8: | ||
519 | dspcntr |= DISPPLANE_8BPP; | ||
520 | break; | ||
521 | case 16: | ||
522 | if (crtc->fb->depth == 15) | ||
523 | dspcntr |= DISPPLANE_15_16BPP; | ||
524 | else | ||
525 | dspcntr |= DISPPLANE_16BPP; | ||
526 | break; | ||
527 | case 24: | ||
528 | case 32: | ||
529 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | ||
530 | break; | ||
531 | default: | ||
532 | dev_err(dev->dev, "Unknown color depth\n"); | ||
533 | ret = -EINVAL; | ||
534 | goto psb_intel_pipe_set_base_exit; | ||
535 | } | ||
536 | REG_WRITE(dspcntr_reg, dspcntr); | ||
537 | |||
538 | dev_dbg(dev->dev, | ||
539 | "Writing base %08lX %08lX %d %d\n", start, offset, x, y); | ||
540 | |||
541 | REG_WRITE(dspbase, offset); | ||
542 | REG_READ(dspbase); | ||
543 | REG_WRITE(dspsurf, start); | ||
544 | REG_READ(dspsurf); | ||
545 | |||
546 | psb_intel_pipe_cleaner: | ||
547 | /* If there was a previous display we can now unpin it */ | ||
548 | if (old_fb) | ||
549 | psb_gtt_unpin(to_psb_fb(old_fb)->gtt); | ||
550 | |||
551 | psb_intel_pipe_set_base_exit: | ||
552 | gma_power_end(dev); | ||
553 | return ret; | ||
554 | } | ||
555 | |||
556 | /** | ||
557 | * Sets the power management mode of the pipe and plane. | ||
558 | * | ||
559 | * This code should probably grow support for turning the cursor off and back | ||
560 | * on appropriately at the same time as we're turning the pipe off/on. | ||
561 | */ | ||
562 | static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
563 | { | ||
564 | struct drm_device *dev = crtc->dev; | ||
565 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
566 | int pipe = psb_intel_crtc->pipe; | ||
567 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
568 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
569 | int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE; | ||
570 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
571 | u32 temp; | ||
572 | bool enabled; | ||
573 | |||
574 | /* XXX: When our outputs are all unaware of DPMS modes other than off | ||
575 | * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. | ||
576 | */ | ||
577 | switch (mode) { | ||
578 | case DRM_MODE_DPMS_ON: | ||
579 | case DRM_MODE_DPMS_STANDBY: | ||
580 | case DRM_MODE_DPMS_SUSPEND: | ||
581 | /* Enable the DPLL */ | ||
582 | temp = REG_READ(dpll_reg); | ||
583 | if ((temp & DPLL_VCO_ENABLE) == 0) { | ||
584 | REG_WRITE(dpll_reg, temp); | ||
585 | REG_READ(dpll_reg); | ||
586 | /* Wait for the clocks to stabilize. */ | ||
587 | udelay(150); | ||
588 | REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
589 | REG_READ(dpll_reg); | ||
590 | /* Wait for the clocks to stabilize. */ | ||
591 | udelay(150); | ||
592 | REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
593 | REG_READ(dpll_reg); | ||
594 | /* Wait for the clocks to stabilize. */ | ||
595 | udelay(150); | ||
596 | } | ||
597 | |||
598 | /* Jim Bish - switch plan and pipe per scott */ | ||
599 | /* Enable the plane */ | ||
600 | temp = REG_READ(dspcntr_reg); | ||
601 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
602 | REG_WRITE(dspcntr_reg, | ||
603 | temp | DISPLAY_PLANE_ENABLE); | ||
604 | /* Flush the plane changes */ | ||
605 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
606 | } | ||
607 | |||
608 | udelay(150); | ||
609 | |||
610 | /* Enable the pipe */ | ||
611 | temp = REG_READ(pipeconf_reg); | ||
612 | if ((temp & PIPEACONF_ENABLE) == 0) | ||
613 | REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); | ||
614 | |||
615 | psb_intel_crtc_load_lut(crtc); | ||
616 | |||
617 | /* Give the overlay scaler a chance to enable | ||
618 | * if it's on this pipe */ | ||
619 | /* psb_intel_crtc_dpms_video(crtc, true); TODO */ | ||
620 | break; | ||
621 | case DRM_MODE_DPMS_OFF: | ||
622 | /* Give the overlay scaler a chance to disable | ||
623 | * if it's on this pipe */ | ||
624 | /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */ | ||
625 | |||
626 | /* Disable the VGA plane that we never use */ | ||
627 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
628 | |||
629 | /* Jim Bish - changed pipe/plane here as well. */ | ||
630 | |||
631 | /* Wait for vblank for the disable to take effect */ | ||
632 | cdv_intel_wait_for_vblank(dev); | ||
633 | |||
634 | /* Next, disable display pipes */ | ||
635 | temp = REG_READ(pipeconf_reg); | ||
636 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
637 | REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); | ||
638 | REG_READ(pipeconf_reg); | ||
639 | } | ||
640 | |||
641 | /* Wait for vblank for the disable to take effect. */ | ||
642 | cdv_intel_wait_for_vblank(dev); | ||
643 | |||
644 | udelay(150); | ||
645 | |||
646 | /* Disable display plane */ | ||
647 | temp = REG_READ(dspcntr_reg); | ||
648 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
649 | REG_WRITE(dspcntr_reg, | ||
650 | temp & ~DISPLAY_PLANE_ENABLE); | ||
651 | /* Flush the plane changes */ | ||
652 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
653 | REG_READ(dspbase_reg); | ||
654 | } | ||
655 | |||
656 | temp = REG_READ(dpll_reg); | ||
657 | if ((temp & DPLL_VCO_ENABLE) != 0) { | ||
658 | REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); | ||
659 | REG_READ(dpll_reg); | ||
660 | } | ||
661 | |||
662 | /* Wait for the clocks to turn off. */ | ||
663 | udelay(150); | ||
664 | break; | ||
665 | } | ||
666 | enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; | ||
667 | /*Set FIFO Watermarks*/ | ||
668 | REG_WRITE(DSPARB, 0x3F3E); | ||
669 | } | ||
670 | |||
671 | static void cdv_intel_crtc_prepare(struct drm_crtc *crtc) | ||
672 | { | ||
673 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
674 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
675 | } | ||
676 | |||
677 | static void cdv_intel_crtc_commit(struct drm_crtc *crtc) | ||
678 | { | ||
679 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
680 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
681 | } | ||
682 | |||
683 | void cdv_intel_encoder_prepare(struct drm_encoder *encoder) | ||
684 | { | ||
685 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
686 | encoder->helper_private; | ||
687 | /* lvds has its own version of prepare see cdv_intel_lvds_prepare */ | ||
688 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
689 | } | ||
690 | |||
691 | void cdv_intel_encoder_commit(struct drm_encoder *encoder) | ||
692 | { | ||
693 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
694 | encoder->helper_private; | ||
695 | /* lvds has its own version of commit see cdv_intel_lvds_commit */ | ||
696 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
697 | } | ||
698 | |||
699 | static bool cdv_intel_crtc_mode_fixup(struct drm_crtc *crtc, | ||
700 | struct drm_display_mode *mode, | ||
701 | struct drm_display_mode *adjusted_mode) | ||
702 | { | ||
703 | return true; | ||
704 | } | ||
705 | |||
706 | |||
707 | /** | ||
708 | * Return the pipe currently connected to the panel fitter, | ||
709 | * or -1 if the panel fitter is not present or not in use | ||
710 | */ | ||
711 | static int cdv_intel_panel_fitter_pipe(struct drm_device *dev) | ||
712 | { | ||
713 | u32 pfit_control; | ||
714 | |||
715 | pfit_control = REG_READ(PFIT_CONTROL); | ||
716 | |||
717 | /* See if the panel fitter is in use */ | ||
718 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
719 | return -1; | ||
720 | return (pfit_control >> 29) & 0x3; | ||
721 | } | ||
722 | |||
723 | static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, | ||
724 | struct drm_display_mode *mode, | ||
725 | struct drm_display_mode *adjusted_mode, | ||
726 | int x, int y, | ||
727 | struct drm_framebuffer *old_fb) | ||
728 | { | ||
729 | struct drm_device *dev = crtc->dev; | ||
730 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
731 | int pipe = psb_intel_crtc->pipe; | ||
732 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
733 | int dpll_md_reg = (psb_intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; | ||
734 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
735 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
736 | int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; | ||
737 | int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; | ||
738 | int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; | ||
739 | int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; | ||
740 | int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; | ||
741 | int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; | ||
742 | int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; | ||
743 | int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; | ||
744 | int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; | ||
745 | int refclk; | ||
746 | struct cdv_intel_clock_t clock; | ||
747 | u32 dpll = 0, dspcntr, pipeconf; | ||
748 | bool ok, is_sdvo = false, is_dvo = false; | ||
749 | bool is_crt = false, is_lvds = false, is_tv = false; | ||
750 | bool is_hdmi = false; | ||
751 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
752 | struct drm_connector *connector; | ||
753 | |||
754 | list_for_each_entry(connector, &mode_config->connector_list, head) { | ||
755 | struct psb_intel_encoder *psb_intel_encoder = | ||
756 | psb_intel_attached_encoder(connector); | ||
757 | |||
758 | if (!connector->encoder | ||
759 | || connector->encoder->crtc != crtc) | ||
760 | continue; | ||
761 | |||
762 | switch (psb_intel_encoder->type) { | ||
763 | case INTEL_OUTPUT_LVDS: | ||
764 | is_lvds = true; | ||
765 | break; | ||
766 | case INTEL_OUTPUT_SDVO: | ||
767 | is_sdvo = true; | ||
768 | break; | ||
769 | case INTEL_OUTPUT_DVO: | ||
770 | is_dvo = true; | ||
771 | break; | ||
772 | case INTEL_OUTPUT_TVOUT: | ||
773 | is_tv = true; | ||
774 | break; | ||
775 | case INTEL_OUTPUT_ANALOG: | ||
776 | is_crt = true; | ||
777 | break; | ||
778 | case INTEL_OUTPUT_HDMI: | ||
779 | is_hdmi = true; | ||
780 | break; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | refclk = 96000; | ||
785 | |||
786 | /* Hack selection about ref clk for CRT */ | ||
787 | /* Select 27MHz as the reference clk for HDMI */ | ||
788 | if (is_crt || is_hdmi) | ||
789 | refclk = 27000; | ||
790 | |||
791 | drm_mode_debug_printmodeline(adjusted_mode); | ||
792 | |||
793 | ok = cdv_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, | ||
794 | &clock); | ||
795 | if (!ok) { | ||
796 | dev_err(dev->dev, "Couldn't find PLL settings for mode!\n"); | ||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | dpll = DPLL_VGA_MODE_DIS; | ||
801 | if (is_tv) { | ||
802 | /* XXX: just matching BIOS for now */ | ||
803 | /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ | ||
804 | dpll |= 3; | ||
805 | } | ||
806 | dpll |= PLL_REF_INPUT_DREFCLK; | ||
807 | |||
808 | dpll |= DPLL_SYNCLOCK_ENABLE; | ||
809 | dpll |= DPLL_VGA_MODE_DIS; | ||
810 | if (is_lvds) | ||
811 | dpll |= DPLLB_MODE_LVDS; | ||
812 | else | ||
813 | dpll |= DPLLB_MODE_DAC_SERIAL; | ||
814 | /* dpll |= (2 << 11); */ | ||
815 | |||
816 | /* setup pipeconf */ | ||
817 | pipeconf = REG_READ(pipeconf_reg); | ||
818 | |||
819 | /* Set up the display plane register */ | ||
820 | dspcntr = DISPPLANE_GAMMA_ENABLE; | ||
821 | |||
822 | if (pipe == 0) | ||
823 | dspcntr |= DISPPLANE_SEL_PIPE_A; | ||
824 | else | ||
825 | dspcntr |= DISPPLANE_SEL_PIPE_B; | ||
826 | |||
827 | dspcntr |= DISPLAY_PLANE_ENABLE; | ||
828 | pipeconf |= PIPEACONF_ENABLE; | ||
829 | |||
830 | REG_WRITE(dpll_reg, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE); | ||
831 | REG_READ(dpll_reg); | ||
832 | |||
833 | cdv_dpll_set_clock_cdv(dev, crtc, &clock); | ||
834 | |||
835 | udelay(150); | ||
836 | |||
837 | |||
838 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. | ||
839 | * This is an exception to the general rule that mode_set doesn't turn | ||
840 | * things on. | ||
841 | */ | ||
842 | if (is_lvds) { | ||
843 | u32 lvds = REG_READ(LVDS); | ||
844 | |||
845 | lvds |= | ||
846 | LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | | ||
847 | LVDS_PIPEB_SELECT; | ||
848 | /* Set the B0-B3 data pairs corresponding to | ||
849 | * whether we're going to | ||
850 | * set the DPLLs for dual-channel mode or not. | ||
851 | */ | ||
852 | if (clock.p2 == 7) | ||
853 | lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; | ||
854 | else | ||
855 | lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); | ||
856 | |||
857 | /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) | ||
858 | * appropriately here, but we need to look more | ||
859 | * thoroughly into how panels behave in the two modes. | ||
860 | */ | ||
861 | |||
862 | REG_WRITE(LVDS, lvds); | ||
863 | REG_READ(LVDS); | ||
864 | } | ||
865 | |||
866 | dpll |= DPLL_VCO_ENABLE; | ||
867 | |||
868 | /* Disable the panel fitter if it was on our pipe */ | ||
869 | if (cdv_intel_panel_fitter_pipe(dev) == pipe) | ||
870 | REG_WRITE(PFIT_CONTROL, 0); | ||
871 | |||
872 | DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); | ||
873 | drm_mode_debug_printmodeline(mode); | ||
874 | |||
875 | REG_WRITE(dpll_reg, | ||
876 | (REG_READ(dpll_reg) & ~DPLL_LOCK) | DPLL_VCO_ENABLE); | ||
877 | REG_READ(dpll_reg); | ||
878 | /* Wait for the clocks to stabilize. */ | ||
879 | udelay(150); /* 42 usec w/o calibration, 110 with. rounded up. */ | ||
880 | |||
881 | if (!(REG_READ(dpll_reg) & DPLL_LOCK)) { | ||
882 | dev_err(dev->dev, "Failed to get DPLL lock\n"); | ||
883 | return -EBUSY; | ||
884 | } | ||
885 | |||
886 | { | ||
887 | int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; | ||
888 | REG_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); | ||
889 | } | ||
890 | |||
891 | REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | | ||
892 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
893 | REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | | ||
894 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
895 | REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | | ||
896 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
897 | REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | | ||
898 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
899 | REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | | ||
900 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
901 | REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | | ||
902 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
903 | /* pipesrc and dspsize control the size that is scaled from, | ||
904 | * which should always be the user's requested size. | ||
905 | */ | ||
906 | REG_WRITE(dspsize_reg, | ||
907 | ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); | ||
908 | REG_WRITE(dsppos_reg, 0); | ||
909 | REG_WRITE(pipesrc_reg, | ||
910 | ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); | ||
911 | REG_WRITE(pipeconf_reg, pipeconf); | ||
912 | REG_READ(pipeconf_reg); | ||
913 | |||
914 | cdv_intel_wait_for_vblank(dev); | ||
915 | |||
916 | REG_WRITE(dspcntr_reg, dspcntr); | ||
917 | |||
918 | /* Flush the plane changes */ | ||
919 | { | ||
920 | struct drm_crtc_helper_funcs *crtc_funcs = | ||
921 | crtc->helper_private; | ||
922 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); | ||
923 | } | ||
924 | |||
925 | cdv_intel_wait_for_vblank(dev); | ||
926 | |||
927 | return 0; | ||
928 | } | ||
929 | |||
930 | /** Loads the palette/gamma unit for the CRTC with the prepared values */ | ||
931 | void cdv_intel_crtc_load_lut(struct drm_crtc *crtc) | ||
932 | { | ||
933 | struct drm_device *dev = crtc->dev; | ||
934 | struct drm_psb_private *dev_priv = | ||
935 | (struct drm_psb_private *)dev->dev_private; | ||
936 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
937 | int palreg = PALETTE_A; | ||
938 | int i; | ||
939 | |||
940 | /* The clocks have to be on to load the palette. */ | ||
941 | if (!crtc->enabled) | ||
942 | return; | ||
943 | |||
944 | switch (psb_intel_crtc->pipe) { | ||
945 | case 0: | ||
946 | break; | ||
947 | case 1: | ||
948 | palreg = PALETTE_B; | ||
949 | break; | ||
950 | case 2: | ||
951 | palreg = PALETTE_C; | ||
952 | break; | ||
953 | default: | ||
954 | dev_err(dev->dev, "Illegal Pipe Number.\n"); | ||
955 | return; | ||
956 | } | ||
957 | |||
958 | if (gma_power_begin(dev, false)) { | ||
959 | for (i = 0; i < 256; i++) { | ||
960 | REG_WRITE(palreg + 4 * i, | ||
961 | ((psb_intel_crtc->lut_r[i] + | ||
962 | psb_intel_crtc->lut_adj[i]) << 16) | | ||
963 | ((psb_intel_crtc->lut_g[i] + | ||
964 | psb_intel_crtc->lut_adj[i]) << 8) | | ||
965 | (psb_intel_crtc->lut_b[i] + | ||
966 | psb_intel_crtc->lut_adj[i])); | ||
967 | } | ||
968 | gma_power_end(dev); | ||
969 | } else { | ||
970 | for (i = 0; i < 256; i++) { | ||
971 | dev_priv->save_palette_a[i] = | ||
972 | ((psb_intel_crtc->lut_r[i] + | ||
973 | psb_intel_crtc->lut_adj[i]) << 16) | | ||
974 | ((psb_intel_crtc->lut_g[i] + | ||
975 | psb_intel_crtc->lut_adj[i]) << 8) | | ||
976 | (psb_intel_crtc->lut_b[i] + | ||
977 | psb_intel_crtc->lut_adj[i]); | ||
978 | } | ||
979 | |||
980 | } | ||
981 | } | ||
982 | |||
983 | /** | ||
984 | * Save HW states of giving crtc | ||
985 | */ | ||
986 | static void cdv_intel_crtc_save(struct drm_crtc *crtc) | ||
987 | { | ||
988 | struct drm_device *dev = crtc->dev; | ||
989 | /* struct drm_psb_private *dev_priv = | ||
990 | (struct drm_psb_private *)dev->dev_private; */ | ||
991 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
992 | struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state; | ||
993 | int pipeA = (psb_intel_crtc->pipe == 0); | ||
994 | uint32_t paletteReg; | ||
995 | int i; | ||
996 | |||
997 | if (!crtc_state) { | ||
998 | dev_dbg(dev->dev, "No CRTC state found\n"); | ||
999 | return; | ||
1000 | } | ||
1001 | |||
1002 | crtc_state->saveDSPCNTR = REG_READ(pipeA ? DSPACNTR : DSPBCNTR); | ||
1003 | crtc_state->savePIPECONF = REG_READ(pipeA ? PIPEACONF : PIPEBCONF); | ||
1004 | crtc_state->savePIPESRC = REG_READ(pipeA ? PIPEASRC : PIPEBSRC); | ||
1005 | crtc_state->saveFP0 = REG_READ(pipeA ? FPA0 : FPB0); | ||
1006 | crtc_state->saveFP1 = REG_READ(pipeA ? FPA1 : FPB1); | ||
1007 | crtc_state->saveDPLL = REG_READ(pipeA ? DPLL_A : DPLL_B); | ||
1008 | crtc_state->saveHTOTAL = REG_READ(pipeA ? HTOTAL_A : HTOTAL_B); | ||
1009 | crtc_state->saveHBLANK = REG_READ(pipeA ? HBLANK_A : HBLANK_B); | ||
1010 | crtc_state->saveHSYNC = REG_READ(pipeA ? HSYNC_A : HSYNC_B); | ||
1011 | crtc_state->saveVTOTAL = REG_READ(pipeA ? VTOTAL_A : VTOTAL_B); | ||
1012 | crtc_state->saveVBLANK = REG_READ(pipeA ? VBLANK_A : VBLANK_B); | ||
1013 | crtc_state->saveVSYNC = REG_READ(pipeA ? VSYNC_A : VSYNC_B); | ||
1014 | crtc_state->saveDSPSTRIDE = REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE); | ||
1015 | |||
1016 | /*NOTE: DSPSIZE DSPPOS only for psb*/ | ||
1017 | crtc_state->saveDSPSIZE = REG_READ(pipeA ? DSPASIZE : DSPBSIZE); | ||
1018 | crtc_state->saveDSPPOS = REG_READ(pipeA ? DSPAPOS : DSPBPOS); | ||
1019 | |||
1020 | crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE); | ||
1021 | |||
1022 | DRM_DEBUG("(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", | ||
1023 | crtc_state->saveDSPCNTR, | ||
1024 | crtc_state->savePIPECONF, | ||
1025 | crtc_state->savePIPESRC, | ||
1026 | crtc_state->saveFP0, | ||
1027 | crtc_state->saveFP1, | ||
1028 | crtc_state->saveDPLL, | ||
1029 | crtc_state->saveHTOTAL, | ||
1030 | crtc_state->saveHBLANK, | ||
1031 | crtc_state->saveHSYNC, | ||
1032 | crtc_state->saveVTOTAL, | ||
1033 | crtc_state->saveVBLANK, | ||
1034 | crtc_state->saveVSYNC, | ||
1035 | crtc_state->saveDSPSTRIDE, | ||
1036 | crtc_state->saveDSPSIZE, | ||
1037 | crtc_state->saveDSPPOS, | ||
1038 | crtc_state->saveDSPBASE | ||
1039 | ); | ||
1040 | |||
1041 | paletteReg = pipeA ? PALETTE_A : PALETTE_B; | ||
1042 | for (i = 0; i < 256; ++i) | ||
1043 | crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2)); | ||
1044 | } | ||
1045 | |||
1046 | /** | ||
1047 | * Restore HW states of giving crtc | ||
1048 | */ | ||
1049 | static void cdv_intel_crtc_restore(struct drm_crtc *crtc) | ||
1050 | { | ||
1051 | struct drm_device *dev = crtc->dev; | ||
1052 | /* struct drm_psb_private * dev_priv = | ||
1053 | (struct drm_psb_private *)dev->dev_private; */ | ||
1054 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1055 | struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state; | ||
1056 | /* struct drm_crtc_helper_funcs * crtc_funcs = crtc->helper_private; */ | ||
1057 | int pipeA = (psb_intel_crtc->pipe == 0); | ||
1058 | uint32_t paletteReg; | ||
1059 | int i; | ||
1060 | |||
1061 | if (!crtc_state) { | ||
1062 | dev_dbg(dev->dev, "No crtc state\n"); | ||
1063 | return; | ||
1064 | } | ||
1065 | |||
1066 | DRM_DEBUG( | ||
1067 | "current:(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", | ||
1068 | REG_READ(pipeA ? DSPACNTR : DSPBCNTR), | ||
1069 | REG_READ(pipeA ? PIPEACONF : PIPEBCONF), | ||
1070 | REG_READ(pipeA ? PIPEASRC : PIPEBSRC), | ||
1071 | REG_READ(pipeA ? FPA0 : FPB0), | ||
1072 | REG_READ(pipeA ? FPA1 : FPB1), | ||
1073 | REG_READ(pipeA ? DPLL_A : DPLL_B), | ||
1074 | REG_READ(pipeA ? HTOTAL_A : HTOTAL_B), | ||
1075 | REG_READ(pipeA ? HBLANK_A : HBLANK_B), | ||
1076 | REG_READ(pipeA ? HSYNC_A : HSYNC_B), | ||
1077 | REG_READ(pipeA ? VTOTAL_A : VTOTAL_B), | ||
1078 | REG_READ(pipeA ? VBLANK_A : VBLANK_B), | ||
1079 | REG_READ(pipeA ? VSYNC_A : VSYNC_B), | ||
1080 | REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE), | ||
1081 | REG_READ(pipeA ? DSPASIZE : DSPBSIZE), | ||
1082 | REG_READ(pipeA ? DSPAPOS : DSPBPOS), | ||
1083 | REG_READ(pipeA ? DSPABASE : DSPBBASE) | ||
1084 | ); | ||
1085 | |||
1086 | DRM_DEBUG( | ||
1087 | "saved: (%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", | ||
1088 | crtc_state->saveDSPCNTR, | ||
1089 | crtc_state->savePIPECONF, | ||
1090 | crtc_state->savePIPESRC, | ||
1091 | crtc_state->saveFP0, | ||
1092 | crtc_state->saveFP1, | ||
1093 | crtc_state->saveDPLL, | ||
1094 | crtc_state->saveHTOTAL, | ||
1095 | crtc_state->saveHBLANK, | ||
1096 | crtc_state->saveHSYNC, | ||
1097 | crtc_state->saveVTOTAL, | ||
1098 | crtc_state->saveVBLANK, | ||
1099 | crtc_state->saveVSYNC, | ||
1100 | crtc_state->saveDSPSTRIDE, | ||
1101 | crtc_state->saveDSPSIZE, | ||
1102 | crtc_state->saveDSPPOS, | ||
1103 | crtc_state->saveDSPBASE | ||
1104 | ); | ||
1105 | |||
1106 | |||
1107 | if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) { | ||
1108 | REG_WRITE(pipeA ? DPLL_A : DPLL_B, | ||
1109 | crtc_state->saveDPLL & ~DPLL_VCO_ENABLE); | ||
1110 | REG_READ(pipeA ? DPLL_A : DPLL_B); | ||
1111 | DRM_DEBUG("write dpll: %x\n", | ||
1112 | REG_READ(pipeA ? DPLL_A : DPLL_B)); | ||
1113 | udelay(150); | ||
1114 | } | ||
1115 | |||
1116 | REG_WRITE(pipeA ? FPA0 : FPB0, crtc_state->saveFP0); | ||
1117 | REG_READ(pipeA ? FPA0 : FPB0); | ||
1118 | |||
1119 | REG_WRITE(pipeA ? FPA1 : FPB1, crtc_state->saveFP1); | ||
1120 | REG_READ(pipeA ? FPA1 : FPB1); | ||
1121 | |||
1122 | REG_WRITE(pipeA ? DPLL_A : DPLL_B, crtc_state->saveDPLL); | ||
1123 | REG_READ(pipeA ? DPLL_A : DPLL_B); | ||
1124 | udelay(150); | ||
1125 | |||
1126 | REG_WRITE(pipeA ? HTOTAL_A : HTOTAL_B, crtc_state->saveHTOTAL); | ||
1127 | REG_WRITE(pipeA ? HBLANK_A : HBLANK_B, crtc_state->saveHBLANK); | ||
1128 | REG_WRITE(pipeA ? HSYNC_A : HSYNC_B, crtc_state->saveHSYNC); | ||
1129 | REG_WRITE(pipeA ? VTOTAL_A : VTOTAL_B, crtc_state->saveVTOTAL); | ||
1130 | REG_WRITE(pipeA ? VBLANK_A : VBLANK_B, crtc_state->saveVBLANK); | ||
1131 | REG_WRITE(pipeA ? VSYNC_A : VSYNC_B, crtc_state->saveVSYNC); | ||
1132 | REG_WRITE(pipeA ? DSPASTRIDE : DSPBSTRIDE, crtc_state->saveDSPSTRIDE); | ||
1133 | |||
1134 | REG_WRITE(pipeA ? DSPASIZE : DSPBSIZE, crtc_state->saveDSPSIZE); | ||
1135 | REG_WRITE(pipeA ? DSPAPOS : DSPBPOS, crtc_state->saveDSPPOS); | ||
1136 | |||
1137 | REG_WRITE(pipeA ? PIPEASRC : PIPEBSRC, crtc_state->savePIPESRC); | ||
1138 | REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE); | ||
1139 | REG_WRITE(pipeA ? PIPEACONF : PIPEBCONF, crtc_state->savePIPECONF); | ||
1140 | |||
1141 | cdv_intel_wait_for_vblank(dev); | ||
1142 | |||
1143 | REG_WRITE(pipeA ? DSPACNTR : DSPBCNTR, crtc_state->saveDSPCNTR); | ||
1144 | REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE); | ||
1145 | |||
1146 | cdv_intel_wait_for_vblank(dev); | ||
1147 | |||
1148 | paletteReg = pipeA ? PALETTE_A : PALETTE_B; | ||
1149 | for (i = 0; i < 256; ++i) | ||
1150 | REG_WRITE(paletteReg + (i << 2), crtc_state->savePalette[i]); | ||
1151 | } | ||
1152 | |||
1153 | static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc, | ||
1154 | struct drm_file *file_priv, | ||
1155 | uint32_t handle, | ||
1156 | uint32_t width, uint32_t height) | ||
1157 | { | ||
1158 | struct drm_device *dev = crtc->dev; | ||
1159 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1160 | int pipe = psb_intel_crtc->pipe; | ||
1161 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; | ||
1162 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; | ||
1163 | uint32_t temp; | ||
1164 | size_t addr = 0; | ||
1165 | struct gtt_range *gt; | ||
1166 | struct drm_gem_object *obj; | ||
1167 | int ret; | ||
1168 | |||
1169 | /* if we want to turn of the cursor ignore width and height */ | ||
1170 | if (!handle) { | ||
1171 | /* turn off the cursor */ | ||
1172 | temp = CURSOR_MODE_DISABLE; | ||
1173 | |||
1174 | if (gma_power_begin(dev, false)) { | ||
1175 | REG_WRITE(control, temp); | ||
1176 | REG_WRITE(base, 0); | ||
1177 | gma_power_end(dev); | ||
1178 | } | ||
1179 | |||
1180 | /* unpin the old GEM object */ | ||
1181 | if (psb_intel_crtc->cursor_obj) { | ||
1182 | gt = container_of(psb_intel_crtc->cursor_obj, | ||
1183 | struct gtt_range, gem); | ||
1184 | psb_gtt_unpin(gt); | ||
1185 | drm_gem_object_unreference(psb_intel_crtc->cursor_obj); | ||
1186 | psb_intel_crtc->cursor_obj = NULL; | ||
1187 | } | ||
1188 | |||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | /* Currently we only support 64x64 cursors */ | ||
1193 | if (width != 64 || height != 64) { | ||
1194 | dev_dbg(dev->dev, "we currently only support 64x64 cursors\n"); | ||
1195 | return -EINVAL; | ||
1196 | } | ||
1197 | |||
1198 | obj = drm_gem_object_lookup(dev, file_priv, handle); | ||
1199 | if (!obj) | ||
1200 | return -ENOENT; | ||
1201 | |||
1202 | if (obj->size < width * height * 4) { | ||
1203 | dev_dbg(dev->dev, "buffer is to small\n"); | ||
1204 | return -ENOMEM; | ||
1205 | } | ||
1206 | |||
1207 | gt = container_of(obj, struct gtt_range, gem); | ||
1208 | |||
1209 | /* Pin the memory into the GTT */ | ||
1210 | ret = psb_gtt_pin(gt); | ||
1211 | if (ret) { | ||
1212 | dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); | ||
1213 | return ret; | ||
1214 | } | ||
1215 | |||
1216 | addr = gt->offset; /* Or resource.start ??? */ | ||
1217 | |||
1218 | psb_intel_crtc->cursor_addr = addr; | ||
1219 | |||
1220 | temp = 0; | ||
1221 | /* set the pipe for the cursor */ | ||
1222 | temp |= (pipe << 28); | ||
1223 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | ||
1224 | |||
1225 | if (gma_power_begin(dev, false)) { | ||
1226 | REG_WRITE(control, temp); | ||
1227 | REG_WRITE(base, addr); | ||
1228 | gma_power_end(dev); | ||
1229 | } | ||
1230 | |||
1231 | /* unpin the old GEM object */ | ||
1232 | if (psb_intel_crtc->cursor_obj) { | ||
1233 | gt = container_of(psb_intel_crtc->cursor_obj, | ||
1234 | struct gtt_range, gem); | ||
1235 | psb_gtt_unpin(gt); | ||
1236 | drm_gem_object_unreference(psb_intel_crtc->cursor_obj); | ||
1237 | psb_intel_crtc->cursor_obj = obj; | ||
1238 | } | ||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1242 | static int cdv_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | ||
1243 | { | ||
1244 | struct drm_device *dev = crtc->dev; | ||
1245 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1246 | int pipe = psb_intel_crtc->pipe; | ||
1247 | uint32_t temp = 0; | ||
1248 | uint32_t adder; | ||
1249 | |||
1250 | |||
1251 | if (x < 0) { | ||
1252 | temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); | ||
1253 | x = -x; | ||
1254 | } | ||
1255 | if (y < 0) { | ||
1256 | temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); | ||
1257 | y = -y; | ||
1258 | } | ||
1259 | |||
1260 | temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); | ||
1261 | temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); | ||
1262 | |||
1263 | adder = psb_intel_crtc->cursor_addr; | ||
1264 | |||
1265 | if (gma_power_begin(dev, false)) { | ||
1266 | REG_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); | ||
1267 | REG_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder); | ||
1268 | gma_power_end(dev); | ||
1269 | } | ||
1270 | return 0; | ||
1271 | } | ||
1272 | |||
1273 | static void cdv_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, | ||
1274 | u16 *green, u16 *blue, uint32_t start, uint32_t size) | ||
1275 | { | ||
1276 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1277 | int i; | ||
1278 | int end = (start + size > 256) ? 256 : start + size; | ||
1279 | |||
1280 | for (i = start; i < end; i++) { | ||
1281 | psb_intel_crtc->lut_r[i] = red[i] >> 8; | ||
1282 | psb_intel_crtc->lut_g[i] = green[i] >> 8; | ||
1283 | psb_intel_crtc->lut_b[i] = blue[i] >> 8; | ||
1284 | } | ||
1285 | |||
1286 | cdv_intel_crtc_load_lut(crtc); | ||
1287 | } | ||
1288 | |||
1289 | static int cdv_crtc_set_config(struct drm_mode_set *set) | ||
1290 | { | ||
1291 | int ret = 0; | ||
1292 | struct drm_device *dev = set->crtc->dev; | ||
1293 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1294 | |||
1295 | if (!dev_priv->rpm_enabled) | ||
1296 | return drm_crtc_helper_set_config(set); | ||
1297 | |||
1298 | pm_runtime_forbid(&dev->pdev->dev); | ||
1299 | |||
1300 | ret = drm_crtc_helper_set_config(set); | ||
1301 | |||
1302 | pm_runtime_allow(&dev->pdev->dev); | ||
1303 | |||
1304 | return ret; | ||
1305 | } | ||
1306 | |||
1307 | /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ | ||
1308 | |||
1309 | /* FIXME: why are we using this, should it be cdv_ in this tree ? */ | ||
1310 | |||
1311 | static void i8xx_clock(int refclk, struct cdv_intel_clock_t *clock) | ||
1312 | { | ||
1313 | clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | ||
1314 | clock->p = clock->p1 * clock->p2; | ||
1315 | clock->vco = refclk * clock->m / (clock->n + 2); | ||
1316 | clock->dot = clock->vco / clock->p; | ||
1317 | } | ||
1318 | |||
1319 | /* Returns the clock of the currently programmed mode of the given pipe. */ | ||
1320 | static int cdv_intel_crtc_clock_get(struct drm_device *dev, | ||
1321 | struct drm_crtc *crtc) | ||
1322 | { | ||
1323 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1324 | int pipe = psb_intel_crtc->pipe; | ||
1325 | u32 dpll; | ||
1326 | u32 fp; | ||
1327 | struct cdv_intel_clock_t clock; | ||
1328 | bool is_lvds; | ||
1329 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1330 | |||
1331 | if (gma_power_begin(dev, false)) { | ||
1332 | dpll = REG_READ((pipe == 0) ? DPLL_A : DPLL_B); | ||
1333 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) | ||
1334 | fp = REG_READ((pipe == 0) ? FPA0 : FPB0); | ||
1335 | else | ||
1336 | fp = REG_READ((pipe == 0) ? FPA1 : FPB1); | ||
1337 | is_lvds = (pipe == 1) && (REG_READ(LVDS) & LVDS_PORT_EN); | ||
1338 | gma_power_end(dev); | ||
1339 | } else { | ||
1340 | dpll = (pipe == 0) ? | ||
1341 | dev_priv->saveDPLL_A : dev_priv->saveDPLL_B; | ||
1342 | |||
1343 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) | ||
1344 | fp = (pipe == 0) ? | ||
1345 | dev_priv->saveFPA0 : | ||
1346 | dev_priv->saveFPB0; | ||
1347 | else | ||
1348 | fp = (pipe == 0) ? | ||
1349 | dev_priv->saveFPA1 : | ||
1350 | dev_priv->saveFPB1; | ||
1351 | |||
1352 | is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN); | ||
1353 | } | ||
1354 | |||
1355 | clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; | ||
1356 | clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; | ||
1357 | clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; | ||
1358 | |||
1359 | if (is_lvds) { | ||
1360 | clock.p1 = | ||
1361 | ffs((dpll & | ||
1362 | DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> | ||
1363 | DPLL_FPA01_P1_POST_DIV_SHIFT); | ||
1364 | if (clock.p1 == 0) { | ||
1365 | clock.p1 = 4; | ||
1366 | dev_err(dev->dev, "PLL %d\n", dpll); | ||
1367 | } | ||
1368 | clock.p2 = 14; | ||
1369 | |||
1370 | if ((dpll & PLL_REF_INPUT_MASK) == | ||
1371 | PLLB_REF_INPUT_SPREADSPECTRUMIN) { | ||
1372 | /* XXX: might not be 66MHz */ | ||
1373 | i8xx_clock(66000, &clock); | ||
1374 | } else | ||
1375 | i8xx_clock(48000, &clock); | ||
1376 | } else { | ||
1377 | if (dpll & PLL_P1_DIVIDE_BY_TWO) | ||
1378 | clock.p1 = 2; | ||
1379 | else { | ||
1380 | clock.p1 = | ||
1381 | ((dpll & | ||
1382 | DPLL_FPA01_P1_POST_DIV_MASK_I830) >> | ||
1383 | DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; | ||
1384 | } | ||
1385 | if (dpll & PLL_P2_DIVIDE_BY_4) | ||
1386 | clock.p2 = 4; | ||
1387 | else | ||
1388 | clock.p2 = 2; | ||
1389 | |||
1390 | i8xx_clock(48000, &clock); | ||
1391 | } | ||
1392 | |||
1393 | /* XXX: It would be nice to validate the clocks, but we can't reuse | ||
1394 | * i830PllIsValid() because it relies on the xf86_config connector | ||
1395 | * configuration being accurate, which it isn't necessarily. | ||
1396 | */ | ||
1397 | |||
1398 | return clock.dot; | ||
1399 | } | ||
1400 | |||
1401 | /** Returns the currently programmed mode of the given pipe. */ | ||
1402 | struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev, | ||
1403 | struct drm_crtc *crtc) | ||
1404 | { | ||
1405 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1406 | int pipe = psb_intel_crtc->pipe; | ||
1407 | struct drm_display_mode *mode; | ||
1408 | int htot; | ||
1409 | int hsync; | ||
1410 | int vtot; | ||
1411 | int vsync; | ||
1412 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1413 | |||
1414 | if (gma_power_begin(dev, false)) { | ||
1415 | htot = REG_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); | ||
1416 | hsync = REG_READ((pipe == 0) ? HSYNC_A : HSYNC_B); | ||
1417 | vtot = REG_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); | ||
1418 | vsync = REG_READ((pipe == 0) ? VSYNC_A : VSYNC_B); | ||
1419 | gma_power_end(dev); | ||
1420 | } else { | ||
1421 | htot = (pipe == 0) ? | ||
1422 | dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B; | ||
1423 | hsync = (pipe == 0) ? | ||
1424 | dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B; | ||
1425 | vtot = (pipe == 0) ? | ||
1426 | dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B; | ||
1427 | vsync = (pipe == 0) ? | ||
1428 | dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B; | ||
1429 | } | ||
1430 | |||
1431 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
1432 | if (!mode) | ||
1433 | return NULL; | ||
1434 | |||
1435 | mode->clock = cdv_intel_crtc_clock_get(dev, crtc); | ||
1436 | mode->hdisplay = (htot & 0xffff) + 1; | ||
1437 | mode->htotal = ((htot & 0xffff0000) >> 16) + 1; | ||
1438 | mode->hsync_start = (hsync & 0xffff) + 1; | ||
1439 | mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; | ||
1440 | mode->vdisplay = (vtot & 0xffff) + 1; | ||
1441 | mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; | ||
1442 | mode->vsync_start = (vsync & 0xffff) + 1; | ||
1443 | mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; | ||
1444 | |||
1445 | drm_mode_set_name(mode); | ||
1446 | drm_mode_set_crtcinfo(mode, 0); | ||
1447 | |||
1448 | return mode; | ||
1449 | } | ||
1450 | |||
1451 | static void cdv_intel_crtc_destroy(struct drm_crtc *crtc) | ||
1452 | { | ||
1453 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1454 | |||
1455 | kfree(psb_intel_crtc->crtc_state); | ||
1456 | drm_crtc_cleanup(crtc); | ||
1457 | kfree(psb_intel_crtc); | ||
1458 | } | ||
1459 | |||
1460 | const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = { | ||
1461 | .dpms = cdv_intel_crtc_dpms, | ||
1462 | .mode_fixup = cdv_intel_crtc_mode_fixup, | ||
1463 | .mode_set = cdv_intel_crtc_mode_set, | ||
1464 | .mode_set_base = cdv_intel_pipe_set_base, | ||
1465 | .prepare = cdv_intel_crtc_prepare, | ||
1466 | .commit = cdv_intel_crtc_commit, | ||
1467 | }; | ||
1468 | |||
1469 | const struct drm_crtc_funcs cdv_intel_crtc_funcs = { | ||
1470 | .save = cdv_intel_crtc_save, | ||
1471 | .restore = cdv_intel_crtc_restore, | ||
1472 | .cursor_set = cdv_intel_crtc_cursor_set, | ||
1473 | .cursor_move = cdv_intel_crtc_cursor_move, | ||
1474 | .gamma_set = cdv_intel_crtc_gamma_set, | ||
1475 | .set_config = cdv_crtc_set_config, | ||
1476 | .destroy = cdv_intel_crtc_destroy, | ||
1477 | }; | ||
1478 | |||
1479 | /* | ||
1480 | * Set the default value of cursor control and base register | ||
1481 | * to zero. This is a workaround for h/w defect on oaktrail | ||
1482 | */ | ||
1483 | void cdv_intel_cursor_init(struct drm_device *dev, int pipe) | ||
1484 | { | ||
1485 | uint32_t control; | ||
1486 | uint32_t base; | ||
1487 | |||
1488 | switch (pipe) { | ||
1489 | case 0: | ||
1490 | control = CURACNTR; | ||
1491 | base = CURABASE; | ||
1492 | break; | ||
1493 | case 1: | ||
1494 | control = CURBCNTR; | ||
1495 | base = CURBBASE; | ||
1496 | break; | ||
1497 | case 2: | ||
1498 | control = CURCCNTR; | ||
1499 | base = CURCBASE; | ||
1500 | break; | ||
1501 | default: | ||
1502 | return; | ||
1503 | } | ||
1504 | |||
1505 | REG_WRITE(control, 0); | ||
1506 | REG_WRITE(base, 0); | ||
1507 | } | ||
1508 | |||
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c new file mode 100644 index 00000000000..50d7cfb5166 --- /dev/null +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c | |||
@@ -0,0 +1,394 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2011 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * jim liu <jim.liu@intel.com> | ||
25 | * | ||
26 | * FIXME: | ||
27 | * We should probably make this generic and share it with Medfield | ||
28 | */ | ||
29 | |||
30 | #include <drm/drmP.h> | ||
31 | #include <drm/drm.h> | ||
32 | #include <drm/drm_crtc.h> | ||
33 | #include <drm/drm_edid.h> | ||
34 | #include "psb_intel_drv.h" | ||
35 | #include "psb_drv.h" | ||
36 | #include "psb_intel_reg.h" | ||
37 | #include <linux/pm_runtime.h> | ||
38 | |||
39 | /* hdmi control bits */ | ||
40 | #define HDMI_NULL_PACKETS_DURING_VSYNC (1 << 9) | ||
41 | #define HDMI_BORDER_ENABLE (1 << 7) | ||
42 | #define HDMI_AUDIO_ENABLE (1 << 6) | ||
43 | #define HDMI_VSYNC_ACTIVE_HIGH (1 << 4) | ||
44 | #define HDMI_HSYNC_ACTIVE_HIGH (1 << 3) | ||
45 | /* hdmi-b control bits */ | ||
46 | #define HDMIB_PIPE_B_SELECT (1 << 30) | ||
47 | |||
48 | |||
49 | struct mid_intel_hdmi_priv { | ||
50 | u32 hdmi_reg; | ||
51 | u32 save_HDMIB; | ||
52 | bool has_hdmi_sink; | ||
53 | bool has_hdmi_audio; | ||
54 | /* Should set this when detect hotplug */ | ||
55 | bool hdmi_device_connected; | ||
56 | struct mdfld_hdmi_i2c *i2c_bus; | ||
57 | struct i2c_adapter *hdmi_i2c_adapter; /* for control functions */ | ||
58 | struct drm_device *dev; | ||
59 | }; | ||
60 | |||
61 | static void cdv_hdmi_mode_set(struct drm_encoder *encoder, | ||
62 | struct drm_display_mode *mode, | ||
63 | struct drm_display_mode *adjusted_mode) | ||
64 | { | ||
65 | struct drm_device *dev = encoder->dev; | ||
66 | struct psb_intel_encoder *psb_intel_encoder = to_psb_intel_encoder(encoder); | ||
67 | struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; | ||
68 | u32 hdmib; | ||
69 | struct drm_crtc *crtc = encoder->crtc; | ||
70 | struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc); | ||
71 | |||
72 | hdmib = (2 << 10); | ||
73 | |||
74 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
75 | hdmib |= HDMI_VSYNC_ACTIVE_HIGH; | ||
76 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
77 | hdmib |= HDMI_HSYNC_ACTIVE_HIGH; | ||
78 | |||
79 | if (intel_crtc->pipe == 1) | ||
80 | hdmib |= HDMIB_PIPE_B_SELECT; | ||
81 | |||
82 | if (hdmi_priv->has_hdmi_audio) { | ||
83 | hdmib |= HDMI_AUDIO_ENABLE; | ||
84 | hdmib |= HDMI_NULL_PACKETS_DURING_VSYNC; | ||
85 | } | ||
86 | |||
87 | REG_WRITE(hdmi_priv->hdmi_reg, hdmib); | ||
88 | REG_READ(hdmi_priv->hdmi_reg); | ||
89 | } | ||
90 | |||
91 | static bool cdv_hdmi_mode_fixup(struct drm_encoder *encoder, | ||
92 | struct drm_display_mode *mode, | ||
93 | struct drm_display_mode *adjusted_mode) | ||
94 | { | ||
95 | return true; | ||
96 | } | ||
97 | |||
98 | static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode) | ||
99 | { | ||
100 | struct drm_device *dev = encoder->dev; | ||
101 | struct psb_intel_encoder *psb_intel_encoder = | ||
102 | to_psb_intel_encoder(encoder); | ||
103 | struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; | ||
104 | u32 hdmib; | ||
105 | |||
106 | hdmib = REG_READ(hdmi_priv->hdmi_reg); | ||
107 | |||
108 | if (mode != DRM_MODE_DPMS_ON) | ||
109 | REG_WRITE(hdmi_priv->hdmi_reg, hdmib & ~HDMIB_PORT_EN); | ||
110 | else | ||
111 | REG_WRITE(hdmi_priv->hdmi_reg, hdmib | HDMIB_PORT_EN); | ||
112 | REG_READ(hdmi_priv->hdmi_reg); | ||
113 | } | ||
114 | |||
115 | static void cdv_hdmi_save(struct drm_connector *connector) | ||
116 | { | ||
117 | struct drm_device *dev = connector->dev; | ||
118 | struct psb_intel_encoder *psb_intel_encoder = | ||
119 | psb_intel_attached_encoder(connector); | ||
120 | struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; | ||
121 | |||
122 | hdmi_priv->save_HDMIB = REG_READ(hdmi_priv->hdmi_reg); | ||
123 | } | ||
124 | |||
125 | static void cdv_hdmi_restore(struct drm_connector *connector) | ||
126 | { | ||
127 | struct drm_device *dev = connector->dev; | ||
128 | struct psb_intel_encoder *psb_intel_encoder = | ||
129 | psb_intel_attached_encoder(connector); | ||
130 | struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; | ||
131 | |||
132 | REG_WRITE(hdmi_priv->hdmi_reg, hdmi_priv->save_HDMIB); | ||
133 | REG_READ(hdmi_priv->hdmi_reg); | ||
134 | } | ||
135 | |||
136 | static enum drm_connector_status cdv_hdmi_detect( | ||
137 | struct drm_connector *connector, bool force) | ||
138 | { | ||
139 | struct psb_intel_encoder *psb_intel_encoder = | ||
140 | psb_intel_attached_encoder(connector); | ||
141 | struct psb_intel_connector *psb_intel_connector = | ||
142 | to_psb_intel_connector(connector); | ||
143 | struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; | ||
144 | struct edid *edid = NULL; | ||
145 | enum drm_connector_status status = connector_status_disconnected; | ||
146 | |||
147 | edid = drm_get_edid(connector, &psb_intel_encoder->i2c_bus->adapter); | ||
148 | |||
149 | hdmi_priv->has_hdmi_sink = false; | ||
150 | hdmi_priv->has_hdmi_audio = false; | ||
151 | if (edid) { | ||
152 | if (edid->input & DRM_EDID_INPUT_DIGITAL) { | ||
153 | status = connector_status_connected; | ||
154 | hdmi_priv->has_hdmi_sink = | ||
155 | drm_detect_hdmi_monitor(edid); | ||
156 | hdmi_priv->has_hdmi_audio = | ||
157 | drm_detect_monitor_audio(edid); | ||
158 | } | ||
159 | |||
160 | psb_intel_connector->base.display_info.raw_edid = NULL; | ||
161 | kfree(edid); | ||
162 | } | ||
163 | return status; | ||
164 | } | ||
165 | |||
166 | static int cdv_hdmi_set_property(struct drm_connector *connector, | ||
167 | struct drm_property *property, | ||
168 | uint64_t value) | ||
169 | { | ||
170 | struct drm_encoder *encoder = connector->encoder; | ||
171 | |||
172 | if (!strcmp(property->name, "scaling mode") && encoder) { | ||
173 | struct psb_intel_crtc *crtc = to_psb_intel_crtc(encoder->crtc); | ||
174 | bool centre; | ||
175 | uint64_t curValue; | ||
176 | |||
177 | if (!crtc) | ||
178 | return -1; | ||
179 | |||
180 | switch (value) { | ||
181 | case DRM_MODE_SCALE_FULLSCREEN: | ||
182 | break; | ||
183 | case DRM_MODE_SCALE_NO_SCALE: | ||
184 | break; | ||
185 | case DRM_MODE_SCALE_ASPECT: | ||
186 | break; | ||
187 | default: | ||
188 | return -1; | ||
189 | } | ||
190 | |||
191 | if (drm_connector_property_get_value(connector, | ||
192 | property, &curValue)) | ||
193 | return -1; | ||
194 | |||
195 | if (curValue == value) | ||
196 | return 0; | ||
197 | |||
198 | if (drm_connector_property_set_value(connector, | ||
199 | property, value)) | ||
200 | return -1; | ||
201 | |||
202 | centre = (curValue == DRM_MODE_SCALE_NO_SCALE) || | ||
203 | (value == DRM_MODE_SCALE_NO_SCALE); | ||
204 | |||
205 | if (crtc->saved_mode.hdisplay != 0 && | ||
206 | crtc->saved_mode.vdisplay != 0) { | ||
207 | if (centre) { | ||
208 | if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode, | ||
209 | encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb)) | ||
210 | return -1; | ||
211 | } else { | ||
212 | struct drm_encoder_helper_funcs *helpers | ||
213 | = encoder->helper_private; | ||
214 | helpers->mode_set(encoder, &crtc->saved_mode, | ||
215 | &crtc->saved_adjusted_mode); | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Return the list of HDMI DDC modes if available. | ||
224 | */ | ||
225 | static int cdv_hdmi_get_modes(struct drm_connector *connector) | ||
226 | { | ||
227 | struct psb_intel_encoder *psb_intel_encoder = | ||
228 | psb_intel_attached_encoder(connector); | ||
229 | struct edid *edid = NULL; | ||
230 | int ret = 0; | ||
231 | |||
232 | edid = drm_get_edid(connector, &psb_intel_encoder->i2c_bus->adapter); | ||
233 | if (edid) { | ||
234 | drm_mode_connector_update_edid_property(connector, edid); | ||
235 | ret = drm_add_edid_modes(connector, edid); | ||
236 | kfree(edid); | ||
237 | } | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | static int cdv_hdmi_mode_valid(struct drm_connector *connector, | ||
242 | struct drm_display_mode *mode) | ||
243 | { | ||
244 | |||
245 | if (mode->clock > 165000) | ||
246 | return MODE_CLOCK_HIGH; | ||
247 | if (mode->clock < 20000) | ||
248 | return MODE_CLOCK_HIGH; | ||
249 | |||
250 | /* just in case */ | ||
251 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
252 | return MODE_NO_DBLESCAN; | ||
253 | |||
254 | /* just in case */ | ||
255 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
256 | return MODE_NO_INTERLACE; | ||
257 | |||
258 | /* | ||
259 | * FIXME: for now we limit the size to 1680x1050 on CDV, otherwise it | ||
260 | * will go beyond the stolen memory size allocated to the framebuffer | ||
261 | */ | ||
262 | if (mode->hdisplay > 1680) | ||
263 | return MODE_PANEL; | ||
264 | if (mode->vdisplay > 1050) | ||
265 | return MODE_PANEL; | ||
266 | return MODE_OK; | ||
267 | } | ||
268 | |||
269 | static void cdv_hdmi_destroy(struct drm_connector *connector) | ||
270 | { | ||
271 | struct psb_intel_encoder *psb_intel_encoder = | ||
272 | psb_intel_attached_encoder(connector); | ||
273 | |||
274 | if (psb_intel_encoder->i2c_bus) | ||
275 | psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); | ||
276 | drm_sysfs_connector_remove(connector); | ||
277 | drm_connector_cleanup(connector); | ||
278 | kfree(connector); | ||
279 | } | ||
280 | |||
281 | static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = { | ||
282 | .dpms = cdv_hdmi_dpms, | ||
283 | .mode_fixup = cdv_hdmi_mode_fixup, | ||
284 | .prepare = psb_intel_encoder_prepare, | ||
285 | .mode_set = cdv_hdmi_mode_set, | ||
286 | .commit = psb_intel_encoder_commit, | ||
287 | }; | ||
288 | |||
289 | static const struct drm_connector_helper_funcs | ||
290 | cdv_hdmi_connector_helper_funcs = { | ||
291 | .get_modes = cdv_hdmi_get_modes, | ||
292 | .mode_valid = cdv_hdmi_mode_valid, | ||
293 | .best_encoder = psb_intel_best_encoder, | ||
294 | }; | ||
295 | |||
296 | static const struct drm_connector_funcs cdv_hdmi_connector_funcs = { | ||
297 | .dpms = drm_helper_connector_dpms, | ||
298 | .save = cdv_hdmi_save, | ||
299 | .restore = cdv_hdmi_restore, | ||
300 | .detect = cdv_hdmi_detect, | ||
301 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
302 | .set_property = cdv_hdmi_set_property, | ||
303 | .destroy = cdv_hdmi_destroy, | ||
304 | }; | ||
305 | |||
306 | void cdv_hdmi_init(struct drm_device *dev, | ||
307 | struct psb_intel_mode_device *mode_dev, int reg) | ||
308 | { | ||
309 | struct psb_intel_encoder *psb_intel_encoder; | ||
310 | struct psb_intel_connector *psb_intel_connector; | ||
311 | struct drm_connector *connector; | ||
312 | struct drm_encoder *encoder; | ||
313 | struct mid_intel_hdmi_priv *hdmi_priv; | ||
314 | int ddc_bus; | ||
315 | |||
316 | psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), | ||
317 | GFP_KERNEL); | ||
318 | |||
319 | if (!psb_intel_encoder) | ||
320 | return; | ||
321 | |||
322 | psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), | ||
323 | GFP_KERNEL); | ||
324 | |||
325 | if (!psb_intel_connector) | ||
326 | goto err_connector; | ||
327 | |||
328 | hdmi_priv = kzalloc(sizeof(struct mid_intel_hdmi_priv), GFP_KERNEL); | ||
329 | |||
330 | if (!hdmi_priv) | ||
331 | goto err_priv; | ||
332 | |||
333 | connector = &psb_intel_connector->base; | ||
334 | encoder = &psb_intel_encoder->base; | ||
335 | drm_connector_init(dev, connector, | ||
336 | &cdv_hdmi_connector_funcs, | ||
337 | DRM_MODE_CONNECTOR_DVID); | ||
338 | |||
339 | drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs, | ||
340 | DRM_MODE_ENCODER_TMDS); | ||
341 | |||
342 | psb_intel_connector_attach_encoder(psb_intel_connector, | ||
343 | psb_intel_encoder); | ||
344 | psb_intel_encoder->type = INTEL_OUTPUT_HDMI; | ||
345 | hdmi_priv->hdmi_reg = reg; | ||
346 | hdmi_priv->has_hdmi_sink = false; | ||
347 | psb_intel_encoder->dev_priv = hdmi_priv; | ||
348 | |||
349 | drm_encoder_helper_add(encoder, &cdv_hdmi_helper_funcs); | ||
350 | drm_connector_helper_add(connector, | ||
351 | &cdv_hdmi_connector_helper_funcs); | ||
352 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
353 | connector->interlace_allowed = false; | ||
354 | connector->doublescan_allowed = false; | ||
355 | |||
356 | drm_connector_attach_property(connector, | ||
357 | dev->mode_config.scaling_mode_property, | ||
358 | DRM_MODE_SCALE_FULLSCREEN); | ||
359 | |||
360 | switch (reg) { | ||
361 | case SDVOB: | ||
362 | ddc_bus = GPIOE; | ||
363 | break; | ||
364 | case SDVOC: | ||
365 | ddc_bus = GPIOD; | ||
366 | break; | ||
367 | default: | ||
368 | DRM_ERROR("unknown reg 0x%x for HDMI\n", reg); | ||
369 | goto failed_ddc; | ||
370 | break; | ||
371 | } | ||
372 | |||
373 | psb_intel_encoder->i2c_bus = psb_intel_i2c_create(dev, | ||
374 | ddc_bus, (reg == SDVOB) ? "HDMIB" : "HDMIC"); | ||
375 | |||
376 | if (!psb_intel_encoder->i2c_bus) { | ||
377 | dev_err(dev->dev, "No ddc adapter available!\n"); | ||
378 | goto failed_ddc; | ||
379 | } | ||
380 | |||
381 | hdmi_priv->hdmi_i2c_adapter = | ||
382 | &(psb_intel_encoder->i2c_bus->adapter); | ||
383 | hdmi_priv->dev = dev; | ||
384 | drm_sysfs_connector_add(connector); | ||
385 | return; | ||
386 | |||
387 | failed_ddc: | ||
388 | drm_encoder_cleanup(encoder); | ||
389 | drm_connector_cleanup(connector); | ||
390 | err_priv: | ||
391 | kfree(psb_intel_connector); | ||
392 | err_connector: | ||
393 | kfree(psb_intel_encoder); | ||
394 | } | ||
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c new file mode 100644 index 00000000000..50e744be985 --- /dev/null +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c | |||
@@ -0,0 +1,732 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2011 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | * Dave Airlie <airlied@linux.ie> | ||
20 | * Jesse Barnes <jesse.barnes@intel.com> | ||
21 | */ | ||
22 | |||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/dmi.h> | ||
25 | #include <drm/drmP.h> | ||
26 | |||
27 | #include "intel_bios.h" | ||
28 | #include "psb_drv.h" | ||
29 | #include "psb_intel_drv.h" | ||
30 | #include "psb_intel_reg.h" | ||
31 | #include "power.h" | ||
32 | #include <linux/pm_runtime.h> | ||
33 | #include "cdv_device.h" | ||
34 | |||
35 | /** | ||
36 | * LVDS I2C backlight control macros | ||
37 | */ | ||
38 | #define BRIGHTNESS_MAX_LEVEL 100 | ||
39 | #define BRIGHTNESS_MASK 0xFF | ||
40 | #define BLC_I2C_TYPE 0x01 | ||
41 | #define BLC_PWM_TYPT 0x02 | ||
42 | |||
43 | #define BLC_POLARITY_NORMAL 0 | ||
44 | #define BLC_POLARITY_INVERSE 1 | ||
45 | |||
46 | #define PSB_BLC_MAX_PWM_REG_FREQ (0xFFFE) | ||
47 | #define PSB_BLC_MIN_PWM_REG_FREQ (0x2) | ||
48 | #define PSB_BLC_PWM_PRECISION_FACTOR (10) | ||
49 | #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) | ||
50 | #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) | ||
51 | |||
52 | struct cdv_intel_lvds_priv { | ||
53 | /** | ||
54 | * Saved LVDO output states | ||
55 | */ | ||
56 | uint32_t savePP_ON; | ||
57 | uint32_t savePP_OFF; | ||
58 | uint32_t saveLVDS; | ||
59 | uint32_t savePP_CONTROL; | ||
60 | uint32_t savePP_CYCLE; | ||
61 | uint32_t savePFIT_CONTROL; | ||
62 | uint32_t savePFIT_PGM_RATIOS; | ||
63 | uint32_t saveBLC_PWM_CTL; | ||
64 | }; | ||
65 | |||
66 | /* | ||
67 | * Returns the maximum level of the backlight duty cycle field. | ||
68 | */ | ||
69 | static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev) | ||
70 | { | ||
71 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
72 | u32 retval; | ||
73 | |||
74 | if (gma_power_begin(dev, false)) { | ||
75 | retval = ((REG_READ(BLC_PWM_CTL) & | ||
76 | BACKLIGHT_MODULATION_FREQ_MASK) >> | ||
77 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | ||
78 | |||
79 | gma_power_end(dev); | ||
80 | } else | ||
81 | retval = ((dev_priv->saveBLC_PWM_CTL & | ||
82 | BACKLIGHT_MODULATION_FREQ_MASK) >> | ||
83 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | ||
84 | |||
85 | return retval; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * Set LVDS backlight level by I2C command | ||
90 | */ | ||
91 | static int cdv_lvds_i2c_set_brightness(struct drm_device *dev, | ||
92 | unsigned int level) | ||
93 | { | ||
94 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
95 | struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; | ||
96 | u8 out_buf[2]; | ||
97 | unsigned int blc_i2c_brightness; | ||
98 | |||
99 | struct i2c_msg msgs[] = { | ||
100 | { | ||
101 | .addr = lvds_i2c_bus->slave_addr, | ||
102 | .flags = 0, | ||
103 | .len = 2, | ||
104 | .buf = out_buf, | ||
105 | } | ||
106 | }; | ||
107 | |||
108 | blc_i2c_brightness = BRIGHTNESS_MASK & ((unsigned int)level * | ||
109 | BRIGHTNESS_MASK / | ||
110 | BRIGHTNESS_MAX_LEVEL); | ||
111 | |||
112 | if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) | ||
113 | blc_i2c_brightness = BRIGHTNESS_MASK - blc_i2c_brightness; | ||
114 | |||
115 | out_buf[0] = dev_priv->lvds_bl->brightnesscmd; | ||
116 | out_buf[1] = (u8)blc_i2c_brightness; | ||
117 | |||
118 | if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) | ||
119 | return 0; | ||
120 | |||
121 | DRM_ERROR("I2C transfer error\n"); | ||
122 | return -1; | ||
123 | } | ||
124 | |||
125 | |||
126 | static int cdv_lvds_pwm_set_brightness(struct drm_device *dev, int level) | ||
127 | { | ||
128 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
129 | |||
130 | u32 max_pwm_blc; | ||
131 | u32 blc_pwm_duty_cycle; | ||
132 | |||
133 | max_pwm_blc = cdv_intel_lvds_get_max_backlight(dev); | ||
134 | |||
135 | /*BLC_PWM_CTL Should be initiated while backlight device init*/ | ||
136 | BUG_ON((max_pwm_blc & PSB_BLC_MAX_PWM_REG_FREQ) == 0); | ||
137 | |||
138 | blc_pwm_duty_cycle = level * max_pwm_blc / BRIGHTNESS_MAX_LEVEL; | ||
139 | |||
140 | if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) | ||
141 | blc_pwm_duty_cycle = max_pwm_blc - blc_pwm_duty_cycle; | ||
142 | |||
143 | blc_pwm_duty_cycle &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; | ||
144 | REG_WRITE(BLC_PWM_CTL, | ||
145 | (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) | | ||
146 | (blc_pwm_duty_cycle)); | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Set LVDS backlight level either by I2C or PWM | ||
153 | */ | ||
154 | void cdv_intel_lvds_set_brightness(struct drm_device *dev, int level) | ||
155 | { | ||
156 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
157 | |||
158 | if (!dev_priv->lvds_bl) { | ||
159 | DRM_ERROR("NO LVDS Backlight Info\n"); | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | if (dev_priv->lvds_bl->type == BLC_I2C_TYPE) | ||
164 | cdv_lvds_i2c_set_brightness(dev, level); | ||
165 | else | ||
166 | cdv_lvds_pwm_set_brightness(dev, level); | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * Sets the backlight level. | ||
171 | * | ||
172 | * level backlight level, from 0 to cdv_intel_lvds_get_max_backlight(). | ||
173 | */ | ||
174 | static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level) | ||
175 | { | ||
176 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
177 | u32 blc_pwm_ctl; | ||
178 | |||
179 | if (gma_power_begin(dev, false)) { | ||
180 | blc_pwm_ctl = | ||
181 | REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; | ||
182 | REG_WRITE(BLC_PWM_CTL, | ||
183 | (blc_pwm_ctl | | ||
184 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); | ||
185 | gma_power_end(dev); | ||
186 | } else { | ||
187 | blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL & | ||
188 | ~BACKLIGHT_DUTY_CYCLE_MASK; | ||
189 | dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl | | ||
190 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * Sets the power state for the panel. | ||
196 | */ | ||
197 | static void cdv_intel_lvds_set_power(struct drm_device *dev, | ||
198 | struct drm_encoder *encoder, bool on) | ||
199 | { | ||
200 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
201 | u32 pp_status; | ||
202 | |||
203 | if (!gma_power_begin(dev, true)) | ||
204 | return; | ||
205 | |||
206 | if (on) { | ||
207 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | | ||
208 | POWER_TARGET_ON); | ||
209 | do { | ||
210 | pp_status = REG_READ(PP_STATUS); | ||
211 | } while ((pp_status & PP_ON) == 0); | ||
212 | |||
213 | cdv_intel_lvds_set_backlight(dev, | ||
214 | dev_priv->mode_dev.backlight_duty_cycle); | ||
215 | } else { | ||
216 | cdv_intel_lvds_set_backlight(dev, 0); | ||
217 | |||
218 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & | ||
219 | ~POWER_TARGET_ON); | ||
220 | do { | ||
221 | pp_status = REG_READ(PP_STATUS); | ||
222 | } while (pp_status & PP_ON); | ||
223 | } | ||
224 | gma_power_end(dev); | ||
225 | } | ||
226 | |||
227 | static void cdv_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
228 | { | ||
229 | struct drm_device *dev = encoder->dev; | ||
230 | if (mode == DRM_MODE_DPMS_ON) | ||
231 | cdv_intel_lvds_set_power(dev, encoder, true); | ||
232 | else | ||
233 | cdv_intel_lvds_set_power(dev, encoder, false); | ||
234 | /* XXX: We never power down the LVDS pairs. */ | ||
235 | } | ||
236 | |||
237 | static void cdv_intel_lvds_save(struct drm_connector *connector) | ||
238 | { | ||
239 | } | ||
240 | |||
241 | static void cdv_intel_lvds_restore(struct drm_connector *connector) | ||
242 | { | ||
243 | } | ||
244 | |||
245 | int cdv_intel_lvds_mode_valid(struct drm_connector *connector, | ||
246 | struct drm_display_mode *mode) | ||
247 | { | ||
248 | struct drm_device *dev = connector->dev; | ||
249 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
250 | struct drm_display_mode *fixed_mode = | ||
251 | dev_priv->mode_dev.panel_fixed_mode; | ||
252 | |||
253 | /* just in case */ | ||
254 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
255 | return MODE_NO_DBLESCAN; | ||
256 | |||
257 | /* just in case */ | ||
258 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
259 | return MODE_NO_INTERLACE; | ||
260 | |||
261 | if (fixed_mode) { | ||
262 | if (mode->hdisplay > fixed_mode->hdisplay) | ||
263 | return MODE_PANEL; | ||
264 | if (mode->vdisplay > fixed_mode->vdisplay) | ||
265 | return MODE_PANEL; | ||
266 | } | ||
267 | return MODE_OK; | ||
268 | } | ||
269 | |||
270 | bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, | ||
271 | struct drm_display_mode *mode, | ||
272 | struct drm_display_mode *adjusted_mode) | ||
273 | { | ||
274 | struct drm_device *dev = encoder->dev; | ||
275 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
276 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
277 | struct drm_encoder *tmp_encoder; | ||
278 | struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; | ||
279 | |||
280 | /* Should never happen!! */ | ||
281 | list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, | ||
282 | head) { | ||
283 | if (tmp_encoder != encoder | ||
284 | && tmp_encoder->crtc == encoder->crtc) { | ||
285 | printk(KERN_ERR "Can't enable LVDS and another " | ||
286 | "encoder on the same pipe\n"); | ||
287 | return false; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * If we have timings from the BIOS for the panel, put them in | ||
293 | * to the adjusted mode. The CRTC will be set up for this mode, | ||
294 | * with the panel scaling set up to source from the H/VDisplay | ||
295 | * of the original mode. | ||
296 | */ | ||
297 | if (panel_fixed_mode != NULL) { | ||
298 | adjusted_mode->hdisplay = panel_fixed_mode->hdisplay; | ||
299 | adjusted_mode->hsync_start = panel_fixed_mode->hsync_start; | ||
300 | adjusted_mode->hsync_end = panel_fixed_mode->hsync_end; | ||
301 | adjusted_mode->htotal = panel_fixed_mode->htotal; | ||
302 | adjusted_mode->vdisplay = panel_fixed_mode->vdisplay; | ||
303 | adjusted_mode->vsync_start = panel_fixed_mode->vsync_start; | ||
304 | adjusted_mode->vsync_end = panel_fixed_mode->vsync_end; | ||
305 | adjusted_mode->vtotal = panel_fixed_mode->vtotal; | ||
306 | adjusted_mode->clock = panel_fixed_mode->clock; | ||
307 | drm_mode_set_crtcinfo(adjusted_mode, | ||
308 | CRTC_INTERLACE_HALVE_V); | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * XXX: It would be nice to support lower refresh rates on the | ||
313 | * panels to reduce power consumption, and perhaps match the | ||
314 | * user's requested refresh rate. | ||
315 | */ | ||
316 | |||
317 | return true; | ||
318 | } | ||
319 | |||
320 | static void cdv_intel_lvds_prepare(struct drm_encoder *encoder) | ||
321 | { | ||
322 | struct drm_device *dev = encoder->dev; | ||
323 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
324 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
325 | |||
326 | if (!gma_power_begin(dev, true)) | ||
327 | return; | ||
328 | |||
329 | mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); | ||
330 | mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & | ||
331 | BACKLIGHT_DUTY_CYCLE_MASK); | ||
332 | |||
333 | cdv_intel_lvds_set_power(dev, encoder, false); | ||
334 | |||
335 | gma_power_end(dev); | ||
336 | } | ||
337 | |||
338 | static void cdv_intel_lvds_commit(struct drm_encoder *encoder) | ||
339 | { | ||
340 | struct drm_device *dev = encoder->dev; | ||
341 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
342 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
343 | |||
344 | if (mode_dev->backlight_duty_cycle == 0) | ||
345 | mode_dev->backlight_duty_cycle = | ||
346 | cdv_intel_lvds_get_max_backlight(dev); | ||
347 | |||
348 | cdv_intel_lvds_set_power(dev, encoder, true); | ||
349 | } | ||
350 | |||
351 | static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, | ||
352 | struct drm_display_mode *mode, | ||
353 | struct drm_display_mode *adjusted_mode) | ||
354 | { | ||
355 | struct drm_device *dev = encoder->dev; | ||
356 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
357 | u32 pfit_control; | ||
358 | |||
359 | /* | ||
360 | * The LVDS pin pair will already have been turned on in the | ||
361 | * cdv_intel_crtc_mode_set since it has a large impact on the DPLL | ||
362 | * settings. | ||
363 | */ | ||
364 | |||
365 | /* | ||
366 | * Enable automatic panel scaling so that non-native modes fill the | ||
367 | * screen. Should be enabled before the pipe is enabled, according to | ||
368 | * register description and PRM. | ||
369 | */ | ||
370 | if (mode->hdisplay != adjusted_mode->hdisplay || | ||
371 | mode->vdisplay != adjusted_mode->vdisplay) | ||
372 | pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | | ||
373 | HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | | ||
374 | HORIZ_INTERP_BILINEAR); | ||
375 | else | ||
376 | pfit_control = 0; | ||
377 | |||
378 | if (dev_priv->lvds_dither) | ||
379 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; | ||
380 | |||
381 | REG_WRITE(PFIT_CONTROL, pfit_control); | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * Detect the LVDS connection. | ||
386 | * | ||
387 | * This always returns CONNECTOR_STATUS_CONNECTED. | ||
388 | * This connector should only have | ||
389 | * been set up if the LVDS was actually connected anyway. | ||
390 | */ | ||
391 | static enum drm_connector_status cdv_intel_lvds_detect( | ||
392 | struct drm_connector *connector, bool force) | ||
393 | { | ||
394 | return connector_status_connected; | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. | ||
399 | */ | ||
400 | static int cdv_intel_lvds_get_modes(struct drm_connector *connector) | ||
401 | { | ||
402 | struct drm_device *dev = connector->dev; | ||
403 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
404 | struct psb_intel_encoder *psb_intel_encoder = | ||
405 | psb_intel_attached_encoder(connector); | ||
406 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
407 | int ret; | ||
408 | |||
409 | ret = psb_intel_ddc_get_modes(connector, &psb_intel_encoder->i2c_bus->adapter); | ||
410 | |||
411 | if (ret) | ||
412 | return ret; | ||
413 | |||
414 | /* Didn't get an EDID, so | ||
415 | * Set wide sync ranges so we get all modes | ||
416 | * handed to valid_mode for checking | ||
417 | */ | ||
418 | connector->display_info.min_vfreq = 0; | ||
419 | connector->display_info.max_vfreq = 200; | ||
420 | connector->display_info.min_hfreq = 0; | ||
421 | connector->display_info.max_hfreq = 200; | ||
422 | if (mode_dev->panel_fixed_mode != NULL) { | ||
423 | struct drm_display_mode *mode = | ||
424 | drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); | ||
425 | drm_mode_probed_add(connector, mode); | ||
426 | return 1; | ||
427 | } | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * cdv_intel_lvds_destroy - unregister and free LVDS structures | ||
434 | * @connector: connector to free | ||
435 | * | ||
436 | * Unregister the DDC bus for this connector then free the driver private | ||
437 | * structure. | ||
438 | */ | ||
439 | void cdv_intel_lvds_destroy(struct drm_connector *connector) | ||
440 | { | ||
441 | struct psb_intel_encoder *psb_intel_encoder = | ||
442 | psb_intel_attached_encoder(connector); | ||
443 | |||
444 | if (psb_intel_encoder->i2c_bus) | ||
445 | psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); | ||
446 | drm_sysfs_connector_remove(connector); | ||
447 | drm_connector_cleanup(connector); | ||
448 | kfree(connector); | ||
449 | } | ||
450 | |||
451 | int cdv_intel_lvds_set_property(struct drm_connector *connector, | ||
452 | struct drm_property *property, | ||
453 | uint64_t value) | ||
454 | { | ||
455 | struct drm_encoder *encoder = connector->encoder; | ||
456 | |||
457 | if (!strcmp(property->name, "scaling mode") && encoder) { | ||
458 | struct psb_intel_crtc *crtc = | ||
459 | to_psb_intel_crtc(encoder->crtc); | ||
460 | uint64_t curValue; | ||
461 | |||
462 | if (!crtc) | ||
463 | return -1; | ||
464 | |||
465 | switch (value) { | ||
466 | case DRM_MODE_SCALE_FULLSCREEN: | ||
467 | break; | ||
468 | case DRM_MODE_SCALE_NO_SCALE: | ||
469 | break; | ||
470 | case DRM_MODE_SCALE_ASPECT: | ||
471 | break; | ||
472 | default: | ||
473 | return -1; | ||
474 | } | ||
475 | |||
476 | if (drm_connector_property_get_value(connector, | ||
477 | property, | ||
478 | &curValue)) | ||
479 | return -1; | ||
480 | |||
481 | if (curValue == value) | ||
482 | return 0; | ||
483 | |||
484 | if (drm_connector_property_set_value(connector, | ||
485 | property, | ||
486 | value)) | ||
487 | return -1; | ||
488 | |||
489 | if (crtc->saved_mode.hdisplay != 0 && | ||
490 | crtc->saved_mode.vdisplay != 0) { | ||
491 | if (!drm_crtc_helper_set_mode(encoder->crtc, | ||
492 | &crtc->saved_mode, | ||
493 | encoder->crtc->x, | ||
494 | encoder->crtc->y, | ||
495 | encoder->crtc->fb)) | ||
496 | return -1; | ||
497 | } | ||
498 | } else if (!strcmp(property->name, "backlight") && encoder) { | ||
499 | if (drm_connector_property_set_value(connector, | ||
500 | property, | ||
501 | value)) | ||
502 | return -1; | ||
503 | else { | ||
504 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
505 | struct drm_psb_private *dev_priv = | ||
506 | encoder->dev->dev_private; | ||
507 | struct backlight_device *bd = | ||
508 | dev_priv->backlight_device; | ||
509 | bd->props.brightness = value; | ||
510 | backlight_update_status(bd); | ||
511 | #endif | ||
512 | } | ||
513 | } else if (!strcmp(property->name, "DPMS") && encoder) { | ||
514 | struct drm_encoder_helper_funcs *helpers = | ||
515 | encoder->helper_private; | ||
516 | helpers->dpms(encoder, value); | ||
517 | } | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static const struct drm_encoder_helper_funcs | ||
522 | cdv_intel_lvds_helper_funcs = { | ||
523 | .dpms = cdv_intel_lvds_encoder_dpms, | ||
524 | .mode_fixup = cdv_intel_lvds_mode_fixup, | ||
525 | .prepare = cdv_intel_lvds_prepare, | ||
526 | .mode_set = cdv_intel_lvds_mode_set, | ||
527 | .commit = cdv_intel_lvds_commit, | ||
528 | }; | ||
529 | |||
530 | static const struct drm_connector_helper_funcs | ||
531 | cdv_intel_lvds_connector_helper_funcs = { | ||
532 | .get_modes = cdv_intel_lvds_get_modes, | ||
533 | .mode_valid = cdv_intel_lvds_mode_valid, | ||
534 | .best_encoder = psb_intel_best_encoder, | ||
535 | }; | ||
536 | |||
537 | static const struct drm_connector_funcs cdv_intel_lvds_connector_funcs = { | ||
538 | .dpms = drm_helper_connector_dpms, | ||
539 | .save = cdv_intel_lvds_save, | ||
540 | .restore = cdv_intel_lvds_restore, | ||
541 | .detect = cdv_intel_lvds_detect, | ||
542 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
543 | .set_property = cdv_intel_lvds_set_property, | ||
544 | .destroy = cdv_intel_lvds_destroy, | ||
545 | }; | ||
546 | |||
547 | |||
548 | static void cdv_intel_lvds_enc_destroy(struct drm_encoder *encoder) | ||
549 | { | ||
550 | drm_encoder_cleanup(encoder); | ||
551 | } | ||
552 | |||
553 | const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = { | ||
554 | .destroy = cdv_intel_lvds_enc_destroy, | ||
555 | }; | ||
556 | |||
557 | /** | ||
558 | * cdv_intel_lvds_init - setup LVDS connectors on this device | ||
559 | * @dev: drm device | ||
560 | * | ||
561 | * Create the connector, register the LVDS DDC bus, and try to figure out what | ||
562 | * modes we can display on the LVDS panel (if present). | ||
563 | */ | ||
564 | void cdv_intel_lvds_init(struct drm_device *dev, | ||
565 | struct psb_intel_mode_device *mode_dev) | ||
566 | { | ||
567 | struct psb_intel_encoder *psb_intel_encoder; | ||
568 | struct psb_intel_connector *psb_intel_connector; | ||
569 | struct cdv_intel_lvds_priv *lvds_priv; | ||
570 | struct drm_connector *connector; | ||
571 | struct drm_encoder *encoder; | ||
572 | struct drm_display_mode *scan; | ||
573 | struct drm_crtc *crtc; | ||
574 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
575 | u32 lvds; | ||
576 | int pipe; | ||
577 | |||
578 | psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), | ||
579 | GFP_KERNEL); | ||
580 | if (!psb_intel_encoder) | ||
581 | return; | ||
582 | |||
583 | psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), | ||
584 | GFP_KERNEL); | ||
585 | if (!psb_intel_connector) | ||
586 | goto failed_connector; | ||
587 | |||
588 | lvds_priv = kzalloc(sizeof(struct cdv_intel_lvds_priv), GFP_KERNEL); | ||
589 | if (!lvds_priv) | ||
590 | goto failed_lvds_priv; | ||
591 | |||
592 | psb_intel_encoder->dev_priv = lvds_priv; | ||
593 | |||
594 | connector = &psb_intel_connector->base; | ||
595 | encoder = &psb_intel_encoder->base; | ||
596 | |||
597 | |||
598 | drm_connector_init(dev, connector, | ||
599 | &cdv_intel_lvds_connector_funcs, | ||
600 | DRM_MODE_CONNECTOR_LVDS); | ||
601 | |||
602 | drm_encoder_init(dev, encoder, | ||
603 | &cdv_intel_lvds_enc_funcs, | ||
604 | DRM_MODE_ENCODER_LVDS); | ||
605 | |||
606 | |||
607 | psb_intel_connector_attach_encoder(psb_intel_connector, | ||
608 | psb_intel_encoder); | ||
609 | psb_intel_encoder->type = INTEL_OUTPUT_LVDS; | ||
610 | |||
611 | drm_encoder_helper_add(encoder, &cdv_intel_lvds_helper_funcs); | ||
612 | drm_connector_helper_add(connector, | ||
613 | &cdv_intel_lvds_connector_helper_funcs); | ||
614 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
615 | connector->interlace_allowed = false; | ||
616 | connector->doublescan_allowed = false; | ||
617 | |||
618 | /*Attach connector properties*/ | ||
619 | drm_connector_attach_property(connector, | ||
620 | dev->mode_config.scaling_mode_property, | ||
621 | DRM_MODE_SCALE_FULLSCREEN); | ||
622 | drm_connector_attach_property(connector, | ||
623 | dev_priv->backlight_property, | ||
624 | BRIGHTNESS_MAX_LEVEL); | ||
625 | |||
626 | /** | ||
627 | * Set up I2C bus | ||
628 | * FIXME: distroy i2c_bus when exit | ||
629 | */ | ||
630 | psb_intel_encoder->i2c_bus = psb_intel_i2c_create(dev, | ||
631 | GPIOB, | ||
632 | "LVDSBLC_B"); | ||
633 | if (!psb_intel_encoder->i2c_bus) { | ||
634 | dev_printk(KERN_ERR, | ||
635 | &dev->pdev->dev, "I2C bus registration failed.\n"); | ||
636 | goto failed_blc_i2c; | ||
637 | } | ||
638 | psb_intel_encoder->i2c_bus->slave_addr = 0x2C; | ||
639 | dev_priv->lvds_i2c_bus = psb_intel_encoder->i2c_bus; | ||
640 | |||
641 | /* | ||
642 | * LVDS discovery: | ||
643 | * 1) check for EDID on DDC | ||
644 | * 2) check for VBT data | ||
645 | * 3) check to see if LVDS is already on | ||
646 | * if none of the above, no panel | ||
647 | * 4) make sure lid is open | ||
648 | * if closed, act like it's not there for now | ||
649 | */ | ||
650 | |||
651 | /* Set up the DDC bus. */ | ||
652 | psb_intel_encoder->ddc_bus = psb_intel_i2c_create(dev, | ||
653 | GPIOC, | ||
654 | "LVDSDDC_C"); | ||
655 | if (!psb_intel_encoder->ddc_bus) { | ||
656 | dev_printk(KERN_ERR, &dev->pdev->dev, | ||
657 | "DDC bus registration " "failed.\n"); | ||
658 | goto failed_ddc; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * Attempt to get the fixed panel mode from DDC. Assume that the | ||
663 | * preferred mode is the right one. | ||
664 | */ | ||
665 | psb_intel_ddc_get_modes(connector, | ||
666 | &psb_intel_encoder->ddc_bus->adapter); | ||
667 | list_for_each_entry(scan, &connector->probed_modes, head) { | ||
668 | if (scan->type & DRM_MODE_TYPE_PREFERRED) { | ||
669 | mode_dev->panel_fixed_mode = | ||
670 | drm_mode_duplicate(dev, scan); | ||
671 | goto out; /* FIXME: check for quirks */ | ||
672 | } | ||
673 | } | ||
674 | |||
675 | /* Failed to get EDID, what about VBT? do we need this?*/ | ||
676 | if (dev_priv->lfp_lvds_vbt_mode) { | ||
677 | mode_dev->panel_fixed_mode = | ||
678 | drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); | ||
679 | if (mode_dev->panel_fixed_mode) { | ||
680 | mode_dev->panel_fixed_mode->type |= | ||
681 | DRM_MODE_TYPE_PREFERRED; | ||
682 | goto out; /* FIXME: check for quirks */ | ||
683 | } | ||
684 | } | ||
685 | /* | ||
686 | * If we didn't get EDID, try checking if the panel is already turned | ||
687 | * on. If so, assume that whatever is currently programmed is the | ||
688 | * correct mode. | ||
689 | */ | ||
690 | lvds = REG_READ(LVDS); | ||
691 | pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; | ||
692 | crtc = psb_intel_get_crtc_from_pipe(dev, pipe); | ||
693 | |||
694 | if (crtc && (lvds & LVDS_PORT_EN)) { | ||
695 | mode_dev->panel_fixed_mode = | ||
696 | cdv_intel_crtc_mode_get(dev, crtc); | ||
697 | if (mode_dev->panel_fixed_mode) { | ||
698 | mode_dev->panel_fixed_mode->type |= | ||
699 | DRM_MODE_TYPE_PREFERRED; | ||
700 | goto out; /* FIXME: check for quirks */ | ||
701 | } | ||
702 | } | ||
703 | |||
704 | /* If we still don't have a mode after all that, give up. */ | ||
705 | if (!mode_dev->panel_fixed_mode) { | ||
706 | DRM_DEBUG | ||
707 | ("Found no modes on the lvds, ignoring the LVDS\n"); | ||
708 | goto failed_find; | ||
709 | } | ||
710 | |||
711 | out: | ||
712 | drm_sysfs_connector_add(connector); | ||
713 | return; | ||
714 | |||
715 | failed_find: | ||
716 | printk(KERN_ERR "Failed find\n"); | ||
717 | if (psb_intel_encoder->ddc_bus) | ||
718 | psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); | ||
719 | failed_ddc: | ||
720 | printk(KERN_ERR "Failed DDC\n"); | ||
721 | if (psb_intel_encoder->i2c_bus) | ||
722 | psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); | ||
723 | failed_blc_i2c: | ||
724 | printk(KERN_ERR "Failed BLC\n"); | ||
725 | drm_encoder_cleanup(encoder); | ||
726 | drm_connector_cleanup(connector); | ||
727 | kfree(lvds_priv); | ||
728 | failed_lvds_priv: | ||
729 | kfree(psb_intel_connector); | ||
730 | failed_connector: | ||
731 | kfree(psb_intel_encoder); | ||
732 | } | ||
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c new file mode 100644 index 00000000000..791c0ef1a65 --- /dev/null +++ b/drivers/gpu/drm/gma500/framebuffer.c | |||
@@ -0,0 +1,831 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007-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 | #include <linux/module.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/tty.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/fb.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/console.h> | ||
31 | |||
32 | #include <drm/drmP.h> | ||
33 | #include <drm/drm.h> | ||
34 | #include <drm/drm_crtc.h> | ||
35 | #include <drm/drm_fb_helper.h> | ||
36 | |||
37 | #include "psb_drv.h" | ||
38 | #include "psb_intel_reg.h" | ||
39 | #include "psb_intel_drv.h" | ||
40 | #include "framebuffer.h" | ||
41 | #include "gtt.h" | ||
42 | |||
43 | static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb); | ||
44 | static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
45 | struct drm_file *file_priv, | ||
46 | unsigned int *handle); | ||
47 | |||
48 | static const struct drm_framebuffer_funcs psb_fb_funcs = { | ||
49 | .destroy = psb_user_framebuffer_destroy, | ||
50 | .create_handle = psb_user_framebuffer_create_handle, | ||
51 | }; | ||
52 | |||
53 | #define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16) | ||
54 | |||
55 | static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
56 | unsigned blue, unsigned transp, | ||
57 | struct fb_info *info) | ||
58 | { | ||
59 | struct psb_fbdev *fbdev = info->par; | ||
60 | struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; | ||
61 | uint32_t v; | ||
62 | |||
63 | if (!fb) | ||
64 | return -ENOMEM; | ||
65 | |||
66 | if (regno > 255) | ||
67 | return 1; | ||
68 | |||
69 | red = CMAP_TOHW(red, info->var.red.length); | ||
70 | blue = CMAP_TOHW(blue, info->var.blue.length); | ||
71 | green = CMAP_TOHW(green, info->var.green.length); | ||
72 | transp = CMAP_TOHW(transp, info->var.transp.length); | ||
73 | |||
74 | v = (red << info->var.red.offset) | | ||
75 | (green << info->var.green.offset) | | ||
76 | (blue << info->var.blue.offset) | | ||
77 | (transp << info->var.transp.offset); | ||
78 | |||
79 | if (regno < 16) { | ||
80 | switch (fb->bits_per_pixel) { | ||
81 | case 16: | ||
82 | ((uint32_t *) info->pseudo_palette)[regno] = v; | ||
83 | break; | ||
84 | case 24: | ||
85 | case 32: | ||
86 | ((uint32_t *) info->pseudo_palette)[regno] = v; | ||
87 | break; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info) | ||
95 | { | ||
96 | struct psb_fbdev *fbdev = info->par; | ||
97 | struct psb_framebuffer *psbfb = &fbdev->pfb; | ||
98 | struct drm_device *dev = psbfb->base.dev; | ||
99 | |||
100 | /* | ||
101 | * We have to poke our nose in here. The core fb code assumes | ||
102 | * panning is part of the hardware that can be invoked before | ||
103 | * the actual fb is mapped. In our case that isn't quite true. | ||
104 | */ | ||
105 | if (psbfb->gtt->npage) { | ||
106 | /* GTT roll shifts in 4K pages, we need to shift the right | ||
107 | number of pages */ | ||
108 | int pages = info->fix.line_length >> 12; | ||
109 | psb_gtt_roll(dev, psbfb->gtt, var->yoffset * pages); | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | void psbfb_suspend(struct drm_device *dev) | ||
115 | { | ||
116 | struct drm_framebuffer *fb = 0; | ||
117 | struct psb_framebuffer *psbfb = to_psb_fb(fb); | ||
118 | |||
119 | console_lock(); | ||
120 | mutex_lock(&dev->mode_config.mutex); | ||
121 | list_for_each_entry(fb, &dev->mode_config.fb_list, head) { | ||
122 | struct fb_info *info = psbfb->fbdev; | ||
123 | fb_set_suspend(info, 1); | ||
124 | drm_fb_helper_blank(FB_BLANK_POWERDOWN, info); | ||
125 | } | ||
126 | mutex_unlock(&dev->mode_config.mutex); | ||
127 | console_unlock(); | ||
128 | } | ||
129 | |||
130 | void psbfb_resume(struct drm_device *dev) | ||
131 | { | ||
132 | struct drm_framebuffer *fb = 0; | ||
133 | struct psb_framebuffer *psbfb = to_psb_fb(fb); | ||
134 | |||
135 | console_lock(); | ||
136 | mutex_lock(&dev->mode_config.mutex); | ||
137 | list_for_each_entry(fb, &dev->mode_config.fb_list, head) { | ||
138 | struct fb_info *info = psbfb->fbdev; | ||
139 | fb_set_suspend(info, 0); | ||
140 | drm_fb_helper_blank(FB_BLANK_UNBLANK, info); | ||
141 | } | ||
142 | mutex_unlock(&dev->mode_config.mutex); | ||
143 | console_unlock(); | ||
144 | drm_helper_disable_unused_functions(dev); | ||
145 | } | ||
146 | |||
147 | static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
148 | { | ||
149 | struct psb_framebuffer *psbfb = vma->vm_private_data; | ||
150 | struct drm_device *dev = psbfb->base.dev; | ||
151 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
152 | int page_num; | ||
153 | int i; | ||
154 | unsigned long address; | ||
155 | int ret; | ||
156 | unsigned long pfn; | ||
157 | /* FIXME: assumes fb at stolen base which may not be true */ | ||
158 | unsigned long phys_addr = (unsigned long)dev_priv->stolen_base; | ||
159 | |||
160 | page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
161 | address = (unsigned long)vmf->virtual_address; | ||
162 | |||
163 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
164 | |||
165 | for (i = 0; i < page_num; i++) { | ||
166 | pfn = (phys_addr >> PAGE_SHIFT); | ||
167 | |||
168 | ret = vm_insert_mixed(vma, address, pfn); | ||
169 | if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) | ||
170 | break; | ||
171 | else if (unlikely(ret != 0)) { | ||
172 | ret = (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; | ||
173 | return ret; | ||
174 | } | ||
175 | address += PAGE_SIZE; | ||
176 | phys_addr += PAGE_SIZE; | ||
177 | } | ||
178 | return VM_FAULT_NOPAGE; | ||
179 | } | ||
180 | |||
181 | static void psbfb_vm_open(struct vm_area_struct *vma) | ||
182 | { | ||
183 | } | ||
184 | |||
185 | static void psbfb_vm_close(struct vm_area_struct *vma) | ||
186 | { | ||
187 | } | ||
188 | |||
189 | static struct vm_operations_struct psbfb_vm_ops = { | ||
190 | .fault = psbfb_vm_fault, | ||
191 | .open = psbfb_vm_open, | ||
192 | .close = psbfb_vm_close | ||
193 | }; | ||
194 | |||
195 | static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
196 | { | ||
197 | struct psb_fbdev *fbdev = info->par; | ||
198 | struct psb_framebuffer *psbfb = &fbdev->pfb; | ||
199 | |||
200 | if (vma->vm_pgoff != 0) | ||
201 | return -EINVAL; | ||
202 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) | ||
203 | return -EINVAL; | ||
204 | |||
205 | if (!psbfb->addr_space) | ||
206 | psbfb->addr_space = vma->vm_file->f_mapping; | ||
207 | /* | ||
208 | * If this is a GEM object then info->screen_base is the virtual | ||
209 | * kernel remapping of the object. FIXME: Review if this is | ||
210 | * suitable for our mmap work | ||
211 | */ | ||
212 | vma->vm_ops = &psbfb_vm_ops; | ||
213 | vma->vm_private_data = (void *)psbfb; | ||
214 | vma->vm_flags |= VM_RESERVED | VM_IO | | ||
215 | VM_MIXEDMAP | VM_DONTEXPAND; | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int psbfb_ioctl(struct fb_info *info, unsigned int cmd, | ||
220 | unsigned long arg) | ||
221 | { | ||
222 | return -ENOTTY; | ||
223 | } | ||
224 | |||
225 | static struct fb_ops psbfb_ops = { | ||
226 | .owner = THIS_MODULE, | ||
227 | .fb_check_var = drm_fb_helper_check_var, | ||
228 | .fb_set_par = drm_fb_helper_set_par, | ||
229 | .fb_blank = drm_fb_helper_blank, | ||
230 | .fb_setcolreg = psbfb_setcolreg, | ||
231 | .fb_fillrect = cfb_fillrect, | ||
232 | .fb_copyarea = psbfb_copyarea, | ||
233 | .fb_imageblit = cfb_imageblit, | ||
234 | .fb_mmap = psbfb_mmap, | ||
235 | .fb_sync = psbfb_sync, | ||
236 | .fb_ioctl = psbfb_ioctl, | ||
237 | }; | ||
238 | |||
239 | static struct fb_ops psbfb_roll_ops = { | ||
240 | .owner = THIS_MODULE, | ||
241 | .fb_check_var = drm_fb_helper_check_var, | ||
242 | .fb_set_par = drm_fb_helper_set_par, | ||
243 | .fb_blank = drm_fb_helper_blank, | ||
244 | .fb_setcolreg = psbfb_setcolreg, | ||
245 | .fb_fillrect = cfb_fillrect, | ||
246 | .fb_copyarea = cfb_copyarea, | ||
247 | .fb_imageblit = cfb_imageblit, | ||
248 | .fb_pan_display = psbfb_pan, | ||
249 | .fb_mmap = psbfb_mmap, | ||
250 | .fb_sync = psbfb_sync, | ||
251 | .fb_ioctl = psbfb_ioctl, | ||
252 | }; | ||
253 | |||
254 | static struct fb_ops psbfb_unaccel_ops = { | ||
255 | .owner = THIS_MODULE, | ||
256 | .fb_check_var = drm_fb_helper_check_var, | ||
257 | .fb_set_par = drm_fb_helper_set_par, | ||
258 | .fb_blank = drm_fb_helper_blank, | ||
259 | .fb_setcolreg = psbfb_setcolreg, | ||
260 | .fb_fillrect = cfb_fillrect, | ||
261 | .fb_copyarea = cfb_copyarea, | ||
262 | .fb_imageblit = cfb_imageblit, | ||
263 | .fb_mmap = psbfb_mmap, | ||
264 | .fb_ioctl = psbfb_ioctl, | ||
265 | }; | ||
266 | |||
267 | /** | ||
268 | * psb_framebuffer_init - initialize a framebuffer | ||
269 | * @dev: our DRM device | ||
270 | * @fb: framebuffer to set up | ||
271 | * @mode_cmd: mode description | ||
272 | * @gt: backing object | ||
273 | * | ||
274 | * Configure and fill in the boilerplate for our frame buffer. Return | ||
275 | * 0 on success or an error code if we fail. | ||
276 | */ | ||
277 | static int psb_framebuffer_init(struct drm_device *dev, | ||
278 | struct psb_framebuffer *fb, | ||
279 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
280 | struct gtt_range *gt) | ||
281 | { | ||
282 | u32 bpp, depth; | ||
283 | int ret; | ||
284 | |||
285 | drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); | ||
286 | |||
287 | if (mode_cmd->pitches[0] & 63) | ||
288 | return -EINVAL; | ||
289 | switch (bpp) { | ||
290 | case 8: | ||
291 | case 16: | ||
292 | case 24: | ||
293 | case 32: | ||
294 | break; | ||
295 | default: | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); | ||
299 | if (ret) { | ||
300 | dev_err(dev->dev, "framebuffer init failed: %d\n", ret); | ||
301 | return ret; | ||
302 | } | ||
303 | drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); | ||
304 | fb->gtt = gt; | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * psb_framebuffer_create - create a framebuffer backed by gt | ||
310 | * @dev: our DRM device | ||
311 | * @mode_cmd: the description of the requested mode | ||
312 | * @gt: the backing object | ||
313 | * | ||
314 | * Create a framebuffer object backed by the gt, and fill in the | ||
315 | * boilerplate required | ||
316 | * | ||
317 | * TODO: review object references | ||
318 | */ | ||
319 | |||
320 | static struct drm_framebuffer *psb_framebuffer_create | ||
321 | (struct drm_device *dev, | ||
322 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
323 | struct gtt_range *gt) | ||
324 | { | ||
325 | struct psb_framebuffer *fb; | ||
326 | int ret; | ||
327 | |||
328 | fb = kzalloc(sizeof(*fb), GFP_KERNEL); | ||
329 | if (!fb) | ||
330 | return ERR_PTR(-ENOMEM); | ||
331 | |||
332 | ret = psb_framebuffer_init(dev, fb, mode_cmd, gt); | ||
333 | if (ret) { | ||
334 | kfree(fb); | ||
335 | return ERR_PTR(ret); | ||
336 | } | ||
337 | return &fb->base; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * psbfb_alloc - allocate frame buffer memory | ||
342 | * @dev: the DRM device | ||
343 | * @aligned_size: space needed | ||
344 | * @force: fall back to GEM buffers if need be | ||
345 | * | ||
346 | * Allocate the frame buffer. In the usual case we get a GTT range that | ||
347 | * is stolen memory backed and life is simple. If there isn't sufficient | ||
348 | * we fail as we don't have the virtual mapping space to really vmap it | ||
349 | * and the kernel console code can't handle non linear framebuffers. | ||
350 | * | ||
351 | * Re-address this as and if the framebuffer layer grows this ability. | ||
352 | */ | ||
353 | static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) | ||
354 | { | ||
355 | struct gtt_range *backing; | ||
356 | /* Begin by trying to use stolen memory backing */ | ||
357 | backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1); | ||
358 | if (backing) { | ||
359 | if (drm_gem_private_object_init(dev, | ||
360 | &backing->gem, aligned_size) == 0) | ||
361 | return backing; | ||
362 | psb_gtt_free_range(dev, backing); | ||
363 | } | ||
364 | return NULL; | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * psbfb_create - create a framebuffer | ||
369 | * @fbdev: the framebuffer device | ||
370 | * @sizes: specification of the layout | ||
371 | * | ||
372 | * Create a framebuffer to the specifications provided | ||
373 | */ | ||
374 | static int psbfb_create(struct psb_fbdev *fbdev, | ||
375 | struct drm_fb_helper_surface_size *sizes) | ||
376 | { | ||
377 | struct drm_device *dev = fbdev->psb_fb_helper.dev; | ||
378 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
379 | struct fb_info *info; | ||
380 | struct drm_framebuffer *fb; | ||
381 | struct psb_framebuffer *psbfb = &fbdev->pfb; | ||
382 | struct drm_mode_fb_cmd2 mode_cmd; | ||
383 | struct device *device = &dev->pdev->dev; | ||
384 | int size; | ||
385 | int ret; | ||
386 | struct gtt_range *backing; | ||
387 | u32 bpp, depth; | ||
388 | int gtt_roll = 0; | ||
389 | int pitch_lines = 0; | ||
390 | |||
391 | mode_cmd.width = sizes->surface_width; | ||
392 | mode_cmd.height = sizes->surface_height; | ||
393 | bpp = sizes->surface_bpp; | ||
394 | |||
395 | /* No 24bit packed */ | ||
396 | if (bpp == 24) | ||
397 | bpp = 32; | ||
398 | |||
399 | do { | ||
400 | /* | ||
401 | * Acceleration via the GTT requires pitch to be | ||
402 | * power of two aligned. Preferably page but less | ||
403 | * is ok with some fonts | ||
404 | */ | ||
405 | mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 4096 >> pitch_lines); | ||
406 | depth = sizes->surface_depth; | ||
407 | |||
408 | size = mode_cmd.pitches[0] * mode_cmd.height; | ||
409 | size = ALIGN(size, PAGE_SIZE); | ||
410 | |||
411 | /* Allocate the fb in the GTT with stolen page backing */ | ||
412 | backing = psbfb_alloc(dev, size); | ||
413 | |||
414 | if (pitch_lines) | ||
415 | pitch_lines *= 2; | ||
416 | else | ||
417 | pitch_lines = 1; | ||
418 | gtt_roll++; | ||
419 | } while (backing == NULL && pitch_lines <= 16); | ||
420 | |||
421 | /* The final pitch we accepted if we succeeded */ | ||
422 | pitch_lines /= 2; | ||
423 | |||
424 | if (backing == NULL) { | ||
425 | /* | ||
426 | * We couldn't get the space we wanted, fall back to the | ||
427 | * display engine requirement instead. The HW requires | ||
428 | * the pitch to be 64 byte aligned | ||
429 | */ | ||
430 | |||
431 | gtt_roll = 0; /* Don't use GTT accelerated scrolling */ | ||
432 | pitch_lines = 64; | ||
433 | |||
434 | mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 64); | ||
435 | |||
436 | size = mode_cmd.pitches[0] * mode_cmd.height; | ||
437 | size = ALIGN(size, PAGE_SIZE); | ||
438 | |||
439 | /* Allocate the framebuffer in the GTT with stolen page backing */ | ||
440 | backing = psbfb_alloc(dev, size); | ||
441 | if (backing == NULL) | ||
442 | return -ENOMEM; | ||
443 | } | ||
444 | |||
445 | mutex_lock(&dev->struct_mutex); | ||
446 | |||
447 | info = framebuffer_alloc(0, device); | ||
448 | if (!info) { | ||
449 | ret = -ENOMEM; | ||
450 | goto out_err1; | ||
451 | } | ||
452 | info->par = fbdev; | ||
453 | |||
454 | mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); | ||
455 | |||
456 | ret = psb_framebuffer_init(dev, psbfb, &mode_cmd, backing); | ||
457 | if (ret) | ||
458 | goto out_unref; | ||
459 | |||
460 | fb = &psbfb->base; | ||
461 | psbfb->fbdev = info; | ||
462 | |||
463 | fbdev->psb_fb_helper.fb = fb; | ||
464 | fbdev->psb_fb_helper.fbdev = info; | ||
465 | |||
466 | strcpy(info->fix.id, "psbfb"); | ||
467 | |||
468 | info->flags = FBINFO_DEFAULT; | ||
469 | if (dev_priv->ops->accel_2d && pitch_lines > 8) /* 2D engine */ | ||
470 | info->fbops = &psbfb_ops; | ||
471 | else if (gtt_roll) { /* GTT rolling seems best */ | ||
472 | info->fbops = &psbfb_roll_ops; | ||
473 | info->flags |= FBINFO_HWACCEL_YPAN; | ||
474 | } else /* Software */ | ||
475 | info->fbops = &psbfb_unaccel_ops; | ||
476 | |||
477 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
478 | if (ret) { | ||
479 | ret = -ENOMEM; | ||
480 | goto out_unref; | ||
481 | } | ||
482 | |||
483 | info->fix.smem_start = dev->mode_config.fb_base; | ||
484 | info->fix.smem_len = size; | ||
485 | info->fix.ywrapstep = gtt_roll; | ||
486 | info->fix.ypanstep = 0; | ||
487 | |||
488 | /* Accessed stolen memory directly */ | ||
489 | info->screen_base = (char *)dev_priv->vram_addr + | ||
490 | backing->offset; | ||
491 | info->screen_size = size; | ||
492 | |||
493 | if (dev_priv->gtt.stolen_size) { | ||
494 | info->apertures = alloc_apertures(1); | ||
495 | if (!info->apertures) { | ||
496 | ret = -ENOMEM; | ||
497 | goto out_unref; | ||
498 | } | ||
499 | info->apertures->ranges[0].base = dev->mode_config.fb_base; | ||
500 | info->apertures->ranges[0].size = dev_priv->gtt.stolen_size; | ||
501 | } | ||
502 | |||
503 | drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | ||
504 | drm_fb_helper_fill_var(info, &fbdev->psb_fb_helper, | ||
505 | sizes->fb_width, sizes->fb_height); | ||
506 | |||
507 | info->fix.mmio_start = pci_resource_start(dev->pdev, 0); | ||
508 | info->fix.mmio_len = pci_resource_len(dev->pdev, 0); | ||
509 | |||
510 | info->pixmap.size = 64 * 1024; | ||
511 | info->pixmap.buf_align = 8; | ||
512 | info->pixmap.access_align = 32; | ||
513 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
514 | info->pixmap.scan_align = 1; | ||
515 | |||
516 | dev_info(dev->dev, "allocated %dx%d fb\n", | ||
517 | psbfb->base.width, psbfb->base.height); | ||
518 | |||
519 | mutex_unlock(&dev->struct_mutex); | ||
520 | return 0; | ||
521 | out_unref: | ||
522 | if (backing->stolen) | ||
523 | psb_gtt_free_range(dev, backing); | ||
524 | else | ||
525 | drm_gem_object_unreference(&backing->gem); | ||
526 | out_err1: | ||
527 | mutex_unlock(&dev->struct_mutex); | ||
528 | psb_gtt_free_range(dev, backing); | ||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | /** | ||
533 | * psb_user_framebuffer_create - create framebuffer | ||
534 | * @dev: our DRM device | ||
535 | * @filp: client file | ||
536 | * @cmd: mode request | ||
537 | * | ||
538 | * Create a new framebuffer backed by a userspace GEM object | ||
539 | */ | ||
540 | static struct drm_framebuffer *psb_user_framebuffer_create | ||
541 | (struct drm_device *dev, struct drm_file *filp, | ||
542 | struct drm_mode_fb_cmd2 *cmd) | ||
543 | { | ||
544 | struct gtt_range *r; | ||
545 | struct drm_gem_object *obj; | ||
546 | |||
547 | /* | ||
548 | * Find the GEM object and thus the gtt range object that is | ||
549 | * to back this space | ||
550 | */ | ||
551 | obj = drm_gem_object_lookup(dev, filp, cmd->handles[0]); | ||
552 | if (obj == NULL) | ||
553 | return ERR_PTR(-ENOENT); | ||
554 | |||
555 | /* Let the core code do all the work */ | ||
556 | r = container_of(obj, struct gtt_range, gem); | ||
557 | return psb_framebuffer_create(dev, cmd, r); | ||
558 | } | ||
559 | |||
560 | static void psbfb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
561 | u16 blue, int regno) | ||
562 | { | ||
563 | } | ||
564 | |||
565 | static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red, | ||
566 | u16 *green, u16 *blue, int regno) | ||
567 | { | ||
568 | } | ||
569 | |||
570 | static int psbfb_probe(struct drm_fb_helper *helper, | ||
571 | struct drm_fb_helper_surface_size *sizes) | ||
572 | { | ||
573 | struct psb_fbdev *psb_fbdev = (struct psb_fbdev *)helper; | ||
574 | int new_fb = 0; | ||
575 | int ret; | ||
576 | |||
577 | if (!helper->fb) { | ||
578 | ret = psbfb_create(psb_fbdev, sizes); | ||
579 | if (ret) | ||
580 | return ret; | ||
581 | new_fb = 1; | ||
582 | } | ||
583 | return new_fb; | ||
584 | } | ||
585 | |||
586 | struct drm_fb_helper_funcs psb_fb_helper_funcs = { | ||
587 | .gamma_set = psbfb_gamma_set, | ||
588 | .gamma_get = psbfb_gamma_get, | ||
589 | .fb_probe = psbfb_probe, | ||
590 | }; | ||
591 | |||
592 | int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) | ||
593 | { | ||
594 | struct fb_info *info; | ||
595 | struct psb_framebuffer *psbfb = &fbdev->pfb; | ||
596 | |||
597 | if (fbdev->psb_fb_helper.fbdev) { | ||
598 | info = fbdev->psb_fb_helper.fbdev; | ||
599 | unregister_framebuffer(info); | ||
600 | if (info->cmap.len) | ||
601 | fb_dealloc_cmap(&info->cmap); | ||
602 | framebuffer_release(info); | ||
603 | } | ||
604 | drm_fb_helper_fini(&fbdev->psb_fb_helper); | ||
605 | drm_framebuffer_cleanup(&psbfb->base); | ||
606 | |||
607 | if (psbfb->gtt) | ||
608 | drm_gem_object_unreference(&psbfb->gtt->gem); | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | int psb_fbdev_init(struct drm_device *dev) | ||
613 | { | ||
614 | struct psb_fbdev *fbdev; | ||
615 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
616 | |||
617 | fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL); | ||
618 | if (!fbdev) { | ||
619 | dev_err(dev->dev, "no memory\n"); | ||
620 | return -ENOMEM; | ||
621 | } | ||
622 | |||
623 | dev_priv->fbdev = fbdev; | ||
624 | fbdev->psb_fb_helper.funcs = &psb_fb_helper_funcs; | ||
625 | |||
626 | drm_fb_helper_init(dev, &fbdev->psb_fb_helper, dev_priv->ops->crtcs, | ||
627 | INTELFB_CONN_LIMIT); | ||
628 | |||
629 | drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper); | ||
630 | drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32); | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | void psb_fbdev_fini(struct drm_device *dev) | ||
635 | { | ||
636 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
637 | |||
638 | if (!dev_priv->fbdev) | ||
639 | return; | ||
640 | |||
641 | psb_fbdev_destroy(dev, dev_priv->fbdev); | ||
642 | kfree(dev_priv->fbdev); | ||
643 | dev_priv->fbdev = NULL; | ||
644 | } | ||
645 | |||
646 | static void psbfb_output_poll_changed(struct drm_device *dev) | ||
647 | { | ||
648 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
649 | struct psb_fbdev *fbdev = (struct psb_fbdev *)dev_priv->fbdev; | ||
650 | drm_fb_helper_hotplug_event(&fbdev->psb_fb_helper); | ||
651 | } | ||
652 | |||
653 | /** | ||
654 | * psb_user_framebuffer_create_handle - add hamdle to a framebuffer | ||
655 | * @fb: framebuffer | ||
656 | * @file_priv: our DRM file | ||
657 | * @handle: returned handle | ||
658 | * | ||
659 | * Our framebuffer object is a GTT range which also contains a GEM | ||
660 | * object. We need to turn it into a handle for userspace. GEM will do | ||
661 | * the work for us | ||
662 | */ | ||
663 | static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
664 | struct drm_file *file_priv, | ||
665 | unsigned int *handle) | ||
666 | { | ||
667 | struct psb_framebuffer *psbfb = to_psb_fb(fb); | ||
668 | struct gtt_range *r = psbfb->gtt; | ||
669 | return drm_gem_handle_create(file_priv, &r->gem, handle); | ||
670 | } | ||
671 | |||
672 | /** | ||
673 | * psb_user_framebuffer_destroy - destruct user created fb | ||
674 | * @fb: framebuffer | ||
675 | * | ||
676 | * User framebuffers are backed by GEM objects so all we have to do is | ||
677 | * clean up a bit and drop the reference, GEM will handle the fallout | ||
678 | */ | ||
679 | static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb) | ||
680 | { | ||
681 | struct psb_framebuffer *psbfb = to_psb_fb(fb); | ||
682 | struct gtt_range *r = psbfb->gtt; | ||
683 | struct drm_device *dev = fb->dev; | ||
684 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
685 | struct psb_fbdev *fbdev = dev_priv->fbdev; | ||
686 | struct drm_crtc *crtc; | ||
687 | int reset = 0; | ||
688 | |||
689 | /* Should never get stolen memory for a user fb */ | ||
690 | WARN_ON(r->stolen); | ||
691 | |||
692 | /* Check if we are erroneously live */ | ||
693 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
694 | if (crtc->fb == fb) | ||
695 | reset = 1; | ||
696 | |||
697 | if (reset) | ||
698 | /* | ||
699 | * Now force a sane response before we permit the DRM CRTC | ||
700 | * layer to do stupid things like blank the display. Instead | ||
701 | * we reset this framebuffer as if the user had forced a reset. | ||
702 | * We must do this before the cleanup so that the DRM layer | ||
703 | * doesn't get a chance to stick its oar in where it isn't | ||
704 | * wanted. | ||
705 | */ | ||
706 | drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper); | ||
707 | |||
708 | /* Let DRM do its clean up */ | ||
709 | drm_framebuffer_cleanup(fb); | ||
710 | /* We are no longer using the resource in GEM */ | ||
711 | drm_gem_object_unreference_unlocked(&r->gem); | ||
712 | kfree(fb); | ||
713 | } | ||
714 | |||
715 | static const struct drm_mode_config_funcs psb_mode_funcs = { | ||
716 | .fb_create = psb_user_framebuffer_create, | ||
717 | .output_poll_changed = psbfb_output_poll_changed, | ||
718 | }; | ||
719 | |||
720 | static int psb_create_backlight_property(struct drm_device *dev) | ||
721 | { | ||
722 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
723 | struct drm_property *backlight; | ||
724 | |||
725 | if (dev_priv->backlight_property) | ||
726 | return 0; | ||
727 | |||
728 | backlight = drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
729 | "backlight", 2); | ||
730 | backlight->values[0] = 0; | ||
731 | backlight->values[1] = 100; | ||
732 | |||
733 | dev_priv->backlight_property = backlight; | ||
734 | |||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static void psb_setup_outputs(struct drm_device *dev) | ||
739 | { | ||
740 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
741 | struct drm_connector *connector; | ||
742 | |||
743 | drm_mode_create_scaling_mode_property(dev); | ||
744 | psb_create_backlight_property(dev); | ||
745 | |||
746 | dev_priv->ops->output_init(dev); | ||
747 | |||
748 | list_for_each_entry(connector, &dev->mode_config.connector_list, | ||
749 | head) { | ||
750 | struct psb_intel_encoder *psb_intel_encoder = | ||
751 | psb_intel_attached_encoder(connector); | ||
752 | struct drm_encoder *encoder = &psb_intel_encoder->base; | ||
753 | int crtc_mask = 0, clone_mask = 0; | ||
754 | |||
755 | /* valid crtcs */ | ||
756 | switch (psb_intel_encoder->type) { | ||
757 | case INTEL_OUTPUT_ANALOG: | ||
758 | crtc_mask = (1 << 0); | ||
759 | clone_mask = (1 << INTEL_OUTPUT_ANALOG); | ||
760 | break; | ||
761 | case INTEL_OUTPUT_SDVO: | ||
762 | crtc_mask = ((1 << 0) | (1 << 1)); | ||
763 | clone_mask = (1 << INTEL_OUTPUT_SDVO); | ||
764 | break; | ||
765 | case INTEL_OUTPUT_LVDS: | ||
766 | if (IS_MRST(dev)) | ||
767 | crtc_mask = (1 << 0); | ||
768 | else | ||
769 | crtc_mask = (1 << 1); | ||
770 | clone_mask = (1 << INTEL_OUTPUT_LVDS); | ||
771 | break; | ||
772 | case INTEL_OUTPUT_MIPI: | ||
773 | crtc_mask = (1 << 0); | ||
774 | clone_mask = (1 << INTEL_OUTPUT_MIPI); | ||
775 | break; | ||
776 | case INTEL_OUTPUT_MIPI2: | ||
777 | crtc_mask = (1 << 2); | ||
778 | clone_mask = (1 << INTEL_OUTPUT_MIPI2); | ||
779 | break; | ||
780 | case INTEL_OUTPUT_HDMI: | ||
781 | if (IS_MFLD(dev)) | ||
782 | crtc_mask = (1 << 1); | ||
783 | else | ||
784 | crtc_mask = (1 << 0); | ||
785 | clone_mask = (1 << INTEL_OUTPUT_HDMI); | ||
786 | break; | ||
787 | } | ||
788 | encoder->possible_crtcs = crtc_mask; | ||
789 | encoder->possible_clones = | ||
790 | psb_intel_connector_clones(dev, clone_mask); | ||
791 | } | ||
792 | } | ||
793 | |||
794 | void psb_modeset_init(struct drm_device *dev) | ||
795 | { | ||
796 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
797 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
798 | int i; | ||
799 | |||
800 | drm_mode_config_init(dev); | ||
801 | |||
802 | dev->mode_config.min_width = 0; | ||
803 | dev->mode_config.min_height = 0; | ||
804 | |||
805 | dev->mode_config.funcs = (void *) &psb_mode_funcs; | ||
806 | |||
807 | /* set memory base */ | ||
808 | /* Oaktrail and Poulsbo should use BAR 2*/ | ||
809 | pci_read_config_dword(dev->pdev, PSB_BSM, (u32 *) | ||
810 | &(dev->mode_config.fb_base)); | ||
811 | |||
812 | /* num pipes is 2 for PSB but 1 for Mrst */ | ||
813 | for (i = 0; i < dev_priv->num_pipe; i++) | ||
814 | psb_intel_crtc_init(dev, i, mode_dev); | ||
815 | |||
816 | dev->mode_config.max_width = 2048; | ||
817 | dev->mode_config.max_height = 2048; | ||
818 | |||
819 | psb_setup_outputs(dev); | ||
820 | } | ||
821 | |||
822 | void psb_modeset_cleanup(struct drm_device *dev) | ||
823 | { | ||
824 | mutex_lock(&dev->struct_mutex); | ||
825 | |||
826 | drm_kms_helper_poll_fini(dev); | ||
827 | psb_fbdev_fini(dev); | ||
828 | drm_mode_config_cleanup(dev); | ||
829 | |||
830 | mutex_unlock(&dev->struct_mutex); | ||
831 | } | ||
diff --git a/drivers/gpu/drm/gma500/framebuffer.h b/drivers/gpu/drm/gma500/framebuffer.h new file mode 100644 index 00000000000..989558a9e6e --- /dev/null +++ b/drivers/gpu/drm/gma500/framebuffer.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2011, Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _FRAMEBUFFER_H_ | ||
23 | #define _FRAMEBUFFER_H_ | ||
24 | |||
25 | #include <drm/drmP.h> | ||
26 | #include <drm/drm_fb_helper.h> | ||
27 | |||
28 | #include "psb_drv.h" | ||
29 | |||
30 | struct psb_framebuffer { | ||
31 | struct drm_framebuffer base; | ||
32 | struct address_space *addr_space; | ||
33 | struct fb_info *fbdev; | ||
34 | struct gtt_range *gtt; | ||
35 | }; | ||
36 | |||
37 | struct psb_fbdev { | ||
38 | struct drm_fb_helper psb_fb_helper; | ||
39 | struct psb_framebuffer pfb; | ||
40 | }; | ||
41 | |||
42 | #define to_psb_fb(x) container_of(x, struct psb_framebuffer, base) | ||
43 | |||
44 | extern int psb_intel_connector_clones(struct drm_device *dev, int type_mask); | ||
45 | |||
46 | #endif | ||
47 | |||
diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c new file mode 100644 index 00000000000..9fbb86868e2 --- /dev/null +++ b/drivers/gpu/drm/gma500/gem.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * psb GEM interface | ||
3 | * | ||
4 | * Copyright (c) 2011, Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Authors: Alan Cox | ||
20 | * | ||
21 | * TODO: | ||
22 | * - we need to work out if the MMU is relevant (eg for | ||
23 | * accelerated operations on a GEM object) | ||
24 | */ | ||
25 | |||
26 | #include <drm/drmP.h> | ||
27 | #include <drm/drm.h> | ||
28 | #include "gma_drm.h" | ||
29 | #include "psb_drv.h" | ||
30 | |||
31 | int psb_gem_init_object(struct drm_gem_object *obj) | ||
32 | { | ||
33 | return -EINVAL; | ||
34 | } | ||
35 | |||
36 | void psb_gem_free_object(struct drm_gem_object *obj) | ||
37 | { | ||
38 | struct gtt_range *gtt = container_of(obj, struct gtt_range, gem); | ||
39 | drm_gem_object_release_wrap(obj); | ||
40 | /* This must occur last as it frees up the memory of the GEM object */ | ||
41 | psb_gtt_free_range(obj->dev, gtt); | ||
42 | } | ||
43 | |||
44 | int psb_gem_get_aperture(struct drm_device *dev, void *data, | ||
45 | struct drm_file *file) | ||
46 | { | ||
47 | return -EINVAL; | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * psb_gem_dumb_map_gtt - buffer mapping for dumb interface | ||
52 | * @file: our drm client file | ||
53 | * @dev: drm device | ||
54 | * @handle: GEM handle to the object (from dumb_create) | ||
55 | * | ||
56 | * Do the necessary setup to allow the mapping of the frame buffer | ||
57 | * into user memory. We don't have to do much here at the moment. | ||
58 | */ | ||
59 | int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, | ||
60 | uint32_t handle, uint64_t *offset) | ||
61 | { | ||
62 | int ret = 0; | ||
63 | struct drm_gem_object *obj; | ||
64 | |||
65 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
66 | return -ENODEV; | ||
67 | |||
68 | mutex_lock(&dev->struct_mutex); | ||
69 | |||
70 | /* GEM does all our handle to object mapping */ | ||
71 | obj = drm_gem_object_lookup(dev, file, handle); | ||
72 | if (obj == NULL) { | ||
73 | ret = -ENOENT; | ||
74 | goto unlock; | ||
75 | } | ||
76 | /* What validation is needed here ? */ | ||
77 | |||
78 | /* Make it mmapable */ | ||
79 | if (!obj->map_list.map) { | ||
80 | ret = gem_create_mmap_offset(obj); | ||
81 | if (ret) | ||
82 | goto out; | ||
83 | } | ||
84 | /* GEM should really work out the hash offsets for us */ | ||
85 | *offset = (u64)obj->map_list.hash.key << PAGE_SHIFT; | ||
86 | out: | ||
87 | drm_gem_object_unreference(obj); | ||
88 | unlock: | ||
89 | mutex_unlock(&dev->struct_mutex); | ||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * psb_gem_create - create a mappable object | ||
95 | * @file: the DRM file of the client | ||
96 | * @dev: our device | ||
97 | * @size: the size requested | ||
98 | * @handlep: returned handle (opaque number) | ||
99 | * | ||
100 | * Create a GEM object, fill in the boilerplate and attach a handle to | ||
101 | * it so that userspace can speak about it. This does the core work | ||
102 | * for the various methods that do/will create GEM objects for things | ||
103 | */ | ||
104 | static int psb_gem_create(struct drm_file *file, | ||
105 | struct drm_device *dev, uint64_t size, uint32_t *handlep) | ||
106 | { | ||
107 | struct gtt_range *r; | ||
108 | int ret; | ||
109 | u32 handle; | ||
110 | |||
111 | size = roundup(size, PAGE_SIZE); | ||
112 | |||
113 | /* Allocate our object - for now a direct gtt range which is not | ||
114 | stolen memory backed */ | ||
115 | r = psb_gtt_alloc_range(dev, size, "gem", 0); | ||
116 | if (r == NULL) { | ||
117 | dev_err(dev->dev, "no memory for %lld byte GEM object\n", size); | ||
118 | return -ENOSPC; | ||
119 | } | ||
120 | /* Initialize the extra goodies GEM needs to do all the hard work */ | ||
121 | if (drm_gem_object_init(dev, &r->gem, size) != 0) { | ||
122 | psb_gtt_free_range(dev, r); | ||
123 | /* GEM doesn't give an error code so use -ENOMEM */ | ||
124 | dev_err(dev->dev, "GEM init failed for %lld\n", size); | ||
125 | return -ENOMEM; | ||
126 | } | ||
127 | /* Give the object a handle so we can carry it more easily */ | ||
128 | ret = drm_gem_handle_create(file, &r->gem, &handle); | ||
129 | if (ret) { | ||
130 | dev_err(dev->dev, "GEM handle failed for %p, %lld\n", | ||
131 | &r->gem, size); | ||
132 | drm_gem_object_release(&r->gem); | ||
133 | psb_gtt_free_range(dev, r); | ||
134 | return ret; | ||
135 | } | ||
136 | /* We have the initial and handle reference but need only one now */ | ||
137 | drm_gem_object_unreference(&r->gem); | ||
138 | *handlep = handle; | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * psb_gem_dumb_create - create a dumb buffer | ||
144 | * @drm_file: our client file | ||
145 | * @dev: our device | ||
146 | * @args: the requested arguments copied from userspace | ||
147 | * | ||
148 | * Allocate a buffer suitable for use for a frame buffer of the | ||
149 | * form described by user space. Give userspace a handle by which | ||
150 | * to reference it. | ||
151 | */ | ||
152 | int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, | ||
153 | struct drm_mode_create_dumb *args) | ||
154 | { | ||
155 | args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64); | ||
156 | args->size = args->pitch * args->height; | ||
157 | return psb_gem_create(file, dev, args->size, &args->handle); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * psb_gem_dumb_destroy - destroy a dumb buffer | ||
162 | * @file: client file | ||
163 | * @dev: our DRM device | ||
164 | * @handle: the object handle | ||
165 | * | ||
166 | * Destroy a handle that was created via psb_gem_dumb_create, at least | ||
167 | * we hope it was created that way. i915 seems to assume the caller | ||
168 | * does the checking but that might be worth review ! FIXME | ||
169 | */ | ||
170 | int psb_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, | ||
171 | uint32_t handle) | ||
172 | { | ||
173 | /* No special work needed, drop the reference and see what falls out */ | ||
174 | return drm_gem_handle_delete(file, handle); | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * psb_gem_fault - pagefault handler for GEM objects | ||
179 | * @vma: the VMA of the GEM object | ||
180 | * @vmf: fault detail | ||
181 | * | ||
182 | * Invoked when a fault occurs on an mmap of a GEM managed area. GEM | ||
183 | * does most of the work for us including the actual map/unmap calls | ||
184 | * but we need to do the actual page work. | ||
185 | * | ||
186 | * This code eventually needs to handle faulting objects in and out | ||
187 | * of the GTT and repacking it when we run out of space. We can put | ||
188 | * that off for now and for our simple uses | ||
189 | * | ||
190 | * The VMA was set up by GEM. In doing so it also ensured that the | ||
191 | * vma->vm_private_data points to the GEM object that is backing this | ||
192 | * mapping. | ||
193 | */ | ||
194 | int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
195 | { | ||
196 | struct drm_gem_object *obj; | ||
197 | struct gtt_range *r; | ||
198 | int ret; | ||
199 | unsigned long pfn; | ||
200 | pgoff_t page_offset; | ||
201 | struct drm_device *dev; | ||
202 | struct drm_psb_private *dev_priv; | ||
203 | |||
204 | obj = vma->vm_private_data; /* GEM object */ | ||
205 | dev = obj->dev; | ||
206 | dev_priv = dev->dev_private; | ||
207 | |||
208 | r = container_of(obj, struct gtt_range, gem); /* Get the gtt range */ | ||
209 | |||
210 | /* Make sure we don't parallel update on a fault, nor move or remove | ||
211 | something from beneath our feet */ | ||
212 | mutex_lock(&dev->struct_mutex); | ||
213 | |||
214 | /* For now the mmap pins the object and it stays pinned. As things | ||
215 | stand that will do us no harm */ | ||
216 | if (r->mmapping == 0) { | ||
217 | ret = psb_gtt_pin(r); | ||
218 | if (ret < 0) { | ||
219 | dev_err(dev->dev, "gma500: pin failed: %d\n", ret); | ||
220 | goto fail; | ||
221 | } | ||
222 | r->mmapping = 1; | ||
223 | } | ||
224 | |||
225 | /* Page relative to the VMA start - we must calculate this ourselves | ||
226 | because vmf->pgoff is the fake GEM offset */ | ||
227 | page_offset = ((unsigned long) vmf->virtual_address - vma->vm_start) | ||
228 | >> PAGE_SHIFT; | ||
229 | |||
230 | /* CPU view of the page, don't go via the GART for CPU writes */ | ||
231 | if (r->stolen) | ||
232 | pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT; | ||
233 | else | ||
234 | pfn = page_to_pfn(r->pages[page_offset]); | ||
235 | ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); | ||
236 | |||
237 | fail: | ||
238 | mutex_unlock(&dev->struct_mutex); | ||
239 | switch (ret) { | ||
240 | case 0: | ||
241 | case -ERESTARTSYS: | ||
242 | case -EINTR: | ||
243 | return VM_FAULT_NOPAGE; | ||
244 | case -ENOMEM: | ||
245 | return VM_FAULT_OOM; | ||
246 | default: | ||
247 | return VM_FAULT_SIGBUS; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | static int psb_gem_create_stolen(struct drm_file *file, struct drm_device *dev, | ||
252 | int size, u32 *handle) | ||
253 | { | ||
254 | struct gtt_range *gtt = psb_gtt_alloc_range(dev, size, "gem", 1); | ||
255 | if (gtt == NULL) | ||
256 | return -ENOMEM; | ||
257 | if (drm_gem_private_object_init(dev, >t->gem, size) != 0) | ||
258 | goto free_gtt; | ||
259 | if (drm_gem_handle_create(file, >t->gem, handle) == 0) | ||
260 | return 0; | ||
261 | free_gtt: | ||
262 | psb_gtt_free_range(dev, gtt); | ||
263 | return -ENOMEM; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * GEM interfaces for our specific client | ||
268 | */ | ||
269 | int psb_gem_create_ioctl(struct drm_device *dev, void *data, | ||
270 | struct drm_file *file) | ||
271 | { | ||
272 | struct drm_psb_gem_create *args = data; | ||
273 | int ret; | ||
274 | if (args->flags & GMA_GEM_CREATE_STOLEN) { | ||
275 | ret = psb_gem_create_stolen(file, dev, args->size, | ||
276 | &args->handle); | ||
277 | if (ret == 0) | ||
278 | return 0; | ||
279 | /* Fall throguh */ | ||
280 | args->flags &= ~GMA_GEM_CREATE_STOLEN; | ||
281 | } | ||
282 | return psb_gem_create(file, dev, args->size, &args->handle); | ||
283 | } | ||
284 | |||
285 | int psb_gem_mmap_ioctl(struct drm_device *dev, void *data, | ||
286 | struct drm_file *file) | ||
287 | { | ||
288 | struct drm_psb_gem_mmap *args = data; | ||
289 | return dev->driver->dumb_map_offset(file, dev, | ||
290 | args->handle, &args->offset); | ||
291 | } | ||
292 | |||
diff --git a/drivers/gpu/drm/gma500/gem_glue.c b/drivers/gpu/drm/gma500/gem_glue.c new file mode 100644 index 00000000000..daac1212065 --- /dev/null +++ b/drivers/gpu/drm/gma500/gem_glue.c | |||
@@ -0,0 +1,89 @@ | |||
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 | #include <drm/drmP.h> | ||
21 | #include <drm/drm.h> | ||
22 | |||
23 | void drm_gem_object_release_wrap(struct drm_gem_object *obj) | ||
24 | { | ||
25 | /* Remove the list map if one is present */ | ||
26 | if (obj->map_list.map) { | ||
27 | struct drm_gem_mm *mm = obj->dev->mm_private; | ||
28 | struct drm_map_list *list = &obj->map_list; | ||
29 | drm_ht_remove_item(&mm->offset_hash, &list->hash); | ||
30 | drm_mm_put_block(list->file_offset_node); | ||
31 | kfree(list->map); | ||
32 | list->map = NULL; | ||
33 | } | ||
34 | drm_gem_object_release(obj); | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * gem_create_mmap_offset - invent an mmap offset | ||
39 | * @obj: our object | ||
40 | * | ||
41 | * Standard implementation of offset generation for mmap as is | ||
42 | * duplicated in several drivers. This belongs in GEM. | ||
43 | */ | ||
44 | int gem_create_mmap_offset(struct drm_gem_object *obj) | ||
45 | { | ||
46 | struct drm_device *dev = obj->dev; | ||
47 | struct drm_gem_mm *mm = dev->mm_private; | ||
48 | struct drm_map_list *list; | ||
49 | struct drm_local_map *map; | ||
50 | int ret; | ||
51 | |||
52 | list = &obj->map_list; | ||
53 | list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); | ||
54 | if (list->map == NULL) | ||
55 | return -ENOMEM; | ||
56 | map = list->map; | ||
57 | map->type = _DRM_GEM; | ||
58 | map->size = obj->size; | ||
59 | map->handle = obj; | ||
60 | |||
61 | list->file_offset_node = drm_mm_search_free(&mm->offset_manager, | ||
62 | obj->size / PAGE_SIZE, 0, 0); | ||
63 | if (!list->file_offset_node) { | ||
64 | dev_err(dev->dev, "failed to allocate offset for bo %d\n", | ||
65 | obj->name); | ||
66 | ret = -ENOSPC; | ||
67 | goto free_it; | ||
68 | } | ||
69 | list->file_offset_node = drm_mm_get_block(list->file_offset_node, | ||
70 | obj->size / PAGE_SIZE, 0); | ||
71 | if (!list->file_offset_node) { | ||
72 | ret = -ENOMEM; | ||
73 | goto free_it; | ||
74 | } | ||
75 | list->hash.key = list->file_offset_node->start; | ||
76 | ret = drm_ht_insert_item(&mm->offset_hash, &list->hash); | ||
77 | if (ret) { | ||
78 | dev_err(dev->dev, "failed to add to map hash\n"); | ||
79 | goto free_mm; | ||
80 | } | ||
81 | return 0; | ||
82 | |||
83 | free_mm: | ||
84 | drm_mm_put_block(list->file_offset_node); | ||
85 | free_it: | ||
86 | kfree(list->map); | ||
87 | list->map = NULL; | ||
88 | return ret; | ||
89 | } | ||
diff --git a/drivers/gpu/drm/gma500/gem_glue.h b/drivers/gpu/drm/gma500/gem_glue.h new file mode 100644 index 00000000000..ce5ce30f74d --- /dev/null +++ b/drivers/gpu/drm/gma500/gem_glue.h | |||
@@ -0,0 +1,2 @@ | |||
1 | extern void drm_gem_object_release_wrap(struct drm_gem_object *obj); | ||
2 | extern int gem_create_mmap_offset(struct drm_gem_object *obj); | ||
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c new file mode 100644 index 00000000000..e770bd190a5 --- /dev/null +++ b/drivers/gpu/drm/gma500/gtt.c | |||
@@ -0,0 +1,553 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007, 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 | * Authors: Thomas Hellstrom <thomas-at-tungstengraphics.com> | ||
19 | * Alan Cox <alan@linux.intel.com> | ||
20 | */ | ||
21 | |||
22 | #include <drm/drmP.h> | ||
23 | #include "psb_drv.h" | ||
24 | |||
25 | |||
26 | /* | ||
27 | * GTT resource allocator - manage page mappings in GTT space | ||
28 | */ | ||
29 | |||
30 | /** | ||
31 | * psb_gtt_mask_pte - generate GTT pte entry | ||
32 | * @pfn: page number to encode | ||
33 | * @type: type of memory in the GTT | ||
34 | * | ||
35 | * Set the GTT entry for the appropriate memory type. | ||
36 | */ | ||
37 | static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type) | ||
38 | { | ||
39 | uint32_t mask = PSB_PTE_VALID; | ||
40 | |||
41 | if (type & PSB_MMU_CACHED_MEMORY) | ||
42 | mask |= PSB_PTE_CACHED; | ||
43 | if (type & PSB_MMU_RO_MEMORY) | ||
44 | mask |= PSB_PTE_RO; | ||
45 | if (type & PSB_MMU_WO_MEMORY) | ||
46 | mask |= PSB_PTE_WO; | ||
47 | |||
48 | return (pfn << PAGE_SHIFT) | mask; | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * psb_gtt_entry - find the GTT entries for a gtt_range | ||
53 | * @dev: our DRM device | ||
54 | * @r: our GTT range | ||
55 | * | ||
56 | * Given a gtt_range object return the GTT offset of the page table | ||
57 | * entries for this gtt_range | ||
58 | */ | ||
59 | u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r) | ||
60 | { | ||
61 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
62 | unsigned long offset; | ||
63 | |||
64 | offset = r->resource.start - dev_priv->gtt_mem->start; | ||
65 | |||
66 | return dev_priv->gtt_map + (offset >> PAGE_SHIFT); | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * psb_gtt_insert - put an object into the GTT | ||
71 | * @dev: our DRM device | ||
72 | * @r: our GTT range | ||
73 | * | ||
74 | * Take our preallocated GTT range and insert the GEM object into | ||
75 | * the GTT. This is protected via the gtt mutex which the caller | ||
76 | * must hold. | ||
77 | */ | ||
78 | static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r) | ||
79 | { | ||
80 | u32 *gtt_slot, pte; | ||
81 | struct page **pages; | ||
82 | int i; | ||
83 | |||
84 | if (r->pages == NULL) { | ||
85 | WARN_ON(1); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | WARN_ON(r->stolen); /* refcount these maybe ? */ | ||
90 | |||
91 | gtt_slot = psb_gtt_entry(dev, r); | ||
92 | pages = r->pages; | ||
93 | |||
94 | /* Make sure changes are visible to the GPU */ | ||
95 | set_pages_array_uc(pages, r->npage); | ||
96 | |||
97 | /* Write our page entries into the GTT itself */ | ||
98 | for (i = r->roll; i < r->npage; i++) { | ||
99 | pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); | ||
100 | iowrite32(pte, gtt_slot++); | ||
101 | } | ||
102 | for (i = 0; i < r->roll; i++) { | ||
103 | pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); | ||
104 | iowrite32(pte, gtt_slot++); | ||
105 | } | ||
106 | /* Make sure all the entries are set before we return */ | ||
107 | ioread32(gtt_slot - 1); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * psb_gtt_remove - remove an object from the GTT | ||
114 | * @dev: our DRM device | ||
115 | * @r: our GTT range | ||
116 | * | ||
117 | * Remove a preallocated GTT range from the GTT. Overwrite all the | ||
118 | * page table entries with the dummy page. This is protected via the gtt | ||
119 | * mutex which the caller must hold. | ||
120 | */ | ||
121 | static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) | ||
122 | { | ||
123 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
124 | u32 *gtt_slot, pte; | ||
125 | int i; | ||
126 | |||
127 | WARN_ON(r->stolen); | ||
128 | |||
129 | gtt_slot = psb_gtt_entry(dev, r); | ||
130 | pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), 0); | ||
131 | |||
132 | for (i = 0; i < r->npage; i++) | ||
133 | iowrite32(pte, gtt_slot++); | ||
134 | ioread32(gtt_slot - 1); | ||
135 | set_pages_array_wb(r->pages, r->npage); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * psb_gtt_roll - set scrolling position | ||
140 | * @dev: our DRM device | ||
141 | * @r: the gtt mapping we are using | ||
142 | * @roll: roll offset | ||
143 | * | ||
144 | * Roll an existing pinned mapping by moving the pages through the GTT. | ||
145 | * This allows us to implement hardware scrolling on the consoles without | ||
146 | * a 2D engine | ||
147 | */ | ||
148 | void psb_gtt_roll(struct drm_device *dev, struct gtt_range *r, int roll) | ||
149 | { | ||
150 | u32 *gtt_slot, pte; | ||
151 | int i; | ||
152 | |||
153 | if (roll >= r->npage) { | ||
154 | WARN_ON(1); | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | r->roll = roll; | ||
159 | |||
160 | /* Not currently in the GTT - no worry we will write the mapping at | ||
161 | the right position when it gets pinned */ | ||
162 | if (!r->stolen && !r->in_gart) | ||
163 | return; | ||
164 | |||
165 | gtt_slot = psb_gtt_entry(dev, r); | ||
166 | |||
167 | for (i = r->roll; i < r->npage; i++) { | ||
168 | pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); | ||
169 | iowrite32(pte, gtt_slot++); | ||
170 | } | ||
171 | for (i = 0; i < r->roll; i++) { | ||
172 | pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); | ||
173 | iowrite32(pte, gtt_slot++); | ||
174 | } | ||
175 | ioread32(gtt_slot - 1); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * psb_gtt_attach_pages - attach and pin GEM pages | ||
180 | * @gt: the gtt range | ||
181 | * | ||
182 | * Pin and build an in kernel list of the pages that back our GEM object. | ||
183 | * While we hold this the pages cannot be swapped out. This is protected | ||
184 | * via the gtt mutex which the caller must hold. | ||
185 | */ | ||
186 | static int psb_gtt_attach_pages(struct gtt_range *gt) | ||
187 | { | ||
188 | struct inode *inode; | ||
189 | struct address_space *mapping; | ||
190 | int i; | ||
191 | struct page *p; | ||
192 | int pages = gt->gem.size / PAGE_SIZE; | ||
193 | |||
194 | WARN_ON(gt->pages); | ||
195 | |||
196 | /* This is the shared memory object that backs the GEM resource */ | ||
197 | inode = gt->gem.filp->f_path.dentry->d_inode; | ||
198 | mapping = inode->i_mapping; | ||
199 | |||
200 | gt->pages = kmalloc(pages * sizeof(struct page *), GFP_KERNEL); | ||
201 | if (gt->pages == NULL) | ||
202 | return -ENOMEM; | ||
203 | gt->npage = pages; | ||
204 | |||
205 | for (i = 0; i < pages; i++) { | ||
206 | /* FIXME: needs updating as per mail from Hugh Dickins */ | ||
207 | p = read_cache_page_gfp(mapping, i, | ||
208 | __GFP_COLD | GFP_KERNEL); | ||
209 | if (IS_ERR(p)) | ||
210 | goto err; | ||
211 | gt->pages[i] = p; | ||
212 | } | ||
213 | return 0; | ||
214 | |||
215 | err: | ||
216 | while (i--) | ||
217 | page_cache_release(gt->pages[i]); | ||
218 | kfree(gt->pages); | ||
219 | gt->pages = NULL; | ||
220 | return PTR_ERR(p); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * psb_gtt_detach_pages - attach and pin GEM pages | ||
225 | * @gt: the gtt range | ||
226 | * | ||
227 | * Undo the effect of psb_gtt_attach_pages. At this point the pages | ||
228 | * must have been removed from the GTT as they could now be paged out | ||
229 | * and move bus address. This is protected via the gtt mutex which the | ||
230 | * caller must hold. | ||
231 | */ | ||
232 | static void psb_gtt_detach_pages(struct gtt_range *gt) | ||
233 | { | ||
234 | int i; | ||
235 | for (i = 0; i < gt->npage; i++) { | ||
236 | /* FIXME: do we need to force dirty */ | ||
237 | set_page_dirty(gt->pages[i]); | ||
238 | page_cache_release(gt->pages[i]); | ||
239 | } | ||
240 | kfree(gt->pages); | ||
241 | gt->pages = NULL; | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * psb_gtt_pin - pin pages into the GTT | ||
246 | * @gt: range to pin | ||
247 | * | ||
248 | * Pin a set of pages into the GTT. The pins are refcounted so that | ||
249 | * multiple pins need multiple unpins to undo. | ||
250 | * | ||
251 | * Non GEM backed objects treat this as a no-op as they are always GTT | ||
252 | * backed objects. | ||
253 | */ | ||
254 | int psb_gtt_pin(struct gtt_range *gt) | ||
255 | { | ||
256 | int ret = 0; | ||
257 | struct drm_device *dev = gt->gem.dev; | ||
258 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
259 | |||
260 | mutex_lock(&dev_priv->gtt_mutex); | ||
261 | |||
262 | if (gt->in_gart == 0 && gt->stolen == 0) { | ||
263 | ret = psb_gtt_attach_pages(gt); | ||
264 | if (ret < 0) | ||
265 | goto out; | ||
266 | ret = psb_gtt_insert(dev, gt); | ||
267 | if (ret < 0) { | ||
268 | psb_gtt_detach_pages(gt); | ||
269 | goto out; | ||
270 | } | ||
271 | } | ||
272 | gt->in_gart++; | ||
273 | out: | ||
274 | mutex_unlock(&dev_priv->gtt_mutex); | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * psb_gtt_unpin - Drop a GTT pin requirement | ||
280 | * @gt: range to pin | ||
281 | * | ||
282 | * Undoes the effect of psb_gtt_pin. On the last drop the GEM object | ||
283 | * will be removed from the GTT which will also drop the page references | ||
284 | * and allow the VM to clean up or page stuff. | ||
285 | * | ||
286 | * Non GEM backed objects treat this as a no-op as they are always GTT | ||
287 | * backed objects. | ||
288 | */ | ||
289 | void psb_gtt_unpin(struct gtt_range *gt) | ||
290 | { | ||
291 | struct drm_device *dev = gt->gem.dev; | ||
292 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
293 | |||
294 | mutex_lock(&dev_priv->gtt_mutex); | ||
295 | |||
296 | WARN_ON(!gt->in_gart); | ||
297 | |||
298 | gt->in_gart--; | ||
299 | if (gt->in_gart == 0 && gt->stolen == 0) { | ||
300 | psb_gtt_remove(dev, gt); | ||
301 | psb_gtt_detach_pages(gt); | ||
302 | } | ||
303 | mutex_unlock(&dev_priv->gtt_mutex); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * GTT resource allocator - allocate and manage GTT address space | ||
308 | */ | ||
309 | |||
310 | /** | ||
311 | * psb_gtt_alloc_range - allocate GTT address space | ||
312 | * @dev: Our DRM device | ||
313 | * @len: length (bytes) of address space required | ||
314 | * @name: resource name | ||
315 | * @backed: resource should be backed by stolen pages | ||
316 | * | ||
317 | * Ask the kernel core to find us a suitable range of addresses | ||
318 | * to use for a GTT mapping. | ||
319 | * | ||
320 | * Returns a gtt_range structure describing the object, or NULL on | ||
321 | * error. On successful return the resource is both allocated and marked | ||
322 | * as in use. | ||
323 | */ | ||
324 | struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, | ||
325 | const char *name, int backed) | ||
326 | { | ||
327 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
328 | struct gtt_range *gt; | ||
329 | struct resource *r = dev_priv->gtt_mem; | ||
330 | int ret; | ||
331 | unsigned long start, end; | ||
332 | |||
333 | if (backed) { | ||
334 | /* The start of the GTT is the stolen pages */ | ||
335 | start = r->start; | ||
336 | end = r->start + dev_priv->gtt.stolen_size - 1; | ||
337 | } else { | ||
338 | /* The rest we will use for GEM backed objects */ | ||
339 | start = r->start + dev_priv->gtt.stolen_size; | ||
340 | end = r->end; | ||
341 | } | ||
342 | |||
343 | gt = kzalloc(sizeof(struct gtt_range), GFP_KERNEL); | ||
344 | if (gt == NULL) | ||
345 | return NULL; | ||
346 | gt->resource.name = name; | ||
347 | gt->stolen = backed; | ||
348 | gt->in_gart = backed; | ||
349 | gt->roll = 0; | ||
350 | /* Ensure this is set for non GEM objects */ | ||
351 | gt->gem.dev = dev; | ||
352 | ret = allocate_resource(dev_priv->gtt_mem, >->resource, | ||
353 | len, start, end, PAGE_SIZE, NULL, NULL); | ||
354 | if (ret == 0) { | ||
355 | gt->offset = gt->resource.start - r->start; | ||
356 | return gt; | ||
357 | } | ||
358 | kfree(gt); | ||
359 | return NULL; | ||
360 | } | ||
361 | |||
362 | /** | ||
363 | * psb_gtt_free_range - release GTT address space | ||
364 | * @dev: our DRM device | ||
365 | * @gt: a mapping created with psb_gtt_alloc_range | ||
366 | * | ||
367 | * Release a resource that was allocated with psb_gtt_alloc_range. If the | ||
368 | * object has been pinned by mmap users we clean this up here currently. | ||
369 | */ | ||
370 | void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt) | ||
371 | { | ||
372 | /* Undo the mmap pin if we are destroying the object */ | ||
373 | if (gt->mmapping) { | ||
374 | psb_gtt_unpin(gt); | ||
375 | gt->mmapping = 0; | ||
376 | } | ||
377 | WARN_ON(gt->in_gart && !gt->stolen); | ||
378 | release_resource(>->resource); | ||
379 | kfree(gt); | ||
380 | } | ||
381 | |||
382 | void psb_gtt_alloc(struct drm_device *dev) | ||
383 | { | ||
384 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
385 | init_rwsem(&dev_priv->gtt.sem); | ||
386 | } | ||
387 | |||
388 | void psb_gtt_takedown(struct drm_device *dev) | ||
389 | { | ||
390 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
391 | |||
392 | if (dev_priv->gtt_map) { | ||
393 | iounmap(dev_priv->gtt_map); | ||
394 | dev_priv->gtt_map = NULL; | ||
395 | } | ||
396 | if (dev_priv->gtt_initialized) { | ||
397 | pci_write_config_word(dev->pdev, PSB_GMCH_CTRL, | ||
398 | dev_priv->gmch_ctrl); | ||
399 | PSB_WVDC32(dev_priv->pge_ctl, PSB_PGETBL_CTL); | ||
400 | (void) PSB_RVDC32(PSB_PGETBL_CTL); | ||
401 | } | ||
402 | if (dev_priv->vram_addr) | ||
403 | iounmap(dev_priv->gtt_map); | ||
404 | } | ||
405 | |||
406 | int psb_gtt_init(struct drm_device *dev, int resume) | ||
407 | { | ||
408 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
409 | unsigned gtt_pages; | ||
410 | unsigned long stolen_size, vram_stolen_size; | ||
411 | unsigned i, num_pages; | ||
412 | unsigned pfn_base; | ||
413 | uint32_t vram_pages; | ||
414 | uint32_t dvmt_mode = 0; | ||
415 | struct psb_gtt *pg; | ||
416 | |||
417 | int ret = 0; | ||
418 | uint32_t pte; | ||
419 | |||
420 | mutex_init(&dev_priv->gtt_mutex); | ||
421 | |||
422 | psb_gtt_alloc(dev); | ||
423 | pg = &dev_priv->gtt; | ||
424 | |||
425 | /* Enable the GTT */ | ||
426 | pci_read_config_word(dev->pdev, PSB_GMCH_CTRL, &dev_priv->gmch_ctrl); | ||
427 | pci_write_config_word(dev->pdev, PSB_GMCH_CTRL, | ||
428 | dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); | ||
429 | |||
430 | dev_priv->pge_ctl = PSB_RVDC32(PSB_PGETBL_CTL); | ||
431 | PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); | ||
432 | (void) PSB_RVDC32(PSB_PGETBL_CTL); | ||
433 | |||
434 | /* The root resource we allocate address space from */ | ||
435 | dev_priv->gtt_initialized = 1; | ||
436 | |||
437 | pg->gtt_phys_start = dev_priv->pge_ctl & PAGE_MASK; | ||
438 | |||
439 | /* | ||
440 | * The video mmu has a hw bug when accessing 0x0D0000000. | ||
441 | * Make gatt start at 0x0e000,0000. This doesn't actually | ||
442 | * matter for us but may do if the video acceleration ever | ||
443 | * gets opened up. | ||
444 | */ | ||
445 | pg->mmu_gatt_start = 0xE0000000; | ||
446 | |||
447 | pg->gtt_start = pci_resource_start(dev->pdev, PSB_GTT_RESOURCE); | ||
448 | gtt_pages = pci_resource_len(dev->pdev, PSB_GTT_RESOURCE) | ||
449 | >> PAGE_SHIFT; | ||
450 | /* Some CDV firmware doesn't report this currently. In which case the | ||
451 | system has 64 gtt pages */ | ||
452 | if (pg->gtt_start == 0 || gtt_pages == 0) { | ||
453 | dev_err(dev->dev, "GTT PCI BAR not initialized.\n"); | ||
454 | gtt_pages = 64; | ||
455 | pg->gtt_start = dev_priv->pge_ctl; | ||
456 | } | ||
457 | |||
458 | pg->gatt_start = pci_resource_start(dev->pdev, PSB_GATT_RESOURCE); | ||
459 | pg->gatt_pages = pci_resource_len(dev->pdev, PSB_GATT_RESOURCE) | ||
460 | >> PAGE_SHIFT; | ||
461 | dev_priv->gtt_mem = &dev->pdev->resource[PSB_GATT_RESOURCE]; | ||
462 | |||
463 | if (pg->gatt_pages == 0 || pg->gatt_start == 0) { | ||
464 | static struct resource fudge; /* Preferably peppermint */ | ||
465 | /* This can occur on CDV SDV systems. Fudge it in this case. | ||
466 | We really don't care what imaginary space is being allocated | ||
467 | at this point */ | ||
468 | dev_err(dev->dev, "GATT PCI BAR not initialized.\n"); | ||
469 | pg->gatt_start = 0x40000000; | ||
470 | pg->gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT; | ||
471 | /* This is a little confusing but in fact the GTT is providing | ||
472 | a view from the GPU into memory and not vice versa. As such | ||
473 | this is really allocating space that is not the same as the | ||
474 | CPU address space on CDV */ | ||
475 | fudge.start = 0x40000000; | ||
476 | fudge.end = 0x40000000 + 128 * 1024 * 1024 - 1; | ||
477 | fudge.name = "fudge"; | ||
478 | fudge.flags = IORESOURCE_MEM; | ||
479 | dev_priv->gtt_mem = &fudge; | ||
480 | } | ||
481 | |||
482 | pci_read_config_dword(dev->pdev, PSB_BSM, &dev_priv->stolen_base); | ||
483 | vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base | ||
484 | - PAGE_SIZE; | ||
485 | |||
486 | stolen_size = vram_stolen_size; | ||
487 | |||
488 | printk(KERN_INFO "Stolen memory information\n"); | ||
489 | printk(KERN_INFO " base in RAM: 0x%x\n", dev_priv->stolen_base); | ||
490 | printk(KERN_INFO " size: %luK, calculated by (GTT RAM base) - (Stolen base), seems wrong\n", | ||
491 | vram_stolen_size/1024); | ||
492 | dvmt_mode = (dev_priv->gmch_ctrl >> 4) & 0x7; | ||
493 | printk(KERN_INFO " the correct size should be: %dM(dvmt mode=%d)\n", | ||
494 | (dvmt_mode == 1) ? 1 : (2 << (dvmt_mode - 1)), dvmt_mode); | ||
495 | |||
496 | if (resume && (gtt_pages != pg->gtt_pages) && | ||
497 | (stolen_size != pg->stolen_size)) { | ||
498 | dev_err(dev->dev, "GTT resume error.\n"); | ||
499 | ret = -EINVAL; | ||
500 | goto out_err; | ||
501 | } | ||
502 | |||
503 | pg->gtt_pages = gtt_pages; | ||
504 | pg->stolen_size = stolen_size; | ||
505 | dev_priv->vram_stolen_size = vram_stolen_size; | ||
506 | |||
507 | /* | ||
508 | * Map the GTT and the stolen memory area | ||
509 | */ | ||
510 | dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start, | ||
511 | gtt_pages << PAGE_SHIFT); | ||
512 | if (!dev_priv->gtt_map) { | ||
513 | dev_err(dev->dev, "Failure to map gtt.\n"); | ||
514 | ret = -ENOMEM; | ||
515 | goto out_err; | ||
516 | } | ||
517 | |||
518 | dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size); | ||
519 | if (!dev_priv->vram_addr) { | ||
520 | dev_err(dev->dev, "Failure to map stolen base.\n"); | ||
521 | ret = -ENOMEM; | ||
522 | goto out_err; | ||
523 | } | ||
524 | |||
525 | /* | ||
526 | * Insert vram stolen pages into the GTT | ||
527 | */ | ||
528 | |||
529 | pfn_base = dev_priv->stolen_base >> PAGE_SHIFT; | ||
530 | vram_pages = num_pages = vram_stolen_size >> PAGE_SHIFT; | ||
531 | printk(KERN_INFO"Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n", | ||
532 | num_pages, pfn_base << PAGE_SHIFT, 0); | ||
533 | for (i = 0; i < num_pages; ++i) { | ||
534 | pte = psb_gtt_mask_pte(pfn_base + i, 0); | ||
535 | iowrite32(pte, dev_priv->gtt_map + i); | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * Init rest of GTT to the scratch page to avoid accidents or scribbles | ||
540 | */ | ||
541 | |||
542 | pfn_base = page_to_pfn(dev_priv->scratch_page); | ||
543 | pte = psb_gtt_mask_pte(pfn_base, 0); | ||
544 | for (; i < gtt_pages; ++i) | ||
545 | iowrite32(pte, dev_priv->gtt_map + i); | ||
546 | |||
547 | (void) ioread32(dev_priv->gtt_map + i - 1); | ||
548 | return 0; | ||
549 | |||
550 | out_err: | ||
551 | psb_gtt_takedown(dev); | ||
552 | return ret; | ||
553 | } | ||
diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h new file mode 100644 index 00000000000..aa1742387f5 --- /dev/null +++ b/drivers/gpu/drm/gma500/gtt.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007-2008, 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 | #ifndef _PSB_GTT_H_ | ||
21 | #define _PSB_GTT_H_ | ||
22 | |||
23 | #include <drm/drmP.h> | ||
24 | |||
25 | /* This wants cleaning up with respect to the psb_dev and un-needed stuff */ | ||
26 | struct psb_gtt { | ||
27 | uint32_t gatt_start; | ||
28 | uint32_t mmu_gatt_start; | ||
29 | uint32_t gtt_start; | ||
30 | uint32_t gtt_phys_start; | ||
31 | unsigned gtt_pages; | ||
32 | unsigned gatt_pages; | ||
33 | unsigned long stolen_size; | ||
34 | unsigned long vram_stolen_size; | ||
35 | struct rw_semaphore sem; | ||
36 | }; | ||
37 | |||
38 | /* Exported functions */ | ||
39 | extern int psb_gtt_init(struct drm_device *dev, int resume); | ||
40 | extern void psb_gtt_takedown(struct drm_device *dev); | ||
41 | |||
42 | /* Each gtt_range describes an allocation in the GTT area */ | ||
43 | struct gtt_range { | ||
44 | struct resource resource; /* Resource for our allocation */ | ||
45 | u32 offset; /* GTT offset of our object */ | ||
46 | struct drm_gem_object gem; /* GEM high level stuff */ | ||
47 | int in_gart; /* Currently in the GART (ref ct) */ | ||
48 | bool stolen; /* Backed from stolen RAM */ | ||
49 | bool mmapping; /* Is mmappable */ | ||
50 | struct page **pages; /* Backing pages if present */ | ||
51 | int npage; /* Number of backing pages */ | ||
52 | int roll; /* Roll applied to the GTT entries */ | ||
53 | }; | ||
54 | |||
55 | extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, | ||
56 | const char *name, int backed); | ||
57 | extern void psb_gtt_kref_put(struct gtt_range *gt); | ||
58 | extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt); | ||
59 | extern int psb_gtt_pin(struct gtt_range *gt); | ||
60 | extern void psb_gtt_unpin(struct gtt_range *gt); | ||
61 | extern void psb_gtt_roll(struct drm_device *dev, | ||
62 | struct gtt_range *gt, int roll); | ||
63 | |||
64 | #endif | ||
diff --git a/drivers/gpu/drm/gma500/intel_bios.c b/drivers/gpu/drm/gma500/intel_bios.c new file mode 100644 index 00000000000..d4d0c5b8bf9 --- /dev/null +++ b/drivers/gpu/drm/gma500/intel_bios.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | * | ||
20 | */ | ||
21 | #include <drm/drmP.h> | ||
22 | #include <drm/drm.h> | ||
23 | #include "gma_drm.h" | ||
24 | #include "psb_drv.h" | ||
25 | #include "psb_intel_drv.h" | ||
26 | #include "psb_intel_reg.h" | ||
27 | #include "intel_bios.h" | ||
28 | |||
29 | |||
30 | static void *find_section(struct bdb_header *bdb, int section_id) | ||
31 | { | ||
32 | u8 *base = (u8 *)bdb; | ||
33 | int index = 0; | ||
34 | u16 total, current_size; | ||
35 | u8 current_id; | ||
36 | |||
37 | /* skip to first section */ | ||
38 | index += bdb->header_size; | ||
39 | total = bdb->bdb_size; | ||
40 | |||
41 | /* walk the sections looking for section_id */ | ||
42 | while (index < total) { | ||
43 | current_id = *(base + index); | ||
44 | index++; | ||
45 | current_size = *((u16 *)(base + index)); | ||
46 | index += 2; | ||
47 | if (current_id == section_id) | ||
48 | return base + index; | ||
49 | index += current_size; | ||
50 | } | ||
51 | |||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, | ||
56 | struct lvds_dvo_timing *dvo_timing) | ||
57 | { | ||
58 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | | ||
59 | dvo_timing->hactive_lo; | ||
60 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + | ||
61 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); | ||
62 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + | ||
63 | dvo_timing->hsync_pulse_width; | ||
64 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + | ||
65 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); | ||
66 | |||
67 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | | ||
68 | dvo_timing->vactive_lo; | ||
69 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + | ||
70 | dvo_timing->vsync_off; | ||
71 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + | ||
72 | dvo_timing->vsync_pulse_width; | ||
73 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + | ||
74 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); | ||
75 | panel_fixed_mode->clock = dvo_timing->clock * 10; | ||
76 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; | ||
77 | |||
78 | /* Some VBTs have bogus h/vtotal values */ | ||
79 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) | ||
80 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; | ||
81 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) | ||
82 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; | ||
83 | |||
84 | drm_mode_set_name(panel_fixed_mode); | ||
85 | } | ||
86 | |||
87 | static void parse_backlight_data(struct drm_psb_private *dev_priv, | ||
88 | struct bdb_header *bdb) | ||
89 | { | ||
90 | struct bdb_lvds_backlight *vbt_lvds_bl = NULL; | ||
91 | struct bdb_lvds_backlight *lvds_bl; | ||
92 | u8 p_type = 0; | ||
93 | void *bl_start = NULL; | ||
94 | struct bdb_lvds_options *lvds_opts | ||
95 | = find_section(bdb, BDB_LVDS_OPTIONS); | ||
96 | |||
97 | dev_priv->lvds_bl = NULL; | ||
98 | |||
99 | if (lvds_opts) | ||
100 | p_type = lvds_opts->panel_type; | ||
101 | else | ||
102 | return; | ||
103 | |||
104 | bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT); | ||
105 | vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start + 1) + p_type; | ||
106 | |||
107 | lvds_bl = kzalloc(sizeof(*vbt_lvds_bl), GFP_KERNEL); | ||
108 | if (!lvds_bl) { | ||
109 | dev_err(dev_priv->dev->dev, "out of memory for backlight data\n"); | ||
110 | return; | ||
111 | } | ||
112 | memcpy(lvds_bl, vbt_lvds_bl, sizeof(*vbt_lvds_bl)); | ||
113 | dev_priv->lvds_bl = lvds_bl; | ||
114 | } | ||
115 | |||
116 | /* Try to find integrated panel data */ | ||
117 | static void parse_lfp_panel_data(struct drm_psb_private *dev_priv, | ||
118 | struct bdb_header *bdb) | ||
119 | { | ||
120 | struct bdb_lvds_options *lvds_options; | ||
121 | struct bdb_lvds_lfp_data *lvds_lfp_data; | ||
122 | struct bdb_lvds_lfp_data_entry *entry; | ||
123 | struct lvds_dvo_timing *dvo_timing; | ||
124 | struct drm_display_mode *panel_fixed_mode; | ||
125 | |||
126 | /* Defaults if we can't find VBT info */ | ||
127 | dev_priv->lvds_dither = 0; | ||
128 | dev_priv->lvds_vbt = 0; | ||
129 | |||
130 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); | ||
131 | if (!lvds_options) | ||
132 | return; | ||
133 | |||
134 | dev_priv->lvds_dither = lvds_options->pixel_dither; | ||
135 | if (lvds_options->panel_type == 0xff) | ||
136 | return; | ||
137 | |||
138 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); | ||
139 | if (!lvds_lfp_data) | ||
140 | return; | ||
141 | |||
142 | |||
143 | entry = &lvds_lfp_data->data[lvds_options->panel_type]; | ||
144 | dvo_timing = &entry->dvo_timing; | ||
145 | |||
146 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), | ||
147 | GFP_KERNEL); | ||
148 | if (panel_fixed_mode == NULL) { | ||
149 | dev_err(dev_priv->dev->dev, "out of memory for fixed panel mode\n"); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | dev_priv->lvds_vbt = 1; | ||
154 | fill_detail_timing_data(panel_fixed_mode, dvo_timing); | ||
155 | |||
156 | if (panel_fixed_mode->htotal > 0 && panel_fixed_mode->vtotal > 0) { | ||
157 | dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; | ||
158 | drm_mode_debug_printmodeline(panel_fixed_mode); | ||
159 | } else { | ||
160 | dev_dbg(dev_priv->dev->dev, "ignoring invalid LVDS VBT\n"); | ||
161 | dev_priv->lvds_vbt = 0; | ||
162 | kfree(panel_fixed_mode); | ||
163 | } | ||
164 | return; | ||
165 | } | ||
166 | |||
167 | /* Try to find sdvo panel data */ | ||
168 | static void parse_sdvo_panel_data(struct drm_psb_private *dev_priv, | ||
169 | struct bdb_header *bdb) | ||
170 | { | ||
171 | struct bdb_sdvo_lvds_options *sdvo_lvds_options; | ||
172 | struct lvds_dvo_timing *dvo_timing; | ||
173 | struct drm_display_mode *panel_fixed_mode; | ||
174 | |||
175 | dev_priv->sdvo_lvds_vbt_mode = NULL; | ||
176 | |||
177 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); | ||
178 | if (!sdvo_lvds_options) | ||
179 | return; | ||
180 | |||
181 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); | ||
182 | if (!dvo_timing) | ||
183 | return; | ||
184 | |||
185 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); | ||
186 | |||
187 | if (!panel_fixed_mode) | ||
188 | return; | ||
189 | |||
190 | fill_detail_timing_data(panel_fixed_mode, | ||
191 | dvo_timing + sdvo_lvds_options->panel_type); | ||
192 | |||
193 | dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; | ||
194 | |||
195 | return; | ||
196 | } | ||
197 | |||
198 | static void parse_general_features(struct drm_psb_private *dev_priv, | ||
199 | struct bdb_header *bdb) | ||
200 | { | ||
201 | struct bdb_general_features *general; | ||
202 | |||
203 | /* Set sensible defaults in case we can't find the general block */ | ||
204 | dev_priv->int_tv_support = 1; | ||
205 | dev_priv->int_crt_support = 1; | ||
206 | |||
207 | general = find_section(bdb, BDB_GENERAL_FEATURES); | ||
208 | if (general) { | ||
209 | dev_priv->int_tv_support = general->int_tv_support; | ||
210 | dev_priv->int_crt_support = general->int_crt_support; | ||
211 | dev_priv->lvds_use_ssc = general->enable_ssc; | ||
212 | |||
213 | if (dev_priv->lvds_use_ssc) { | ||
214 | dev_priv->lvds_ssc_freq | ||
215 | = general->ssc_freq ? 100 : 96; | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * psb_intel_init_bios - initialize VBIOS settings & find VBT | ||
222 | * @dev: DRM device | ||
223 | * | ||
224 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers | ||
225 | * to appropriate values. | ||
226 | * | ||
227 | * VBT existence is a sanity check that is relied on by other i830_bios.c code. | ||
228 | * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may | ||
229 | * feed an updated VBT back through that, compared to what we'll fetch using | ||
230 | * this method of groping around in the BIOS data. | ||
231 | * | ||
232 | * Returns 0 on success, nonzero on failure. | ||
233 | */ | ||
234 | bool psb_intel_init_bios(struct drm_device *dev) | ||
235 | { | ||
236 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
237 | struct pci_dev *pdev = dev->pdev; | ||
238 | struct vbt_header *vbt = NULL; | ||
239 | struct bdb_header *bdb; | ||
240 | u8 __iomem *bios; | ||
241 | size_t size; | ||
242 | int i; | ||
243 | |||
244 | bios = pci_map_rom(pdev, &size); | ||
245 | if (!bios) | ||
246 | return -1; | ||
247 | |||
248 | /* Scour memory looking for the VBT signature */ | ||
249 | for (i = 0; i + 4 < size; i++) { | ||
250 | if (!memcmp(bios + i, "$VBT", 4)) { | ||
251 | vbt = (struct vbt_header *)(bios + i); | ||
252 | break; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | if (!vbt) { | ||
257 | dev_err(dev->dev, "VBT signature missing\n"); | ||
258 | pci_unmap_rom(pdev, bios); | ||
259 | return -1; | ||
260 | } | ||
261 | |||
262 | bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); | ||
263 | |||
264 | /* Grab useful general definitions */ | ||
265 | parse_general_features(dev_priv, bdb); | ||
266 | parse_lfp_panel_data(dev_priv, bdb); | ||
267 | parse_sdvo_panel_data(dev_priv, bdb); | ||
268 | parse_backlight_data(dev_priv, bdb); | ||
269 | |||
270 | pci_unmap_rom(pdev, bios); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * Destroy and free VBT data | ||
277 | */ | ||
278 | void psb_intel_destroy_bios(struct drm_device *dev) | ||
279 | { | ||
280 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
281 | struct drm_display_mode *sdvo_lvds_vbt_mode = | ||
282 | dev_priv->sdvo_lvds_vbt_mode; | ||
283 | struct drm_display_mode *lfp_lvds_vbt_mode = | ||
284 | dev_priv->lfp_lvds_vbt_mode; | ||
285 | struct bdb_lvds_backlight *lvds_bl = | ||
286 | dev_priv->lvds_bl; | ||
287 | |||
288 | /*free sdvo panel mode*/ | ||
289 | if (sdvo_lvds_vbt_mode) { | ||
290 | dev_priv->sdvo_lvds_vbt_mode = NULL; | ||
291 | kfree(sdvo_lvds_vbt_mode); | ||
292 | } | ||
293 | |||
294 | if (lfp_lvds_vbt_mode) { | ||
295 | dev_priv->lfp_lvds_vbt_mode = NULL; | ||
296 | kfree(lfp_lvds_vbt_mode); | ||
297 | } | ||
298 | |||
299 | if (lvds_bl) { | ||
300 | dev_priv->lvds_bl = NULL; | ||
301 | kfree(lvds_bl); | ||
302 | } | ||
303 | } | ||
diff --git a/drivers/gpu/drm/gma500/intel_bios.h b/drivers/gpu/drm/gma500/intel_bios.h new file mode 100644 index 00000000000..70f1bf01818 --- /dev/null +++ b/drivers/gpu/drm/gma500/intel_bios.h | |||
@@ -0,0 +1,430 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _I830_BIOS_H_ | ||
23 | #define _I830_BIOS_H_ | ||
24 | |||
25 | #include <drm/drmP.h> | ||
26 | |||
27 | struct vbt_header { | ||
28 | u8 signature[20]; /**< Always starts with 'VBT$' */ | ||
29 | u16 version; /**< decimal */ | ||
30 | u16 header_size; /**< in bytes */ | ||
31 | u16 vbt_size; /**< in bytes */ | ||
32 | u8 vbt_checksum; | ||
33 | u8 reserved0; | ||
34 | u32 bdb_offset; /**< from beginning of VBT */ | ||
35 | u32 aim_offset[4]; /**< from beginning of VBT */ | ||
36 | } __attribute__((packed)); | ||
37 | |||
38 | |||
39 | struct bdb_header { | ||
40 | u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ | ||
41 | u16 version; /**< decimal */ | ||
42 | u16 header_size; /**< in bytes */ | ||
43 | u16 bdb_size; /**< in bytes */ | ||
44 | }; | ||
45 | |||
46 | /* strictly speaking, this is a "skip" block, but it has interesting info */ | ||
47 | struct vbios_data { | ||
48 | u8 type; /* 0 == desktop, 1 == mobile */ | ||
49 | u8 relstage; | ||
50 | u8 chipset; | ||
51 | u8 lvds_present:1; | ||
52 | u8 tv_present:1; | ||
53 | u8 rsvd2:6; /* finish byte */ | ||
54 | u8 rsvd3[4]; | ||
55 | u8 signon[155]; | ||
56 | u8 copyright[61]; | ||
57 | u16 code_segment; | ||
58 | u8 dos_boot_mode; | ||
59 | u8 bandwidth_percent; | ||
60 | u8 rsvd4; /* popup memory size */ | ||
61 | u8 resize_pci_bios; | ||
62 | u8 rsvd5; /* is crt already on ddc2 */ | ||
63 | } __attribute__((packed)); | ||
64 | |||
65 | /* | ||
66 | * There are several types of BIOS data blocks (BDBs), each block has | ||
67 | * an ID and size in the first 3 bytes (ID in first, size in next 2). | ||
68 | * Known types are listed below. | ||
69 | */ | ||
70 | #define BDB_GENERAL_FEATURES 1 | ||
71 | #define BDB_GENERAL_DEFINITIONS 2 | ||
72 | #define BDB_OLD_TOGGLE_LIST 3 | ||
73 | #define BDB_MODE_SUPPORT_LIST 4 | ||
74 | #define BDB_GENERIC_MODE_TABLE 5 | ||
75 | #define BDB_EXT_MMIO_REGS 6 | ||
76 | #define BDB_SWF_IO 7 | ||
77 | #define BDB_SWF_MMIO 8 | ||
78 | #define BDB_DOT_CLOCK_TABLE 9 | ||
79 | #define BDB_MODE_REMOVAL_TABLE 10 | ||
80 | #define BDB_CHILD_DEVICE_TABLE 11 | ||
81 | #define BDB_DRIVER_FEATURES 12 | ||
82 | #define BDB_DRIVER_PERSISTENCE 13 | ||
83 | #define BDB_EXT_TABLE_PTRS 14 | ||
84 | #define BDB_DOT_CLOCK_OVERRIDE 15 | ||
85 | #define BDB_DISPLAY_SELECT 16 | ||
86 | /* 17 rsvd */ | ||
87 | #define BDB_DRIVER_ROTATION 18 | ||
88 | #define BDB_DISPLAY_REMOVE 19 | ||
89 | #define BDB_OEM_CUSTOM 20 | ||
90 | #define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ | ||
91 | #define BDB_SDVO_LVDS_OPTIONS 22 | ||
92 | #define BDB_SDVO_PANEL_DTDS 23 | ||
93 | #define BDB_SDVO_LVDS_PNP_IDS 24 | ||
94 | #define BDB_SDVO_LVDS_POWER_SEQ 25 | ||
95 | #define BDB_TV_OPTIONS 26 | ||
96 | #define BDB_LVDS_OPTIONS 40 | ||
97 | #define BDB_LVDS_LFP_DATA_PTRS 41 | ||
98 | #define BDB_LVDS_LFP_DATA 42 | ||
99 | #define BDB_LVDS_BACKLIGHT 43 | ||
100 | #define BDB_LVDS_POWER 44 | ||
101 | #define BDB_SKIP 254 /* VBIOS private block, ignore */ | ||
102 | |||
103 | struct bdb_general_features { | ||
104 | /* bits 1 */ | ||
105 | u8 panel_fitting:2; | ||
106 | u8 flexaim:1; | ||
107 | u8 msg_enable:1; | ||
108 | u8 clear_screen:3; | ||
109 | u8 color_flip:1; | ||
110 | |||
111 | /* bits 2 */ | ||
112 | u8 download_ext_vbt:1; | ||
113 | u8 enable_ssc:1; | ||
114 | u8 ssc_freq:1; | ||
115 | u8 enable_lfp_on_override:1; | ||
116 | u8 disable_ssc_ddt:1; | ||
117 | u8 rsvd8:3; /* finish byte */ | ||
118 | |||
119 | /* bits 3 */ | ||
120 | u8 disable_smooth_vision:1; | ||
121 | u8 single_dvi:1; | ||
122 | u8 rsvd9:6; /* finish byte */ | ||
123 | |||
124 | /* bits 4 */ | ||
125 | u8 legacy_monitor_detect; | ||
126 | |||
127 | /* bits 5 */ | ||
128 | u8 int_crt_support:1; | ||
129 | u8 int_tv_support:1; | ||
130 | u8 rsvd11:6; /* finish byte */ | ||
131 | } __attribute__((packed)); | ||
132 | |||
133 | struct bdb_general_definitions { | ||
134 | /* DDC GPIO */ | ||
135 | u8 crt_ddc_gmbus_pin; | ||
136 | |||
137 | /* DPMS bits */ | ||
138 | u8 dpms_acpi:1; | ||
139 | u8 skip_boot_crt_detect:1; | ||
140 | u8 dpms_aim:1; | ||
141 | u8 rsvd1:5; /* finish byte */ | ||
142 | |||
143 | /* boot device bits */ | ||
144 | u8 boot_display[2]; | ||
145 | u8 child_dev_size; | ||
146 | |||
147 | /* device info */ | ||
148 | u8 tv_or_lvds_info[33]; | ||
149 | u8 dev1[33]; | ||
150 | u8 dev2[33]; | ||
151 | u8 dev3[33]; | ||
152 | u8 dev4[33]; | ||
153 | /* may be another device block here on some platforms */ | ||
154 | }; | ||
155 | |||
156 | struct bdb_lvds_options { | ||
157 | u8 panel_type; | ||
158 | u8 rsvd1; | ||
159 | /* LVDS capabilities, stored in a dword */ | ||
160 | u8 pfit_mode:2; | ||
161 | u8 pfit_text_mode_enhanced:1; | ||
162 | u8 pfit_gfx_mode_enhanced:1; | ||
163 | u8 pfit_ratio_auto:1; | ||
164 | u8 pixel_dither:1; | ||
165 | u8 lvds_edid:1; | ||
166 | u8 rsvd2:1; | ||
167 | u8 rsvd4; | ||
168 | } __attribute__((packed)); | ||
169 | |||
170 | struct bdb_lvds_backlight { | ||
171 | u8 type:2; | ||
172 | u8 pol:1; | ||
173 | u8 gpio:3; | ||
174 | u8 gmbus:2; | ||
175 | u16 freq; | ||
176 | u8 minbrightness; | ||
177 | u8 i2caddr; | ||
178 | u8 brightnesscmd; | ||
179 | /*FIXME: more...*/ | ||
180 | } __attribute__((packed)); | ||
181 | |||
182 | /* LFP pointer table contains entries to the struct below */ | ||
183 | struct bdb_lvds_lfp_data_ptr { | ||
184 | u16 fp_timing_offset; /* offsets are from start of bdb */ | ||
185 | u8 fp_table_size; | ||
186 | u16 dvo_timing_offset; | ||
187 | u8 dvo_table_size; | ||
188 | u16 panel_pnp_id_offset; | ||
189 | u8 pnp_table_size; | ||
190 | } __attribute__((packed)); | ||
191 | |||
192 | struct bdb_lvds_lfp_data_ptrs { | ||
193 | u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ | ||
194 | struct bdb_lvds_lfp_data_ptr ptr[16]; | ||
195 | } __attribute__((packed)); | ||
196 | |||
197 | /* LFP data has 3 blocks per entry */ | ||
198 | struct lvds_fp_timing { | ||
199 | u16 x_res; | ||
200 | u16 y_res; | ||
201 | u32 lvds_reg; | ||
202 | u32 lvds_reg_val; | ||
203 | u32 pp_on_reg; | ||
204 | u32 pp_on_reg_val; | ||
205 | u32 pp_off_reg; | ||
206 | u32 pp_off_reg_val; | ||
207 | u32 pp_cycle_reg; | ||
208 | u32 pp_cycle_reg_val; | ||
209 | u32 pfit_reg; | ||
210 | u32 pfit_reg_val; | ||
211 | u16 terminator; | ||
212 | } __attribute__((packed)); | ||
213 | |||
214 | struct lvds_dvo_timing { | ||
215 | u16 clock; /**< In 10khz */ | ||
216 | u8 hactive_lo; | ||
217 | u8 hblank_lo; | ||
218 | u8 hblank_hi:4; | ||
219 | u8 hactive_hi:4; | ||
220 | u8 vactive_lo; | ||
221 | u8 vblank_lo; | ||
222 | u8 vblank_hi:4; | ||
223 | u8 vactive_hi:4; | ||
224 | u8 hsync_off_lo; | ||
225 | u8 hsync_pulse_width; | ||
226 | u8 vsync_pulse_width:4; | ||
227 | u8 vsync_off:4; | ||
228 | u8 rsvd0:6; | ||
229 | u8 hsync_off_hi:2; | ||
230 | u8 h_image; | ||
231 | u8 v_image; | ||
232 | u8 max_hv; | ||
233 | u8 h_border; | ||
234 | u8 v_border; | ||
235 | u8 rsvd1:3; | ||
236 | u8 digital:2; | ||
237 | u8 vsync_positive:1; | ||
238 | u8 hsync_positive:1; | ||
239 | u8 rsvd2:1; | ||
240 | } __attribute__((packed)); | ||
241 | |||
242 | struct lvds_pnp_id { | ||
243 | u16 mfg_name; | ||
244 | u16 product_code; | ||
245 | u32 serial; | ||
246 | u8 mfg_week; | ||
247 | u8 mfg_year; | ||
248 | } __attribute__((packed)); | ||
249 | |||
250 | struct bdb_lvds_lfp_data_entry { | ||
251 | struct lvds_fp_timing fp_timing; | ||
252 | struct lvds_dvo_timing dvo_timing; | ||
253 | struct lvds_pnp_id pnp_id; | ||
254 | } __attribute__((packed)); | ||
255 | |||
256 | struct bdb_lvds_lfp_data { | ||
257 | struct bdb_lvds_lfp_data_entry data[16]; | ||
258 | } __attribute__((packed)); | ||
259 | |||
260 | struct aimdb_header { | ||
261 | char signature[16]; | ||
262 | char oem_device[20]; | ||
263 | u16 aimdb_version; | ||
264 | u16 aimdb_header_size; | ||
265 | u16 aimdb_size; | ||
266 | } __attribute__((packed)); | ||
267 | |||
268 | struct aimdb_block { | ||
269 | u8 aimdb_id; | ||
270 | u16 aimdb_size; | ||
271 | } __attribute__((packed)); | ||
272 | |||
273 | struct vch_panel_data { | ||
274 | u16 fp_timing_offset; | ||
275 | u8 fp_timing_size; | ||
276 | u16 dvo_timing_offset; | ||
277 | u8 dvo_timing_size; | ||
278 | u16 text_fitting_offset; | ||
279 | u8 text_fitting_size; | ||
280 | u16 graphics_fitting_offset; | ||
281 | u8 graphics_fitting_size; | ||
282 | } __attribute__((packed)); | ||
283 | |||
284 | struct vch_bdb_22 { | ||
285 | struct aimdb_block aimdb_block; | ||
286 | struct vch_panel_data panels[16]; | ||
287 | } __attribute__((packed)); | ||
288 | |||
289 | struct bdb_sdvo_lvds_options { | ||
290 | u8 panel_backlight; | ||
291 | u8 h40_set_panel_type; | ||
292 | u8 panel_type; | ||
293 | u8 ssc_clk_freq; | ||
294 | u16 als_low_trip; | ||
295 | u16 als_high_trip; | ||
296 | u8 sclalarcoeff_tab_row_num; | ||
297 | u8 sclalarcoeff_tab_row_size; | ||
298 | u8 coefficient[8]; | ||
299 | u8 panel_misc_bits_1; | ||
300 | u8 panel_misc_bits_2; | ||
301 | u8 panel_misc_bits_3; | ||
302 | u8 panel_misc_bits_4; | ||
303 | } __attribute__((packed)); | ||
304 | |||
305 | |||
306 | extern bool psb_intel_init_bios(struct drm_device *dev); | ||
307 | extern void psb_intel_destroy_bios(struct drm_device *dev); | ||
308 | |||
309 | /* | ||
310 | * Driver<->VBIOS interaction occurs through scratch bits in | ||
311 | * GR18 & SWF*. | ||
312 | */ | ||
313 | |||
314 | /* GR18 bits are set on display switch and hotkey events */ | ||
315 | #define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ | ||
316 | #define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ | ||
317 | #define GR18_HK_NONE (0x0<<3) | ||
318 | #define GR18_HK_LFP_STRETCH (0x1<<3) | ||
319 | #define GR18_HK_TOGGLE_DISP (0x2<<3) | ||
320 | #define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ | ||
321 | #define GR18_HK_POPUP_DISABLED (0x6<<3) | ||
322 | #define GR18_HK_POPUP_ENABLED (0x7<<3) | ||
323 | #define GR18_HK_PFIT (0x8<<3) | ||
324 | #define GR18_HK_APM_CHANGE (0xa<<3) | ||
325 | #define GR18_HK_MULTIPLE (0xc<<3) | ||
326 | #define GR18_USER_INT_EN (1<<2) | ||
327 | #define GR18_A0000_FLUSH_EN (1<<1) | ||
328 | #define GR18_SMM_EN (1<<0) | ||
329 | |||
330 | /* Set by driver, cleared by VBIOS */ | ||
331 | #define SWF00_YRES_SHIFT 16 | ||
332 | #define SWF00_XRES_SHIFT 0 | ||
333 | #define SWF00_RES_MASK 0xffff | ||
334 | |||
335 | /* Set by VBIOS at boot time and driver at runtime */ | ||
336 | #define SWF01_TV2_FORMAT_SHIFT 8 | ||
337 | #define SWF01_TV1_FORMAT_SHIFT 0 | ||
338 | #define SWF01_TV_FORMAT_MASK 0xffff | ||
339 | |||
340 | #define SWF10_VBIOS_BLC_I2C_EN (1<<29) | ||
341 | #define SWF10_GTT_OVERRIDE_EN (1<<28) | ||
342 | #define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ | ||
343 | #define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) | ||
344 | #define SWF10_OLD_TOGGLE 0x0 | ||
345 | #define SWF10_TOGGLE_LIST_1 0x1 | ||
346 | #define SWF10_TOGGLE_LIST_2 0x2 | ||
347 | #define SWF10_TOGGLE_LIST_3 0x3 | ||
348 | #define SWF10_TOGGLE_LIST_4 0x4 | ||
349 | #define SWF10_PANNING_EN (1<<23) | ||
350 | #define SWF10_DRIVER_LOADED (1<<22) | ||
351 | #define SWF10_EXTENDED_DESKTOP (1<<21) | ||
352 | #define SWF10_EXCLUSIVE_MODE (1<<20) | ||
353 | #define SWF10_OVERLAY_EN (1<<19) | ||
354 | #define SWF10_PLANEB_HOLDOFF (1<<18) | ||
355 | #define SWF10_PLANEA_HOLDOFF (1<<17) | ||
356 | #define SWF10_VGA_HOLDOFF (1<<16) | ||
357 | #define SWF10_ACTIVE_DISP_MASK 0xffff | ||
358 | #define SWF10_PIPEB_LFP2 (1<<15) | ||
359 | #define SWF10_PIPEB_EFP2 (1<<14) | ||
360 | #define SWF10_PIPEB_TV2 (1<<13) | ||
361 | #define SWF10_PIPEB_CRT2 (1<<12) | ||
362 | #define SWF10_PIPEB_LFP (1<<11) | ||
363 | #define SWF10_PIPEB_EFP (1<<10) | ||
364 | #define SWF10_PIPEB_TV (1<<9) | ||
365 | #define SWF10_PIPEB_CRT (1<<8) | ||
366 | #define SWF10_PIPEA_LFP2 (1<<7) | ||
367 | #define SWF10_PIPEA_EFP2 (1<<6) | ||
368 | #define SWF10_PIPEA_TV2 (1<<5) | ||
369 | #define SWF10_PIPEA_CRT2 (1<<4) | ||
370 | #define SWF10_PIPEA_LFP (1<<3) | ||
371 | #define SWF10_PIPEA_EFP (1<<2) | ||
372 | #define SWF10_PIPEA_TV (1<<1) | ||
373 | #define SWF10_PIPEA_CRT (1<<0) | ||
374 | |||
375 | #define SWF11_MEMORY_SIZE_SHIFT 16 | ||
376 | #define SWF11_SV_TEST_EN (1<<15) | ||
377 | #define SWF11_IS_AGP (1<<14) | ||
378 | #define SWF11_DISPLAY_HOLDOFF (1<<13) | ||
379 | #define SWF11_DPMS_REDUCED (1<<12) | ||
380 | #define SWF11_IS_VBE_MODE (1<<11) | ||
381 | #define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ | ||
382 | #define SWF11_DPMS_MASK 0x07 | ||
383 | #define SWF11_DPMS_OFF (1<<2) | ||
384 | #define SWF11_DPMS_SUSPEND (1<<1) | ||
385 | #define SWF11_DPMS_STANDBY (1<<0) | ||
386 | #define SWF11_DPMS_ON 0 | ||
387 | |||
388 | #define SWF14_GFX_PFIT_EN (1<<31) | ||
389 | #define SWF14_TEXT_PFIT_EN (1<<30) | ||
390 | #define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */ | ||
391 | #define SWF14_POPUP_EN (1<<28) | ||
392 | #define SWF14_DISPLAY_HOLDOFF (1<<27) | ||
393 | #define SWF14_DISP_DETECT_EN (1<<26) | ||
394 | #define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ | ||
395 | #define SWF14_DRIVER_STATUS (1<<24) | ||
396 | #define SWF14_OS_TYPE_WIN9X (1<<23) | ||
397 | #define SWF14_OS_TYPE_WINNT (1<<22) | ||
398 | /* 21:19 rsvd */ | ||
399 | #define SWF14_PM_TYPE_MASK 0x00070000 | ||
400 | #define SWF14_PM_ACPI_VIDEO (0x4 << 16) | ||
401 | #define SWF14_PM_ACPI (0x3 << 16) | ||
402 | #define SWF14_PM_APM_12 (0x2 << 16) | ||
403 | #define SWF14_PM_APM_11 (0x1 << 16) | ||
404 | #define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ | ||
405 | /* if GR18 indicates a display switch */ | ||
406 | #define SWF14_DS_PIPEB_LFP2_EN (1<<15) | ||
407 | #define SWF14_DS_PIPEB_EFP2_EN (1<<14) | ||
408 | #define SWF14_DS_PIPEB_TV2_EN (1<<13) | ||
409 | #define SWF14_DS_PIPEB_CRT2_EN (1<<12) | ||
410 | #define SWF14_DS_PIPEB_LFP_EN (1<<11) | ||
411 | #define SWF14_DS_PIPEB_EFP_EN (1<<10) | ||
412 | #define SWF14_DS_PIPEB_TV_EN (1<<9) | ||
413 | #define SWF14_DS_PIPEB_CRT_EN (1<<8) | ||
414 | #define SWF14_DS_PIPEA_LFP2_EN (1<<7) | ||
415 | #define SWF14_DS_PIPEA_EFP2_EN (1<<6) | ||
416 | #define SWF14_DS_PIPEA_TV2_EN (1<<5) | ||
417 | #define SWF14_DS_PIPEA_CRT2_EN (1<<4) | ||
418 | #define SWF14_DS_PIPEA_LFP_EN (1<<3) | ||
419 | #define SWF14_DS_PIPEA_EFP_EN (1<<2) | ||
420 | #define SWF14_DS_PIPEA_TV_EN (1<<1) | ||
421 | #define SWF14_DS_PIPEA_CRT_EN (1<<0) | ||
422 | /* if GR18 indicates a panel fitting request */ | ||
423 | #define SWF14_PFIT_EN (1<<0) /* 0 means disable */ | ||
424 | /* if GR18 indicates an APM change request */ | ||
425 | #define SWF14_APM_HIBERNATE 0x4 | ||
426 | #define SWF14_APM_SUSPEND 0x3 | ||
427 | #define SWF14_APM_STANDBY 0x1 | ||
428 | #define SWF14_APM_RESTORE 0x0 | ||
429 | |||
430 | #endif /* _I830_BIOS_H_ */ | ||
diff --git a/drivers/gpu/drm/gma500/intel_gmbus.c b/drivers/gpu/drm/gma500/intel_gmbus.c new file mode 100644 index 00000000000..147584ac8d0 --- /dev/null +++ b/drivers/gpu/drm/gma500/intel_gmbus.c | |||
@@ -0,0 +1,493 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
3 | * Copyright © 2006-2008,2010 Intel Corporation | ||
4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the next | ||
14 | * paragraph) shall be included in all copies or substantial portions of the | ||
15 | * Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
23 | * DEALINGS IN THE SOFTWARE. | ||
24 | * | ||
25 | * Authors: | ||
26 | * Eric Anholt <eric@anholt.net> | ||
27 | * Chris Wilson <chris@chris-wilson.co.uk> | ||
28 | */ | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/i2c-algo-bit.h> | ||
32 | #include "drmP.h" | ||
33 | #include "drm.h" | ||
34 | #include "psb_intel_drv.h" | ||
35 | #include "gma_drm.h" | ||
36 | #include "psb_drv.h" | ||
37 | #include "psb_intel_reg.h" | ||
38 | |||
39 | #define _wait_for(COND, MS, W) ({ \ | ||
40 | unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ | ||
41 | int ret__ = 0; \ | ||
42 | while (! (COND)) { \ | ||
43 | if (time_after(jiffies, timeout__)) { \ | ||
44 | ret__ = -ETIMEDOUT; \ | ||
45 | break; \ | ||
46 | } \ | ||
47 | if (W && !(in_atomic() || in_dbg_master())) msleep(W); \ | ||
48 | } \ | ||
49 | ret__; \ | ||
50 | }) | ||
51 | |||
52 | #define wait_for(COND, MS) _wait_for(COND, MS, 1) | ||
53 | #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) | ||
54 | |||
55 | /* Intel GPIO access functions */ | ||
56 | |||
57 | #define I2C_RISEFALL_TIME 20 | ||
58 | |||
59 | static inline struct intel_gmbus * | ||
60 | to_intel_gmbus(struct i2c_adapter *i2c) | ||
61 | { | ||
62 | return container_of(i2c, struct intel_gmbus, adapter); | ||
63 | } | ||
64 | |||
65 | struct intel_gpio { | ||
66 | struct i2c_adapter adapter; | ||
67 | struct i2c_algo_bit_data algo; | ||
68 | struct drm_psb_private *dev_priv; | ||
69 | u32 reg; | ||
70 | }; | ||
71 | |||
72 | void | ||
73 | gma_intel_i2c_reset(struct drm_device *dev) | ||
74 | { | ||
75 | REG_WRITE(GMBUS0, 0); | ||
76 | } | ||
77 | |||
78 | static void intel_i2c_quirk_set(struct drm_psb_private *dev_priv, bool enable) | ||
79 | { | ||
80 | /* When using bit bashing for I2C, this bit needs to be set to 1 */ | ||
81 | /* FIXME: We are never Pineview, right? | ||
82 | |||
83 | u32 val; | ||
84 | |||
85 | if (!IS_PINEVIEW(dev_priv->dev)) | ||
86 | return; | ||
87 | |||
88 | val = REG_READ(DSPCLK_GATE_D); | ||
89 | if (enable) | ||
90 | val |= DPCUNIT_CLOCK_GATE_DISABLE; | ||
91 | else | ||
92 | val &= ~DPCUNIT_CLOCK_GATE_DISABLE; | ||
93 | REG_WRITE(DSPCLK_GATE_D, val); | ||
94 | |||
95 | return; | ||
96 | */ | ||
97 | } | ||
98 | |||
99 | static u32 get_reserved(struct intel_gpio *gpio) | ||
100 | { | ||
101 | struct drm_psb_private *dev_priv = gpio->dev_priv; | ||
102 | struct drm_device *dev = dev_priv->dev; | ||
103 | u32 reserved = 0; | ||
104 | |||
105 | /* On most chips, these bits must be preserved in software. */ | ||
106 | reserved = REG_READ(gpio->reg) & | ||
107 | (GPIO_DATA_PULLUP_DISABLE | | ||
108 | GPIO_CLOCK_PULLUP_DISABLE); | ||
109 | |||
110 | return reserved; | ||
111 | } | ||
112 | |||
113 | static int get_clock(void *data) | ||
114 | { | ||
115 | struct intel_gpio *gpio = data; | ||
116 | struct drm_psb_private *dev_priv = gpio->dev_priv; | ||
117 | struct drm_device *dev = dev_priv->dev; | ||
118 | u32 reserved = get_reserved(gpio); | ||
119 | REG_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK); | ||
120 | REG_WRITE(gpio->reg, reserved); | ||
121 | return (REG_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0; | ||
122 | } | ||
123 | |||
124 | static int get_data(void *data) | ||
125 | { | ||
126 | struct intel_gpio *gpio = data; | ||
127 | struct drm_psb_private *dev_priv = gpio->dev_priv; | ||
128 | struct drm_device *dev = dev_priv->dev; | ||
129 | u32 reserved = get_reserved(gpio); | ||
130 | REG_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK); | ||
131 | REG_WRITE(gpio->reg, reserved); | ||
132 | return (REG_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0; | ||
133 | } | ||
134 | |||
135 | static void set_clock(void *data, int state_high) | ||
136 | { | ||
137 | struct intel_gpio *gpio = data; | ||
138 | struct drm_psb_private *dev_priv = gpio->dev_priv; | ||
139 | struct drm_device *dev = dev_priv->dev; | ||
140 | u32 reserved = get_reserved(gpio); | ||
141 | u32 clock_bits; | ||
142 | |||
143 | if (state_high) | ||
144 | clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; | ||
145 | else | ||
146 | clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | | ||
147 | GPIO_CLOCK_VAL_MASK; | ||
148 | |||
149 | REG_WRITE(gpio->reg, reserved | clock_bits); | ||
150 | REG_READ(gpio->reg); /* Posting */ | ||
151 | } | ||
152 | |||
153 | static void set_data(void *data, int state_high) | ||
154 | { | ||
155 | struct intel_gpio *gpio = data; | ||
156 | struct drm_psb_private *dev_priv = gpio->dev_priv; | ||
157 | struct drm_device *dev = dev_priv->dev; | ||
158 | u32 reserved = get_reserved(gpio); | ||
159 | u32 data_bits; | ||
160 | |||
161 | if (state_high) | ||
162 | data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; | ||
163 | else | ||
164 | data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | | ||
165 | GPIO_DATA_VAL_MASK; | ||
166 | |||
167 | REG_WRITE(gpio->reg, reserved | data_bits); | ||
168 | REG_READ(gpio->reg); | ||
169 | } | ||
170 | |||
171 | static struct i2c_adapter * | ||
172 | intel_gpio_create(struct drm_psb_private *dev_priv, u32 pin) | ||
173 | { | ||
174 | static const int map_pin_to_reg[] = { | ||
175 | 0, | ||
176 | GPIOB, | ||
177 | GPIOA, | ||
178 | GPIOC, | ||
179 | GPIOD, | ||
180 | GPIOE, | ||
181 | 0, | ||
182 | GPIOF, | ||
183 | }; | ||
184 | struct intel_gpio *gpio; | ||
185 | |||
186 | if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin]) | ||
187 | return NULL; | ||
188 | |||
189 | gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL); | ||
190 | if (gpio == NULL) | ||
191 | return NULL; | ||
192 | |||
193 | gpio->reg = map_pin_to_reg[pin]; | ||
194 | gpio->dev_priv = dev_priv; | ||
195 | |||
196 | snprintf(gpio->adapter.name, sizeof(gpio->adapter.name), | ||
197 | "gma500 GPIO%c", "?BACDE?F"[pin]); | ||
198 | gpio->adapter.owner = THIS_MODULE; | ||
199 | gpio->adapter.algo_data = &gpio->algo; | ||
200 | gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev; | ||
201 | gpio->algo.setsda = set_data; | ||
202 | gpio->algo.setscl = set_clock; | ||
203 | gpio->algo.getsda = get_data; | ||
204 | gpio->algo.getscl = get_clock; | ||
205 | gpio->algo.udelay = I2C_RISEFALL_TIME; | ||
206 | gpio->algo.timeout = usecs_to_jiffies(2200); | ||
207 | gpio->algo.data = gpio; | ||
208 | |||
209 | if (i2c_bit_add_bus(&gpio->adapter)) | ||
210 | goto out_free; | ||
211 | |||
212 | return &gpio->adapter; | ||
213 | |||
214 | out_free: | ||
215 | kfree(gpio); | ||
216 | return NULL; | ||
217 | } | ||
218 | |||
219 | static int | ||
220 | intel_i2c_quirk_xfer(struct drm_psb_private *dev_priv, | ||
221 | struct i2c_adapter *adapter, | ||
222 | struct i2c_msg *msgs, | ||
223 | int num) | ||
224 | { | ||
225 | struct intel_gpio *gpio = container_of(adapter, | ||
226 | struct intel_gpio, | ||
227 | adapter); | ||
228 | int ret; | ||
229 | |||
230 | gma_intel_i2c_reset(dev_priv->dev); | ||
231 | |||
232 | intel_i2c_quirk_set(dev_priv, true); | ||
233 | set_data(gpio, 1); | ||
234 | set_clock(gpio, 1); | ||
235 | udelay(I2C_RISEFALL_TIME); | ||
236 | |||
237 | ret = adapter->algo->master_xfer(adapter, msgs, num); | ||
238 | |||
239 | set_data(gpio, 1); | ||
240 | set_clock(gpio, 1); | ||
241 | intel_i2c_quirk_set(dev_priv, false); | ||
242 | |||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | static int | ||
247 | gmbus_xfer(struct i2c_adapter *adapter, | ||
248 | struct i2c_msg *msgs, | ||
249 | int num) | ||
250 | { | ||
251 | struct intel_gmbus *bus = container_of(adapter, | ||
252 | struct intel_gmbus, | ||
253 | adapter); | ||
254 | struct drm_psb_private *dev_priv = adapter->algo_data; | ||
255 | struct drm_device *dev = dev_priv->dev; | ||
256 | int i, reg_offset; | ||
257 | |||
258 | if (bus->force_bit) | ||
259 | return intel_i2c_quirk_xfer(dev_priv, | ||
260 | bus->force_bit, msgs, num); | ||
261 | |||
262 | reg_offset = 0; | ||
263 | |||
264 | REG_WRITE(GMBUS0 + reg_offset, bus->reg0); | ||
265 | |||
266 | for (i = 0; i < num; i++) { | ||
267 | u16 len = msgs[i].len; | ||
268 | u8 *buf = msgs[i].buf; | ||
269 | |||
270 | if (msgs[i].flags & I2C_M_RD) { | ||
271 | REG_WRITE(GMBUS1 + reg_offset, | ||
272 | GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) | | ||
273 | (len << GMBUS_BYTE_COUNT_SHIFT) | | ||
274 | (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | | ||
275 | GMBUS_SLAVE_READ | GMBUS_SW_RDY); | ||
276 | REG_READ(GMBUS2+reg_offset); | ||
277 | do { | ||
278 | u32 val, loop = 0; | ||
279 | |||
280 | if (wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) | ||
281 | goto timeout; | ||
282 | if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) | ||
283 | goto clear_err; | ||
284 | |||
285 | val = REG_READ(GMBUS3 + reg_offset); | ||
286 | do { | ||
287 | *buf++ = val & 0xff; | ||
288 | val >>= 8; | ||
289 | } while (--len && ++loop < 4); | ||
290 | } while (len); | ||
291 | } else { | ||
292 | u32 val, loop; | ||
293 | |||
294 | val = loop = 0; | ||
295 | do { | ||
296 | val |= *buf++ << (8 * loop); | ||
297 | } while (--len && ++loop < 4); | ||
298 | |||
299 | REG_WRITE(GMBUS3 + reg_offset, val); | ||
300 | REG_WRITE(GMBUS1 + reg_offset, | ||
301 | (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) | | ||
302 | (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) | | ||
303 | (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | | ||
304 | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); | ||
305 | REG_READ(GMBUS2+reg_offset); | ||
306 | |||
307 | while (len) { | ||
308 | if (wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) | ||
309 | goto timeout; | ||
310 | if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) | ||
311 | goto clear_err; | ||
312 | |||
313 | val = loop = 0; | ||
314 | do { | ||
315 | val |= *buf++ << (8 * loop); | ||
316 | } while (--len && ++loop < 4); | ||
317 | |||
318 | REG_WRITE(GMBUS3 + reg_offset, val); | ||
319 | REG_READ(GMBUS2+reg_offset); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | if (i + 1 < num && wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50)) | ||
324 | goto timeout; | ||
325 | if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) | ||
326 | goto clear_err; | ||
327 | } | ||
328 | |||
329 | goto done; | ||
330 | |||
331 | clear_err: | ||
332 | /* Toggle the Software Clear Interrupt bit. This has the effect | ||
333 | * of resetting the GMBUS controller and so clearing the | ||
334 | * BUS_ERROR raised by the slave's NAK. | ||
335 | */ | ||
336 | REG_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT); | ||
337 | REG_WRITE(GMBUS1 + reg_offset, 0); | ||
338 | |||
339 | done: | ||
340 | /* Mark the GMBUS interface as disabled. We will re-enable it at the | ||
341 | * start of the next xfer, till then let it sleep. | ||
342 | */ | ||
343 | REG_WRITE(GMBUS0 + reg_offset, 0); | ||
344 | return i; | ||
345 | |||
346 | timeout: | ||
347 | DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", | ||
348 | bus->reg0 & 0xff, bus->adapter.name); | ||
349 | REG_WRITE(GMBUS0 + reg_offset, 0); | ||
350 | |||
351 | /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ | ||
352 | bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); | ||
353 | if (!bus->force_bit) | ||
354 | return -ENOMEM; | ||
355 | |||
356 | return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num); | ||
357 | } | ||
358 | |||
359 | static u32 gmbus_func(struct i2c_adapter *adapter) | ||
360 | { | ||
361 | struct intel_gmbus *bus = container_of(adapter, | ||
362 | struct intel_gmbus, | ||
363 | adapter); | ||
364 | |||
365 | if (bus->force_bit) | ||
366 | bus->force_bit->algo->functionality(bus->force_bit); | ||
367 | |||
368 | return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | | ||
369 | /* I2C_FUNC_10BIT_ADDR | */ | ||
370 | I2C_FUNC_SMBUS_READ_BLOCK_DATA | | ||
371 | I2C_FUNC_SMBUS_BLOCK_PROC_CALL); | ||
372 | } | ||
373 | |||
374 | static const struct i2c_algorithm gmbus_algorithm = { | ||
375 | .master_xfer = gmbus_xfer, | ||
376 | .functionality = gmbus_func | ||
377 | }; | ||
378 | |||
379 | /** | ||
380 | * intel_gmbus_setup - instantiate all Intel i2c GMBuses | ||
381 | * @dev: DRM device | ||
382 | */ | ||
383 | int gma_intel_setup_gmbus(struct drm_device *dev) | ||
384 | { | ||
385 | static const char *names[GMBUS_NUM_PORTS] = { | ||
386 | "disabled", | ||
387 | "ssc", | ||
388 | "vga", | ||
389 | "panel", | ||
390 | "dpc", | ||
391 | "dpb", | ||
392 | "reserved", | ||
393 | "dpd", | ||
394 | }; | ||
395 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
396 | int ret, i; | ||
397 | |||
398 | dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS, | ||
399 | GFP_KERNEL); | ||
400 | if (dev_priv->gmbus == NULL) | ||
401 | return -ENOMEM; | ||
402 | |||
403 | for (i = 0; i < GMBUS_NUM_PORTS; i++) { | ||
404 | struct intel_gmbus *bus = &dev_priv->gmbus[i]; | ||
405 | |||
406 | bus->adapter.owner = THIS_MODULE; | ||
407 | bus->adapter.class = I2C_CLASS_DDC; | ||
408 | snprintf(bus->adapter.name, | ||
409 | sizeof(bus->adapter.name), | ||
410 | "gma500 gmbus %s", | ||
411 | names[i]); | ||
412 | |||
413 | bus->adapter.dev.parent = &dev->pdev->dev; | ||
414 | bus->adapter.algo_data = dev_priv; | ||
415 | |||
416 | bus->adapter.algo = &gmbus_algorithm; | ||
417 | ret = i2c_add_adapter(&bus->adapter); | ||
418 | if (ret) | ||
419 | goto err; | ||
420 | |||
421 | /* By default use a conservative clock rate */ | ||
422 | bus->reg0 = i | GMBUS_RATE_100KHZ; | ||
423 | |||
424 | /* XXX force bit banging until GMBUS is fully debugged */ | ||
425 | bus->force_bit = intel_gpio_create(dev_priv, i); | ||
426 | } | ||
427 | |||
428 | gma_intel_i2c_reset(dev_priv->dev); | ||
429 | |||
430 | return 0; | ||
431 | |||
432 | err: | ||
433 | while (--i) { | ||
434 | struct intel_gmbus *bus = &dev_priv->gmbus[i]; | ||
435 | i2c_del_adapter(&bus->adapter); | ||
436 | } | ||
437 | kfree(dev_priv->gmbus); | ||
438 | dev_priv->gmbus = NULL; | ||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | void gma_intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed) | ||
443 | { | ||
444 | struct intel_gmbus *bus = to_intel_gmbus(adapter); | ||
445 | |||
446 | /* speed: | ||
447 | * 0x0 = 100 KHz | ||
448 | * 0x1 = 50 KHz | ||
449 | * 0x2 = 400 KHz | ||
450 | * 0x3 = 1000 Khz | ||
451 | */ | ||
452 | bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | (speed << 8); | ||
453 | } | ||
454 | |||
455 | void gma_intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) | ||
456 | { | ||
457 | struct intel_gmbus *bus = to_intel_gmbus(adapter); | ||
458 | |||
459 | if (force_bit) { | ||
460 | if (bus->force_bit == NULL) { | ||
461 | struct drm_psb_private *dev_priv = adapter->algo_data; | ||
462 | bus->force_bit = intel_gpio_create(dev_priv, | ||
463 | bus->reg0 & 0xff); | ||
464 | } | ||
465 | } else { | ||
466 | if (bus->force_bit) { | ||
467 | i2c_del_adapter(bus->force_bit); | ||
468 | kfree(bus->force_bit); | ||
469 | bus->force_bit = NULL; | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | |||
474 | void gma_intel_teardown_gmbus(struct drm_device *dev) | ||
475 | { | ||
476 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
477 | int i; | ||
478 | |||
479 | if (dev_priv->gmbus == NULL) | ||
480 | return; | ||
481 | |||
482 | for (i = 0; i < GMBUS_NUM_PORTS; i++) { | ||
483 | struct intel_gmbus *bus = &dev_priv->gmbus[i]; | ||
484 | if (bus->force_bit) { | ||
485 | i2c_del_adapter(bus->force_bit); | ||
486 | kfree(bus->force_bit); | ||
487 | } | ||
488 | i2c_del_adapter(&bus->adapter); | ||
489 | } | ||
490 | |||
491 | kfree(dev_priv->gmbus); | ||
492 | dev_priv->gmbus = NULL; | ||
493 | } | ||
diff --git a/drivers/gpu/drm/gma500/intel_i2c.c b/drivers/gpu/drm/gma500/intel_i2c.c new file mode 100644 index 00000000000..98a28c20955 --- /dev/null +++ b/drivers/gpu/drm/gma500/intel_i2c.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | */ | ||
20 | #include <linux/export.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/i2c-algo-bit.h> | ||
23 | |||
24 | #include "psb_drv.h" | ||
25 | #include "psb_intel_reg.h" | ||
26 | |||
27 | /* | ||
28 | * Intel GPIO access functions | ||
29 | */ | ||
30 | |||
31 | #define I2C_RISEFALL_TIME 20 | ||
32 | |||
33 | static int get_clock(void *data) | ||
34 | { | ||
35 | struct psb_intel_i2c_chan *chan = data; | ||
36 | struct drm_device *dev = chan->drm_dev; | ||
37 | u32 val; | ||
38 | |||
39 | val = REG_READ(chan->reg); | ||
40 | return (val & GPIO_CLOCK_VAL_IN) != 0; | ||
41 | } | ||
42 | |||
43 | static int get_data(void *data) | ||
44 | { | ||
45 | struct psb_intel_i2c_chan *chan = data; | ||
46 | struct drm_device *dev = chan->drm_dev; | ||
47 | u32 val; | ||
48 | |||
49 | val = REG_READ(chan->reg); | ||
50 | return (val & GPIO_DATA_VAL_IN) != 0; | ||
51 | } | ||
52 | |||
53 | static void set_clock(void *data, int state_high) | ||
54 | { | ||
55 | struct psb_intel_i2c_chan *chan = data; | ||
56 | struct drm_device *dev = chan->drm_dev; | ||
57 | u32 reserved = 0, clock_bits; | ||
58 | |||
59 | /* On most chips, these bits must be preserved in software. */ | ||
60 | reserved = | ||
61 | REG_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
62 | GPIO_CLOCK_PULLUP_DISABLE); | ||
63 | |||
64 | if (state_high) | ||
65 | clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; | ||
66 | else | ||
67 | clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | | ||
68 | GPIO_CLOCK_VAL_MASK; | ||
69 | REG_WRITE(chan->reg, reserved | clock_bits); | ||
70 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
71 | } | ||
72 | |||
73 | static void set_data(void *data, int state_high) | ||
74 | { | ||
75 | struct psb_intel_i2c_chan *chan = data; | ||
76 | struct drm_device *dev = chan->drm_dev; | ||
77 | u32 reserved = 0, data_bits; | ||
78 | |||
79 | /* On most chips, these bits must be preserved in software. */ | ||
80 | reserved = | ||
81 | REG_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
82 | GPIO_CLOCK_PULLUP_DISABLE); | ||
83 | |||
84 | if (state_high) | ||
85 | data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; | ||
86 | else | ||
87 | data_bits = | ||
88 | GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | | ||
89 | GPIO_DATA_VAL_MASK; | ||
90 | |||
91 | REG_WRITE(chan->reg, reserved | data_bits); | ||
92 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * psb_intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg | ||
97 | * @dev: DRM device | ||
98 | * @output: driver specific output device | ||
99 | * @reg: GPIO reg to use | ||
100 | * @name: name for this bus | ||
101 | * | ||
102 | * Creates and registers a new i2c bus with the Linux i2c layer, for use | ||
103 | * in output probing and control (e.g. DDC or SDVO control functions). | ||
104 | * | ||
105 | * Possible values for @reg include: | ||
106 | * %GPIOA | ||
107 | * %GPIOB | ||
108 | * %GPIOC | ||
109 | * %GPIOD | ||
110 | * %GPIOE | ||
111 | * %GPIOF | ||
112 | * %GPIOG | ||
113 | * %GPIOH | ||
114 | * see PRM for details on how these different busses are used. | ||
115 | */ | ||
116 | struct psb_intel_i2c_chan *psb_intel_i2c_create(struct drm_device *dev, | ||
117 | const u32 reg, const char *name) | ||
118 | { | ||
119 | struct psb_intel_i2c_chan *chan; | ||
120 | |||
121 | chan = kzalloc(sizeof(struct psb_intel_i2c_chan), GFP_KERNEL); | ||
122 | if (!chan) | ||
123 | goto out_free; | ||
124 | |||
125 | chan->drm_dev = dev; | ||
126 | chan->reg = reg; | ||
127 | snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); | ||
128 | chan->adapter.owner = THIS_MODULE; | ||
129 | chan->adapter.algo_data = &chan->algo; | ||
130 | chan->adapter.dev.parent = &dev->pdev->dev; | ||
131 | chan->algo.setsda = set_data; | ||
132 | chan->algo.setscl = set_clock; | ||
133 | chan->algo.getsda = get_data; | ||
134 | chan->algo.getscl = get_clock; | ||
135 | chan->algo.udelay = 20; | ||
136 | chan->algo.timeout = usecs_to_jiffies(2200); | ||
137 | chan->algo.data = chan; | ||
138 | |||
139 | i2c_set_adapdata(&chan->adapter, chan); | ||
140 | |||
141 | if (i2c_bit_add_bus(&chan->adapter)) | ||
142 | goto out_free; | ||
143 | |||
144 | /* JJJ: raise SCL and SDA? */ | ||
145 | set_data(chan, 1); | ||
146 | set_clock(chan, 1); | ||
147 | udelay(20); | ||
148 | |||
149 | return chan; | ||
150 | |||
151 | out_free: | ||
152 | kfree(chan); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * psb_intel_i2c_destroy - unregister and free i2c bus resources | ||
158 | * @output: channel to free | ||
159 | * | ||
160 | * Unregister the adapter from the i2c layer, then free the structure. | ||
161 | */ | ||
162 | void psb_intel_i2c_destroy(struct psb_intel_i2c_chan *chan) | ||
163 | { | ||
164 | if (!chan) | ||
165 | return; | ||
166 | |||
167 | i2c_del_adapter(&chan->adapter); | ||
168 | kfree(chan); | ||
169 | } | ||
diff --git a/drivers/gpu/drm/gma500/intel_opregion.c b/drivers/gpu/drm/gma500/intel_opregion.c new file mode 100644 index 00000000000..d946bc1b17b --- /dev/null +++ b/drivers/gpu/drm/gma500/intel_opregion.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * FIXME: resolve with the i915 version | ||
24 | */ | ||
25 | |||
26 | #include "psb_drv.h" | ||
27 | |||
28 | struct opregion_header { | ||
29 | u8 signature[16]; | ||
30 | u32 size; | ||
31 | u32 opregion_ver; | ||
32 | u8 bios_ver[32]; | ||
33 | u8 vbios_ver[16]; | ||
34 | u8 driver_ver[16]; | ||
35 | u32 mboxes; | ||
36 | u8 reserved[164]; | ||
37 | } __packed; | ||
38 | |||
39 | struct opregion_apci { | ||
40 | /*FIXME: add it later*/ | ||
41 | } __packed; | ||
42 | |||
43 | struct opregion_swsci { | ||
44 | /*FIXME: add it later*/ | ||
45 | } __packed; | ||
46 | |||
47 | struct opregion_acpi { | ||
48 | /*FIXME: add it later*/ | ||
49 | } __packed; | ||
50 | |||
51 | int gma_intel_opregion_init(struct drm_device *dev) | ||
52 | { | ||
53 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
54 | u32 opregion_phy; | ||
55 | void *base; | ||
56 | u32 *lid_state; | ||
57 | |||
58 | dev_priv->lid_state = NULL; | ||
59 | |||
60 | pci_read_config_dword(dev->pdev, 0xfc, &opregion_phy); | ||
61 | if (opregion_phy == 0) | ||
62 | return -ENOTSUPP; | ||
63 | |||
64 | base = ioremap(opregion_phy, 8*1024); | ||
65 | if (!base) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | lid_state = base + 0x01ac; | ||
69 | |||
70 | dev_priv->lid_state = lid_state; | ||
71 | dev_priv->lid_last_state = readl(lid_state); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | int gma_intel_opregion_exit(struct drm_device *dev) | ||
76 | { | ||
77 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
78 | if (dev_priv->lid_state) | ||
79 | iounmap(dev_priv->lid_state); | ||
80 | return 0; | ||
81 | } | ||
diff --git a/drivers/gpu/drm/gma500/mid_bios.c b/drivers/gpu/drm/gma500/mid_bios.c new file mode 100644 index 00000000000..5eee9ad80da --- /dev/null +++ b/drivers/gpu/drm/gma500/mid_bios.c | |||
@@ -0,0 +1,263 @@ | |||
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> | ||
28 | #include "gma_drm.h" | ||
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 | ||
48 | if (pci_root == NULL) { | ||
49 | WARN_ON(1); | ||
50 | return; | ||
51 | } | ||
52 | |||
53 | |||
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 | |||
110 | if (pci_gfx_root == NULL) { | ||
111 | WARN_ON(1); | ||
112 | return; | ||
113 | } | ||
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 | |||
121 | static void mid_get_vbt_data(struct drm_psb_private *dev_priv) | ||
122 | { | ||
123 | struct drm_device *dev = dev_priv->dev; | ||
124 | struct oaktrail_vbt *vbt = &dev_priv->vbt_data; | ||
125 | u32 addr; | ||
126 | u16 new_size; | ||
127 | u8 *vbt_virtual; | ||
128 | u8 bpi; | ||
129 | u8 number_desc = 0; | ||
130 | struct oaktrail_timing_info *dp_ti = &dev_priv->gct_data.DTD; | ||
131 | struct gct_r10_timing_info ti; | ||
132 | void *pGCT; | ||
133 | struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); | ||
134 | |||
135 | /* Get the address of the platform config vbt, B0:D2:F0;0xFC */ | ||
136 | pci_read_config_dword(pci_gfx_root, 0xFC, &addr); | ||
137 | pci_dev_put(pci_gfx_root); | ||
138 | |||
139 | dev_dbg(dev->dev, "drm platform config address is %x\n", addr); | ||
140 | |||
141 | /* check for platform config address == 0. */ | ||
142 | /* this means fw doesn't support vbt */ | ||
143 | |||
144 | if (addr == 0) { | ||
145 | vbt->size = 0; | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | /* get the virtual address of the vbt */ | ||
150 | vbt_virtual = ioremap(addr, sizeof(*vbt)); | ||
151 | if (vbt_virtual == NULL) { | ||
152 | vbt->size = 0; | ||
153 | return; | ||
154 | } | ||
155 | |||
156 | memcpy(vbt, vbt_virtual, sizeof(*vbt)); | ||
157 | iounmap(vbt_virtual); /* Free virtual address space */ | ||
158 | |||
159 | /* No matching signature don't process the data */ | ||
160 | if (memcmp(vbt->signature, "$GCT", 4)) { | ||
161 | vbt->size = 0; | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | dev_dbg(dev->dev, "GCT revision is %x\n", vbt->revision); | ||
166 | |||
167 | switch (vbt->revision) { | ||
168 | case 0: | ||
169 | vbt->oaktrail_gct = ioremap(addr + sizeof(*vbt) - 4, | ||
170 | vbt->size - sizeof(*vbt) + 4); | ||
171 | pGCT = vbt->oaktrail_gct; | ||
172 | bpi = ((struct oaktrail_gct_v1 *)pGCT)->PD.BootPanelIndex; | ||
173 | dev_priv->gct_data.bpi = bpi; | ||
174 | dev_priv->gct_data.pt = | ||
175 | ((struct oaktrail_gct_v1 *)pGCT)->PD.PanelType; | ||
176 | memcpy(&dev_priv->gct_data.DTD, | ||
177 | &((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].DTD, | ||
178 | sizeof(struct oaktrail_timing_info)); | ||
179 | dev_priv->gct_data.Panel_Port_Control = | ||
180 | ((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].Panel_Port_Control; | ||
181 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | ||
182 | ((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor; | ||
183 | break; | ||
184 | case 1: | ||
185 | vbt->oaktrail_gct = ioremap(addr + sizeof(*vbt) - 4, | ||
186 | vbt->size - sizeof(*vbt) + 4); | ||
187 | pGCT = vbt->oaktrail_gct; | ||
188 | bpi = ((struct oaktrail_gct_v2 *)pGCT)->PD.BootPanelIndex; | ||
189 | dev_priv->gct_data.bpi = bpi; | ||
190 | dev_priv->gct_data.pt = | ||
191 | ((struct oaktrail_gct_v2 *)pGCT)->PD.PanelType; | ||
192 | memcpy(&dev_priv->gct_data.DTD, | ||
193 | &((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].DTD, | ||
194 | sizeof(struct oaktrail_timing_info)); | ||
195 | dev_priv->gct_data.Panel_Port_Control = | ||
196 | ((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].Panel_Port_Control; | ||
197 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | ||
198 | ((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor; | ||
199 | break; | ||
200 | case 0x10: | ||
201 | /*header definition changed from rev 01 (v2) to rev 10h. */ | ||
202 | /*so, some values have changed location*/ | ||
203 | new_size = vbt->checksum; /*checksum contains lo size byte*/ | ||
204 | /*LSB of oaktrail_gct contains hi size byte*/ | ||
205 | new_size |= ((0xff & (unsigned int)(long)vbt->oaktrail_gct)) << 8; | ||
206 | |||
207 | vbt->checksum = vbt->size; /*size contains the checksum*/ | ||
208 | if (new_size > 0xff) | ||
209 | vbt->size = 0xff; /*restrict size to 255*/ | ||
210 | else | ||
211 | vbt->size = new_size; | ||
212 | |||
213 | /* number of descriptors defined in the GCT */ | ||
214 | number_desc = ((0xff00 & (unsigned int)(long)vbt->oaktrail_gct)) >> 8; | ||
215 | bpi = ((0xff0000 & (unsigned int)(long)vbt->oaktrail_gct)) >> 16; | ||
216 | vbt->oaktrail_gct = ioremap(addr + GCT_R10_HEADER_SIZE, | ||
217 | GCT_R10_DISPLAY_DESC_SIZE * number_desc); | ||
218 | pGCT = vbt->oaktrail_gct; | ||
219 | pGCT = (u8 *)pGCT + (bpi*GCT_R10_DISPLAY_DESC_SIZE); | ||
220 | dev_priv->gct_data.bpi = bpi; /*save boot panel id*/ | ||
221 | |||
222 | /*copy the GCT display timings into a temp structure*/ | ||
223 | memcpy(&ti, pGCT, sizeof(struct gct_r10_timing_info)); | ||
224 | |||
225 | /*now copy the temp struct into the dev_priv->gct_data*/ | ||
226 | dp_ti->pixel_clock = ti.pixel_clock; | ||
227 | dp_ti->hactive_hi = ti.hactive_hi; | ||
228 | dp_ti->hactive_lo = ti.hactive_lo; | ||
229 | dp_ti->hblank_hi = ti.hblank_hi; | ||
230 | dp_ti->hblank_lo = ti.hblank_lo; | ||
231 | dp_ti->hsync_offset_hi = ti.hsync_offset_hi; | ||
232 | dp_ti->hsync_offset_lo = ti.hsync_offset_lo; | ||
233 | dp_ti->hsync_pulse_width_hi = ti.hsync_pulse_width_hi; | ||
234 | dp_ti->hsync_pulse_width_lo = ti.hsync_pulse_width_lo; | ||
235 | dp_ti->vactive_hi = ti.vactive_hi; | ||
236 | dp_ti->vactive_lo = ti.vactive_lo; | ||
237 | dp_ti->vblank_hi = ti.vblank_hi; | ||
238 | dp_ti->vblank_lo = ti.vblank_lo; | ||
239 | dp_ti->vsync_offset_hi = ti.vsync_offset_hi; | ||
240 | dp_ti->vsync_offset_lo = ti.vsync_offset_lo; | ||
241 | dp_ti->vsync_pulse_width_hi = ti.vsync_pulse_width_hi; | ||
242 | dp_ti->vsync_pulse_width_lo = ti.vsync_pulse_width_lo; | ||
243 | |||
244 | /* Move the MIPI_Display_Descriptor data from GCT to dev priv */ | ||
245 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor = | ||
246 | *((u8 *)pGCT + 0x0d); | ||
247 | dev_priv->gct_data.Panel_MIPI_Display_Descriptor |= | ||
248 | (*((u8 *)pGCT + 0x0e)) << 8; | ||
249 | break; | ||
250 | default: | ||
251 | dev_err(dev->dev, "Unknown revision of GCT!\n"); | ||
252 | vbt->size = 0; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | int mid_chip_setup(struct drm_device *dev) | ||
257 | { | ||
258 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
259 | mid_get_fuse_settings(dev); | ||
260 | mid_get_vbt_data(dev_priv); | ||
261 | mid_get_pci_revID(dev_priv); | ||
262 | return 0; | ||
263 | } | ||
diff --git a/drivers/gpu/drm/gma500/mid_bios.h b/drivers/gpu/drm/gma500/mid_bios.h new file mode 100644 index 00000000000..00e7d564b7e --- /dev/null +++ b/drivers/gpu/drm/gma500/mid_bios.h | |||
@@ -0,0 +1,21 @@ | |||
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 | extern int mid_chip_setup(struct drm_device *dev); | ||
21 | |||
diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c new file mode 100644 index 00000000000..c904d73b1de --- /dev/null +++ b/drivers/gpu/drm/gma500/mmu.c | |||
@@ -0,0 +1,858 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007, Intel Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | **************************************************************************/ | ||
18 | #include <drm/drmP.h> | ||
19 | #include "psb_drv.h" | ||
20 | #include "psb_reg.h" | ||
21 | |||
22 | /* | ||
23 | * Code for the SGX MMU: | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * clflush on one processor only: | ||
28 | * clflush should apparently flush the cache line on all processors in an | ||
29 | * SMP system. | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | * kmap atomic: | ||
34 | * The usage of the slots must be completely encapsulated within a spinlock, and | ||
35 | * no other functions that may be using the locks for other purposed may be | ||
36 | * called from within the locked region. | ||
37 | * Since the slots are per processor, this will guarantee that we are the only | ||
38 | * user. | ||
39 | */ | ||
40 | |||
41 | /* | ||
42 | * TODO: Inserting ptes from an interrupt handler: | ||
43 | * This may be desirable for some SGX functionality where the GPU can fault in | ||
44 | * needed pages. For that, we need to make an atomic insert_pages function, that | ||
45 | * may fail. | ||
46 | * If it fails, the caller need to insert the page using a workqueue function, | ||
47 | * but on average it should be fast. | ||
48 | */ | ||
49 | |||
50 | struct psb_mmu_driver { | ||
51 | /* protects driver- and pd structures. Always take in read mode | ||
52 | * before taking the page table spinlock. | ||
53 | */ | ||
54 | struct rw_semaphore sem; | ||
55 | |||
56 | /* protects page tables, directory tables and pt tables. | ||
57 | * and pt structures. | ||
58 | */ | ||
59 | spinlock_t lock; | ||
60 | |||
61 | atomic_t needs_tlbflush; | ||
62 | |||
63 | uint8_t __iomem *register_map; | ||
64 | struct psb_mmu_pd *default_pd; | ||
65 | /*uint32_t bif_ctrl;*/ | ||
66 | int has_clflush; | ||
67 | int clflush_add; | ||
68 | unsigned long clflush_mask; | ||
69 | |||
70 | struct drm_psb_private *dev_priv; | ||
71 | }; | ||
72 | |||
73 | struct psb_mmu_pd; | ||
74 | |||
75 | struct psb_mmu_pt { | ||
76 | struct psb_mmu_pd *pd; | ||
77 | uint32_t index; | ||
78 | uint32_t count; | ||
79 | struct page *p; | ||
80 | uint32_t *v; | ||
81 | }; | ||
82 | |||
83 | struct psb_mmu_pd { | ||
84 | struct psb_mmu_driver *driver; | ||
85 | int hw_context; | ||
86 | struct psb_mmu_pt **tables; | ||
87 | struct page *p; | ||
88 | struct page *dummy_pt; | ||
89 | struct page *dummy_page; | ||
90 | uint32_t pd_mask; | ||
91 | uint32_t invalid_pde; | ||
92 | uint32_t invalid_pte; | ||
93 | }; | ||
94 | |||
95 | static inline uint32_t psb_mmu_pt_index(uint32_t offset) | ||
96 | { | ||
97 | return (offset >> PSB_PTE_SHIFT) & 0x3FF; | ||
98 | } | ||
99 | |||
100 | static inline uint32_t psb_mmu_pd_index(uint32_t offset) | ||
101 | { | ||
102 | return offset >> PSB_PDE_SHIFT; | ||
103 | } | ||
104 | |||
105 | static inline void psb_clflush(void *addr) | ||
106 | { | ||
107 | __asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory"); | ||
108 | } | ||
109 | |||
110 | static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, | ||
111 | void *addr) | ||
112 | { | ||
113 | if (!driver->has_clflush) | ||
114 | return; | ||
115 | |||
116 | mb(); | ||
117 | psb_clflush(addr); | ||
118 | mb(); | ||
119 | } | ||
120 | |||
121 | static void psb_page_clflush(struct psb_mmu_driver *driver, struct page* page) | ||
122 | { | ||
123 | uint32_t clflush_add = driver->clflush_add >> PAGE_SHIFT; | ||
124 | uint32_t clflush_count = PAGE_SIZE / clflush_add; | ||
125 | int i; | ||
126 | uint8_t *clf; | ||
127 | |||
128 | clf = kmap_atomic(page, KM_USER0); | ||
129 | mb(); | ||
130 | for (i = 0; i < clflush_count; ++i) { | ||
131 | psb_clflush(clf); | ||
132 | clf += clflush_add; | ||
133 | } | ||
134 | mb(); | ||
135 | kunmap_atomic(clf, KM_USER0); | ||
136 | } | ||
137 | |||
138 | static void psb_pages_clflush(struct psb_mmu_driver *driver, | ||
139 | struct page *page[], unsigned long num_pages) | ||
140 | { | ||
141 | int i; | ||
142 | |||
143 | if (!driver->has_clflush) | ||
144 | return ; | ||
145 | |||
146 | for (i = 0; i < num_pages; i++) | ||
147 | psb_page_clflush(driver, *page++); | ||
148 | } | ||
149 | |||
150 | static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, | ||
151 | int force) | ||
152 | { | ||
153 | atomic_set(&driver->needs_tlbflush, 0); | ||
154 | } | ||
155 | |||
156 | static void psb_mmu_flush_pd(struct psb_mmu_driver *driver, int force) | ||
157 | { | ||
158 | down_write(&driver->sem); | ||
159 | psb_mmu_flush_pd_locked(driver, force); | ||
160 | up_write(&driver->sem); | ||
161 | } | ||
162 | |||
163 | void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot) | ||
164 | { | ||
165 | if (rc_prot) | ||
166 | down_write(&driver->sem); | ||
167 | if (rc_prot) | ||
168 | up_write(&driver->sem); | ||
169 | } | ||
170 | |||
171 | void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context) | ||
172 | { | ||
173 | /*ttm_tt_cache_flush(&pd->p, 1);*/ | ||
174 | psb_pages_clflush(pd->driver, &pd->p, 1); | ||
175 | down_write(&pd->driver->sem); | ||
176 | wmb(); | ||
177 | psb_mmu_flush_pd_locked(pd->driver, 1); | ||
178 | pd->hw_context = hw_context; | ||
179 | up_write(&pd->driver->sem); | ||
180 | |||
181 | } | ||
182 | |||
183 | static inline unsigned long psb_pd_addr_end(unsigned long addr, | ||
184 | unsigned long end) | ||
185 | { | ||
186 | |||
187 | addr = (addr + PSB_PDE_MASK + 1) & ~PSB_PDE_MASK; | ||
188 | return (addr < end) ? addr : end; | ||
189 | } | ||
190 | |||
191 | static inline uint32_t psb_mmu_mask_pte(uint32_t pfn, int type) | ||
192 | { | ||
193 | uint32_t mask = PSB_PTE_VALID; | ||
194 | |||
195 | if (type & PSB_MMU_CACHED_MEMORY) | ||
196 | mask |= PSB_PTE_CACHED; | ||
197 | if (type & PSB_MMU_RO_MEMORY) | ||
198 | mask |= PSB_PTE_RO; | ||
199 | if (type & PSB_MMU_WO_MEMORY) | ||
200 | mask |= PSB_PTE_WO; | ||
201 | |||
202 | return (pfn << PAGE_SHIFT) | mask; | ||
203 | } | ||
204 | |||
205 | struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, | ||
206 | int trap_pagefaults, int invalid_type) | ||
207 | { | ||
208 | struct psb_mmu_pd *pd = kmalloc(sizeof(*pd), GFP_KERNEL); | ||
209 | uint32_t *v; | ||
210 | int i; | ||
211 | |||
212 | if (!pd) | ||
213 | return NULL; | ||
214 | |||
215 | pd->p = alloc_page(GFP_DMA32); | ||
216 | if (!pd->p) | ||
217 | goto out_err1; | ||
218 | pd->dummy_pt = alloc_page(GFP_DMA32); | ||
219 | if (!pd->dummy_pt) | ||
220 | goto out_err2; | ||
221 | pd->dummy_page = alloc_page(GFP_DMA32); | ||
222 | if (!pd->dummy_page) | ||
223 | goto out_err3; | ||
224 | |||
225 | if (!trap_pagefaults) { | ||
226 | pd->invalid_pde = | ||
227 | psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), | ||
228 | invalid_type); | ||
229 | pd->invalid_pte = | ||
230 | psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), | ||
231 | invalid_type); | ||
232 | } else { | ||
233 | pd->invalid_pde = 0; | ||
234 | pd->invalid_pte = 0; | ||
235 | } | ||
236 | |||
237 | v = kmap(pd->dummy_pt); | ||
238 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) | ||
239 | v[i] = pd->invalid_pte; | ||
240 | |||
241 | kunmap(pd->dummy_pt); | ||
242 | |||
243 | v = kmap(pd->p); | ||
244 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) | ||
245 | v[i] = pd->invalid_pde; | ||
246 | |||
247 | kunmap(pd->p); | ||
248 | |||
249 | clear_page(kmap(pd->dummy_page)); | ||
250 | kunmap(pd->dummy_page); | ||
251 | |||
252 | pd->tables = vmalloc_user(sizeof(struct psb_mmu_pt *) * 1024); | ||
253 | if (!pd->tables) | ||
254 | goto out_err4; | ||
255 | |||
256 | pd->hw_context = -1; | ||
257 | pd->pd_mask = PSB_PTE_VALID; | ||
258 | pd->driver = driver; | ||
259 | |||
260 | return pd; | ||
261 | |||
262 | out_err4: | ||
263 | __free_page(pd->dummy_page); | ||
264 | out_err3: | ||
265 | __free_page(pd->dummy_pt); | ||
266 | out_err2: | ||
267 | __free_page(pd->p); | ||
268 | out_err1: | ||
269 | kfree(pd); | ||
270 | return NULL; | ||
271 | } | ||
272 | |||
273 | void psb_mmu_free_pt(struct psb_mmu_pt *pt) | ||
274 | { | ||
275 | __free_page(pt->p); | ||
276 | kfree(pt); | ||
277 | } | ||
278 | |||
279 | void psb_mmu_free_pagedir(struct psb_mmu_pd *pd) | ||
280 | { | ||
281 | struct psb_mmu_driver *driver = pd->driver; | ||
282 | struct psb_mmu_pt *pt; | ||
283 | int i; | ||
284 | |||
285 | down_write(&driver->sem); | ||
286 | if (pd->hw_context != -1) | ||
287 | psb_mmu_flush_pd_locked(driver, 1); | ||
288 | |||
289 | /* Should take the spinlock here, but we don't need to do that | ||
290 | since we have the semaphore in write mode. */ | ||
291 | |||
292 | for (i = 0; i < 1024; ++i) { | ||
293 | pt = pd->tables[i]; | ||
294 | if (pt) | ||
295 | psb_mmu_free_pt(pt); | ||
296 | } | ||
297 | |||
298 | vfree(pd->tables); | ||
299 | __free_page(pd->dummy_page); | ||
300 | __free_page(pd->dummy_pt); | ||
301 | __free_page(pd->p); | ||
302 | kfree(pd); | ||
303 | up_write(&driver->sem); | ||
304 | } | ||
305 | |||
306 | static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) | ||
307 | { | ||
308 | struct psb_mmu_pt *pt = kmalloc(sizeof(*pt), GFP_KERNEL); | ||
309 | void *v; | ||
310 | uint32_t clflush_add = pd->driver->clflush_add >> PAGE_SHIFT; | ||
311 | uint32_t clflush_count = PAGE_SIZE / clflush_add; | ||
312 | spinlock_t *lock = &pd->driver->lock; | ||
313 | uint8_t *clf; | ||
314 | uint32_t *ptes; | ||
315 | int i; | ||
316 | |||
317 | if (!pt) | ||
318 | return NULL; | ||
319 | |||
320 | pt->p = alloc_page(GFP_DMA32); | ||
321 | if (!pt->p) { | ||
322 | kfree(pt); | ||
323 | return NULL; | ||
324 | } | ||
325 | |||
326 | spin_lock(lock); | ||
327 | |||
328 | v = kmap_atomic(pt->p, KM_USER0); | ||
329 | clf = (uint8_t *) v; | ||
330 | ptes = (uint32_t *) v; | ||
331 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) | ||
332 | *ptes++ = pd->invalid_pte; | ||
333 | |||
334 | |||
335 | if (pd->driver->has_clflush && pd->hw_context != -1) { | ||
336 | mb(); | ||
337 | for (i = 0; i < clflush_count; ++i) { | ||
338 | psb_clflush(clf); | ||
339 | clf += clflush_add; | ||
340 | } | ||
341 | mb(); | ||
342 | } | ||
343 | |||
344 | kunmap_atomic(v, KM_USER0); | ||
345 | spin_unlock(lock); | ||
346 | |||
347 | pt->count = 0; | ||
348 | pt->pd = pd; | ||
349 | pt->index = 0; | ||
350 | |||
351 | return pt; | ||
352 | } | ||
353 | |||
354 | struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, | ||
355 | unsigned long addr) | ||
356 | { | ||
357 | uint32_t index = psb_mmu_pd_index(addr); | ||
358 | struct psb_mmu_pt *pt; | ||
359 | uint32_t *v; | ||
360 | spinlock_t *lock = &pd->driver->lock; | ||
361 | |||
362 | spin_lock(lock); | ||
363 | pt = pd->tables[index]; | ||
364 | while (!pt) { | ||
365 | spin_unlock(lock); | ||
366 | pt = psb_mmu_alloc_pt(pd); | ||
367 | if (!pt) | ||
368 | return NULL; | ||
369 | spin_lock(lock); | ||
370 | |||
371 | if (pd->tables[index]) { | ||
372 | spin_unlock(lock); | ||
373 | psb_mmu_free_pt(pt); | ||
374 | spin_lock(lock); | ||
375 | pt = pd->tables[index]; | ||
376 | continue; | ||
377 | } | ||
378 | |||
379 | v = kmap_atomic(pd->p, KM_USER0); | ||
380 | pd->tables[index] = pt; | ||
381 | v[index] = (page_to_pfn(pt->p) << 12) | pd->pd_mask; | ||
382 | pt->index = index; | ||
383 | kunmap_atomic((void *) v, KM_USER0); | ||
384 | |||
385 | if (pd->hw_context != -1) { | ||
386 | psb_mmu_clflush(pd->driver, (void *) &v[index]); | ||
387 | atomic_set(&pd->driver->needs_tlbflush, 1); | ||
388 | } | ||
389 | } | ||
390 | pt->v = kmap_atomic(pt->p, KM_USER0); | ||
391 | return pt; | ||
392 | } | ||
393 | |||
394 | static struct psb_mmu_pt *psb_mmu_pt_map_lock(struct psb_mmu_pd *pd, | ||
395 | unsigned long addr) | ||
396 | { | ||
397 | uint32_t index = psb_mmu_pd_index(addr); | ||
398 | struct psb_mmu_pt *pt; | ||
399 | spinlock_t *lock = &pd->driver->lock; | ||
400 | |||
401 | spin_lock(lock); | ||
402 | pt = pd->tables[index]; | ||
403 | if (!pt) { | ||
404 | spin_unlock(lock); | ||
405 | return NULL; | ||
406 | } | ||
407 | pt->v = kmap_atomic(pt->p, KM_USER0); | ||
408 | return pt; | ||
409 | } | ||
410 | |||
411 | static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) | ||
412 | { | ||
413 | struct psb_mmu_pd *pd = pt->pd; | ||
414 | uint32_t *v; | ||
415 | |||
416 | kunmap_atomic(pt->v, KM_USER0); | ||
417 | if (pt->count == 0) { | ||
418 | v = kmap_atomic(pd->p, KM_USER0); | ||
419 | v[pt->index] = pd->invalid_pde; | ||
420 | pd->tables[pt->index] = NULL; | ||
421 | |||
422 | if (pd->hw_context != -1) { | ||
423 | psb_mmu_clflush(pd->driver, | ||
424 | (void *) &v[pt->index]); | ||
425 | atomic_set(&pd->driver->needs_tlbflush, 1); | ||
426 | } | ||
427 | kunmap_atomic(pt->v, KM_USER0); | ||
428 | spin_unlock(&pd->driver->lock); | ||
429 | psb_mmu_free_pt(pt); | ||
430 | return; | ||
431 | } | ||
432 | spin_unlock(&pd->driver->lock); | ||
433 | } | ||
434 | |||
435 | static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, | ||
436 | unsigned long addr, uint32_t pte) | ||
437 | { | ||
438 | pt->v[psb_mmu_pt_index(addr)] = pte; | ||
439 | } | ||
440 | |||
441 | static inline void psb_mmu_invalidate_pte(struct psb_mmu_pt *pt, | ||
442 | unsigned long addr) | ||
443 | { | ||
444 | pt->v[psb_mmu_pt_index(addr)] = pt->pd->invalid_pte; | ||
445 | } | ||
446 | |||
447 | |||
448 | void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, | ||
449 | uint32_t mmu_offset, uint32_t gtt_start, | ||
450 | uint32_t gtt_pages) | ||
451 | { | ||
452 | uint32_t *v; | ||
453 | uint32_t start = psb_mmu_pd_index(mmu_offset); | ||
454 | struct psb_mmu_driver *driver = pd->driver; | ||
455 | int num_pages = gtt_pages; | ||
456 | |||
457 | down_read(&driver->sem); | ||
458 | spin_lock(&driver->lock); | ||
459 | |||
460 | v = kmap_atomic(pd->p, KM_USER0); | ||
461 | v += start; | ||
462 | |||
463 | while (gtt_pages--) { | ||
464 | *v++ = gtt_start | pd->pd_mask; | ||
465 | gtt_start += PAGE_SIZE; | ||
466 | } | ||
467 | |||
468 | /*ttm_tt_cache_flush(&pd->p, num_pages);*/ | ||
469 | psb_pages_clflush(pd->driver, &pd->p, num_pages); | ||
470 | kunmap_atomic(v, KM_USER0); | ||
471 | spin_unlock(&driver->lock); | ||
472 | |||
473 | if (pd->hw_context != -1) | ||
474 | atomic_set(&pd->driver->needs_tlbflush, 1); | ||
475 | |||
476 | up_read(&pd->driver->sem); | ||
477 | psb_mmu_flush_pd(pd->driver, 0); | ||
478 | } | ||
479 | |||
480 | struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver) | ||
481 | { | ||
482 | struct psb_mmu_pd *pd; | ||
483 | |||
484 | /* down_read(&driver->sem); */ | ||
485 | pd = driver->default_pd; | ||
486 | /* up_read(&driver->sem); */ | ||
487 | |||
488 | return pd; | ||
489 | } | ||
490 | |||
491 | /* Returns the physical address of the PD shared by sgx/msvdx */ | ||
492 | uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver) | ||
493 | { | ||
494 | struct psb_mmu_pd *pd; | ||
495 | |||
496 | pd = psb_mmu_get_default_pd(driver); | ||
497 | return page_to_pfn(pd->p) << PAGE_SHIFT; | ||
498 | } | ||
499 | |||
500 | void psb_mmu_driver_takedown(struct psb_mmu_driver *driver) | ||
501 | { | ||
502 | psb_mmu_free_pagedir(driver->default_pd); | ||
503 | kfree(driver); | ||
504 | } | ||
505 | |||
506 | struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, | ||
507 | int trap_pagefaults, | ||
508 | int invalid_type, | ||
509 | struct drm_psb_private *dev_priv) | ||
510 | { | ||
511 | struct psb_mmu_driver *driver; | ||
512 | |||
513 | driver = kmalloc(sizeof(*driver), GFP_KERNEL); | ||
514 | |||
515 | if (!driver) | ||
516 | return NULL; | ||
517 | driver->dev_priv = dev_priv; | ||
518 | |||
519 | driver->default_pd = psb_mmu_alloc_pd(driver, trap_pagefaults, | ||
520 | invalid_type); | ||
521 | if (!driver->default_pd) | ||
522 | goto out_err1; | ||
523 | |||
524 | spin_lock_init(&driver->lock); | ||
525 | init_rwsem(&driver->sem); | ||
526 | down_write(&driver->sem); | ||
527 | driver->register_map = registers; | ||
528 | atomic_set(&driver->needs_tlbflush, 1); | ||
529 | |||
530 | driver->has_clflush = 0; | ||
531 | |||
532 | if (boot_cpu_has(X86_FEATURE_CLFLSH)) { | ||
533 | uint32_t tfms, misc, cap0, cap4, clflush_size; | ||
534 | |||
535 | /* | ||
536 | * clflush size is determined at kernel setup for x86_64 | ||
537 | * but not for i386. We have to do it here. | ||
538 | */ | ||
539 | |||
540 | cpuid(0x00000001, &tfms, &misc, &cap0, &cap4); | ||
541 | clflush_size = ((misc >> 8) & 0xff) * 8; | ||
542 | driver->has_clflush = 1; | ||
543 | driver->clflush_add = | ||
544 | PAGE_SIZE * clflush_size / sizeof(uint32_t); | ||
545 | driver->clflush_mask = driver->clflush_add - 1; | ||
546 | driver->clflush_mask = ~driver->clflush_mask; | ||
547 | } | ||
548 | |||
549 | up_write(&driver->sem); | ||
550 | return driver; | ||
551 | |||
552 | out_err1: | ||
553 | kfree(driver); | ||
554 | return NULL; | ||
555 | } | ||
556 | |||
557 | static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, | ||
558 | unsigned long address, uint32_t num_pages, | ||
559 | uint32_t desired_tile_stride, | ||
560 | uint32_t hw_tile_stride) | ||
561 | { | ||
562 | struct psb_mmu_pt *pt; | ||
563 | uint32_t rows = 1; | ||
564 | uint32_t i; | ||
565 | unsigned long addr; | ||
566 | unsigned long end; | ||
567 | unsigned long next; | ||
568 | unsigned long add; | ||
569 | unsigned long row_add; | ||
570 | unsigned long clflush_add = pd->driver->clflush_add; | ||
571 | unsigned long clflush_mask = pd->driver->clflush_mask; | ||
572 | |||
573 | if (!pd->driver->has_clflush) { | ||
574 | /*ttm_tt_cache_flush(&pd->p, num_pages);*/ | ||
575 | psb_pages_clflush(pd->driver, &pd->p, num_pages); | ||
576 | return; | ||
577 | } | ||
578 | |||
579 | if (hw_tile_stride) | ||
580 | rows = num_pages / desired_tile_stride; | ||
581 | else | ||
582 | desired_tile_stride = num_pages; | ||
583 | |||
584 | add = desired_tile_stride << PAGE_SHIFT; | ||
585 | row_add = hw_tile_stride << PAGE_SHIFT; | ||
586 | mb(); | ||
587 | for (i = 0; i < rows; ++i) { | ||
588 | |||
589 | addr = address; | ||
590 | end = addr + add; | ||
591 | |||
592 | do { | ||
593 | next = psb_pd_addr_end(addr, end); | ||
594 | pt = psb_mmu_pt_map_lock(pd, addr); | ||
595 | if (!pt) | ||
596 | continue; | ||
597 | do { | ||
598 | psb_clflush(&pt->v | ||
599 | [psb_mmu_pt_index(addr)]); | ||
600 | } while (addr += | ||
601 | clflush_add, | ||
602 | (addr & clflush_mask) < next); | ||
603 | |||
604 | psb_mmu_pt_unmap_unlock(pt); | ||
605 | } while (addr = next, next != end); | ||
606 | address += row_add; | ||
607 | } | ||
608 | mb(); | ||
609 | } | ||
610 | |||
611 | void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, | ||
612 | unsigned long address, uint32_t num_pages) | ||
613 | { | ||
614 | struct psb_mmu_pt *pt; | ||
615 | unsigned long addr; | ||
616 | unsigned long end; | ||
617 | unsigned long next; | ||
618 | unsigned long f_address = address; | ||
619 | |||
620 | down_read(&pd->driver->sem); | ||
621 | |||
622 | addr = address; | ||
623 | end = addr + (num_pages << PAGE_SHIFT); | ||
624 | |||
625 | do { | ||
626 | next = psb_pd_addr_end(addr, end); | ||
627 | pt = psb_mmu_pt_alloc_map_lock(pd, addr); | ||
628 | if (!pt) | ||
629 | goto out; | ||
630 | do { | ||
631 | psb_mmu_invalidate_pte(pt, addr); | ||
632 | --pt->count; | ||
633 | } while (addr += PAGE_SIZE, addr < next); | ||
634 | psb_mmu_pt_unmap_unlock(pt); | ||
635 | |||
636 | } while (addr = next, next != end); | ||
637 | |||
638 | out: | ||
639 | if (pd->hw_context != -1) | ||
640 | psb_mmu_flush_ptes(pd, f_address, num_pages, 1, 1); | ||
641 | |||
642 | up_read(&pd->driver->sem); | ||
643 | |||
644 | if (pd->hw_context != -1) | ||
645 | psb_mmu_flush(pd->driver, 0); | ||
646 | |||
647 | return; | ||
648 | } | ||
649 | |||
650 | void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address, | ||
651 | uint32_t num_pages, uint32_t desired_tile_stride, | ||
652 | uint32_t hw_tile_stride) | ||
653 | { | ||
654 | struct psb_mmu_pt *pt; | ||
655 | uint32_t rows = 1; | ||
656 | uint32_t i; | ||
657 | unsigned long addr; | ||
658 | unsigned long end; | ||
659 | unsigned long next; | ||
660 | unsigned long add; | ||
661 | unsigned long row_add; | ||
662 | unsigned long f_address = address; | ||
663 | |||
664 | if (hw_tile_stride) | ||
665 | rows = num_pages / desired_tile_stride; | ||
666 | else | ||
667 | desired_tile_stride = num_pages; | ||
668 | |||
669 | add = desired_tile_stride << PAGE_SHIFT; | ||
670 | row_add = hw_tile_stride << PAGE_SHIFT; | ||
671 | |||
672 | /* down_read(&pd->driver->sem); */ | ||
673 | |||
674 | /* Make sure we only need to flush this processor's cache */ | ||
675 | |||
676 | for (i = 0; i < rows; ++i) { | ||
677 | |||
678 | addr = address; | ||
679 | end = addr + add; | ||
680 | |||
681 | do { | ||
682 | next = psb_pd_addr_end(addr, end); | ||
683 | pt = psb_mmu_pt_map_lock(pd, addr); | ||
684 | if (!pt) | ||
685 | continue; | ||
686 | do { | ||
687 | psb_mmu_invalidate_pte(pt, addr); | ||
688 | --pt->count; | ||
689 | |||
690 | } while (addr += PAGE_SIZE, addr < next); | ||
691 | psb_mmu_pt_unmap_unlock(pt); | ||
692 | |||
693 | } while (addr = next, next != end); | ||
694 | address += row_add; | ||
695 | } | ||
696 | if (pd->hw_context != -1) | ||
697 | psb_mmu_flush_ptes(pd, f_address, num_pages, | ||
698 | desired_tile_stride, hw_tile_stride); | ||
699 | |||
700 | /* up_read(&pd->driver->sem); */ | ||
701 | |||
702 | if (pd->hw_context != -1) | ||
703 | psb_mmu_flush(pd->driver, 0); | ||
704 | } | ||
705 | |||
706 | int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, | ||
707 | unsigned long address, uint32_t num_pages, | ||
708 | int type) | ||
709 | { | ||
710 | struct psb_mmu_pt *pt; | ||
711 | uint32_t pte; | ||
712 | unsigned long addr; | ||
713 | unsigned long end; | ||
714 | unsigned long next; | ||
715 | unsigned long f_address = address; | ||
716 | int ret = 0; | ||
717 | |||
718 | down_read(&pd->driver->sem); | ||
719 | |||
720 | addr = address; | ||
721 | end = addr + (num_pages << PAGE_SHIFT); | ||
722 | |||
723 | do { | ||
724 | next = psb_pd_addr_end(addr, end); | ||
725 | pt = psb_mmu_pt_alloc_map_lock(pd, addr); | ||
726 | if (!pt) { | ||
727 | ret = -ENOMEM; | ||
728 | goto out; | ||
729 | } | ||
730 | do { | ||
731 | pte = psb_mmu_mask_pte(start_pfn++, type); | ||
732 | psb_mmu_set_pte(pt, addr, pte); | ||
733 | pt->count++; | ||
734 | } while (addr += PAGE_SIZE, addr < next); | ||
735 | psb_mmu_pt_unmap_unlock(pt); | ||
736 | |||
737 | } while (addr = next, next != end); | ||
738 | |||
739 | out: | ||
740 | if (pd->hw_context != -1) | ||
741 | psb_mmu_flush_ptes(pd, f_address, num_pages, 1, 1); | ||
742 | |||
743 | up_read(&pd->driver->sem); | ||
744 | |||
745 | if (pd->hw_context != -1) | ||
746 | psb_mmu_flush(pd->driver, 1); | ||
747 | |||
748 | return ret; | ||
749 | } | ||
750 | |||
751 | int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, | ||
752 | unsigned long address, uint32_t num_pages, | ||
753 | uint32_t desired_tile_stride, | ||
754 | uint32_t hw_tile_stride, int type) | ||
755 | { | ||
756 | struct psb_mmu_pt *pt; | ||
757 | uint32_t rows = 1; | ||
758 | uint32_t i; | ||
759 | uint32_t pte; | ||
760 | unsigned long addr; | ||
761 | unsigned long end; | ||
762 | unsigned long next; | ||
763 | unsigned long add; | ||
764 | unsigned long row_add; | ||
765 | unsigned long f_address = address; | ||
766 | int ret = 0; | ||
767 | |||
768 | if (hw_tile_stride) { | ||
769 | if (num_pages % desired_tile_stride != 0) | ||
770 | return -EINVAL; | ||
771 | rows = num_pages / desired_tile_stride; | ||
772 | } else { | ||
773 | desired_tile_stride = num_pages; | ||
774 | } | ||
775 | |||
776 | add = desired_tile_stride << PAGE_SHIFT; | ||
777 | row_add = hw_tile_stride << PAGE_SHIFT; | ||
778 | |||
779 | down_read(&pd->driver->sem); | ||
780 | |||
781 | for (i = 0; i < rows; ++i) { | ||
782 | |||
783 | addr = address; | ||
784 | end = addr + add; | ||
785 | |||
786 | do { | ||
787 | next = psb_pd_addr_end(addr, end); | ||
788 | pt = psb_mmu_pt_alloc_map_lock(pd, addr); | ||
789 | if (!pt) { | ||
790 | ret = -ENOMEM; | ||
791 | goto out; | ||
792 | } | ||
793 | do { | ||
794 | pte = | ||
795 | psb_mmu_mask_pte(page_to_pfn(*pages++), | ||
796 | type); | ||
797 | psb_mmu_set_pte(pt, addr, pte); | ||
798 | pt->count++; | ||
799 | } while (addr += PAGE_SIZE, addr < next); | ||
800 | psb_mmu_pt_unmap_unlock(pt); | ||
801 | |||
802 | } while (addr = next, next != end); | ||
803 | |||
804 | address += row_add; | ||
805 | } | ||
806 | out: | ||
807 | if (pd->hw_context != -1) | ||
808 | psb_mmu_flush_ptes(pd, f_address, num_pages, | ||
809 | desired_tile_stride, hw_tile_stride); | ||
810 | |||
811 | up_read(&pd->driver->sem); | ||
812 | |||
813 | if (pd->hw_context != -1) | ||
814 | psb_mmu_flush(pd->driver, 1); | ||
815 | |||
816 | return ret; | ||
817 | } | ||
818 | |||
819 | int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, | ||
820 | unsigned long *pfn) | ||
821 | { | ||
822 | int ret; | ||
823 | struct psb_mmu_pt *pt; | ||
824 | uint32_t tmp; | ||
825 | spinlock_t *lock = &pd->driver->lock; | ||
826 | |||
827 | down_read(&pd->driver->sem); | ||
828 | pt = psb_mmu_pt_map_lock(pd, virtual); | ||
829 | if (!pt) { | ||
830 | uint32_t *v; | ||
831 | |||
832 | spin_lock(lock); | ||
833 | v = kmap_atomic(pd->p, KM_USER0); | ||
834 | tmp = v[psb_mmu_pd_index(virtual)]; | ||
835 | kunmap_atomic(v, KM_USER0); | ||
836 | spin_unlock(lock); | ||
837 | |||
838 | if (tmp != pd->invalid_pde || !(tmp & PSB_PTE_VALID) || | ||
839 | !(pd->invalid_pte & PSB_PTE_VALID)) { | ||
840 | ret = -EINVAL; | ||
841 | goto out; | ||
842 | } | ||
843 | ret = 0; | ||
844 | *pfn = pd->invalid_pte >> PAGE_SHIFT; | ||
845 | goto out; | ||
846 | } | ||
847 | tmp = pt->v[psb_mmu_pt_index(virtual)]; | ||
848 | if (!(tmp & PSB_PTE_VALID)) { | ||
849 | ret = -EINVAL; | ||
850 | } else { | ||
851 | ret = 0; | ||
852 | *pfn = tmp >> PAGE_SHIFT; | ||
853 | } | ||
854 | psb_mmu_pt_unmap_unlock(pt); | ||
855 | out: | ||
856 | up_read(&pd->driver->sem); | ||
857 | return ret; | ||
858 | } | ||
diff --git a/drivers/gpu/drm/gma500/oaktrail.h b/drivers/gpu/drm/gma500/oaktrail.h new file mode 100644 index 00000000000..2da1f368f14 --- /dev/null +++ b/drivers/gpu/drm/gma500/oaktrail.h | |||
@@ -0,0 +1,252 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007-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 | /* MID device specific descriptors */ | ||
21 | |||
22 | struct oaktrail_vbt { | ||
23 | s8 signature[4]; /*4 bytes,"$GCT" */ | ||
24 | u8 revision; | ||
25 | u8 size; | ||
26 | u8 checksum; | ||
27 | void *oaktrail_gct; | ||
28 | } __packed; | ||
29 | |||
30 | struct oaktrail_timing_info { | ||
31 | u16 pixel_clock; | ||
32 | u8 hactive_lo; | ||
33 | u8 hblank_lo; | ||
34 | u8 hblank_hi:4; | ||
35 | u8 hactive_hi:4; | ||
36 | u8 vactive_lo; | ||
37 | u8 vblank_lo; | ||
38 | u8 vblank_hi:4; | ||
39 | u8 vactive_hi:4; | ||
40 | u8 hsync_offset_lo; | ||
41 | u8 hsync_pulse_width_lo; | ||
42 | u8 vsync_pulse_width_lo:4; | ||
43 | u8 vsync_offset_lo:4; | ||
44 | u8 vsync_pulse_width_hi:2; | ||
45 | u8 vsync_offset_hi:2; | ||
46 | u8 hsync_pulse_width_hi:2; | ||
47 | u8 hsync_offset_hi:2; | ||
48 | u8 width_mm_lo; | ||
49 | u8 height_mm_lo; | ||
50 | u8 height_mm_hi:4; | ||
51 | u8 width_mm_hi:4; | ||
52 | u8 hborder; | ||
53 | u8 vborder; | ||
54 | u8 unknown0:1; | ||
55 | u8 hsync_positive:1; | ||
56 | u8 vsync_positive:1; | ||
57 | u8 separate_sync:2; | ||
58 | u8 stereo:1; | ||
59 | u8 unknown6:1; | ||
60 | u8 interlaced:1; | ||
61 | } __packed; | ||
62 | |||
63 | struct gct_r10_timing_info { | ||
64 | u16 pixel_clock; | ||
65 | u32 hactive_lo:8; | ||
66 | u32 hactive_hi:4; | ||
67 | u32 hblank_lo:8; | ||
68 | u32 hblank_hi:4; | ||
69 | u32 hsync_offset_lo:8; | ||
70 | u16 hsync_offset_hi:2; | ||
71 | u16 hsync_pulse_width_lo:8; | ||
72 | u16 hsync_pulse_width_hi:2; | ||
73 | u16 hsync_positive:1; | ||
74 | u16 rsvd_1:3; | ||
75 | u8 vactive_lo:8; | ||
76 | u16 vactive_hi:4; | ||
77 | u16 vblank_lo:8; | ||
78 | u16 vblank_hi:4; | ||
79 | u16 vsync_offset_lo:4; | ||
80 | u16 vsync_offset_hi:2; | ||
81 | u16 vsync_pulse_width_lo:4; | ||
82 | u16 vsync_pulse_width_hi:2; | ||
83 | u16 vsync_positive:1; | ||
84 | u16 rsvd_2:3; | ||
85 | } __packed; | ||
86 | |||
87 | struct oaktrail_panel_descriptor_v1 { | ||
88 | u32 Panel_Port_Control; /* 1 dword, Register 0x61180 if LVDS */ | ||
89 | /* 0x61190 if MIPI */ | ||
90 | u32 Panel_Power_On_Sequencing;/*1 dword,Register 0x61208,*/ | ||
91 | u32 Panel_Power_Off_Sequencing;/*1 dword,Register 0x6120C,*/ | ||
92 | u32 Panel_Power_Cycle_Delay_and_Reference_Divisor;/* 1 dword */ | ||
93 | /* Register 0x61210 */ | ||
94 | struct oaktrail_timing_info DTD;/*18 bytes, Standard definition */ | ||
95 | u16 Panel_Backlight_Inverter_Descriptor;/* 16 bits, as follows */ | ||
96 | /* Bit 0, Frequency, 15 bits,0 - 32767Hz */ | ||
97 | /* Bit 15, Polarity, 1 bit, 0: Normal, 1: Inverted */ | ||
98 | u16 Panel_MIPI_Display_Descriptor; | ||
99 | /*16 bits, Defined as follows: */ | ||
100 | /* if MIPI, 0x0000 if LVDS */ | ||
101 | /* Bit 0, Type, 2 bits, */ | ||
102 | /* 0: Type-1, */ | ||
103 | /* 1: Type-2, */ | ||
104 | /* 2: Type-3, */ | ||
105 | /* 3: Type-4 */ | ||
106 | /* Bit 2, Pixel Format, 4 bits */ | ||
107 | /* Bit0: 16bpp (not supported in LNC), */ | ||
108 | /* Bit1: 18bpp loosely packed, */ | ||
109 | /* Bit2: 18bpp packed, */ | ||
110 | /* Bit3: 24bpp */ | ||
111 | /* Bit 6, Reserved, 2 bits, 00b */ | ||
112 | /* Bit 8, Minimum Supported Frame Rate, 6 bits, 0 - 63Hz */ | ||
113 | /* Bit 14, Reserved, 2 bits, 00b */ | ||
114 | } __packed; | ||
115 | |||
116 | struct oaktrail_panel_descriptor_v2 { | ||
117 | u32 Panel_Port_Control; /* 1 dword, Register 0x61180 if LVDS */ | ||
118 | /* 0x61190 if MIPI */ | ||
119 | u32 Panel_Power_On_Sequencing;/*1 dword,Register 0x61208,*/ | ||
120 | u32 Panel_Power_Off_Sequencing;/*1 dword,Register 0x6120C,*/ | ||
121 | u8 Panel_Power_Cycle_Delay_and_Reference_Divisor;/* 1 byte */ | ||
122 | /* Register 0x61210 */ | ||
123 | struct oaktrail_timing_info DTD;/*18 bytes, Standard definition */ | ||
124 | u16 Panel_Backlight_Inverter_Descriptor;/*16 bits, as follows*/ | ||
125 | /*Bit 0, Frequency, 16 bits, 0 - 32767Hz*/ | ||
126 | u8 Panel_Initial_Brightness;/* [7:0] 0 - 100% */ | ||
127 | /*Bit 7, Polarity, 1 bit,0: Normal, 1: Inverted*/ | ||
128 | u16 Panel_MIPI_Display_Descriptor; | ||
129 | /*16 bits, Defined as follows: */ | ||
130 | /* if MIPI, 0x0000 if LVDS */ | ||
131 | /* Bit 0, Type, 2 bits, */ | ||
132 | /* 0: Type-1, */ | ||
133 | /* 1: Type-2, */ | ||
134 | /* 2: Type-3, */ | ||
135 | /* 3: Type-4 */ | ||
136 | /* Bit 2, Pixel Format, 4 bits */ | ||
137 | /* Bit0: 16bpp (not supported in LNC), */ | ||
138 | /* Bit1: 18bpp loosely packed, */ | ||
139 | /* Bit2: 18bpp packed, */ | ||
140 | /* Bit3: 24bpp */ | ||
141 | /* Bit 6, Reserved, 2 bits, 00b */ | ||
142 | /* Bit 8, Minimum Supported Frame Rate, 6 bits, 0 - 63Hz */ | ||
143 | /* Bit 14, Reserved, 2 bits, 00b */ | ||
144 | } __packed; | ||
145 | |||
146 | union oaktrail_panel_rx { | ||
147 | struct { | ||
148 | u16 NumberOfLanes:2; /*Num of Lanes, 2 bits,0 = 1 lane,*/ | ||
149 | /* 1 = 2 lanes, 2 = 3 lanes, 3 = 4 lanes. */ | ||
150 | u16 MaxLaneFreq:3; /* 0: 100MHz, 1: 200MHz, 2: 300MHz, */ | ||
151 | /*3: 400MHz, 4: 500MHz, 5: 600MHz, 6: 700MHz, 7: 800MHz.*/ | ||
152 | u16 SupportedVideoTransferMode:2; /*0: Non-burst only */ | ||
153 | /* 1: Burst and non-burst */ | ||
154 | /* 2/3: Reserved */ | ||
155 | u16 HSClkBehavior:1; /*0: Continuous, 1: Non-continuous*/ | ||
156 | u16 DuoDisplaySupport:1; /*1 bit,0: No, 1: Yes*/ | ||
157 | u16 ECC_ChecksumCapabilities:1;/*1 bit,0: No, 1: Yes*/ | ||
158 | u16 BidirectionalCommunication:1;/*1 bit,0: No, 1: Yes */ | ||
159 | u16 Rsvd:5;/*5 bits,00000b */ | ||
160 | } panelrx; | ||
161 | u16 panel_receiver; | ||
162 | } __packed; | ||
163 | |||
164 | struct oaktrail_gct_v1 { | ||
165 | union { /*8 bits,Defined as follows: */ | ||
166 | struct { | ||
167 | u8 PanelType:4; /*4 bits, Bit field for panels*/ | ||
168 | /* 0 - 3: 0 = LVDS, 1 = MIPI*/ | ||
169 | /*2 bits,Specifies which of the*/ | ||
170 | u8 BootPanelIndex:2; | ||
171 | /* 4 panels to use by default*/ | ||
172 | u8 BootMIPI_DSI_RxIndex:2;/*Specifies which of*/ | ||
173 | /* the 4 MIPI DSI receivers to use*/ | ||
174 | } PD; | ||
175 | u8 PanelDescriptor; | ||
176 | }; | ||
177 | struct oaktrail_panel_descriptor_v1 panel[4];/*panel descrs,38 bytes each*/ | ||
178 | union oaktrail_panel_rx panelrx[4]; /* panel receivers*/ | ||
179 | } __packed; | ||
180 | |||
181 | struct oaktrail_gct_v2 { | ||
182 | union { /*8 bits,Defined as follows: */ | ||
183 | struct { | ||
184 | u8 PanelType:4; /*4 bits, Bit field for panels*/ | ||
185 | /* 0 - 3: 0 = LVDS, 1 = MIPI*/ | ||
186 | /*2 bits,Specifies which of the*/ | ||
187 | u8 BootPanelIndex:2; | ||
188 | /* 4 panels to use by default*/ | ||
189 | u8 BootMIPI_DSI_RxIndex:2;/*Specifies which of*/ | ||
190 | /* the 4 MIPI DSI receivers to use*/ | ||
191 | } PD; | ||
192 | u8 PanelDescriptor; | ||
193 | }; | ||
194 | struct oaktrail_panel_descriptor_v2 panel[4];/*panel descrs,38 bytes each*/ | ||
195 | union oaktrail_panel_rx panelrx[4]; /* panel receivers*/ | ||
196 | } __packed; | ||
197 | |||
198 | struct oaktrail_gct_data { | ||
199 | u8 bpi; /* boot panel index, number of panel used during boot */ | ||
200 | u8 pt; /* panel type, 4 bit field, 0=lvds, 1=mipi */ | ||
201 | struct oaktrail_timing_info DTD; /* timing info for the selected panel */ | ||
202 | u32 Panel_Port_Control; | ||
203 | u32 PP_On_Sequencing;/*1 dword,Register 0x61208,*/ | ||
204 | u32 PP_Off_Sequencing;/*1 dword,Register 0x6120C,*/ | ||
205 | u32 PP_Cycle_Delay; | ||
206 | u16 Panel_Backlight_Inverter_Descriptor; | ||
207 | u16 Panel_MIPI_Display_Descriptor; | ||
208 | } __packed; | ||
209 | |||
210 | #define MODE_SETTING_IN_CRTC 0x1 | ||
211 | #define MODE_SETTING_IN_ENCODER 0x2 | ||
212 | #define MODE_SETTING_ON_GOING 0x3 | ||
213 | #define MODE_SETTING_IN_DSR 0x4 | ||
214 | #define MODE_SETTING_ENCODER_DONE 0x8 | ||
215 | |||
216 | #define GCT_R10_HEADER_SIZE 16 | ||
217 | #define GCT_R10_DISPLAY_DESC_SIZE 28 | ||
218 | |||
219 | /* | ||
220 | * Moorestown HDMI interfaces | ||
221 | */ | ||
222 | |||
223 | struct oaktrail_hdmi_dev { | ||
224 | struct pci_dev *dev; | ||
225 | void __iomem *regs; | ||
226 | unsigned int mmio, mmio_len; | ||
227 | int dpms_mode; | ||
228 | struct hdmi_i2c_dev *i2c_dev; | ||
229 | |||
230 | /* register state */ | ||
231 | u32 saveDPLL_CTRL; | ||
232 | u32 saveDPLL_DIV_CTRL; | ||
233 | u32 saveDPLL_ADJUST; | ||
234 | u32 saveDPLL_UPDATE; | ||
235 | u32 saveDPLL_CLK_ENABLE; | ||
236 | u32 savePCH_HTOTAL_B; | ||
237 | u32 savePCH_HBLANK_B; | ||
238 | u32 savePCH_HSYNC_B; | ||
239 | u32 savePCH_VTOTAL_B; | ||
240 | u32 savePCH_VBLANK_B; | ||
241 | u32 savePCH_VSYNC_B; | ||
242 | u32 savePCH_PIPEBCONF; | ||
243 | u32 savePCH_PIPEBSRC; | ||
244 | }; | ||
245 | |||
246 | extern void oaktrail_hdmi_setup(struct drm_device *dev); | ||
247 | extern void oaktrail_hdmi_teardown(struct drm_device *dev); | ||
248 | extern int oaktrail_hdmi_i2c_init(struct pci_dev *dev); | ||
249 | extern void oaktrail_hdmi_i2c_exit(struct pci_dev *dev); | ||
250 | extern void oaktrail_hdmi_save(struct drm_device *dev); | ||
251 | extern void oaktrail_hdmi_restore(struct drm_device *dev); | ||
252 | extern void oaktrail_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); | ||
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c new file mode 100644 index 00000000000..9d12a3ee160 --- /dev/null +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c | |||
@@ -0,0 +1,604 @@ | |||
1 | /* | ||
2 | * Copyright © 2009 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | */ | ||
17 | |||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | |||
21 | #include <drm/drmP.h> | ||
22 | #include "framebuffer.h" | ||
23 | #include "psb_drv.h" | ||
24 | #include "psb_intel_drv.h" | ||
25 | #include "psb_intel_reg.h" | ||
26 | #include "psb_intel_display.h" | ||
27 | #include "power.h" | ||
28 | |||
29 | struct psb_intel_range_t { | ||
30 | int min, max; | ||
31 | }; | ||
32 | |||
33 | struct oaktrail_limit_t { | ||
34 | struct psb_intel_range_t dot, m, p1; | ||
35 | }; | ||
36 | |||
37 | struct oaktrail_clock_t { | ||
38 | /* derived values */ | ||
39 | int dot; | ||
40 | int m; | ||
41 | int p1; | ||
42 | }; | ||
43 | |||
44 | #define MRST_LIMIT_LVDS_100L 0 | ||
45 | #define MRST_LIMIT_LVDS_83 1 | ||
46 | #define MRST_LIMIT_LVDS_100 2 | ||
47 | |||
48 | #define MRST_DOT_MIN 19750 | ||
49 | #define MRST_DOT_MAX 120000 | ||
50 | #define MRST_M_MIN_100L 20 | ||
51 | #define MRST_M_MIN_100 10 | ||
52 | #define MRST_M_MIN_83 12 | ||
53 | #define MRST_M_MAX_100L 34 | ||
54 | #define MRST_M_MAX_100 17 | ||
55 | #define MRST_M_MAX_83 20 | ||
56 | #define MRST_P1_MIN 2 | ||
57 | #define MRST_P1_MAX_0 7 | ||
58 | #define MRST_P1_MAX_1 8 | ||
59 | |||
60 | static const struct oaktrail_limit_t oaktrail_limits[] = { | ||
61 | { /* MRST_LIMIT_LVDS_100L */ | ||
62 | .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, | ||
63 | .m = {.min = MRST_M_MIN_100L, .max = MRST_M_MAX_100L}, | ||
64 | .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1}, | ||
65 | }, | ||
66 | { /* MRST_LIMIT_LVDS_83L */ | ||
67 | .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, | ||
68 | .m = {.min = MRST_M_MIN_83, .max = MRST_M_MAX_83}, | ||
69 | .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_0}, | ||
70 | }, | ||
71 | { /* MRST_LIMIT_LVDS_100 */ | ||
72 | .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, | ||
73 | .m = {.min = MRST_M_MIN_100, .max = MRST_M_MAX_100}, | ||
74 | .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1}, | ||
75 | }, | ||
76 | }; | ||
77 | |||
78 | #define MRST_M_MIN 10 | ||
79 | static const u32 oaktrail_m_converts[] = { | ||
80 | 0x2B, 0x15, 0x2A, 0x35, 0x1A, 0x0D, 0x26, 0x33, 0x19, 0x2C, | ||
81 | 0x36, 0x3B, 0x1D, 0x2E, 0x37, 0x1B, 0x2D, 0x16, 0x0B, 0x25, | ||
82 | 0x12, 0x09, 0x24, 0x32, 0x39, 0x1c, | ||
83 | }; | ||
84 | |||
85 | static const struct oaktrail_limit_t *oaktrail_limit(struct drm_crtc *crtc) | ||
86 | { | ||
87 | const struct oaktrail_limit_t *limit = NULL; | ||
88 | struct drm_device *dev = crtc->dev; | ||
89 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
90 | |||
91 | if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) | ||
92 | || psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)) { | ||
93 | switch (dev_priv->core_freq) { | ||
94 | case 100: | ||
95 | limit = &oaktrail_limits[MRST_LIMIT_LVDS_100L]; | ||
96 | break; | ||
97 | case 166: | ||
98 | limit = &oaktrail_limits[MRST_LIMIT_LVDS_83]; | ||
99 | break; | ||
100 | case 200: | ||
101 | limit = &oaktrail_limits[MRST_LIMIT_LVDS_100]; | ||
102 | break; | ||
103 | } | ||
104 | } else { | ||
105 | limit = NULL; | ||
106 | dev_err(dev->dev, "oaktrail_limit Wrong display type.\n"); | ||
107 | } | ||
108 | |||
109 | return limit; | ||
110 | } | ||
111 | |||
112 | /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ | ||
113 | static void oaktrail_clock(int refclk, struct oaktrail_clock_t *clock) | ||
114 | { | ||
115 | clock->dot = (refclk * clock->m) / (14 * clock->p1); | ||
116 | } | ||
117 | |||
118 | void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock) | ||
119 | { | ||
120 | pr_debug("%s: dotclock = %d, m = %d, p1 = %d.\n", | ||
121 | prefix, clock->dot, clock->m, clock->p1); | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * Returns a set of divisors for the desired target clock with the given refclk, | ||
126 | * or FALSE. Divisor values are the actual divisors for | ||
127 | */ | ||
128 | static bool | ||
129 | mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk, | ||
130 | struct oaktrail_clock_t *best_clock) | ||
131 | { | ||
132 | struct oaktrail_clock_t clock; | ||
133 | const struct oaktrail_limit_t *limit = oaktrail_limit(crtc); | ||
134 | int err = target; | ||
135 | |||
136 | memset(best_clock, 0, sizeof(*best_clock)); | ||
137 | |||
138 | for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { | ||
139 | for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; | ||
140 | clock.p1++) { | ||
141 | int this_err; | ||
142 | |||
143 | oaktrail_clock(refclk, &clock); | ||
144 | |||
145 | this_err = abs(clock.dot - target); | ||
146 | if (this_err < err) { | ||
147 | *best_clock = clock; | ||
148 | err = this_err; | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | dev_dbg(crtc->dev->dev, "mrstFindBestPLL err = %d.\n", err); | ||
153 | return err != target; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * Sets the power management mode of the pipe and plane. | ||
158 | * | ||
159 | * This code should probably grow support for turning the cursor off and back | ||
160 | * on appropriately at the same time as we're turning the pipe off/on. | ||
161 | */ | ||
162 | static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
163 | { | ||
164 | struct drm_device *dev = crtc->dev; | ||
165 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
166 | int pipe = psb_intel_crtc->pipe; | ||
167 | int dpll_reg = (pipe == 0) ? MRST_DPLL_A : DPLL_B; | ||
168 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
169 | int dspbase_reg = (pipe == 0) ? MRST_DSPABASE : DSPBBASE; | ||
170 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
171 | u32 temp; | ||
172 | bool enabled; | ||
173 | |||
174 | if (!gma_power_begin(dev, true)) | ||
175 | return; | ||
176 | |||
177 | /* XXX: When our outputs are all unaware of DPMS modes other than off | ||
178 | * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. | ||
179 | */ | ||
180 | switch (mode) { | ||
181 | case DRM_MODE_DPMS_ON: | ||
182 | case DRM_MODE_DPMS_STANDBY: | ||
183 | case DRM_MODE_DPMS_SUSPEND: | ||
184 | /* Enable the DPLL */ | ||
185 | temp = REG_READ(dpll_reg); | ||
186 | if ((temp & DPLL_VCO_ENABLE) == 0) { | ||
187 | REG_WRITE(dpll_reg, temp); | ||
188 | REG_READ(dpll_reg); | ||
189 | /* Wait for the clocks to stabilize. */ | ||
190 | udelay(150); | ||
191 | REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
192 | REG_READ(dpll_reg); | ||
193 | /* Wait for the clocks to stabilize. */ | ||
194 | udelay(150); | ||
195 | REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
196 | REG_READ(dpll_reg); | ||
197 | /* Wait for the clocks to stabilize. */ | ||
198 | udelay(150); | ||
199 | } | ||
200 | /* Enable the pipe */ | ||
201 | temp = REG_READ(pipeconf_reg); | ||
202 | if ((temp & PIPEACONF_ENABLE) == 0) | ||
203 | REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); | ||
204 | /* Enable the plane */ | ||
205 | temp = REG_READ(dspcntr_reg); | ||
206 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
207 | REG_WRITE(dspcntr_reg, | ||
208 | temp | DISPLAY_PLANE_ENABLE); | ||
209 | /* Flush the plane changes */ | ||
210 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
211 | } | ||
212 | |||
213 | psb_intel_crtc_load_lut(crtc); | ||
214 | |||
215 | /* Give the overlay scaler a chance to enable | ||
216 | if it's on this pipe */ | ||
217 | /* psb_intel_crtc_dpms_video(crtc, true); TODO */ | ||
218 | break; | ||
219 | case DRM_MODE_DPMS_OFF: | ||
220 | /* Give the overlay scaler a chance to disable | ||
221 | * if it's on this pipe */ | ||
222 | /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */ | ||
223 | |||
224 | /* Disable the VGA plane that we never use */ | ||
225 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
226 | /* Disable display plane */ | ||
227 | temp = REG_READ(dspcntr_reg); | ||
228 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
229 | REG_WRITE(dspcntr_reg, | ||
230 | temp & ~DISPLAY_PLANE_ENABLE); | ||
231 | /* Flush the plane changes */ | ||
232 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
233 | REG_READ(dspbase_reg); | ||
234 | } | ||
235 | |||
236 | /* Next, disable display pipes */ | ||
237 | temp = REG_READ(pipeconf_reg); | ||
238 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
239 | REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); | ||
240 | REG_READ(pipeconf_reg); | ||
241 | } | ||
242 | /* Wait for for the pipe disable to take effect. */ | ||
243 | psb_intel_wait_for_vblank(dev); | ||
244 | |||
245 | temp = REG_READ(dpll_reg); | ||
246 | if ((temp & DPLL_VCO_ENABLE) != 0) { | ||
247 | REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); | ||
248 | REG_READ(dpll_reg); | ||
249 | } | ||
250 | |||
251 | /* Wait for the clocks to turn off. */ | ||
252 | udelay(150); | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; | ||
257 | |||
258 | /*Set FIFO Watermarks*/ | ||
259 | REG_WRITE(DSPARB, 0x3FFF); | ||
260 | REG_WRITE(DSPFW1, 0x3F88080A); | ||
261 | REG_WRITE(DSPFW2, 0x0b060808); | ||
262 | REG_WRITE(DSPFW3, 0x0); | ||
263 | REG_WRITE(DSPFW4, 0x08030404); | ||
264 | REG_WRITE(DSPFW5, 0x04040404); | ||
265 | REG_WRITE(DSPFW6, 0x78); | ||
266 | REG_WRITE(0x70400, REG_READ(0x70400) | 0x4000); | ||
267 | /* Must write Bit 14 of the Chicken Bit Register */ | ||
268 | |||
269 | gma_power_end(dev); | ||
270 | } | ||
271 | |||
272 | /** | ||
273 | * Return the pipe currently connected to the panel fitter, | ||
274 | * or -1 if the panel fitter is not present or not in use | ||
275 | */ | ||
276 | static int oaktrail_panel_fitter_pipe(struct drm_device *dev) | ||
277 | { | ||
278 | u32 pfit_control; | ||
279 | |||
280 | pfit_control = REG_READ(PFIT_CONTROL); | ||
281 | |||
282 | /* See if the panel fitter is in use */ | ||
283 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
284 | return -1; | ||
285 | return (pfit_control >> 29) & 3; | ||
286 | } | ||
287 | |||
288 | static int oaktrail_crtc_mode_set(struct drm_crtc *crtc, | ||
289 | struct drm_display_mode *mode, | ||
290 | struct drm_display_mode *adjusted_mode, | ||
291 | int x, int y, | ||
292 | struct drm_framebuffer *old_fb) | ||
293 | { | ||
294 | struct drm_device *dev = crtc->dev; | ||
295 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
296 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
297 | int pipe = psb_intel_crtc->pipe; | ||
298 | int fp_reg = (pipe == 0) ? MRST_FPA0 : FPB0; | ||
299 | int dpll_reg = (pipe == 0) ? MRST_DPLL_A : DPLL_B; | ||
300 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
301 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
302 | int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; | ||
303 | int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; | ||
304 | int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; | ||
305 | int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; | ||
306 | int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; | ||
307 | int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; | ||
308 | int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; | ||
309 | int refclk = 0; | ||
310 | struct oaktrail_clock_t clock; | ||
311 | u32 dpll = 0, fp = 0, dspcntr, pipeconf; | ||
312 | bool ok, is_sdvo = false; | ||
313 | bool is_crt = false, is_lvds = false, is_tv = false; | ||
314 | bool is_mipi = false; | ||
315 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
316 | struct psb_intel_encoder *psb_intel_encoder = NULL; | ||
317 | uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; | ||
318 | struct drm_connector *connector; | ||
319 | |||
320 | if (!gma_power_begin(dev, true)) | ||
321 | return 0; | ||
322 | |||
323 | memcpy(&psb_intel_crtc->saved_mode, | ||
324 | mode, | ||
325 | sizeof(struct drm_display_mode)); | ||
326 | memcpy(&psb_intel_crtc->saved_adjusted_mode, | ||
327 | adjusted_mode, | ||
328 | sizeof(struct drm_display_mode)); | ||
329 | |||
330 | list_for_each_entry(connector, &mode_config->connector_list, head) { | ||
331 | if (!connector->encoder || connector->encoder->crtc != crtc) | ||
332 | continue; | ||
333 | |||
334 | psb_intel_encoder = psb_intel_attached_encoder(connector); | ||
335 | |||
336 | switch (psb_intel_encoder->type) { | ||
337 | case INTEL_OUTPUT_LVDS: | ||
338 | is_lvds = true; | ||
339 | break; | ||
340 | case INTEL_OUTPUT_SDVO: | ||
341 | is_sdvo = true; | ||
342 | break; | ||
343 | case INTEL_OUTPUT_TVOUT: | ||
344 | is_tv = true; | ||
345 | break; | ||
346 | case INTEL_OUTPUT_ANALOG: | ||
347 | is_crt = true; | ||
348 | break; | ||
349 | case INTEL_OUTPUT_MIPI: | ||
350 | is_mipi = true; | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | /* Disable the VGA plane that we never use */ | ||
356 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
357 | |||
358 | /* Disable the panel fitter if it was on our pipe */ | ||
359 | if (oaktrail_panel_fitter_pipe(dev) == pipe) | ||
360 | REG_WRITE(PFIT_CONTROL, 0); | ||
361 | |||
362 | REG_WRITE(pipesrc_reg, | ||
363 | ((mode->crtc_hdisplay - 1) << 16) | | ||
364 | (mode->crtc_vdisplay - 1)); | ||
365 | |||
366 | if (psb_intel_encoder) | ||
367 | drm_connector_property_get_value(connector, | ||
368 | dev->mode_config.scaling_mode_property, &scalingType); | ||
369 | |||
370 | if (scalingType == DRM_MODE_SCALE_NO_SCALE) { | ||
371 | /* Moorestown doesn't have register support for centering so | ||
372 | * we need to mess with the h/vblank and h/vsync start and | ||
373 | * ends to get centering */ | ||
374 | int offsetX = 0, offsetY = 0; | ||
375 | |||
376 | offsetX = (adjusted_mode->crtc_hdisplay - | ||
377 | mode->crtc_hdisplay) / 2; | ||
378 | offsetY = (adjusted_mode->crtc_vdisplay - | ||
379 | mode->crtc_vdisplay) / 2; | ||
380 | |||
381 | REG_WRITE(htot_reg, (mode->crtc_hdisplay - 1) | | ||
382 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
383 | REG_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) | | ||
384 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
385 | REG_WRITE(hblank_reg, | ||
386 | (adjusted_mode->crtc_hblank_start - offsetX - 1) | | ||
387 | ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16)); | ||
388 | REG_WRITE(hsync_reg, | ||
389 | (adjusted_mode->crtc_hsync_start - offsetX - 1) | | ||
390 | ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16)); | ||
391 | REG_WRITE(vblank_reg, | ||
392 | (adjusted_mode->crtc_vblank_start - offsetY - 1) | | ||
393 | ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16)); | ||
394 | REG_WRITE(vsync_reg, | ||
395 | (adjusted_mode->crtc_vsync_start - offsetY - 1) | | ||
396 | ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16)); | ||
397 | } else { | ||
398 | REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | | ||
399 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
400 | REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | | ||
401 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
402 | REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | | ||
403 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
404 | REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | | ||
405 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
406 | REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | | ||
407 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
408 | REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | | ||
409 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
410 | } | ||
411 | |||
412 | /* Flush the plane changes */ | ||
413 | { | ||
414 | struct drm_crtc_helper_funcs *crtc_funcs = | ||
415 | crtc->helper_private; | ||
416 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); | ||
417 | } | ||
418 | |||
419 | /* setup pipeconf */ | ||
420 | pipeconf = REG_READ(pipeconf_reg); | ||
421 | |||
422 | /* Set up the display plane register */ | ||
423 | dspcntr = REG_READ(dspcntr_reg); | ||
424 | dspcntr |= DISPPLANE_GAMMA_ENABLE; | ||
425 | |||
426 | if (pipe == 0) | ||
427 | dspcntr |= DISPPLANE_SEL_PIPE_A; | ||
428 | else | ||
429 | dspcntr |= DISPPLANE_SEL_PIPE_B; | ||
430 | |||
431 | dev_priv->dspcntr = dspcntr |= DISPLAY_PLANE_ENABLE; | ||
432 | dev_priv->pipeconf = pipeconf |= PIPEACONF_ENABLE; | ||
433 | |||
434 | if (is_mipi) | ||
435 | goto oaktrail_crtc_mode_set_exit; | ||
436 | |||
437 | refclk = dev_priv->core_freq * 1000; | ||
438 | |||
439 | dpll = 0; /*BIT16 = 0 for 100MHz reference */ | ||
440 | |||
441 | ok = mrstFindBestPLL(crtc, adjusted_mode->clock, refclk, &clock); | ||
442 | |||
443 | if (!ok) { | ||
444 | dev_dbg(dev->dev, "mrstFindBestPLL fail in oaktrail_crtc_mode_set.\n"); | ||
445 | } else { | ||
446 | dev_dbg(dev->dev, "oaktrail_crtc_mode_set pixel clock = %d," | ||
447 | "m = %x, p1 = %x.\n", clock.dot, clock.m, | ||
448 | clock.p1); | ||
449 | } | ||
450 | |||
451 | fp = oaktrail_m_converts[(clock.m - MRST_M_MIN)] << 8; | ||
452 | |||
453 | dpll |= DPLL_VGA_MODE_DIS; | ||
454 | |||
455 | |||
456 | dpll |= DPLL_VCO_ENABLE; | ||
457 | |||
458 | if (is_lvds) | ||
459 | dpll |= DPLLA_MODE_LVDS; | ||
460 | else | ||
461 | dpll |= DPLLB_MODE_DAC_SERIAL; | ||
462 | |||
463 | if (is_sdvo) { | ||
464 | int sdvo_pixel_multiply = | ||
465 | adjusted_mode->clock / mode->clock; | ||
466 | |||
467 | dpll |= DPLL_DVO_HIGH_SPEED; | ||
468 | dpll |= | ||
469 | (sdvo_pixel_multiply - | ||
470 | 1) << SDVO_MULTIPLIER_SHIFT_HIRES; | ||
471 | } | ||
472 | |||
473 | |||
474 | /* compute bitmask from p1 value */ | ||
475 | dpll |= (1 << (clock.p1 - 2)) << 17; | ||
476 | |||
477 | dpll |= DPLL_VCO_ENABLE; | ||
478 | |||
479 | mrstPrintPll("chosen", &clock); | ||
480 | |||
481 | if (dpll & DPLL_VCO_ENABLE) { | ||
482 | REG_WRITE(fp_reg, fp); | ||
483 | REG_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); | ||
484 | REG_READ(dpll_reg); | ||
485 | /* Check the DPLLA lock bit PIPEACONF[29] */ | ||
486 | udelay(150); | ||
487 | } | ||
488 | |||
489 | REG_WRITE(fp_reg, fp); | ||
490 | REG_WRITE(dpll_reg, dpll); | ||
491 | REG_READ(dpll_reg); | ||
492 | /* Wait for the clocks to stabilize. */ | ||
493 | udelay(150); | ||
494 | |||
495 | /* write it again -- the BIOS does, after all */ | ||
496 | REG_WRITE(dpll_reg, dpll); | ||
497 | REG_READ(dpll_reg); | ||
498 | /* Wait for the clocks to stabilize. */ | ||
499 | udelay(150); | ||
500 | |||
501 | REG_WRITE(pipeconf_reg, pipeconf); | ||
502 | REG_READ(pipeconf_reg); | ||
503 | psb_intel_wait_for_vblank(dev); | ||
504 | |||
505 | REG_WRITE(dspcntr_reg, dspcntr); | ||
506 | psb_intel_wait_for_vblank(dev); | ||
507 | |||
508 | oaktrail_crtc_mode_set_exit: | ||
509 | gma_power_end(dev); | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static bool oaktrail_crtc_mode_fixup(struct drm_crtc *crtc, | ||
514 | struct drm_display_mode *mode, | ||
515 | struct drm_display_mode *adjusted_mode) | ||
516 | { | ||
517 | return true; | ||
518 | } | ||
519 | |||
520 | int oaktrail_pipe_set_base(struct drm_crtc *crtc, | ||
521 | int x, int y, struct drm_framebuffer *old_fb) | ||
522 | { | ||
523 | struct drm_device *dev = crtc->dev; | ||
524 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
525 | struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); | ||
526 | int pipe = psb_intel_crtc->pipe; | ||
527 | unsigned long start, offset; | ||
528 | |||
529 | int dspbase = (pipe == 0 ? DSPALINOFF : DSPBBASE); | ||
530 | int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); | ||
531 | int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; | ||
532 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
533 | u32 dspcntr; | ||
534 | int ret = 0; | ||
535 | |||
536 | /* no fb bound */ | ||
537 | if (!crtc->fb) { | ||
538 | dev_dbg(dev->dev, "No FB bound\n"); | ||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | if (!gma_power_begin(dev, true)) | ||
543 | return 0; | ||
544 | |||
545 | start = psbfb->gtt->offset; | ||
546 | offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); | ||
547 | |||
548 | REG_WRITE(dspstride, crtc->fb->pitches[0]); | ||
549 | |||
550 | dspcntr = REG_READ(dspcntr_reg); | ||
551 | dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; | ||
552 | |||
553 | switch (crtc->fb->bits_per_pixel) { | ||
554 | case 8: | ||
555 | dspcntr |= DISPPLANE_8BPP; | ||
556 | break; | ||
557 | case 16: | ||
558 | if (crtc->fb->depth == 15) | ||
559 | dspcntr |= DISPPLANE_15_16BPP; | ||
560 | else | ||
561 | dspcntr |= DISPPLANE_16BPP; | ||
562 | break; | ||
563 | case 24: | ||
564 | case 32: | ||
565 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | ||
566 | break; | ||
567 | default: | ||
568 | dev_err(dev->dev, "Unknown color depth\n"); | ||
569 | ret = -EINVAL; | ||
570 | goto pipe_set_base_exit; | ||
571 | } | ||
572 | REG_WRITE(dspcntr_reg, dspcntr); | ||
573 | |||
574 | REG_WRITE(dspbase, offset); | ||
575 | REG_READ(dspbase); | ||
576 | REG_WRITE(dspsurf, start); | ||
577 | REG_READ(dspsurf); | ||
578 | |||
579 | pipe_set_base_exit: | ||
580 | gma_power_end(dev); | ||
581 | return ret; | ||
582 | } | ||
583 | |||
584 | static void oaktrail_crtc_prepare(struct drm_crtc *crtc) | ||
585 | { | ||
586 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
587 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
588 | } | ||
589 | |||
590 | static void oaktrail_crtc_commit(struct drm_crtc *crtc) | ||
591 | { | ||
592 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
593 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
594 | } | ||
595 | |||
596 | const struct drm_crtc_helper_funcs oaktrail_helper_funcs = { | ||
597 | .dpms = oaktrail_crtc_dpms, | ||
598 | .mode_fixup = oaktrail_crtc_mode_fixup, | ||
599 | .mode_set = oaktrail_crtc_mode_set, | ||
600 | .mode_set_base = oaktrail_pipe_set_base, | ||
601 | .prepare = oaktrail_crtc_prepare, | ||
602 | .commit = oaktrail_crtc_commit, | ||
603 | }; | ||
604 | |||
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c new file mode 100644 index 00000000000..63aea2f010d --- /dev/null +++ b/drivers/gpu/drm/gma500/oaktrail_device.c | |||
@@ -0,0 +1,512 @@ | |||
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 | #include <linux/backlight.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/dmi.h> | ||
23 | #include <drm/drmP.h> | ||
24 | #include <drm/drm.h> | ||
25 | #include "gma_drm.h" | ||
26 | #include "psb_drv.h" | ||
27 | #include "psb_reg.h" | ||
28 | #include "psb_intel_reg.h" | ||
29 | #include <asm/mrst.h> | ||
30 | #include <asm/intel_scu_ipc.h> | ||
31 | #include "mid_bios.h" | ||
32 | #include "intel_bios.h" | ||
33 | |||
34 | static int oaktrail_output_init(struct drm_device *dev) | ||
35 | { | ||
36 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
37 | if (dev_priv->iLVDS_enable) | ||
38 | oaktrail_lvds_init(dev, &dev_priv->mode_dev); | ||
39 | else | ||
40 | dev_err(dev->dev, "DSI is not supported\n"); | ||
41 | if (dev_priv->hdmi_priv) | ||
42 | oaktrail_hdmi_init(dev, &dev_priv->mode_dev); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * Provide the low level interfaces for the Moorestown backlight | ||
48 | */ | ||
49 | |||
50 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
51 | |||
52 | #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF | ||
53 | #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ | ||
54 | #define BLC_PWM_FREQ_CALC_CONSTANT 32 | ||
55 | #define MHz 1000000 | ||
56 | #define BLC_ADJUSTMENT_MAX 100 | ||
57 | |||
58 | static struct backlight_device *oaktrail_backlight_device; | ||
59 | static int oaktrail_brightness; | ||
60 | |||
61 | static int oaktrail_set_brightness(struct backlight_device *bd) | ||
62 | { | ||
63 | struct drm_device *dev = bl_get_data(oaktrail_backlight_device); | ||
64 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
65 | int level = bd->props.brightness; | ||
66 | u32 blc_pwm_ctl; | ||
67 | u32 max_pwm_blc; | ||
68 | |||
69 | /* Percentage 1-100% being valid */ | ||
70 | if (level < 1) | ||
71 | level = 1; | ||
72 | |||
73 | if (gma_power_begin(dev, 0)) { | ||
74 | /* Calculate and set the brightness value */ | ||
75 | max_pwm_blc = REG_READ(BLC_PWM_CTL) >> 16; | ||
76 | blc_pwm_ctl = level * max_pwm_blc / 100; | ||
77 | |||
78 | /* Adjust the backlight level with the percent in | ||
79 | * dev_priv->blc_adj1; | ||
80 | */ | ||
81 | blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj1; | ||
82 | blc_pwm_ctl = blc_pwm_ctl / 100; | ||
83 | |||
84 | /* Adjust the backlight level with the percent in | ||
85 | * dev_priv->blc_adj2; | ||
86 | */ | ||
87 | blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj2; | ||
88 | blc_pwm_ctl = blc_pwm_ctl / 100; | ||
89 | |||
90 | /* force PWM bit on */ | ||
91 | REG_WRITE(BLC_PWM_CTL2, (0x80000000 | REG_READ(BLC_PWM_CTL2))); | ||
92 | REG_WRITE(BLC_PWM_CTL, (max_pwm_blc << 16) | blc_pwm_ctl); | ||
93 | gma_power_end(dev); | ||
94 | } | ||
95 | oaktrail_brightness = level; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static int oaktrail_get_brightness(struct backlight_device *bd) | ||
100 | { | ||
101 | /* return locally cached var instead of HW read (due to DPST etc.) */ | ||
102 | /* FIXME: ideally return actual value in case firmware fiddled with | ||
103 | it */ | ||
104 | return oaktrail_brightness; | ||
105 | } | ||
106 | |||
107 | static int device_backlight_init(struct drm_device *dev) | ||
108 | { | ||
109 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
110 | unsigned long core_clock; | ||
111 | u16 bl_max_freq; | ||
112 | uint32_t value; | ||
113 | uint32_t blc_pwm_precision_factor; | ||
114 | |||
115 | dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX; | ||
116 | dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX; | ||
117 | bl_max_freq = 256; | ||
118 | /* this needs to be set elsewhere */ | ||
119 | blc_pwm_precision_factor = BLC_PWM_PRECISION_FACTOR; | ||
120 | |||
121 | core_clock = dev_priv->core_freq; | ||
122 | |||
123 | value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; | ||
124 | value *= blc_pwm_precision_factor; | ||
125 | value /= bl_max_freq; | ||
126 | value /= blc_pwm_precision_factor; | ||
127 | |||
128 | if (value > (unsigned long long)MRST_BLC_MAX_PWM_REG_FREQ) | ||
129 | return -ERANGE; | ||
130 | |||
131 | if (gma_power_begin(dev, false)) { | ||
132 | REG_WRITE(BLC_PWM_CTL2, (0x80000000 | REG_READ(BLC_PWM_CTL2))); | ||
133 | REG_WRITE(BLC_PWM_CTL, value | (value << 16)); | ||
134 | gma_power_end(dev); | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static const struct backlight_ops oaktrail_ops = { | ||
140 | .get_brightness = oaktrail_get_brightness, | ||
141 | .update_status = oaktrail_set_brightness, | ||
142 | }; | ||
143 | |||
144 | int oaktrail_backlight_init(struct drm_device *dev) | ||
145 | { | ||
146 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
147 | int ret; | ||
148 | struct backlight_properties props; | ||
149 | |||
150 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
151 | props.max_brightness = 100; | ||
152 | props.type = BACKLIGHT_PLATFORM; | ||
153 | |||
154 | oaktrail_backlight_device = backlight_device_register("oaktrail-bl", | ||
155 | NULL, (void *)dev, &oaktrail_ops, &props); | ||
156 | |||
157 | if (IS_ERR(oaktrail_backlight_device)) | ||
158 | return PTR_ERR(oaktrail_backlight_device); | ||
159 | |||
160 | ret = device_backlight_init(dev); | ||
161 | if (ret < 0) { | ||
162 | backlight_device_unregister(oaktrail_backlight_device); | ||
163 | return ret; | ||
164 | } | ||
165 | oaktrail_backlight_device->props.brightness = 100; | ||
166 | oaktrail_backlight_device->props.max_brightness = 100; | ||
167 | backlight_update_status(oaktrail_backlight_device); | ||
168 | dev_priv->backlight_device = oaktrail_backlight_device; | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | #endif | ||
173 | |||
174 | /* | ||
175 | * Provide the Moorestown specific chip logic and low level methods | ||
176 | * for power management | ||
177 | */ | ||
178 | |||
179 | static void oaktrail_init_pm(struct drm_device *dev) | ||
180 | { | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * oaktrail_save_display_registers - save registers lost on suspend | ||
185 | * @dev: our DRM device | ||
186 | * | ||
187 | * Save the state we need in order to be able to restore the interface | ||
188 | * upon resume from suspend | ||
189 | */ | ||
190 | static int oaktrail_save_display_registers(struct drm_device *dev) | ||
191 | { | ||
192 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
193 | int i; | ||
194 | u32 pp_stat; | ||
195 | |||
196 | /* Display arbitration control + watermarks */ | ||
197 | dev_priv->saveDSPARB = PSB_RVDC32(DSPARB); | ||
198 | dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1); | ||
199 | dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2); | ||
200 | dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3); | ||
201 | dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4); | ||
202 | dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5); | ||
203 | dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6); | ||
204 | dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT); | ||
205 | |||
206 | /* Pipe & plane A info */ | ||
207 | dev_priv->savePIPEACONF = PSB_RVDC32(PIPEACONF); | ||
208 | dev_priv->savePIPEASRC = PSB_RVDC32(PIPEASRC); | ||
209 | dev_priv->saveFPA0 = PSB_RVDC32(MRST_FPA0); | ||
210 | dev_priv->saveFPA1 = PSB_RVDC32(MRST_FPA1); | ||
211 | dev_priv->saveDPLL_A = PSB_RVDC32(MRST_DPLL_A); | ||
212 | dev_priv->saveHTOTAL_A = PSB_RVDC32(HTOTAL_A); | ||
213 | dev_priv->saveHBLANK_A = PSB_RVDC32(HBLANK_A); | ||
214 | dev_priv->saveHSYNC_A = PSB_RVDC32(HSYNC_A); | ||
215 | dev_priv->saveVTOTAL_A = PSB_RVDC32(VTOTAL_A); | ||
216 | dev_priv->saveVBLANK_A = PSB_RVDC32(VBLANK_A); | ||
217 | dev_priv->saveVSYNC_A = PSB_RVDC32(VSYNC_A); | ||
218 | dev_priv->saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A); | ||
219 | dev_priv->saveDSPACNTR = PSB_RVDC32(DSPACNTR); | ||
220 | dev_priv->saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE); | ||
221 | dev_priv->saveDSPAADDR = PSB_RVDC32(DSPABASE); | ||
222 | dev_priv->saveDSPASURF = PSB_RVDC32(DSPASURF); | ||
223 | dev_priv->saveDSPALINOFF = PSB_RVDC32(DSPALINOFF); | ||
224 | dev_priv->saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF); | ||
225 | |||
226 | /* Save cursor regs */ | ||
227 | dev_priv->saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR); | ||
228 | dev_priv->saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE); | ||
229 | dev_priv->saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS); | ||
230 | |||
231 | /* Save palette (gamma) */ | ||
232 | for (i = 0; i < 256; i++) | ||
233 | dev_priv->save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2)); | ||
234 | |||
235 | if (dev_priv->hdmi_priv) | ||
236 | oaktrail_hdmi_save(dev); | ||
237 | |||
238 | /* Save performance state */ | ||
239 | dev_priv->savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE); | ||
240 | |||
241 | /* LVDS state */ | ||
242 | dev_priv->savePP_CONTROL = PSB_RVDC32(PP_CONTROL); | ||
243 | dev_priv->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS); | ||
244 | dev_priv->savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS); | ||
245 | dev_priv->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL); | ||
246 | dev_priv->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2); | ||
247 | dev_priv->saveLVDS = PSB_RVDC32(LVDS); | ||
248 | dev_priv->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL); | ||
249 | dev_priv->savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON); | ||
250 | dev_priv->savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF); | ||
251 | dev_priv->savePP_DIVISOR = PSB_RVDC32(PP_CYCLE); | ||
252 | |||
253 | /* HW overlay */ | ||
254 | dev_priv->saveOV_OVADD = PSB_RVDC32(OV_OVADD); | ||
255 | dev_priv->saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0); | ||
256 | dev_priv->saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1); | ||
257 | dev_priv->saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2); | ||
258 | dev_priv->saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3); | ||
259 | dev_priv->saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4); | ||
260 | dev_priv->saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5); | ||
261 | |||
262 | /* DPST registers */ | ||
263 | dev_priv->saveHISTOGRAM_INT_CONTROL_REG = | ||
264 | PSB_RVDC32(HISTOGRAM_INT_CONTROL); | ||
265 | dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG = | ||
266 | PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL); | ||
267 | dev_priv->savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC); | ||
268 | |||
269 | if (dev_priv->iLVDS_enable) { | ||
270 | /* Shut down the panel */ | ||
271 | PSB_WVDC32(0, PP_CONTROL); | ||
272 | |||
273 | do { | ||
274 | pp_stat = PSB_RVDC32(PP_STATUS); | ||
275 | } while (pp_stat & 0x80000000); | ||
276 | |||
277 | /* Turn off the plane */ | ||
278 | PSB_WVDC32(0x58000000, DSPACNTR); | ||
279 | /* Trigger the plane disable */ | ||
280 | PSB_WVDC32(0, DSPASURF); | ||
281 | |||
282 | /* Wait ~4 ticks */ | ||
283 | msleep(4); | ||
284 | |||
285 | /* Turn off pipe */ | ||
286 | PSB_WVDC32(0x0, PIPEACONF); | ||
287 | /* Wait ~8 ticks */ | ||
288 | msleep(8); | ||
289 | |||
290 | /* Turn off PLLs */ | ||
291 | PSB_WVDC32(0, MRST_DPLL_A); | ||
292 | } | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | /** | ||
297 | * oaktrail_restore_display_registers - restore lost register state | ||
298 | * @dev: our DRM device | ||
299 | * | ||
300 | * Restore register state that was lost during suspend and resume. | ||
301 | */ | ||
302 | static int oaktrail_restore_display_registers(struct drm_device *dev) | ||
303 | { | ||
304 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
305 | u32 pp_stat; | ||
306 | int i; | ||
307 | |||
308 | /* Display arbitration + watermarks */ | ||
309 | PSB_WVDC32(dev_priv->saveDSPARB, DSPARB); | ||
310 | PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1); | ||
311 | PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2); | ||
312 | PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3); | ||
313 | PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4); | ||
314 | PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5); | ||
315 | PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6); | ||
316 | PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT); | ||
317 | |||
318 | /* Make sure VGA plane is off. it initializes to on after reset!*/ | ||
319 | PSB_WVDC32(0x80000000, VGACNTRL); | ||
320 | |||
321 | /* set the plls */ | ||
322 | PSB_WVDC32(dev_priv->saveFPA0, MRST_FPA0); | ||
323 | PSB_WVDC32(dev_priv->saveFPA1, MRST_FPA1); | ||
324 | |||
325 | /* Actually enable it */ | ||
326 | PSB_WVDC32(dev_priv->saveDPLL_A, MRST_DPLL_A); | ||
327 | DRM_UDELAY(150); | ||
328 | |||
329 | /* Restore mode */ | ||
330 | PSB_WVDC32(dev_priv->saveHTOTAL_A, HTOTAL_A); | ||
331 | PSB_WVDC32(dev_priv->saveHBLANK_A, HBLANK_A); | ||
332 | PSB_WVDC32(dev_priv->saveHSYNC_A, HSYNC_A); | ||
333 | PSB_WVDC32(dev_priv->saveVTOTAL_A, VTOTAL_A); | ||
334 | PSB_WVDC32(dev_priv->saveVBLANK_A, VBLANK_A); | ||
335 | PSB_WVDC32(dev_priv->saveVSYNC_A, VSYNC_A); | ||
336 | PSB_WVDC32(dev_priv->savePIPEASRC, PIPEASRC); | ||
337 | PSB_WVDC32(dev_priv->saveBCLRPAT_A, BCLRPAT_A); | ||
338 | |||
339 | /* Restore performance mode*/ | ||
340 | PSB_WVDC32(dev_priv->savePERF_MODE, MRST_PERF_MODE); | ||
341 | |||
342 | /* Enable the pipe*/ | ||
343 | if (dev_priv->iLVDS_enable) | ||
344 | PSB_WVDC32(dev_priv->savePIPEACONF, PIPEACONF); | ||
345 | |||
346 | /* Set up the plane*/ | ||
347 | PSB_WVDC32(dev_priv->saveDSPALINOFF, DSPALINOFF); | ||
348 | PSB_WVDC32(dev_priv->saveDSPASTRIDE, DSPASTRIDE); | ||
349 | PSB_WVDC32(dev_priv->saveDSPATILEOFF, DSPATILEOFF); | ||
350 | |||
351 | /* Enable the plane */ | ||
352 | PSB_WVDC32(dev_priv->saveDSPACNTR, DSPACNTR); | ||
353 | PSB_WVDC32(dev_priv->saveDSPASURF, DSPASURF); | ||
354 | |||
355 | /* Enable Cursor A */ | ||
356 | PSB_WVDC32(dev_priv->saveDSPACURSOR_CTRL, CURACNTR); | ||
357 | PSB_WVDC32(dev_priv->saveDSPACURSOR_POS, CURAPOS); | ||
358 | PSB_WVDC32(dev_priv->saveDSPACURSOR_BASE, CURABASE); | ||
359 | |||
360 | /* Restore palette (gamma) */ | ||
361 | for (i = 0; i < 256; i++) | ||
362 | PSB_WVDC32(dev_priv->save_palette_a[i], PALETTE_A + (i << 2)); | ||
363 | |||
364 | if (dev_priv->hdmi_priv) | ||
365 | oaktrail_hdmi_restore(dev); | ||
366 | |||
367 | if (dev_priv->iLVDS_enable) { | ||
368 | PSB_WVDC32(dev_priv->saveBLC_PWM_CTL2, BLC_PWM_CTL2); | ||
369 | PSB_WVDC32(dev_priv->saveLVDS, LVDS); /*port 61180h*/ | ||
370 | PSB_WVDC32(dev_priv->savePFIT_CONTROL, PFIT_CONTROL); | ||
371 | PSB_WVDC32(dev_priv->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS); | ||
372 | PSB_WVDC32(dev_priv->savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS); | ||
373 | PSB_WVDC32(dev_priv->saveBLC_PWM_CTL, BLC_PWM_CTL); | ||
374 | PSB_WVDC32(dev_priv->savePP_ON_DELAYS, LVDSPP_ON); | ||
375 | PSB_WVDC32(dev_priv->savePP_OFF_DELAYS, LVDSPP_OFF); | ||
376 | PSB_WVDC32(dev_priv->savePP_DIVISOR, PP_CYCLE); | ||
377 | PSB_WVDC32(dev_priv->savePP_CONTROL, PP_CONTROL); | ||
378 | } | ||
379 | |||
380 | /* Wait for cycle delay */ | ||
381 | do { | ||
382 | pp_stat = PSB_RVDC32(PP_STATUS); | ||
383 | } while (pp_stat & 0x08000000); | ||
384 | |||
385 | /* Wait for panel power up */ | ||
386 | do { | ||
387 | pp_stat = PSB_RVDC32(PP_STATUS); | ||
388 | } while (pp_stat & 0x10000000); | ||
389 | |||
390 | /* Restore HW overlay */ | ||
391 | PSB_WVDC32(dev_priv->saveOV_OVADD, OV_OVADD); | ||
392 | PSB_WVDC32(dev_priv->saveOV_OGAMC0, OV_OGAMC0); | ||
393 | PSB_WVDC32(dev_priv->saveOV_OGAMC1, OV_OGAMC1); | ||
394 | PSB_WVDC32(dev_priv->saveOV_OGAMC2, OV_OGAMC2); | ||
395 | PSB_WVDC32(dev_priv->saveOV_OGAMC3, OV_OGAMC3); | ||
396 | PSB_WVDC32(dev_priv->saveOV_OGAMC4, OV_OGAMC4); | ||
397 | PSB_WVDC32(dev_priv->saveOV_OGAMC5, OV_OGAMC5); | ||
398 | |||
399 | /* DPST registers */ | ||
400 | PSB_WVDC32(dev_priv->saveHISTOGRAM_INT_CONTROL_REG, | ||
401 | HISTOGRAM_INT_CONTROL); | ||
402 | PSB_WVDC32(dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG, | ||
403 | HISTOGRAM_LOGIC_CONTROL); | ||
404 | PSB_WVDC32(dev_priv->savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC); | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | /** | ||
410 | * oaktrail_power_down - power down the display island | ||
411 | * @dev: our DRM device | ||
412 | * | ||
413 | * Power down the display interface of our device | ||
414 | */ | ||
415 | static int oaktrail_power_down(struct drm_device *dev) | ||
416 | { | ||
417 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
418 | u32 pwr_mask ; | ||
419 | u32 pwr_sts; | ||
420 | |||
421 | pwr_mask = PSB_PWRGT_DISPLAY_MASK; | ||
422 | outl(pwr_mask, dev_priv->ospm_base + PSB_PM_SSC); | ||
423 | |||
424 | while (true) { | ||
425 | pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS); | ||
426 | if ((pwr_sts & pwr_mask) == pwr_mask) | ||
427 | break; | ||
428 | else | ||
429 | udelay(10); | ||
430 | } | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | /* | ||
435 | * oaktrail_power_up | ||
436 | * | ||
437 | * Restore power to the specified island(s) (powergating) | ||
438 | */ | ||
439 | static int oaktrail_power_up(struct drm_device *dev) | ||
440 | { | ||
441 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
442 | u32 pwr_mask = PSB_PWRGT_DISPLAY_MASK; | ||
443 | u32 pwr_sts, pwr_cnt; | ||
444 | |||
445 | pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC); | ||
446 | pwr_cnt &= ~pwr_mask; | ||
447 | outl(pwr_cnt, (dev_priv->ospm_base + PSB_PM_SSC)); | ||
448 | |||
449 | while (true) { | ||
450 | pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS); | ||
451 | if ((pwr_sts & pwr_mask) == 0) | ||
452 | break; | ||
453 | else | ||
454 | udelay(10); | ||
455 | } | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | |||
460 | static int oaktrail_chip_setup(struct drm_device *dev) | ||
461 | { | ||
462 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
463 | struct oaktrail_vbt *vbt = &dev_priv->vbt_data; | ||
464 | int ret; | ||
465 | |||
466 | ret = mid_chip_setup(dev); | ||
467 | if (ret < 0) | ||
468 | return ret; | ||
469 | if (vbt->size == 0) { | ||
470 | /* Now pull the BIOS data */ | ||
471 | gma_intel_opregion_init(dev); | ||
472 | psb_intel_init_bios(dev); | ||
473 | } | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static void oaktrail_teardown(struct drm_device *dev) | ||
478 | { | ||
479 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
480 | struct oaktrail_vbt *vbt = &dev_priv->vbt_data; | ||
481 | |||
482 | oaktrail_hdmi_teardown(dev); | ||
483 | if (vbt->size == 0) | ||
484 | psb_intel_destroy_bios(dev); | ||
485 | } | ||
486 | |||
487 | const struct psb_ops oaktrail_chip_ops = { | ||
488 | .name = "Oaktrail", | ||
489 | .accel_2d = 1, | ||
490 | .pipes = 2, | ||
491 | .crtcs = 2, | ||
492 | .sgx_offset = MRST_SGX_OFFSET, | ||
493 | |||
494 | .chip_setup = oaktrail_chip_setup, | ||
495 | .chip_teardown = oaktrail_teardown, | ||
496 | .crtc_helper = &oaktrail_helper_funcs, | ||
497 | .crtc_funcs = &psb_intel_crtc_funcs, | ||
498 | |||
499 | .output_init = oaktrail_output_init, | ||
500 | |||
501 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
502 | .backlight_init = oaktrail_backlight_init, | ||
503 | #endif | ||
504 | |||
505 | .init_pm = oaktrail_init_pm, | ||
506 | .save_regs = oaktrail_save_display_registers, | ||
507 | .restore_regs = oaktrail_restore_display_registers, | ||
508 | .power_down = oaktrail_power_down, | ||
509 | .power_up = oaktrail_power_up, | ||
510 | |||
511 | .i2c_bus = 1, | ||
512 | }; | ||
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c new file mode 100644 index 00000000000..36878a60080 --- /dev/null +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c | |||
@@ -0,0 +1,859 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Li Peng <peng.li@intel.com> | ||
25 | */ | ||
26 | |||
27 | #include <drm/drmP.h> | ||
28 | #include <drm/drm.h> | ||
29 | #include "psb_intel_drv.h" | ||
30 | #include "psb_intel_reg.h" | ||
31 | #include "psb_drv.h" | ||
32 | |||
33 | #define HDMI_READ(reg) readl(hdmi_dev->regs + (reg)) | ||
34 | #define HDMI_WRITE(reg, val) writel(val, hdmi_dev->regs + (reg)) | ||
35 | |||
36 | #define HDMI_HCR 0x1000 | ||
37 | #define HCR_ENABLE_HDCP (1 << 5) | ||
38 | #define HCR_ENABLE_AUDIO (1 << 2) | ||
39 | #define HCR_ENABLE_PIXEL (1 << 1) | ||
40 | #define HCR_ENABLE_TMDS (1 << 0) | ||
41 | |||
42 | #define HDMI_HICR 0x1004 | ||
43 | #define HDMI_HSR 0x1008 | ||
44 | #define HDMI_HISR 0x100C | ||
45 | #define HDMI_DETECT_HDP (1 << 0) | ||
46 | |||
47 | #define HDMI_VIDEO_REG 0x3000 | ||
48 | #define HDMI_UNIT_EN (1 << 7) | ||
49 | #define HDMI_MODE_OUTPUT (1 << 0) | ||
50 | #define HDMI_HBLANK_A 0x3100 | ||
51 | |||
52 | #define HDMI_AUDIO_CTRL 0x4000 | ||
53 | #define HDMI_ENABLE_AUDIO (1 << 0) | ||
54 | |||
55 | #define PCH_HTOTAL_B 0x3100 | ||
56 | #define PCH_HBLANK_B 0x3104 | ||
57 | #define PCH_HSYNC_B 0x3108 | ||
58 | #define PCH_VTOTAL_B 0x310C | ||
59 | #define PCH_VBLANK_B 0x3110 | ||
60 | #define PCH_VSYNC_B 0x3114 | ||
61 | #define PCH_PIPEBSRC 0x311C | ||
62 | |||
63 | #define PCH_PIPEB_DSL 0x3800 | ||
64 | #define PCH_PIPEB_SLC 0x3804 | ||
65 | #define PCH_PIPEBCONF 0x3808 | ||
66 | #define PCH_PIPEBSTAT 0x3824 | ||
67 | |||
68 | #define CDVO_DFT 0x5000 | ||
69 | #define CDVO_SLEWRATE 0x5004 | ||
70 | #define CDVO_STRENGTH 0x5008 | ||
71 | #define CDVO_RCOMP 0x500C | ||
72 | |||
73 | #define DPLL_CTRL 0x6000 | ||
74 | #define DPLL_PDIV_SHIFT 16 | ||
75 | #define DPLL_PDIV_MASK (0xf << 16) | ||
76 | #define DPLL_PWRDN (1 << 4) | ||
77 | #define DPLL_RESET (1 << 3) | ||
78 | #define DPLL_FASTEN (1 << 2) | ||
79 | #define DPLL_ENSTAT (1 << 1) | ||
80 | #define DPLL_DITHEN (1 << 0) | ||
81 | |||
82 | #define DPLL_DIV_CTRL 0x6004 | ||
83 | #define DPLL_CLKF_MASK 0xffffffc0 | ||
84 | #define DPLL_CLKR_MASK (0x3f) | ||
85 | |||
86 | #define DPLL_CLK_ENABLE 0x6008 | ||
87 | #define DPLL_EN_DISP (1 << 31) | ||
88 | #define DPLL_SEL_HDMI (1 << 8) | ||
89 | #define DPLL_EN_HDMI (1 << 1) | ||
90 | #define DPLL_EN_VGA (1 << 0) | ||
91 | |||
92 | #define DPLL_ADJUST 0x600C | ||
93 | #define DPLL_STATUS 0x6010 | ||
94 | #define DPLL_UPDATE 0x6014 | ||
95 | #define DPLL_DFT 0x6020 | ||
96 | |||
97 | struct intel_range { | ||
98 | int min, max; | ||
99 | }; | ||
100 | |||
101 | struct oaktrail_hdmi_limit { | ||
102 | struct intel_range vco, np, nr, nf; | ||
103 | }; | ||
104 | |||
105 | struct oaktrail_hdmi_clock { | ||
106 | int np; | ||
107 | int nr; | ||
108 | int nf; | ||
109 | int dot; | ||
110 | }; | ||
111 | |||
112 | #define VCO_MIN 320000 | ||
113 | #define VCO_MAX 1650000 | ||
114 | #define NP_MIN 1 | ||
115 | #define NP_MAX 15 | ||
116 | #define NR_MIN 1 | ||
117 | #define NR_MAX 64 | ||
118 | #define NF_MIN 2 | ||
119 | #define NF_MAX 4095 | ||
120 | |||
121 | static const struct oaktrail_hdmi_limit oaktrail_hdmi_limit = { | ||
122 | .vco = { .min = VCO_MIN, .max = VCO_MAX }, | ||
123 | .np = { .min = NP_MIN, .max = NP_MAX }, | ||
124 | .nr = { .min = NR_MIN, .max = NR_MAX }, | ||
125 | .nf = { .min = NF_MIN, .max = NF_MAX }, | ||
126 | }; | ||
127 | |||
128 | static void wait_for_vblank(struct drm_device *dev) | ||
129 | { | ||
130 | /* FIXME: Can we do this as a sleep ? */ | ||
131 | /* Wait for 20ms, i.e. one cycle at 50hz. */ | ||
132 | mdelay(20); | ||
133 | } | ||
134 | |||
135 | static void scu_busy_loop(void *scu_base) | ||
136 | { | ||
137 | u32 status = 0; | ||
138 | u32 loop_count = 0; | ||
139 | |||
140 | status = readl(scu_base + 0x04); | ||
141 | while (status & 1) { | ||
142 | udelay(1); /* scu processing time is in few u secods */ | ||
143 | status = readl(scu_base + 0x04); | ||
144 | loop_count++; | ||
145 | /* break if scu doesn't reset busy bit after huge retry */ | ||
146 | if (loop_count > 1000) { | ||
147 | DRM_DEBUG_KMS("SCU IPC timed out"); | ||
148 | return; | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | static void oaktrail_hdmi_reset(struct drm_device *dev) | ||
154 | { | ||
155 | void *base; | ||
156 | /* FIXME: at least make these defines */ | ||
157 | unsigned int scu_ipc_mmio = 0xff11c000; | ||
158 | int scu_len = 1024; | ||
159 | |||
160 | base = ioremap((resource_size_t)scu_ipc_mmio, scu_len); | ||
161 | if (base == NULL) { | ||
162 | DRM_ERROR("failed to map SCU mmio\n"); | ||
163 | return; | ||
164 | } | ||
165 | |||
166 | /* scu ipc: assert hdmi controller reset */ | ||
167 | writel(0xff11d118, base + 0x0c); | ||
168 | writel(0x7fffffdf, base + 0x80); | ||
169 | writel(0x42005, base + 0x0); | ||
170 | scu_busy_loop(base); | ||
171 | |||
172 | /* scu ipc: de-assert hdmi controller reset */ | ||
173 | writel(0xff11d118, base + 0x0c); | ||
174 | writel(0x7fffffff, base + 0x80); | ||
175 | writel(0x42005, base + 0x0); | ||
176 | scu_busy_loop(base); | ||
177 | |||
178 | iounmap(base); | ||
179 | } | ||
180 | |||
181 | static void oaktrail_hdmi_audio_enable(struct drm_device *dev) | ||
182 | { | ||
183 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
184 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
185 | |||
186 | HDMI_WRITE(HDMI_HCR, 0x67); | ||
187 | HDMI_READ(HDMI_HCR); | ||
188 | |||
189 | HDMI_WRITE(0x51a8, 0x10); | ||
190 | HDMI_READ(0x51a8); | ||
191 | |||
192 | HDMI_WRITE(HDMI_AUDIO_CTRL, 0x1); | ||
193 | HDMI_READ(HDMI_AUDIO_CTRL); | ||
194 | } | ||
195 | |||
196 | static void oaktrail_hdmi_audio_disable(struct drm_device *dev) | ||
197 | { | ||
198 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
199 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
200 | |||
201 | HDMI_WRITE(0x51a8, 0x0); | ||
202 | HDMI_READ(0x51a8); | ||
203 | |||
204 | HDMI_WRITE(HDMI_AUDIO_CTRL, 0x0); | ||
205 | HDMI_READ(HDMI_AUDIO_CTRL); | ||
206 | |||
207 | HDMI_WRITE(HDMI_HCR, 0x47); | ||
208 | HDMI_READ(HDMI_HCR); | ||
209 | } | ||
210 | |||
211 | void oaktrail_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode) | ||
212 | { | ||
213 | struct drm_device *dev = crtc->dev; | ||
214 | u32 temp; | ||
215 | |||
216 | switch (mode) { | ||
217 | case DRM_MODE_DPMS_OFF: | ||
218 | /* Disable VGACNTRL */ | ||
219 | REG_WRITE(VGACNTRL, 0x80000000); | ||
220 | |||
221 | /* Disable plane */ | ||
222 | temp = REG_READ(DSPBCNTR); | ||
223 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
224 | REG_WRITE(DSPBCNTR, temp & ~DISPLAY_PLANE_ENABLE); | ||
225 | REG_READ(DSPBCNTR); | ||
226 | /* Flush the plane changes */ | ||
227 | REG_WRITE(DSPBSURF, REG_READ(DSPBSURF)); | ||
228 | REG_READ(DSPBSURF); | ||
229 | } | ||
230 | |||
231 | /* Disable pipe B */ | ||
232 | temp = REG_READ(PIPEBCONF); | ||
233 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
234 | REG_WRITE(PIPEBCONF, temp & ~PIPEACONF_ENABLE); | ||
235 | REG_READ(PIPEBCONF); | ||
236 | } | ||
237 | |||
238 | /* Disable LNW Pipes, etc */ | ||
239 | temp = REG_READ(PCH_PIPEBCONF); | ||
240 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
241 | REG_WRITE(PCH_PIPEBCONF, temp & ~PIPEACONF_ENABLE); | ||
242 | REG_READ(PCH_PIPEBCONF); | ||
243 | } | ||
244 | /* wait for pipe off */ | ||
245 | udelay(150); | ||
246 | /* Disable dpll */ | ||
247 | temp = REG_READ(DPLL_CTRL); | ||
248 | if ((temp & DPLL_PWRDN) == 0) { | ||
249 | REG_WRITE(DPLL_CTRL, temp | (DPLL_PWRDN | DPLL_RESET)); | ||
250 | REG_WRITE(DPLL_STATUS, 0x1); | ||
251 | } | ||
252 | /* wait for dpll off */ | ||
253 | udelay(150); | ||
254 | break; | ||
255 | case DRM_MODE_DPMS_ON: | ||
256 | case DRM_MODE_DPMS_STANDBY: | ||
257 | case DRM_MODE_DPMS_SUSPEND: | ||
258 | /* Enable dpll */ | ||
259 | temp = REG_READ(DPLL_CTRL); | ||
260 | if ((temp & DPLL_PWRDN) != 0) { | ||
261 | REG_WRITE(DPLL_CTRL, temp & ~(DPLL_PWRDN | DPLL_RESET)); | ||
262 | temp = REG_READ(DPLL_CLK_ENABLE); | ||
263 | REG_WRITE(DPLL_CLK_ENABLE, temp | DPLL_EN_DISP | DPLL_SEL_HDMI | DPLL_EN_HDMI); | ||
264 | REG_READ(DPLL_CLK_ENABLE); | ||
265 | } | ||
266 | /* wait for dpll warm up */ | ||
267 | udelay(150); | ||
268 | |||
269 | /* Enable pipe B */ | ||
270 | temp = REG_READ(PIPEBCONF); | ||
271 | if ((temp & PIPEACONF_ENABLE) == 0) { | ||
272 | REG_WRITE(PIPEBCONF, temp | PIPEACONF_ENABLE); | ||
273 | REG_READ(PIPEBCONF); | ||
274 | } | ||
275 | |||
276 | /* Enable LNW Pipe B */ | ||
277 | temp = REG_READ(PCH_PIPEBCONF); | ||
278 | if ((temp & PIPEACONF_ENABLE) == 0) { | ||
279 | REG_WRITE(PCH_PIPEBCONF, temp | PIPEACONF_ENABLE); | ||
280 | REG_READ(PCH_PIPEBCONF); | ||
281 | } | ||
282 | wait_for_vblank(dev); | ||
283 | |||
284 | /* Enable plane */ | ||
285 | temp = REG_READ(DSPBCNTR); | ||
286 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
287 | REG_WRITE(DSPBCNTR, temp | DISPLAY_PLANE_ENABLE); | ||
288 | /* Flush the plane changes */ | ||
289 | REG_WRITE(DSPBSURF, REG_READ(DSPBSURF)); | ||
290 | REG_READ(DSPBSURF); | ||
291 | } | ||
292 | psb_intel_crtc_load_lut(crtc); | ||
293 | } | ||
294 | /* DSPARB */ | ||
295 | REG_WRITE(DSPARB, 0x00003fbf); | ||
296 | /* FW1 */ | ||
297 | REG_WRITE(0x70034, 0x3f880a0a); | ||
298 | /* FW2 */ | ||
299 | REG_WRITE(0x70038, 0x0b060808); | ||
300 | /* FW4 */ | ||
301 | REG_WRITE(0x70050, 0x08030404); | ||
302 | /* FW5 */ | ||
303 | REG_WRITE(0x70054, 0x04040404); | ||
304 | /* LNC Chicken Bits */ | ||
305 | REG_WRITE(0x70400, 0x4000); | ||
306 | } | ||
307 | |||
308 | |||
309 | static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode) | ||
310 | { | ||
311 | static int dpms_mode = -1; | ||
312 | |||
313 | struct drm_device *dev = encoder->dev; | ||
314 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
315 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
316 | u32 temp; | ||
317 | |||
318 | if (dpms_mode == mode) | ||
319 | return; | ||
320 | |||
321 | if (mode != DRM_MODE_DPMS_ON) | ||
322 | temp = 0x0; | ||
323 | else | ||
324 | temp = 0x99; | ||
325 | |||
326 | dpms_mode = mode; | ||
327 | HDMI_WRITE(HDMI_VIDEO_REG, temp); | ||
328 | } | ||
329 | |||
330 | static unsigned int htotal_calculate(struct drm_display_mode *mode) | ||
331 | { | ||
332 | u32 htotal, new_crtc_htotal; | ||
333 | |||
334 | htotal = (mode->crtc_hdisplay - 1) | ((mode->crtc_htotal - 1) << 16); | ||
335 | |||
336 | /* | ||
337 | * 1024 x 768 new_crtc_htotal = 0x1024; | ||
338 | * 1280 x 1024 new_crtc_htotal = 0x0c34; | ||
339 | */ | ||
340 | new_crtc_htotal = (mode->crtc_htotal - 1) * 200 * 1000 / mode->clock; | ||
341 | |||
342 | return (mode->crtc_hdisplay - 1) | (new_crtc_htotal << 16); | ||
343 | } | ||
344 | |||
345 | static void oaktrail_hdmi_find_dpll(struct drm_crtc *crtc, int target, | ||
346 | int refclk, struct oaktrail_hdmi_clock *best_clock) | ||
347 | { | ||
348 | int np_min, np_max, nr_min, nr_max; | ||
349 | int np, nr, nf; | ||
350 | |||
351 | np_min = DIV_ROUND_UP(oaktrail_hdmi_limit.vco.min, target * 10); | ||
352 | np_max = oaktrail_hdmi_limit.vco.max / (target * 10); | ||
353 | if (np_min < oaktrail_hdmi_limit.np.min) | ||
354 | np_min = oaktrail_hdmi_limit.np.min; | ||
355 | if (np_max > oaktrail_hdmi_limit.np.max) | ||
356 | np_max = oaktrail_hdmi_limit.np.max; | ||
357 | |||
358 | nr_min = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_max)); | ||
359 | nr_max = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_min)); | ||
360 | if (nr_min < oaktrail_hdmi_limit.nr.min) | ||
361 | nr_min = oaktrail_hdmi_limit.nr.min; | ||
362 | if (nr_max > oaktrail_hdmi_limit.nr.max) | ||
363 | nr_max = oaktrail_hdmi_limit.nr.max; | ||
364 | |||
365 | np = DIV_ROUND_UP((refclk * 1000), (target * 10 * nr_max)); | ||
366 | nr = DIV_ROUND_UP((refclk * 1000), (target * 10 * np)); | ||
367 | nf = DIV_ROUND_CLOSEST((target * 10 * np * nr), refclk); | ||
368 | DRM_DEBUG_KMS("np, nr, nf %d %d %d\n", np, nr, nf); | ||
369 | |||
370 | /* | ||
371 | * 1024 x 768 np = 1; nr = 0x26; nf = 0x0fd8000; | ||
372 | * 1280 x 1024 np = 1; nr = 0x17; nf = 0x1034000; | ||
373 | */ | ||
374 | best_clock->np = np; | ||
375 | best_clock->nr = nr - 1; | ||
376 | best_clock->nf = (nf << 14); | ||
377 | } | ||
378 | |||
379 | int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, | ||
380 | struct drm_display_mode *mode, | ||
381 | struct drm_display_mode *adjusted_mode, | ||
382 | int x, int y, | ||
383 | struct drm_framebuffer *old_fb) | ||
384 | { | ||
385 | struct drm_device *dev = crtc->dev; | ||
386 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
387 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
388 | int pipe = 1; | ||
389 | int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; | ||
390 | int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; | ||
391 | int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; | ||
392 | int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; | ||
393 | int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; | ||
394 | int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; | ||
395 | int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; | ||
396 | int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; | ||
397 | int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; | ||
398 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
399 | int refclk; | ||
400 | struct oaktrail_hdmi_clock clock; | ||
401 | u32 dspcntr, pipeconf, dpll, temp; | ||
402 | int dspcntr_reg = DSPBCNTR; | ||
403 | |||
404 | /* Disable the VGA plane that we never use */ | ||
405 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
406 | |||
407 | /* XXX: Disable the panel fitter if it was on our pipe */ | ||
408 | |||
409 | /* Disable dpll if necessary */ | ||
410 | dpll = REG_READ(DPLL_CTRL); | ||
411 | if ((dpll & DPLL_PWRDN) == 0) { | ||
412 | REG_WRITE(DPLL_CTRL, dpll | (DPLL_PWRDN | DPLL_RESET)); | ||
413 | REG_WRITE(DPLL_DIV_CTRL, 0x00000000); | ||
414 | REG_WRITE(DPLL_STATUS, 0x1); | ||
415 | } | ||
416 | udelay(150); | ||
417 | |||
418 | /* reset controller: FIXME - can we sort out the ioremap mess ? */ | ||
419 | iounmap(hdmi_dev->regs); | ||
420 | oaktrail_hdmi_reset(dev); | ||
421 | |||
422 | /* program and enable dpll */ | ||
423 | refclk = 25000; | ||
424 | oaktrail_hdmi_find_dpll(crtc, adjusted_mode->clock, refclk, &clock); | ||
425 | |||
426 | /* Setting DPLL */ | ||
427 | dpll = REG_READ(DPLL_CTRL); | ||
428 | dpll &= ~DPLL_PDIV_MASK; | ||
429 | dpll &= ~(DPLL_PWRDN | DPLL_RESET); | ||
430 | REG_WRITE(DPLL_CTRL, 0x00000008); | ||
431 | REG_WRITE(DPLL_DIV_CTRL, ((clock.nf << 6) | clock.nr)); | ||
432 | REG_WRITE(DPLL_ADJUST, ((clock.nf >> 14) - 1)); | ||
433 | REG_WRITE(DPLL_CTRL, (dpll | (clock.np << DPLL_PDIV_SHIFT) | DPLL_ENSTAT | DPLL_DITHEN)); | ||
434 | REG_WRITE(DPLL_UPDATE, 0x80000000); | ||
435 | REG_WRITE(DPLL_CLK_ENABLE, 0x80050102); | ||
436 | udelay(150); | ||
437 | |||
438 | hdmi_dev->regs = ioremap(hdmi_dev->mmio, hdmi_dev->mmio_len); | ||
439 | if (hdmi_dev->regs == NULL) { | ||
440 | DRM_ERROR("failed to do hdmi mmio mapping\n"); | ||
441 | return -ENOMEM; | ||
442 | } | ||
443 | |||
444 | /* configure HDMI */ | ||
445 | HDMI_WRITE(0x1004, 0x1fd); | ||
446 | HDMI_WRITE(0x2000, 0x1); | ||
447 | HDMI_WRITE(0x2008, 0x0); | ||
448 | HDMI_WRITE(0x3130, 0x8); | ||
449 | HDMI_WRITE(0x101c, 0x1800810); | ||
450 | |||
451 | temp = htotal_calculate(adjusted_mode); | ||
452 | REG_WRITE(htot_reg, temp); | ||
453 | REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
454 | REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
455 | REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
456 | REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
457 | REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
458 | REG_WRITE(pipesrc_reg, | ||
459 | ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1)); | ||
460 | |||
461 | REG_WRITE(PCH_HTOTAL_B, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
462 | REG_WRITE(PCH_HBLANK_B, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
463 | REG_WRITE(PCH_HSYNC_B, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
464 | REG_WRITE(PCH_VTOTAL_B, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
465 | REG_WRITE(PCH_VBLANK_B, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
466 | REG_WRITE(PCH_VSYNC_B, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
467 | REG_WRITE(PCH_PIPEBSRC, | ||
468 | ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1)); | ||
469 | |||
470 | temp = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start; | ||
471 | HDMI_WRITE(HDMI_HBLANK_A, ((adjusted_mode->crtc_hdisplay - 1) << 16) | temp); | ||
472 | |||
473 | REG_WRITE(dspsize_reg, | ||
474 | ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); | ||
475 | REG_WRITE(dsppos_reg, 0); | ||
476 | |||
477 | /* Flush the plane changes */ | ||
478 | { | ||
479 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
480 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); | ||
481 | } | ||
482 | |||
483 | /* Set up the display plane register */ | ||
484 | dspcntr = REG_READ(dspcntr_reg); | ||
485 | dspcntr |= DISPPLANE_GAMMA_ENABLE; | ||
486 | dspcntr |= DISPPLANE_SEL_PIPE_B; | ||
487 | dspcntr |= DISPLAY_PLANE_ENABLE; | ||
488 | |||
489 | /* setup pipeconf */ | ||
490 | pipeconf = REG_READ(pipeconf_reg); | ||
491 | pipeconf |= PIPEACONF_ENABLE; | ||
492 | |||
493 | REG_WRITE(pipeconf_reg, pipeconf); | ||
494 | REG_READ(pipeconf_reg); | ||
495 | |||
496 | REG_WRITE(PCH_PIPEBCONF, pipeconf); | ||
497 | REG_READ(PCH_PIPEBCONF); | ||
498 | wait_for_vblank(dev); | ||
499 | |||
500 | REG_WRITE(dspcntr_reg, dspcntr); | ||
501 | wait_for_vblank(dev); | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, | ||
507 | struct drm_display_mode *mode) | ||
508 | { | ||
509 | if (mode->clock > 165000) | ||
510 | return MODE_CLOCK_HIGH; | ||
511 | if (mode->clock < 20000) | ||
512 | return MODE_CLOCK_LOW; | ||
513 | |||
514 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
515 | return MODE_NO_DBLESCAN; | ||
516 | |||
517 | return MODE_OK; | ||
518 | } | ||
519 | |||
520 | static bool oaktrail_hdmi_mode_fixup(struct drm_encoder *encoder, | ||
521 | struct drm_display_mode *mode, | ||
522 | struct drm_display_mode *adjusted_mode) | ||
523 | { | ||
524 | return true; | ||
525 | } | ||
526 | |||
527 | static enum drm_connector_status | ||
528 | oaktrail_hdmi_detect(struct drm_connector *connector, bool force) | ||
529 | { | ||
530 | enum drm_connector_status status; | ||
531 | struct drm_device *dev = connector->dev; | ||
532 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
533 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
534 | u32 temp; | ||
535 | |||
536 | temp = HDMI_READ(HDMI_HSR); | ||
537 | DRM_DEBUG_KMS("HDMI_HSR %x\n", temp); | ||
538 | |||
539 | if ((temp & HDMI_DETECT_HDP) != 0) | ||
540 | status = connector_status_connected; | ||
541 | else | ||
542 | status = connector_status_disconnected; | ||
543 | |||
544 | return status; | ||
545 | } | ||
546 | |||
547 | static const unsigned char raw_edid[] = { | ||
548 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x10, 0xac, 0x2f, 0xa0, | ||
549 | 0x53, 0x55, 0x33, 0x30, 0x16, 0x13, 0x01, 0x03, 0x0e, 0x3a, 0x24, 0x78, | ||
550 | 0xea, 0xe9, 0xf5, 0xac, 0x51, 0x30, 0xb4, 0x25, 0x11, 0x50, 0x54, 0xa5, | ||
551 | 0x4b, 0x00, 0x81, 0x80, 0xa9, 0x40, 0x71, 0x4f, 0xb3, 0x00, 0x01, 0x01, | ||
552 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x28, 0x3c, 0x80, 0xa0, 0x70, 0xb0, | ||
553 | 0x23, 0x40, 0x30, 0x20, 0x36, 0x00, 0x46, 0x6c, 0x21, 0x00, 0x00, 0x1a, | ||
554 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x47, 0x4e, 0x37, 0x32, 0x31, 0x39, 0x35, | ||
555 | 0x52, 0x30, 0x33, 0x55, 0x53, 0x0a, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x44, | ||
556 | 0x45, 0x4c, 0x4c, 0x20, 0x32, 0x37, 0x30, 0x39, 0x57, 0x0a, 0x20, 0x20, | ||
557 | 0x00, 0x00, 0x00, 0xfd, 0x00, 0x38, 0x4c, 0x1e, 0x53, 0x11, 0x00, 0x0a, | ||
558 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x8d | ||
559 | }; | ||
560 | |||
561 | static int oaktrail_hdmi_get_modes(struct drm_connector *connector) | ||
562 | { | ||
563 | struct drm_device *dev = connector->dev; | ||
564 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
565 | struct i2c_adapter *i2c_adap; | ||
566 | struct edid *edid; | ||
567 | struct drm_display_mode *mode, *t; | ||
568 | int i = 0, ret = 0; | ||
569 | |||
570 | i2c_adap = i2c_get_adapter(3); | ||
571 | if (i2c_adap == NULL) { | ||
572 | DRM_ERROR("No ddc adapter available!\n"); | ||
573 | edid = (struct edid *)raw_edid; | ||
574 | } else { | ||
575 | edid = (struct edid *)raw_edid; | ||
576 | /* FIXME ? edid = drm_get_edid(connector, i2c_adap); */ | ||
577 | } | ||
578 | |||
579 | if (edid) { | ||
580 | drm_mode_connector_update_edid_property(connector, edid); | ||
581 | ret = drm_add_edid_modes(connector, edid); | ||
582 | connector->display_info.raw_edid = NULL; | ||
583 | } | ||
584 | |||
585 | /* | ||
586 | * prune modes that require frame buffer bigger than stolen mem | ||
587 | */ | ||
588 | list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { | ||
589 | if ((mode->hdisplay * mode->vdisplay * 4) >= dev_priv->vram_stolen_size) { | ||
590 | i++; | ||
591 | drm_mode_remove(connector, mode); | ||
592 | } | ||
593 | } | ||
594 | return ret - i; | ||
595 | } | ||
596 | |||
597 | static void oaktrail_hdmi_mode_set(struct drm_encoder *encoder, | ||
598 | struct drm_display_mode *mode, | ||
599 | struct drm_display_mode *adjusted_mode) | ||
600 | { | ||
601 | struct drm_device *dev = encoder->dev; | ||
602 | |||
603 | oaktrail_hdmi_audio_enable(dev); | ||
604 | return; | ||
605 | } | ||
606 | |||
607 | static void oaktrail_hdmi_destroy(struct drm_connector *connector) | ||
608 | { | ||
609 | return; | ||
610 | } | ||
611 | |||
612 | static const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = { | ||
613 | .dpms = oaktrail_hdmi_dpms, | ||
614 | .mode_fixup = oaktrail_hdmi_mode_fixup, | ||
615 | .prepare = psb_intel_encoder_prepare, | ||
616 | .mode_set = oaktrail_hdmi_mode_set, | ||
617 | .commit = psb_intel_encoder_commit, | ||
618 | }; | ||
619 | |||
620 | static const struct drm_connector_helper_funcs | ||
621 | oaktrail_hdmi_connector_helper_funcs = { | ||
622 | .get_modes = oaktrail_hdmi_get_modes, | ||
623 | .mode_valid = oaktrail_hdmi_mode_valid, | ||
624 | .best_encoder = psb_intel_best_encoder, | ||
625 | }; | ||
626 | |||
627 | static const struct drm_connector_funcs oaktrail_hdmi_connector_funcs = { | ||
628 | .dpms = drm_helper_connector_dpms, | ||
629 | .detect = oaktrail_hdmi_detect, | ||
630 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
631 | .destroy = oaktrail_hdmi_destroy, | ||
632 | }; | ||
633 | |||
634 | static void oaktrail_hdmi_enc_destroy(struct drm_encoder *encoder) | ||
635 | { | ||
636 | drm_encoder_cleanup(encoder); | ||
637 | } | ||
638 | |||
639 | static const struct drm_encoder_funcs oaktrail_hdmi_enc_funcs = { | ||
640 | .destroy = oaktrail_hdmi_enc_destroy, | ||
641 | }; | ||
642 | |||
643 | void oaktrail_hdmi_init(struct drm_device *dev, | ||
644 | struct psb_intel_mode_device *mode_dev) | ||
645 | { | ||
646 | struct psb_intel_encoder *psb_intel_encoder; | ||
647 | struct psb_intel_connector *psb_intel_connector; | ||
648 | struct drm_connector *connector; | ||
649 | struct drm_encoder *encoder; | ||
650 | |||
651 | psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); | ||
652 | if (!psb_intel_encoder) | ||
653 | return; | ||
654 | |||
655 | psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); | ||
656 | if (!psb_intel_connector) | ||
657 | goto failed_connector; | ||
658 | |||
659 | connector = &psb_intel_connector->base; | ||
660 | encoder = &psb_intel_encoder->base; | ||
661 | drm_connector_init(dev, connector, | ||
662 | &oaktrail_hdmi_connector_funcs, | ||
663 | DRM_MODE_CONNECTOR_DVID); | ||
664 | |||
665 | drm_encoder_init(dev, encoder, | ||
666 | &oaktrail_hdmi_enc_funcs, | ||
667 | DRM_MODE_ENCODER_TMDS); | ||
668 | |||
669 | psb_intel_connector_attach_encoder(psb_intel_connector, | ||
670 | psb_intel_encoder); | ||
671 | |||
672 | psb_intel_encoder->type = INTEL_OUTPUT_HDMI; | ||
673 | drm_encoder_helper_add(encoder, &oaktrail_hdmi_helper_funcs); | ||
674 | drm_connector_helper_add(connector, &oaktrail_hdmi_connector_helper_funcs); | ||
675 | |||
676 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
677 | connector->interlace_allowed = false; | ||
678 | connector->doublescan_allowed = false; | ||
679 | drm_sysfs_connector_add(connector); | ||
680 | |||
681 | return; | ||
682 | |||
683 | failed_connector: | ||
684 | kfree(psb_intel_encoder); | ||
685 | } | ||
686 | |||
687 | static DEFINE_PCI_DEVICE_TABLE(hdmi_ids) = { | ||
688 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080d) }, | ||
689 | {} | ||
690 | }; | ||
691 | |||
692 | void oaktrail_hdmi_setup(struct drm_device *dev) | ||
693 | { | ||
694 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
695 | struct pci_dev *pdev; | ||
696 | struct oaktrail_hdmi_dev *hdmi_dev; | ||
697 | int ret; | ||
698 | |||
699 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x080d, NULL); | ||
700 | if (!pdev) | ||
701 | return; | ||
702 | |||
703 | hdmi_dev = kzalloc(sizeof(struct oaktrail_hdmi_dev), GFP_KERNEL); | ||
704 | if (!hdmi_dev) { | ||
705 | dev_err(dev->dev, "failed to allocate memory\n"); | ||
706 | goto out; | ||
707 | } | ||
708 | |||
709 | |||
710 | ret = pci_enable_device(pdev); | ||
711 | if (ret) { | ||
712 | dev_err(dev->dev, "failed to enable hdmi controller\n"); | ||
713 | goto free; | ||
714 | } | ||
715 | |||
716 | hdmi_dev->mmio = pci_resource_start(pdev, 0); | ||
717 | hdmi_dev->mmio_len = pci_resource_len(pdev, 0); | ||
718 | hdmi_dev->regs = ioremap(hdmi_dev->mmio, hdmi_dev->mmio_len); | ||
719 | if (!hdmi_dev->regs) { | ||
720 | dev_err(dev->dev, "failed to map hdmi mmio\n"); | ||
721 | goto free; | ||
722 | } | ||
723 | |||
724 | hdmi_dev->dev = pdev; | ||
725 | pci_set_drvdata(pdev, hdmi_dev); | ||
726 | |||
727 | /* Initialize i2c controller */ | ||
728 | ret = oaktrail_hdmi_i2c_init(hdmi_dev->dev); | ||
729 | if (ret) | ||
730 | dev_err(dev->dev, "HDMI I2C initialization failed\n"); | ||
731 | |||
732 | dev_priv->hdmi_priv = hdmi_dev; | ||
733 | oaktrail_hdmi_audio_disable(dev); | ||
734 | return; | ||
735 | |||
736 | free: | ||
737 | kfree(hdmi_dev); | ||
738 | out: | ||
739 | return; | ||
740 | } | ||
741 | |||
742 | void oaktrail_hdmi_teardown(struct drm_device *dev) | ||
743 | { | ||
744 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
745 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
746 | struct pci_dev *pdev; | ||
747 | |||
748 | if (hdmi_dev) { | ||
749 | pdev = hdmi_dev->dev; | ||
750 | pci_set_drvdata(pdev, NULL); | ||
751 | oaktrail_hdmi_i2c_exit(pdev); | ||
752 | iounmap(hdmi_dev->regs); | ||
753 | kfree(hdmi_dev); | ||
754 | pci_dev_put(pdev); | ||
755 | } | ||
756 | } | ||
757 | |||
758 | /* save HDMI register state */ | ||
759 | void oaktrail_hdmi_save(struct drm_device *dev) | ||
760 | { | ||
761 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
762 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
763 | int i; | ||
764 | |||
765 | /* dpll */ | ||
766 | hdmi_dev->saveDPLL_CTRL = PSB_RVDC32(DPLL_CTRL); | ||
767 | hdmi_dev->saveDPLL_DIV_CTRL = PSB_RVDC32(DPLL_DIV_CTRL); | ||
768 | hdmi_dev->saveDPLL_ADJUST = PSB_RVDC32(DPLL_ADJUST); | ||
769 | hdmi_dev->saveDPLL_UPDATE = PSB_RVDC32(DPLL_UPDATE); | ||
770 | hdmi_dev->saveDPLL_CLK_ENABLE = PSB_RVDC32(DPLL_CLK_ENABLE); | ||
771 | |||
772 | /* pipe B */ | ||
773 | dev_priv->savePIPEBCONF = PSB_RVDC32(PIPEBCONF); | ||
774 | dev_priv->savePIPEBSRC = PSB_RVDC32(PIPEBSRC); | ||
775 | dev_priv->saveHTOTAL_B = PSB_RVDC32(HTOTAL_B); | ||
776 | dev_priv->saveHBLANK_B = PSB_RVDC32(HBLANK_B); | ||
777 | dev_priv->saveHSYNC_B = PSB_RVDC32(HSYNC_B); | ||
778 | dev_priv->saveVTOTAL_B = PSB_RVDC32(VTOTAL_B); | ||
779 | dev_priv->saveVBLANK_B = PSB_RVDC32(VBLANK_B); | ||
780 | dev_priv->saveVSYNC_B = PSB_RVDC32(VSYNC_B); | ||
781 | |||
782 | hdmi_dev->savePCH_PIPEBCONF = PSB_RVDC32(PCH_PIPEBCONF); | ||
783 | hdmi_dev->savePCH_PIPEBSRC = PSB_RVDC32(PCH_PIPEBSRC); | ||
784 | hdmi_dev->savePCH_HTOTAL_B = PSB_RVDC32(PCH_HTOTAL_B); | ||
785 | hdmi_dev->savePCH_HBLANK_B = PSB_RVDC32(PCH_HBLANK_B); | ||
786 | hdmi_dev->savePCH_HSYNC_B = PSB_RVDC32(PCH_HSYNC_B); | ||
787 | hdmi_dev->savePCH_VTOTAL_B = PSB_RVDC32(PCH_VTOTAL_B); | ||
788 | hdmi_dev->savePCH_VBLANK_B = PSB_RVDC32(PCH_VBLANK_B); | ||
789 | hdmi_dev->savePCH_VSYNC_B = PSB_RVDC32(PCH_VSYNC_B); | ||
790 | |||
791 | /* plane */ | ||
792 | dev_priv->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR); | ||
793 | dev_priv->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE); | ||
794 | dev_priv->saveDSPBADDR = PSB_RVDC32(DSPBBASE); | ||
795 | dev_priv->saveDSPBSURF = PSB_RVDC32(DSPBSURF); | ||
796 | dev_priv->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF); | ||
797 | dev_priv->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF); | ||
798 | |||
799 | /* cursor B */ | ||
800 | dev_priv->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR); | ||
801 | dev_priv->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE); | ||
802 | dev_priv->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS); | ||
803 | |||
804 | /* save palette */ | ||
805 | for (i = 0; i < 256; i++) | ||
806 | dev_priv->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2)); | ||
807 | } | ||
808 | |||
809 | /* restore HDMI register state */ | ||
810 | void oaktrail_hdmi_restore(struct drm_device *dev) | ||
811 | { | ||
812 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
813 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
814 | int i; | ||
815 | |||
816 | /* dpll */ | ||
817 | PSB_WVDC32(hdmi_dev->saveDPLL_CTRL, DPLL_CTRL); | ||
818 | PSB_WVDC32(hdmi_dev->saveDPLL_DIV_CTRL, DPLL_DIV_CTRL); | ||
819 | PSB_WVDC32(hdmi_dev->saveDPLL_ADJUST, DPLL_ADJUST); | ||
820 | PSB_WVDC32(hdmi_dev->saveDPLL_UPDATE, DPLL_UPDATE); | ||
821 | PSB_WVDC32(hdmi_dev->saveDPLL_CLK_ENABLE, DPLL_CLK_ENABLE); | ||
822 | DRM_UDELAY(150); | ||
823 | |||
824 | /* pipe */ | ||
825 | PSB_WVDC32(dev_priv->savePIPEBSRC, PIPEBSRC); | ||
826 | PSB_WVDC32(dev_priv->saveHTOTAL_B, HTOTAL_B); | ||
827 | PSB_WVDC32(dev_priv->saveHBLANK_B, HBLANK_B); | ||
828 | PSB_WVDC32(dev_priv->saveHSYNC_B, HSYNC_B); | ||
829 | PSB_WVDC32(dev_priv->saveVTOTAL_B, VTOTAL_B); | ||
830 | PSB_WVDC32(dev_priv->saveVBLANK_B, VBLANK_B); | ||
831 | PSB_WVDC32(dev_priv->saveVSYNC_B, VSYNC_B); | ||
832 | |||
833 | PSB_WVDC32(hdmi_dev->savePCH_PIPEBSRC, PCH_PIPEBSRC); | ||
834 | PSB_WVDC32(hdmi_dev->savePCH_HTOTAL_B, PCH_HTOTAL_B); | ||
835 | PSB_WVDC32(hdmi_dev->savePCH_HBLANK_B, PCH_HBLANK_B); | ||
836 | PSB_WVDC32(hdmi_dev->savePCH_HSYNC_B, PCH_HSYNC_B); | ||
837 | PSB_WVDC32(hdmi_dev->savePCH_VTOTAL_B, PCH_VTOTAL_B); | ||
838 | PSB_WVDC32(hdmi_dev->savePCH_VBLANK_B, PCH_VBLANK_B); | ||
839 | PSB_WVDC32(hdmi_dev->savePCH_VSYNC_B, PCH_VSYNC_B); | ||
840 | |||
841 | PSB_WVDC32(dev_priv->savePIPEBCONF, PIPEBCONF); | ||
842 | PSB_WVDC32(hdmi_dev->savePCH_PIPEBCONF, PCH_PIPEBCONF); | ||
843 | |||
844 | /* plane */ | ||
845 | PSB_WVDC32(dev_priv->saveDSPBLINOFF, DSPBLINOFF); | ||
846 | PSB_WVDC32(dev_priv->saveDSPBSTRIDE, DSPBSTRIDE); | ||
847 | PSB_WVDC32(dev_priv->saveDSPBTILEOFF, DSPBTILEOFF); | ||
848 | PSB_WVDC32(dev_priv->saveDSPBCNTR, DSPBCNTR); | ||
849 | PSB_WVDC32(dev_priv->saveDSPBSURF, DSPBSURF); | ||
850 | |||
851 | /* cursor B */ | ||
852 | PSB_WVDC32(dev_priv->saveDSPBCURSOR_CTRL, CURBCNTR); | ||
853 | PSB_WVDC32(dev_priv->saveDSPBCURSOR_POS, CURBPOS); | ||
854 | PSB_WVDC32(dev_priv->saveDSPBCURSOR_BASE, CURBBASE); | ||
855 | |||
856 | /* restore palette */ | ||
857 | for (i = 0; i < 256; i++) | ||
858 | PSB_WVDC32(dev_priv->save_palette_b[i], PALETTE_B + (i << 2)); | ||
859 | } | ||
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c new file mode 100644 index 00000000000..705440874ac --- /dev/null +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Li Peng <peng.li@intel.com> | ||
25 | */ | ||
26 | |||
27 | #include <linux/export.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include "psb_drv.h" | ||
34 | |||
35 | #define HDMI_READ(reg) readl(hdmi_dev->regs + (reg)) | ||
36 | #define HDMI_WRITE(reg, val) writel(val, hdmi_dev->regs + (reg)) | ||
37 | |||
38 | #define HDMI_HCR 0x1000 | ||
39 | #define HCR_DETECT_HDP (1 << 6) | ||
40 | #define HCR_ENABLE_HDCP (1 << 5) | ||
41 | #define HCR_ENABLE_AUDIO (1 << 2) | ||
42 | #define HCR_ENABLE_PIXEL (1 << 1) | ||
43 | #define HCR_ENABLE_TMDS (1 << 0) | ||
44 | #define HDMI_HICR 0x1004 | ||
45 | #define HDMI_INTR_I2C_ERROR (1 << 4) | ||
46 | #define HDMI_INTR_I2C_FULL (1 << 3) | ||
47 | #define HDMI_INTR_I2C_DONE (1 << 2) | ||
48 | #define HDMI_INTR_HPD (1 << 0) | ||
49 | #define HDMI_HSR 0x1008 | ||
50 | #define HDMI_HISR 0x100C | ||
51 | #define HDMI_HI2CRDB0 0x1200 | ||
52 | #define HDMI_HI2CHCR 0x1240 | ||
53 | #define HI2C_HDCP_WRITE (0 << 2) | ||
54 | #define HI2C_HDCP_RI_READ (1 << 2) | ||
55 | #define HI2C_HDCP_READ (2 << 2) | ||
56 | #define HI2C_EDID_READ (3 << 2) | ||
57 | #define HI2C_READ_CONTINUE (1 << 1) | ||
58 | #define HI2C_ENABLE_TRANSACTION (1 << 0) | ||
59 | |||
60 | #define HDMI_ICRH 0x1100 | ||
61 | #define HDMI_HI2CTDR0 0x1244 | ||
62 | #define HDMI_HI2CTDR1 0x1248 | ||
63 | |||
64 | #define I2C_STAT_INIT 0 | ||
65 | #define I2C_READ_DONE 1 | ||
66 | #define I2C_TRANSACTION_DONE 2 | ||
67 | |||
68 | struct hdmi_i2c_dev { | ||
69 | struct i2c_adapter *adap; | ||
70 | struct mutex i2c_lock; | ||
71 | struct completion complete; | ||
72 | int status; | ||
73 | struct i2c_msg *msg; | ||
74 | int buf_offset; | ||
75 | }; | ||
76 | |||
77 | static void hdmi_i2c_irq_enable(struct oaktrail_hdmi_dev *hdmi_dev) | ||
78 | { | ||
79 | u32 temp; | ||
80 | |||
81 | temp = HDMI_READ(HDMI_HICR); | ||
82 | temp |= (HDMI_INTR_I2C_ERROR | HDMI_INTR_I2C_FULL | HDMI_INTR_I2C_DONE); | ||
83 | HDMI_WRITE(HDMI_HICR, temp); | ||
84 | HDMI_READ(HDMI_HICR); | ||
85 | } | ||
86 | |||
87 | static void hdmi_i2c_irq_disable(struct oaktrail_hdmi_dev *hdmi_dev) | ||
88 | { | ||
89 | HDMI_WRITE(HDMI_HICR, 0x0); | ||
90 | HDMI_READ(HDMI_HICR); | ||
91 | } | ||
92 | |||
93 | static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg) | ||
94 | { | ||
95 | struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap); | ||
96 | struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | ||
97 | u32 temp; | ||
98 | |||
99 | i2c_dev->status = I2C_STAT_INIT; | ||
100 | i2c_dev->msg = pmsg; | ||
101 | i2c_dev->buf_offset = 0; | ||
102 | INIT_COMPLETION(i2c_dev->complete); | ||
103 | |||
104 | /* Enable I2C transaction */ | ||
105 | temp = ((pmsg->len) << 20) | HI2C_EDID_READ | HI2C_ENABLE_TRANSACTION; | ||
106 | HDMI_WRITE(HDMI_HI2CHCR, temp); | ||
107 | HDMI_READ(HDMI_HI2CHCR); | ||
108 | |||
109 | while (i2c_dev->status != I2C_TRANSACTION_DONE) | ||
110 | wait_for_completion_interruptible_timeout(&i2c_dev->complete, | ||
111 | 10 * HZ); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int xfer_write(struct i2c_adapter *adap, struct i2c_msg *pmsg) | ||
117 | { | ||
118 | /* | ||
119 | * XXX: i2c write seems isn't useful for EDID probe, don't do anything | ||
120 | */ | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap, | ||
125 | struct i2c_msg *pmsg, | ||
126 | int num) | ||
127 | { | ||
128 | struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap); | ||
129 | struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | ||
130 | int i, err = 0; | ||
131 | |||
132 | mutex_lock(&i2c_dev->i2c_lock); | ||
133 | |||
134 | /* Enable i2c unit */ | ||
135 | HDMI_WRITE(HDMI_ICRH, 0x00008760); | ||
136 | |||
137 | /* Enable irq */ | ||
138 | hdmi_i2c_irq_enable(hdmi_dev); | ||
139 | for (i = 0; i < num; i++) { | ||
140 | if (pmsg->len && pmsg->buf) { | ||
141 | if (pmsg->flags & I2C_M_RD) | ||
142 | err = xfer_read(adap, pmsg); | ||
143 | else | ||
144 | err = xfer_write(adap, pmsg); | ||
145 | } | ||
146 | pmsg++; /* next message */ | ||
147 | } | ||
148 | |||
149 | /* Disable irq */ | ||
150 | hdmi_i2c_irq_disable(hdmi_dev); | ||
151 | |||
152 | mutex_unlock(&i2c_dev->i2c_lock); | ||
153 | |||
154 | return i; | ||
155 | } | ||
156 | |||
157 | static u32 oaktrail_hdmi_i2c_func(struct i2c_adapter *adapter) | ||
158 | { | ||
159 | return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; | ||
160 | } | ||
161 | |||
162 | static const struct i2c_algorithm oaktrail_hdmi_i2c_algorithm = { | ||
163 | .master_xfer = oaktrail_hdmi_i2c_access, | ||
164 | .functionality = oaktrail_hdmi_i2c_func, | ||
165 | }; | ||
166 | |||
167 | static struct i2c_adapter oaktrail_hdmi_i2c_adapter = { | ||
168 | .name = "oaktrail_hdmi_i2c", | ||
169 | .nr = 3, | ||
170 | .owner = THIS_MODULE, | ||
171 | .class = I2C_CLASS_DDC, | ||
172 | .algo = &oaktrail_hdmi_i2c_algorithm, | ||
173 | }; | ||
174 | |||
175 | static void hdmi_i2c_read(struct oaktrail_hdmi_dev *hdmi_dev) | ||
176 | { | ||
177 | struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | ||
178 | struct i2c_msg *msg = i2c_dev->msg; | ||
179 | u8 *buf = msg->buf; | ||
180 | u32 temp; | ||
181 | int i, offset; | ||
182 | |||
183 | offset = i2c_dev->buf_offset; | ||
184 | for (i = 0; i < 0x10; i++) { | ||
185 | temp = HDMI_READ(HDMI_HI2CRDB0 + (i * 4)); | ||
186 | memcpy(buf + (offset + i * 4), &temp, 4); | ||
187 | } | ||
188 | i2c_dev->buf_offset += (0x10 * 4); | ||
189 | |||
190 | /* clearing read buffer full intr */ | ||
191 | temp = HDMI_READ(HDMI_HISR); | ||
192 | HDMI_WRITE(HDMI_HISR, temp | HDMI_INTR_I2C_FULL); | ||
193 | HDMI_READ(HDMI_HISR); | ||
194 | |||
195 | /* continue read transaction */ | ||
196 | temp = HDMI_READ(HDMI_HI2CHCR); | ||
197 | HDMI_WRITE(HDMI_HI2CHCR, temp | HI2C_READ_CONTINUE); | ||
198 | HDMI_READ(HDMI_HI2CHCR); | ||
199 | |||
200 | i2c_dev->status = I2C_READ_DONE; | ||
201 | return; | ||
202 | } | ||
203 | |||
204 | static void hdmi_i2c_transaction_done(struct oaktrail_hdmi_dev *hdmi_dev) | ||
205 | { | ||
206 | struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | ||
207 | u32 temp; | ||
208 | |||
209 | /* clear transaction done intr */ | ||
210 | temp = HDMI_READ(HDMI_HISR); | ||
211 | HDMI_WRITE(HDMI_HISR, temp | HDMI_INTR_I2C_DONE); | ||
212 | HDMI_READ(HDMI_HISR); | ||
213 | |||
214 | |||
215 | temp = HDMI_READ(HDMI_HI2CHCR); | ||
216 | HDMI_WRITE(HDMI_HI2CHCR, temp & ~HI2C_ENABLE_TRANSACTION); | ||
217 | HDMI_READ(HDMI_HI2CHCR); | ||
218 | |||
219 | i2c_dev->status = I2C_TRANSACTION_DONE; | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | static irqreturn_t oaktrail_hdmi_i2c_handler(int this_irq, void *dev) | ||
224 | { | ||
225 | struct oaktrail_hdmi_dev *hdmi_dev = dev; | ||
226 | struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | ||
227 | u32 stat; | ||
228 | |||
229 | stat = HDMI_READ(HDMI_HISR); | ||
230 | |||
231 | if (stat & HDMI_INTR_HPD) { | ||
232 | HDMI_WRITE(HDMI_HISR, stat | HDMI_INTR_HPD); | ||
233 | HDMI_READ(HDMI_HISR); | ||
234 | } | ||
235 | |||
236 | if (stat & HDMI_INTR_I2C_FULL) | ||
237 | hdmi_i2c_read(hdmi_dev); | ||
238 | |||
239 | if (stat & HDMI_INTR_I2C_DONE) | ||
240 | hdmi_i2c_transaction_done(hdmi_dev); | ||
241 | |||
242 | complete(&i2c_dev->complete); | ||
243 | |||
244 | return IRQ_HANDLED; | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * choose alternate function 2 of GPIO pin 52, 53, | ||
249 | * which is used by HDMI I2C logic | ||
250 | */ | ||
251 | static void oaktrail_hdmi_i2c_gpio_fix(void) | ||
252 | { | ||
253 | void *base; | ||
254 | unsigned int gpio_base = 0xff12c000; | ||
255 | int gpio_len = 0x1000; | ||
256 | u32 temp; | ||
257 | |||
258 | base = ioremap((resource_size_t)gpio_base, gpio_len); | ||
259 | if (base == NULL) { | ||
260 | DRM_ERROR("gpio ioremap fail\n"); | ||
261 | return; | ||
262 | } | ||
263 | |||
264 | temp = readl(base + 0x44); | ||
265 | DRM_DEBUG_DRIVER("old gpio val %x\n", temp); | ||
266 | writel((temp | 0x00000a00), (base + 0x44)); | ||
267 | temp = readl(base + 0x44); | ||
268 | DRM_DEBUG_DRIVER("new gpio val %x\n", temp); | ||
269 | |||
270 | iounmap(base); | ||
271 | } | ||
272 | |||
273 | int oaktrail_hdmi_i2c_init(struct pci_dev *dev) | ||
274 | { | ||
275 | struct oaktrail_hdmi_dev *hdmi_dev; | ||
276 | struct hdmi_i2c_dev *i2c_dev; | ||
277 | int ret; | ||
278 | |||
279 | hdmi_dev = pci_get_drvdata(dev); | ||
280 | |||
281 | i2c_dev = kzalloc(sizeof(struct hdmi_i2c_dev), GFP_KERNEL); | ||
282 | if (i2c_dev == NULL) { | ||
283 | DRM_ERROR("Can't allocate interface\n"); | ||
284 | ret = -ENOMEM; | ||
285 | goto exit; | ||
286 | } | ||
287 | |||
288 | i2c_dev->adap = &oaktrail_hdmi_i2c_adapter; | ||
289 | i2c_dev->status = I2C_STAT_INIT; | ||
290 | init_completion(&i2c_dev->complete); | ||
291 | mutex_init(&i2c_dev->i2c_lock); | ||
292 | i2c_set_adapdata(&oaktrail_hdmi_i2c_adapter, hdmi_dev); | ||
293 | hdmi_dev->i2c_dev = i2c_dev; | ||
294 | |||
295 | /* Enable HDMI I2C function on gpio */ | ||
296 | oaktrail_hdmi_i2c_gpio_fix(); | ||
297 | |||
298 | /* request irq */ | ||
299 | ret = request_irq(dev->irq, oaktrail_hdmi_i2c_handler, IRQF_SHARED, | ||
300 | oaktrail_hdmi_i2c_adapter.name, hdmi_dev); | ||
301 | if (ret) { | ||
302 | DRM_ERROR("Failed to request IRQ for I2C controller\n"); | ||
303 | goto err; | ||
304 | } | ||
305 | |||
306 | /* Adapter registration */ | ||
307 | ret = i2c_add_numbered_adapter(&oaktrail_hdmi_i2c_adapter); | ||
308 | return ret; | ||
309 | |||
310 | err: | ||
311 | kfree(i2c_dev); | ||
312 | exit: | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | void oaktrail_hdmi_i2c_exit(struct pci_dev *dev) | ||
317 | { | ||
318 | struct oaktrail_hdmi_dev *hdmi_dev; | ||
319 | struct hdmi_i2c_dev *i2c_dev; | ||
320 | |||
321 | hdmi_dev = pci_get_drvdata(dev); | ||
322 | if (i2c_del_adapter(&oaktrail_hdmi_i2c_adapter)) | ||
323 | DRM_DEBUG_DRIVER("Failed to delete hdmi-i2c adapter\n"); | ||
324 | |||
325 | i2c_dev = hdmi_dev->i2c_dev; | ||
326 | kfree(i2c_dev); | ||
327 | free_irq(dev->irq, hdmi_dev); | ||
328 | } | ||
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c new file mode 100644 index 00000000000..238bbe10530 --- /dev/null +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2009 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | * Dave Airlie <airlied@linux.ie> | ||
20 | * Jesse Barnes <jesse.barnes@intel.com> | ||
21 | */ | ||
22 | |||
23 | #include <linux/i2c.h> | ||
24 | #include <drm/drmP.h> | ||
25 | #include <asm/mrst.h> | ||
26 | |||
27 | #include "intel_bios.h" | ||
28 | #include "psb_drv.h" | ||
29 | #include "psb_intel_drv.h" | ||
30 | #include "psb_intel_reg.h" | ||
31 | #include "power.h" | ||
32 | #include <linux/pm_runtime.h> | ||
33 | |||
34 | /* The max/min PWM frequency in BPCR[31:17] - */ | ||
35 | /* The smallest number is 1 (not 0) that can fit in the | ||
36 | * 15-bit field of the and then*/ | ||
37 | /* shifts to the left by one bit to get the actual 16-bit | ||
38 | * value that the 15-bits correspond to.*/ | ||
39 | #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF | ||
40 | #define BRIGHTNESS_MAX_LEVEL 100 | ||
41 | |||
42 | /** | ||
43 | * Sets the power state for the panel. | ||
44 | */ | ||
45 | static void oaktrail_lvds_set_power(struct drm_device *dev, | ||
46 | struct psb_intel_encoder *psb_intel_encoder, | ||
47 | bool on) | ||
48 | { | ||
49 | u32 pp_status; | ||
50 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
51 | |||
52 | if (!gma_power_begin(dev, true)) | ||
53 | return; | ||
54 | |||
55 | if (on) { | ||
56 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | | ||
57 | POWER_TARGET_ON); | ||
58 | do { | ||
59 | pp_status = REG_READ(PP_STATUS); | ||
60 | } while ((pp_status & (PP_ON | PP_READY)) == PP_READY); | ||
61 | dev_priv->is_lvds_on = true; | ||
62 | if (dev_priv->ops->lvds_bl_power) | ||
63 | dev_priv->ops->lvds_bl_power(dev, true); | ||
64 | } else { | ||
65 | if (dev_priv->ops->lvds_bl_power) | ||
66 | dev_priv->ops->lvds_bl_power(dev, false); | ||
67 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & | ||
68 | ~POWER_TARGET_ON); | ||
69 | do { | ||
70 | pp_status = REG_READ(PP_STATUS); | ||
71 | } while (pp_status & PP_ON); | ||
72 | dev_priv->is_lvds_on = false; | ||
73 | pm_request_idle(&dev->pdev->dev); | ||
74 | } | ||
75 | gma_power_end(dev); | ||
76 | } | ||
77 | |||
78 | static void oaktrail_lvds_dpms(struct drm_encoder *encoder, int mode) | ||
79 | { | ||
80 | struct drm_device *dev = encoder->dev; | ||
81 | struct psb_intel_encoder *psb_intel_encoder = | ||
82 | to_psb_intel_encoder(encoder); | ||
83 | |||
84 | if (mode == DRM_MODE_DPMS_ON) | ||
85 | oaktrail_lvds_set_power(dev, psb_intel_encoder, true); | ||
86 | else | ||
87 | oaktrail_lvds_set_power(dev, psb_intel_encoder, false); | ||
88 | |||
89 | /* XXX: We never power down the LVDS pairs. */ | ||
90 | } | ||
91 | |||
92 | static void oaktrail_lvds_mode_set(struct drm_encoder *encoder, | ||
93 | struct drm_display_mode *mode, | ||
94 | struct drm_display_mode *adjusted_mode) | ||
95 | { | ||
96 | struct drm_device *dev = encoder->dev; | ||
97 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
98 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
99 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
100 | struct drm_connector *connector = NULL; | ||
101 | struct drm_crtc *crtc = encoder->crtc; | ||
102 | u32 lvds_port; | ||
103 | uint64_t v = DRM_MODE_SCALE_FULLSCREEN; | ||
104 | |||
105 | if (!gma_power_begin(dev, true)) | ||
106 | return; | ||
107 | |||
108 | /* | ||
109 | * The LVDS pin pair will already have been turned on in the | ||
110 | * psb_intel_crtc_mode_set since it has a large impact on the DPLL | ||
111 | * settings. | ||
112 | */ | ||
113 | lvds_port = (REG_READ(LVDS) & | ||
114 | (~LVDS_PIPEB_SELECT)) | | ||
115 | LVDS_PORT_EN | | ||
116 | LVDS_BORDER_EN; | ||
117 | |||
118 | /* If the firmware says dither on Moorestown, or the BIOS does | ||
119 | on Oaktrail then enable dithering */ | ||
120 | if (mode_dev->panel_wants_dither || dev_priv->lvds_dither) | ||
121 | lvds_port |= MRST_PANEL_8TO6_DITHER_ENABLE; | ||
122 | |||
123 | REG_WRITE(LVDS, lvds_port); | ||
124 | |||
125 | /* Find the connector we're trying to set up */ | ||
126 | list_for_each_entry(connector, &mode_config->connector_list, head) { | ||
127 | if (!connector->encoder || connector->encoder->crtc != crtc) | ||
128 | continue; | ||
129 | } | ||
130 | |||
131 | if (!connector) { | ||
132 | DRM_ERROR("Couldn't find connector when setting mode"); | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | drm_connector_property_get_value( | ||
137 | connector, | ||
138 | dev->mode_config.scaling_mode_property, | ||
139 | &v); | ||
140 | |||
141 | if (v == DRM_MODE_SCALE_NO_SCALE) | ||
142 | REG_WRITE(PFIT_CONTROL, 0); | ||
143 | else if (v == DRM_MODE_SCALE_ASPECT) { | ||
144 | if ((mode->vdisplay != adjusted_mode->crtc_vdisplay) || | ||
145 | (mode->hdisplay != adjusted_mode->crtc_hdisplay)) { | ||
146 | if ((adjusted_mode->crtc_hdisplay * mode->vdisplay) == | ||
147 | (mode->hdisplay * adjusted_mode->crtc_vdisplay)) | ||
148 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | ||
149 | else if ((adjusted_mode->crtc_hdisplay * | ||
150 | mode->vdisplay) > (mode->hdisplay * | ||
151 | adjusted_mode->crtc_vdisplay)) | ||
152 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | | ||
153 | PFIT_SCALING_MODE_PILLARBOX); | ||
154 | else | ||
155 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | | ||
156 | PFIT_SCALING_MODE_LETTERBOX); | ||
157 | } else | ||
158 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | ||
159 | } else /*(v == DRM_MODE_SCALE_FULLSCREEN)*/ | ||
160 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | ||
161 | |||
162 | gma_power_end(dev); | ||
163 | } | ||
164 | |||
165 | static void oaktrail_lvds_prepare(struct drm_encoder *encoder) | ||
166 | { | ||
167 | struct drm_device *dev = encoder->dev; | ||
168 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
169 | struct psb_intel_encoder *psb_intel_encoder = | ||
170 | to_psb_intel_encoder(encoder); | ||
171 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
172 | |||
173 | if (!gma_power_begin(dev, true)) | ||
174 | return; | ||
175 | |||
176 | mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); | ||
177 | mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & | ||
178 | BACKLIGHT_DUTY_CYCLE_MASK); | ||
179 | oaktrail_lvds_set_power(dev, psb_intel_encoder, false); | ||
180 | gma_power_end(dev); | ||
181 | } | ||
182 | |||
183 | static u32 oaktrail_lvds_get_max_backlight(struct drm_device *dev) | ||
184 | { | ||
185 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
186 | u32 ret; | ||
187 | |||
188 | if (gma_power_begin(dev, false)) { | ||
189 | ret = ((REG_READ(BLC_PWM_CTL) & | ||
190 | BACKLIGHT_MODULATION_FREQ_MASK) >> | ||
191 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | ||
192 | |||
193 | gma_power_end(dev); | ||
194 | } else | ||
195 | ret = ((dev_priv->saveBLC_PWM_CTL & | ||
196 | BACKLIGHT_MODULATION_FREQ_MASK) >> | ||
197 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static void oaktrail_lvds_commit(struct drm_encoder *encoder) | ||
203 | { | ||
204 | struct drm_device *dev = encoder->dev; | ||
205 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
206 | struct psb_intel_encoder *psb_intel_encoder = | ||
207 | to_psb_intel_encoder(encoder); | ||
208 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
209 | |||
210 | if (mode_dev->backlight_duty_cycle == 0) | ||
211 | mode_dev->backlight_duty_cycle = | ||
212 | oaktrail_lvds_get_max_backlight(dev); | ||
213 | oaktrail_lvds_set_power(dev, psb_intel_encoder, true); | ||
214 | } | ||
215 | |||
216 | static const struct drm_encoder_helper_funcs oaktrail_lvds_helper_funcs = { | ||
217 | .dpms = oaktrail_lvds_dpms, | ||
218 | .mode_fixup = psb_intel_lvds_mode_fixup, | ||
219 | .prepare = oaktrail_lvds_prepare, | ||
220 | .mode_set = oaktrail_lvds_mode_set, | ||
221 | .commit = oaktrail_lvds_commit, | ||
222 | }; | ||
223 | |||
224 | static struct drm_display_mode lvds_configuration_modes[] = { | ||
225 | /* hard coded fixed mode for TPO LTPS LPJ040K001A */ | ||
226 | { DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER, 33264, 800, 836, | ||
227 | 846, 1056, 0, 480, 489, 491, 525, 0, 0) }, | ||
228 | /* hard coded fixed mode for LVDS 800x480 */ | ||
229 | { DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER, 30994, 800, 801, | ||
230 | 802, 1024, 0, 480, 481, 482, 525, 0, 0) }, | ||
231 | /* hard coded fixed mode for Samsung 480wsvga LVDS 1024x600@75 */ | ||
232 | { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 53990, 1024, 1072, | ||
233 | 1104, 1184, 0, 600, 603, 604, 608, 0, 0) }, | ||
234 | /* hard coded fixed mode for Samsung 480wsvga LVDS 1024x600@75 */ | ||
235 | { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 53990, 1024, 1104, | ||
236 | 1136, 1184, 0, 600, 603, 604, 608, 0, 0) }, | ||
237 | /* hard coded fixed mode for Sharp wsvga LVDS 1024x600 */ | ||
238 | { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 48885, 1024, 1124, | ||
239 | 1204, 1312, 0, 600, 607, 610, 621, 0, 0) }, | ||
240 | /* hard coded fixed mode for LVDS 1024x768 */ | ||
241 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, | ||
242 | 1184, 1344, 0, 768, 771, 777, 806, 0, 0) }, | ||
243 | /* hard coded fixed mode for LVDS 1366x768 */ | ||
244 | { DRM_MODE("1366x768", DRM_MODE_TYPE_DRIVER, 77500, 1366, 1430, | ||
245 | 1558, 1664, 0, 768, 769, 770, 776, 0, 0) }, | ||
246 | }; | ||
247 | |||
248 | /* Returns the panel fixed mode from configuration. */ | ||
249 | |||
250 | static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, | ||
251 | struct psb_intel_mode_device *mode_dev) | ||
252 | { | ||
253 | struct drm_display_mode *mode = NULL; | ||
254 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
255 | struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; | ||
256 | |||
257 | mode_dev->panel_fixed_mode = NULL; | ||
258 | |||
259 | /* Use the firmware provided data on Moorestown */ | ||
260 | if (dev_priv->vbt_data.size != 0x00) { /*if non-zero, then use vbt*/ | ||
261 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
262 | if (!mode) | ||
263 | return; | ||
264 | |||
265 | mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; | ||
266 | mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; | ||
267 | mode->hsync_start = mode->hdisplay + \ | ||
268 | ((ti->hsync_offset_hi << 8) | \ | ||
269 | ti->hsync_offset_lo); | ||
270 | mode->hsync_end = mode->hsync_start + \ | ||
271 | ((ti->hsync_pulse_width_hi << 8) | \ | ||
272 | ti->hsync_pulse_width_lo); | ||
273 | mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ | ||
274 | ti->hblank_lo); | ||
275 | mode->vsync_start = \ | ||
276 | mode->vdisplay + ((ti->vsync_offset_hi << 4) | \ | ||
277 | ti->vsync_offset_lo); | ||
278 | mode->vsync_end = \ | ||
279 | mode->vsync_start + ((ti->vsync_pulse_width_hi << 4) | \ | ||
280 | ti->vsync_pulse_width_lo); | ||
281 | mode->vtotal = mode->vdisplay + \ | ||
282 | ((ti->vblank_hi << 8) | ti->vblank_lo); | ||
283 | mode->clock = ti->pixel_clock * 10; | ||
284 | #if 0 | ||
285 | printk(KERN_INFO "hdisplay is %d\n", mode->hdisplay); | ||
286 | printk(KERN_INFO "vdisplay is %d\n", mode->vdisplay); | ||
287 | printk(KERN_INFO "HSS is %d\n", mode->hsync_start); | ||
288 | printk(KERN_INFO "HSE is %d\n", mode->hsync_end); | ||
289 | printk(KERN_INFO "htotal is %d\n", mode->htotal); | ||
290 | printk(KERN_INFO "VSS is %d\n", mode->vsync_start); | ||
291 | printk(KERN_INFO "VSE is %d\n", mode->vsync_end); | ||
292 | printk(KERN_INFO "vtotal is %d\n", mode->vtotal); | ||
293 | printk(KERN_INFO "clock is %d\n", mode->clock); | ||
294 | #endif | ||
295 | mode_dev->panel_fixed_mode = mode; | ||
296 | } | ||
297 | |||
298 | /* Use the BIOS VBT mode if available */ | ||
299 | if (mode_dev->panel_fixed_mode == NULL && mode_dev->vbt_mode) | ||
300 | mode_dev->panel_fixed_mode = drm_mode_duplicate(dev, | ||
301 | mode_dev->vbt_mode); | ||
302 | |||
303 | /* Then try the LVDS VBT mode */ | ||
304 | if (mode_dev->panel_fixed_mode == NULL) | ||
305 | if (dev_priv->lfp_lvds_vbt_mode) | ||
306 | mode_dev->panel_fixed_mode = | ||
307 | drm_mode_duplicate(dev, | ||
308 | dev_priv->lfp_lvds_vbt_mode); | ||
309 | /* Then guess */ | ||
310 | if (mode_dev->panel_fixed_mode == NULL) | ||
311 | mode_dev->panel_fixed_mode | ||
312 | = drm_mode_duplicate(dev, &lvds_configuration_modes[2]); | ||
313 | |||
314 | drm_mode_set_name(mode_dev->panel_fixed_mode); | ||
315 | drm_mode_set_crtcinfo(mode_dev->panel_fixed_mode, 0); | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * oaktrail_lvds_init - setup LVDS connectors on this device | ||
320 | * @dev: drm device | ||
321 | * | ||
322 | * Create the connector, register the LVDS DDC bus, and try to figure out what | ||
323 | * modes we can display on the LVDS panel (if present). | ||
324 | */ | ||
325 | void oaktrail_lvds_init(struct drm_device *dev, | ||
326 | struct psb_intel_mode_device *mode_dev) | ||
327 | { | ||
328 | struct psb_intel_encoder *psb_intel_encoder; | ||
329 | struct psb_intel_connector *psb_intel_connector; | ||
330 | struct drm_connector *connector; | ||
331 | struct drm_encoder *encoder; | ||
332 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
333 | struct edid *edid; | ||
334 | int ret = 0; | ||
335 | struct i2c_adapter *i2c_adap; | ||
336 | struct drm_display_mode *scan; /* *modes, *bios_mode; */ | ||
337 | |||
338 | psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); | ||
339 | if (!psb_intel_encoder) | ||
340 | return; | ||
341 | |||
342 | psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); | ||
343 | if (!psb_intel_connector) | ||
344 | goto failed_connector; | ||
345 | |||
346 | connector = &psb_intel_connector->base; | ||
347 | encoder = &psb_intel_encoder->base; | ||
348 | dev_priv->is_lvds_on = true; | ||
349 | drm_connector_init(dev, connector, | ||
350 | &psb_intel_lvds_connector_funcs, | ||
351 | DRM_MODE_CONNECTOR_LVDS); | ||
352 | |||
353 | drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs, | ||
354 | DRM_MODE_ENCODER_LVDS); | ||
355 | |||
356 | psb_intel_connector_attach_encoder(psb_intel_connector, | ||
357 | psb_intel_encoder); | ||
358 | psb_intel_encoder->type = INTEL_OUTPUT_LVDS; | ||
359 | |||
360 | drm_encoder_helper_add(encoder, &oaktrail_lvds_helper_funcs); | ||
361 | drm_connector_helper_add(connector, | ||
362 | &psb_intel_lvds_connector_helper_funcs); | ||
363 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
364 | connector->interlace_allowed = false; | ||
365 | connector->doublescan_allowed = false; | ||
366 | |||
367 | drm_connector_attach_property(connector, | ||
368 | dev->mode_config.scaling_mode_property, | ||
369 | DRM_MODE_SCALE_FULLSCREEN); | ||
370 | drm_connector_attach_property(connector, | ||
371 | dev_priv->backlight_property, | ||
372 | BRIGHTNESS_MAX_LEVEL); | ||
373 | |||
374 | mode_dev->panel_wants_dither = false; | ||
375 | if (dev_priv->vbt_data.size != 0x00) | ||
376 | mode_dev->panel_wants_dither = (dev_priv->gct_data. | ||
377 | Panel_Port_Control & MRST_PANEL_8TO6_DITHER_ENABLE); | ||
378 | if (dev_priv->lvds_dither) | ||
379 | mode_dev->panel_wants_dither = 1; | ||
380 | |||
381 | /* | ||
382 | * LVDS discovery: | ||
383 | * 1) check for EDID on DDC | ||
384 | * 2) check for VBT data | ||
385 | * 3) check to see if LVDS is already on | ||
386 | * if none of the above, no panel | ||
387 | * 4) make sure lid is open | ||
388 | * if closed, act like it's not there for now | ||
389 | */ | ||
390 | |||
391 | i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus); | ||
392 | if (i2c_adap == NULL) | ||
393 | dev_err(dev->dev, "No ddc adapter available!\n"); | ||
394 | /* | ||
395 | * Attempt to get the fixed panel mode from DDC. Assume that the | ||
396 | * preferred mode is the right one. | ||
397 | */ | ||
398 | if (i2c_adap) { | ||
399 | edid = drm_get_edid(connector, i2c_adap); | ||
400 | if (edid) { | ||
401 | drm_mode_connector_update_edid_property(connector, | ||
402 | edid); | ||
403 | ret = drm_add_edid_modes(connector, edid); | ||
404 | kfree(edid); | ||
405 | } | ||
406 | |||
407 | list_for_each_entry(scan, &connector->probed_modes, head) { | ||
408 | if (scan->type & DRM_MODE_TYPE_PREFERRED) { | ||
409 | mode_dev->panel_fixed_mode = | ||
410 | drm_mode_duplicate(dev, scan); | ||
411 | goto out; /* FIXME: check for quirks */ | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | /* | ||
416 | * If we didn't get EDID, try geting panel timing | ||
417 | * from configuration data | ||
418 | */ | ||
419 | oaktrail_lvds_get_configuration_mode(dev, mode_dev); | ||
420 | |||
421 | if (mode_dev->panel_fixed_mode) { | ||
422 | mode_dev->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
423 | goto out; /* FIXME: check for quirks */ | ||
424 | } | ||
425 | |||
426 | /* If we still don't have a mode after all that, give up. */ | ||
427 | if (!mode_dev->panel_fixed_mode) { | ||
428 | dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); | ||
429 | goto failed_find; | ||
430 | } | ||
431 | |||
432 | out: | ||
433 | drm_sysfs_connector_add(connector); | ||
434 | return; | ||
435 | |||
436 | failed_find: | ||
437 | dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); | ||
438 | if (psb_intel_encoder->ddc_bus) | ||
439 | psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); | ||
440 | |||
441 | /* failed_ddc: */ | ||
442 | |||
443 | drm_encoder_cleanup(encoder); | ||
444 | drm_connector_cleanup(connector); | ||
445 | kfree(psb_intel_connector); | ||
446 | failed_connector: | ||
447 | kfree(psb_intel_encoder); | ||
448 | } | ||
449 | |||
diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c new file mode 100644 index 00000000000..94025693bae --- /dev/null +++ b/drivers/gpu/drm/gma500/power.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2009-2011, Intel Corporation. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice (including the next | ||
13 | * paragraph) shall be included in all copies or substantial portions of the | ||
14 | * Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | * SOFTWARE. | ||
23 | * | ||
24 | * Authors: | ||
25 | * Benjamin Defnet <benjamin.r.defnet@intel.com> | ||
26 | * Rajesh Poornachandran <rajesh.poornachandran@intel.com> | ||
27 | * Massively reworked | ||
28 | * Alan Cox <alan@linux.intel.com> | ||
29 | */ | ||
30 | |||
31 | #include "power.h" | ||
32 | #include "psb_drv.h" | ||
33 | #include "psb_reg.h" | ||
34 | #include "psb_intel_reg.h" | ||
35 | #include <linux/mutex.h> | ||
36 | #include <linux/pm_runtime.h> | ||
37 | |||
38 | static struct mutex power_mutex; /* Serialize power ops */ | ||
39 | static spinlock_t power_ctrl_lock; /* Serialize power claim */ | ||
40 | |||
41 | /** | ||
42 | * gma_power_init - initialise power manager | ||
43 | * @dev: our device | ||
44 | * | ||
45 | * Set up for power management tracking of our hardware. | ||
46 | */ | ||
47 | void gma_power_init(struct drm_device *dev) | ||
48 | { | ||
49 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
50 | |||
51 | /* FIXME: Move APM/OSPM base into relevant device code */ | ||
52 | dev_priv->apm_base = dev_priv->apm_reg & 0xffff; | ||
53 | dev_priv->ospm_base &= 0xffff; | ||
54 | |||
55 | dev_priv->display_power = true; /* We start active */ | ||
56 | dev_priv->display_count = 0; /* Currently no users */ | ||
57 | dev_priv->suspended = false; /* And not suspended */ | ||
58 | spin_lock_init(&power_ctrl_lock); | ||
59 | mutex_init(&power_mutex); | ||
60 | |||
61 | dev_priv->ops->init_pm(dev); | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * gma_power_uninit - end power manager | ||
66 | * @dev: device to end for | ||
67 | * | ||
68 | * Undo the effects of gma_power_init | ||
69 | */ | ||
70 | void gma_power_uninit(struct drm_device *dev) | ||
71 | { | ||
72 | pm_runtime_disable(&dev->pdev->dev); | ||
73 | pm_runtime_set_suspended(&dev->pdev->dev); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * gma_suspend_display - suspend the display logic | ||
78 | * @dev: our DRM device | ||
79 | * | ||
80 | * Suspend the display logic of the graphics interface | ||
81 | */ | ||
82 | static void gma_suspend_display(struct drm_device *dev) | ||
83 | { | ||
84 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
85 | |||
86 | if (dev_priv->suspended) | ||
87 | return; | ||
88 | dev_priv->ops->save_regs(dev); | ||
89 | dev_priv->ops->power_down(dev); | ||
90 | dev_priv->display_power = false; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * gma_resume_display - resume display side logic | ||
95 | * | ||
96 | * Resume the display hardware restoring state and enabling | ||
97 | * as necessary. | ||
98 | */ | ||
99 | static void gma_resume_display(struct pci_dev *pdev) | ||
100 | { | ||
101 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
102 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
103 | |||
104 | if (dev_priv->suspended == false) | ||
105 | return; | ||
106 | |||
107 | /* turn on the display power island */ | ||
108 | dev_priv->ops->power_up(dev); | ||
109 | dev_priv->suspended = false; | ||
110 | dev_priv->display_power = true; | ||
111 | |||
112 | PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); | ||
113 | pci_write_config_word(pdev, PSB_GMCH_CTRL, | ||
114 | dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); | ||
115 | dev_priv->ops->restore_regs(dev); | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * gma_suspend_pci - suspend PCI side | ||
120 | * @pdev: PCI device | ||
121 | * | ||
122 | * Perform the suspend processing on our PCI device state | ||
123 | */ | ||
124 | static void gma_suspend_pci(struct pci_dev *pdev) | ||
125 | { | ||
126 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
127 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
128 | int bsm, vbt; | ||
129 | |||
130 | if (dev_priv->suspended) | ||
131 | return; | ||
132 | |||
133 | pci_save_state(pdev); | ||
134 | pci_read_config_dword(pdev, 0x5C, &bsm); | ||
135 | dev_priv->saveBSM = bsm; | ||
136 | pci_read_config_dword(pdev, 0xFC, &vbt); | ||
137 | dev_priv->saveVBT = vbt; | ||
138 | pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr); | ||
139 | pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data); | ||
140 | |||
141 | pci_disable_device(pdev); | ||
142 | pci_set_power_state(pdev, PCI_D3hot); | ||
143 | |||
144 | dev_priv->suspended = true; | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * gma_resume_pci - resume helper | ||
149 | * @dev: our PCI device | ||
150 | * | ||
151 | * Perform the resume processing on our PCI device state - rewrite | ||
152 | * register state and re-enable the PCI device | ||
153 | */ | ||
154 | static bool gma_resume_pci(struct pci_dev *pdev) | ||
155 | { | ||
156 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
157 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
158 | int ret; | ||
159 | |||
160 | if (!dev_priv->suspended) | ||
161 | return true; | ||
162 | |||
163 | pci_set_power_state(pdev, PCI_D0); | ||
164 | pci_restore_state(pdev); | ||
165 | pci_write_config_dword(pdev, 0x5c, dev_priv->saveBSM); | ||
166 | pci_write_config_dword(pdev, 0xFC, dev_priv->saveVBT); | ||
167 | /* restoring MSI address and data in PCIx space */ | ||
168 | pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr); | ||
169 | pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data); | ||
170 | ret = pci_enable_device(pdev); | ||
171 | |||
172 | if (ret != 0) | ||
173 | dev_err(&pdev->dev, "pci_enable failed: %d\n", ret); | ||
174 | else | ||
175 | dev_priv->suspended = false; | ||
176 | return !dev_priv->suspended; | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * gma_power_suspend - bus callback for suspend | ||
181 | * @pdev: our PCI device | ||
182 | * @state: suspend type | ||
183 | * | ||
184 | * Called back by the PCI layer during a suspend of the system. We | ||
185 | * perform the necessary shut down steps and save enough state that | ||
186 | * we can undo this when resume is called. | ||
187 | */ | ||
188 | int gma_power_suspend(struct device *_dev) | ||
189 | { | ||
190 | struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev); | ||
191 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
192 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
193 | |||
194 | mutex_lock(&power_mutex); | ||
195 | if (!dev_priv->suspended) { | ||
196 | if (dev_priv->display_count) { | ||
197 | mutex_unlock(&power_mutex); | ||
198 | return -EBUSY; | ||
199 | } | ||
200 | psb_irq_uninstall(dev); | ||
201 | gma_suspend_display(dev); | ||
202 | gma_suspend_pci(pdev); | ||
203 | } | ||
204 | mutex_unlock(&power_mutex); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * gma_power_resume - resume power | ||
210 | * @pdev: PCI device | ||
211 | * | ||
212 | * Resume the PCI side of the graphics and then the displays | ||
213 | */ | ||
214 | int gma_power_resume(struct device *_dev) | ||
215 | { | ||
216 | struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev); | ||
217 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
218 | |||
219 | mutex_lock(&power_mutex); | ||
220 | gma_resume_pci(pdev); | ||
221 | gma_resume_display(pdev); | ||
222 | psb_irq_preinstall(dev); | ||
223 | psb_irq_postinstall(dev); | ||
224 | mutex_unlock(&power_mutex); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * gma_power_is_on - returne true if power is on | ||
230 | * @dev: our DRM device | ||
231 | * | ||
232 | * Returns true if the display island power is on at this moment | ||
233 | */ | ||
234 | bool gma_power_is_on(struct drm_device *dev) | ||
235 | { | ||
236 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
237 | return dev_priv->display_power; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * gma_power_begin - begin requiring power | ||
242 | * @dev: our DRM device | ||
243 | * @force_on: true to force power on | ||
244 | * | ||
245 | * Begin an action that requires the display power island is enabled. | ||
246 | * We refcount the islands. | ||
247 | */ | ||
248 | bool gma_power_begin(struct drm_device *dev, bool force_on) | ||
249 | { | ||
250 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
251 | int ret; | ||
252 | unsigned long flags; | ||
253 | |||
254 | spin_lock_irqsave(&power_ctrl_lock, flags); | ||
255 | /* Power already on ? */ | ||
256 | if (dev_priv->display_power) { | ||
257 | dev_priv->display_count++; | ||
258 | pm_runtime_get(&dev->pdev->dev); | ||
259 | spin_unlock_irqrestore(&power_ctrl_lock, flags); | ||
260 | return true; | ||
261 | } | ||
262 | if (force_on == false) | ||
263 | goto out_false; | ||
264 | |||
265 | /* Ok power up needed */ | ||
266 | ret = gma_resume_pci(dev->pdev); | ||
267 | if (ret == 0) { | ||
268 | psb_irq_preinstall(dev); | ||
269 | psb_irq_postinstall(dev); | ||
270 | pm_runtime_get(&dev->pdev->dev); | ||
271 | dev_priv->display_count++; | ||
272 | spin_unlock_irqrestore(&power_ctrl_lock, flags); | ||
273 | return true; | ||
274 | } | ||
275 | out_false: | ||
276 | spin_unlock_irqrestore(&power_ctrl_lock, flags); | ||
277 | return false; | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * gma_power_end - end use of power | ||
282 | * @dev: Our DRM device | ||
283 | * | ||
284 | * Indicate that one of our gma_power_begin() requested periods when | ||
285 | * the diplay island power is needed has completed. | ||
286 | */ | ||
287 | void gma_power_end(struct drm_device *dev) | ||
288 | { | ||
289 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
290 | unsigned long flags; | ||
291 | spin_lock_irqsave(&power_ctrl_lock, flags); | ||
292 | dev_priv->display_count--; | ||
293 | WARN_ON(dev_priv->display_count < 0); | ||
294 | spin_unlock_irqrestore(&power_ctrl_lock, flags); | ||
295 | pm_runtime_put(&dev->pdev->dev); | ||
296 | } | ||
297 | |||
298 | int psb_runtime_suspend(struct device *dev) | ||
299 | { | ||
300 | return gma_power_suspend(dev); | ||
301 | } | ||
302 | |||
303 | int psb_runtime_resume(struct device *dev) | ||
304 | { | ||
305 | return gma_power_resume(dev);; | ||
306 | } | ||
307 | |||
308 | int psb_runtime_idle(struct device *dev) | ||
309 | { | ||
310 | struct drm_device *drmdev = pci_get_drvdata(to_pci_dev(dev)); | ||
311 | struct drm_psb_private *dev_priv = drmdev->dev_private; | ||
312 | if (dev_priv->display_count) | ||
313 | return 0; | ||
314 | else | ||
315 | return 1; | ||
316 | } | ||
diff --git a/drivers/gpu/drm/gma500/power.h b/drivers/gpu/drm/gma500/power.h new file mode 100644 index 00000000000..1969d2ecb32 --- /dev/null +++ b/drivers/gpu/drm/gma500/power.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2009-2011, Intel Corporation. | ||
3 | * All Rights Reserved. | ||
4 | |||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice (including the next | ||
13 | * paragraph) shall be included in all copies or substantial portions of the | ||
14 | * Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | * SOFTWARE. | ||
23 | * | ||
24 | * Authors: | ||
25 | * Benjamin Defnet <benjamin.r.defnet@intel.com> | ||
26 | * Rajesh Poornachandran <rajesh.poornachandran@intel.com> | ||
27 | * Massively reworked | ||
28 | * Alan Cox <alan@linux.intel.com> | ||
29 | */ | ||
30 | #ifndef _PSB_POWERMGMT_H_ | ||
31 | #define _PSB_POWERMGMT_H_ | ||
32 | |||
33 | #include <linux/pci.h> | ||
34 | #include <drm/drmP.h> | ||
35 | |||
36 | void gma_power_init(struct drm_device *dev); | ||
37 | void gma_power_uninit(struct drm_device *dev); | ||
38 | |||
39 | /* | ||
40 | * The kernel bus power management will call these functions | ||
41 | */ | ||
42 | int gma_power_suspend(struct device *dev); | ||
43 | int gma_power_resume(struct device *dev); | ||
44 | |||
45 | /* | ||
46 | * These are the functions the driver should use to wrap all hw access | ||
47 | * (i.e. register reads and writes) | ||
48 | */ | ||
49 | bool gma_power_begin(struct drm_device *dev, bool force); | ||
50 | void gma_power_end(struct drm_device *dev); | ||
51 | |||
52 | /* | ||
53 | * Use this function to do an instantaneous check for if the hw is on. | ||
54 | * Only use this in cases where you know the mutex is already held such | ||
55 | * as in irq install/uninstall and you need to | ||
56 | * prevent a deadlock situation. Otherwise use gma_power_begin(). | ||
57 | */ | ||
58 | bool gma_power_is_on(struct drm_device *dev); | ||
59 | |||
60 | /* | ||
61 | * GFX-Runtime PM callbacks | ||
62 | */ | ||
63 | int psb_runtime_suspend(struct device *dev); | ||
64 | int psb_runtime_resume(struct device *dev); | ||
65 | int psb_runtime_idle(struct device *dev); | ||
66 | |||
67 | #endif /*_PSB_POWERMGMT_H_*/ | ||
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c new file mode 100644 index 00000000000..e5f5906172b --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_device.c | |||
@@ -0,0 +1,328 @@ | |||
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 | #include <linux/backlight.h> | ||
21 | #include <drm/drmP.h> | ||
22 | #include <drm/drm.h> | ||
23 | #include "gma_drm.h" | ||
24 | #include "psb_drv.h" | ||
25 | #include "psb_reg.h" | ||
26 | #include "psb_intel_reg.h" | ||
27 | #include "intel_bios.h" | ||
28 | |||
29 | |||
30 | static int psb_output_init(struct drm_device *dev) | ||
31 | { | ||
32 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
33 | psb_intel_lvds_init(dev, &dev_priv->mode_dev); | ||
34 | psb_intel_sdvo_init(dev, SDVOB); | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
39 | |||
40 | /* | ||
41 | * Poulsbo Backlight Interfaces | ||
42 | */ | ||
43 | |||
44 | #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ | ||
45 | #define BLC_PWM_FREQ_CALC_CONSTANT 32 | ||
46 | #define MHz 1000000 | ||
47 | |||
48 | #define PSB_BLC_PWM_PRECISION_FACTOR 10 | ||
49 | #define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE | ||
50 | #define PSB_BLC_MIN_PWM_REG_FREQ 0x2 | ||
51 | |||
52 | #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) | ||
53 | #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) | ||
54 | |||
55 | static int psb_brightness; | ||
56 | static struct backlight_device *psb_backlight_device; | ||
57 | |||
58 | static int psb_get_brightness(struct backlight_device *bd) | ||
59 | { | ||
60 | /* return locally cached var instead of HW read (due to DPST etc.) */ | ||
61 | /* FIXME: ideally return actual value in case firmware fiddled with | ||
62 | it */ | ||
63 | return psb_brightness; | ||
64 | } | ||
65 | |||
66 | |||
67 | static int psb_backlight_setup(struct drm_device *dev) | ||
68 | { | ||
69 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
70 | unsigned long core_clock; | ||
71 | /* u32 bl_max_freq; */ | ||
72 | /* unsigned long value; */ | ||
73 | u16 bl_max_freq; | ||
74 | uint32_t value; | ||
75 | uint32_t blc_pwm_precision_factor; | ||
76 | |||
77 | /* get bl_max_freq and pol from dev_priv*/ | ||
78 | if (!dev_priv->lvds_bl) { | ||
79 | dev_err(dev->dev, "Has no valid LVDS backlight info\n"); | ||
80 | return -ENOENT; | ||
81 | } | ||
82 | bl_max_freq = dev_priv->lvds_bl->freq; | ||
83 | blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR; | ||
84 | |||
85 | core_clock = dev_priv->core_freq; | ||
86 | |||
87 | value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; | ||
88 | value *= blc_pwm_precision_factor; | ||
89 | value /= bl_max_freq; | ||
90 | value /= blc_pwm_precision_factor; | ||
91 | |||
92 | if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ || | ||
93 | value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ) | ||
94 | return -ERANGE; | ||
95 | else { | ||
96 | value &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; | ||
97 | REG_WRITE(BLC_PWM_CTL, | ||
98 | (value << PSB_BACKLIGHT_PWM_CTL_SHIFT) | (value)); | ||
99 | } | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int psb_set_brightness(struct backlight_device *bd) | ||
104 | { | ||
105 | struct drm_device *dev = bl_get_data(psb_backlight_device); | ||
106 | int level = bd->props.brightness; | ||
107 | |||
108 | /* Percentage 1-100% being valid */ | ||
109 | if (level < 1) | ||
110 | level = 1; | ||
111 | |||
112 | psb_intel_lvds_set_brightness(dev, level); | ||
113 | psb_brightness = level; | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static const struct backlight_ops psb_ops = { | ||
118 | .get_brightness = psb_get_brightness, | ||
119 | .update_status = psb_set_brightness, | ||
120 | }; | ||
121 | |||
122 | static int psb_backlight_init(struct drm_device *dev) | ||
123 | { | ||
124 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
125 | int ret; | ||
126 | struct backlight_properties props; | ||
127 | |||
128 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
129 | props.max_brightness = 100; | ||
130 | props.type = BACKLIGHT_PLATFORM; | ||
131 | |||
132 | psb_backlight_device = backlight_device_register("psb-bl", | ||
133 | NULL, (void *)dev, &psb_ops, &props); | ||
134 | if (IS_ERR(psb_backlight_device)) | ||
135 | return PTR_ERR(psb_backlight_device); | ||
136 | |||
137 | ret = psb_backlight_setup(dev); | ||
138 | if (ret < 0) { | ||
139 | backlight_device_unregister(psb_backlight_device); | ||
140 | psb_backlight_device = NULL; | ||
141 | return ret; | ||
142 | } | ||
143 | psb_backlight_device->props.brightness = 100; | ||
144 | psb_backlight_device->props.max_brightness = 100; | ||
145 | backlight_update_status(psb_backlight_device); | ||
146 | dev_priv->backlight_device = psb_backlight_device; | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | #endif | ||
151 | |||
152 | /* | ||
153 | * Provide the Poulsbo specific chip logic and low level methods | ||
154 | * for power management | ||
155 | */ | ||
156 | |||
157 | static void psb_init_pm(struct drm_device *dev) | ||
158 | { | ||
159 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
160 | |||
161 | u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL); | ||
162 | gating &= ~3; /* Disable 2D clock gating */ | ||
163 | gating |= 1; | ||
164 | PSB_WSGX32(gating, PSB_CR_CLKGATECTL); | ||
165 | PSB_RSGX32(PSB_CR_CLKGATECTL); | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * psb_save_display_registers - save registers lost on suspend | ||
170 | * @dev: our DRM device | ||
171 | * | ||
172 | * Save the state we need in order to be able to restore the interface | ||
173 | * upon resume from suspend | ||
174 | */ | ||
175 | static int psb_save_display_registers(struct drm_device *dev) | ||
176 | { | ||
177 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
178 | struct drm_crtc *crtc; | ||
179 | struct drm_connector *connector; | ||
180 | |||
181 | /* Display arbitration control + watermarks */ | ||
182 | dev_priv->saveDSPARB = PSB_RVDC32(DSPARB); | ||
183 | dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1); | ||
184 | dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2); | ||
185 | dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3); | ||
186 | dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4); | ||
187 | dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5); | ||
188 | dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6); | ||
189 | dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT); | ||
190 | |||
191 | /* Save crtc and output state */ | ||
192 | mutex_lock(&dev->mode_config.mutex); | ||
193 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
194 | if (drm_helper_crtc_in_use(crtc)) | ||
195 | crtc->funcs->save(crtc); | ||
196 | } | ||
197 | |||
198 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) | ||
199 | connector->funcs->save(connector); | ||
200 | |||
201 | mutex_unlock(&dev->mode_config.mutex); | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * psb_restore_display_registers - restore lost register state | ||
207 | * @dev: our DRM device | ||
208 | * | ||
209 | * Restore register state that was lost during suspend and resume. | ||
210 | */ | ||
211 | static int psb_restore_display_registers(struct drm_device *dev) | ||
212 | { | ||
213 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
214 | struct drm_crtc *crtc; | ||
215 | struct drm_connector *connector; | ||
216 | |||
217 | /* Display arbitration + watermarks */ | ||
218 | PSB_WVDC32(dev_priv->saveDSPARB, DSPARB); | ||
219 | PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1); | ||
220 | PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2); | ||
221 | PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3); | ||
222 | PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4); | ||
223 | PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5); | ||
224 | PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6); | ||
225 | PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT); | ||
226 | |||
227 | /*make sure VGA plane is off. it initializes to on after reset!*/ | ||
228 | PSB_WVDC32(0x80000000, VGACNTRL); | ||
229 | |||
230 | mutex_lock(&dev->mode_config.mutex); | ||
231 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
232 | if (drm_helper_crtc_in_use(crtc)) | ||
233 | crtc->funcs->restore(crtc); | ||
234 | |||
235 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) | ||
236 | connector->funcs->restore(connector); | ||
237 | |||
238 | mutex_unlock(&dev->mode_config.mutex); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int psb_power_down(struct drm_device *dev) | ||
243 | { | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int psb_power_up(struct drm_device *dev) | ||
248 | { | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static void psb_get_core_freq(struct drm_device *dev) | ||
253 | { | ||
254 | uint32_t clock; | ||
255 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | ||
256 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
257 | |||
258 | /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/ | ||
259 | /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/ | ||
260 | |||
261 | pci_write_config_dword(pci_root, 0xD0, 0xD0050300); | ||
262 | pci_read_config_dword(pci_root, 0xD4, &clock); | ||
263 | pci_dev_put(pci_root); | ||
264 | |||
265 | switch (clock & 0x07) { | ||
266 | case 0: | ||
267 | dev_priv->core_freq = 100; | ||
268 | break; | ||
269 | case 1: | ||
270 | dev_priv->core_freq = 133; | ||
271 | break; | ||
272 | case 2: | ||
273 | dev_priv->core_freq = 150; | ||
274 | break; | ||
275 | case 3: | ||
276 | dev_priv->core_freq = 178; | ||
277 | break; | ||
278 | case 4: | ||
279 | dev_priv->core_freq = 200; | ||
280 | break; | ||
281 | case 5: | ||
282 | case 6: | ||
283 | case 7: | ||
284 | dev_priv->core_freq = 266; | ||
285 | default: | ||
286 | dev_priv->core_freq = 0; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | static int psb_chip_setup(struct drm_device *dev) | ||
291 | { | ||
292 | psb_get_core_freq(dev); | ||
293 | gma_intel_setup_gmbus(dev); | ||
294 | gma_intel_opregion_init(dev); | ||
295 | psb_intel_init_bios(dev); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static void psb_chip_teardown(struct drm_device *dev) | ||
300 | { | ||
301 | gma_intel_teardown_gmbus(dev); | ||
302 | } | ||
303 | |||
304 | const struct psb_ops psb_chip_ops = { | ||
305 | .name = "Poulsbo", | ||
306 | .accel_2d = 1, | ||
307 | .pipes = 2, | ||
308 | .crtcs = 2, | ||
309 | .sgx_offset = PSB_SGX_OFFSET, | ||
310 | .chip_setup = psb_chip_setup, | ||
311 | .chip_teardown = psb_chip_teardown, | ||
312 | |||
313 | .crtc_helper = &psb_intel_helper_funcs, | ||
314 | .crtc_funcs = &psb_intel_crtc_funcs, | ||
315 | |||
316 | .output_init = psb_output_init, | ||
317 | |||
318 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
319 | .backlight_init = psb_backlight_init, | ||
320 | #endif | ||
321 | |||
322 | .init_pm = psb_init_pm, | ||
323 | .save_regs = psb_save_display_registers, | ||
324 | .restore_regs = psb_restore_display_registers, | ||
325 | .power_down = psb_power_down, | ||
326 | .power_up = psb_power_up, | ||
327 | }; | ||
328 | |||
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c new file mode 100644 index 00000000000..f14768f2b36 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_drv.c | |||
@@ -0,0 +1,703 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007-2011, Intel Corporation. | ||
3 | * All Rights Reserved. | ||
4 | * Copyright (c) 2008, Tungsten Graphics, Inc. Cedar Park, TX., USA. | ||
5 | * All Rights Reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | * | ||
20 | **************************************************************************/ | ||
21 | |||
22 | #include <drm/drmP.h> | ||
23 | #include <drm/drm.h> | ||
24 | #include "gma_drm.h" | ||
25 | #include "psb_drv.h" | ||
26 | #include "framebuffer.h" | ||
27 | #include "psb_reg.h" | ||
28 | #include "psb_intel_reg.h" | ||
29 | #include "intel_bios.h" | ||
30 | #include "mid_bios.h" | ||
31 | #include <drm/drm_pciids.h> | ||
32 | #include "power.h" | ||
33 | #include <linux/cpu.h> | ||
34 | #include <linux/notifier.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/pm_runtime.h> | ||
37 | #include <acpi/video.h> | ||
38 | #include <linux/module.h> | ||
39 | |||
40 | static int drm_psb_trap_pagefaults; | ||
41 | |||
42 | static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | ||
43 | |||
44 | MODULE_PARM_DESC(trap_pagefaults, "Error and reset on MMU pagefaults"); | ||
45 | module_param_named(trap_pagefaults, drm_psb_trap_pagefaults, int, 0600); | ||
46 | |||
47 | |||
48 | static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { | ||
49 | { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, | ||
50 | { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, | ||
51 | #if defined(CONFIG_DRM_GMA600) | ||
52 | { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
53 | { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
54 | { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
55 | { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
56 | { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
57 | { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
58 | { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
59 | { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
60 | /* Atom E620 */ | ||
61 | { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | ||
62 | #endif | ||
63 | #if defined(CONFIG_DRM_GMA3600) | ||
64 | { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | ||
65 | { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | ||
66 | { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | ||
67 | { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | ||
68 | { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | ||
69 | { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | ||
70 | { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | ||
71 | { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | ||
72 | #endif | ||
73 | { 0, 0, 0} | ||
74 | }; | ||
75 | MODULE_DEVICE_TABLE(pci, pciidlist); | ||
76 | |||
77 | /* | ||
78 | * Standard IOCTLs. | ||
79 | */ | ||
80 | |||
81 | #define DRM_IOCTL_PSB_ADB \ | ||
82 | DRM_IOWR(DRM_GMA_ADB + DRM_COMMAND_BASE, uint32_t) | ||
83 | #define DRM_IOCTL_PSB_MODE_OPERATION \ | ||
84 | DRM_IOWR(DRM_GMA_MODE_OPERATION + DRM_COMMAND_BASE, \ | ||
85 | struct drm_psb_mode_operation_arg) | ||
86 | #define DRM_IOCTL_PSB_STOLEN_MEMORY \ | ||
87 | DRM_IOWR(DRM_GMA_STOLEN_MEMORY + DRM_COMMAND_BASE, \ | ||
88 | struct drm_psb_stolen_memory_arg) | ||
89 | #define DRM_IOCTL_PSB_GAMMA \ | ||
90 | DRM_IOWR(DRM_GMA_GAMMA + DRM_COMMAND_BASE, \ | ||
91 | struct drm_psb_dpst_lut_arg) | ||
92 | #define DRM_IOCTL_PSB_DPST_BL \ | ||
93 | DRM_IOWR(DRM_GMA_DPST_BL + DRM_COMMAND_BASE, \ | ||
94 | uint32_t) | ||
95 | #define DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID \ | ||
96 | DRM_IOWR(DRM_GMA_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \ | ||
97 | struct drm_psb_get_pipe_from_crtc_id_arg) | ||
98 | #define DRM_IOCTL_PSB_GEM_CREATE \ | ||
99 | DRM_IOWR(DRM_GMA_GEM_CREATE + DRM_COMMAND_BASE, \ | ||
100 | struct drm_psb_gem_create) | ||
101 | #define DRM_IOCTL_PSB_GEM_MMAP \ | ||
102 | DRM_IOWR(DRM_GMA_GEM_MMAP + DRM_COMMAND_BASE, \ | ||
103 | struct drm_psb_gem_mmap) | ||
104 | |||
105 | static int psb_adb_ioctl(struct drm_device *dev, void *data, | ||
106 | struct drm_file *file_priv); | ||
107 | static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, | ||
108 | struct drm_file *file_priv); | ||
109 | static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, | ||
110 | struct drm_file *file_priv); | ||
111 | static int psb_gamma_ioctl(struct drm_device *dev, void *data, | ||
112 | struct drm_file *file_priv); | ||
113 | static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, | ||
114 | struct drm_file *file_priv); | ||
115 | |||
116 | #define PSB_IOCTL_DEF(ioctl, func, flags) \ | ||
117 | [DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func} | ||
118 | |||
119 | static struct drm_ioctl_desc psb_ioctls[] = { | ||
120 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_ADB, psb_adb_ioctl, DRM_AUTH), | ||
121 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_MODE_OPERATION, psb_mode_operation_ioctl, | ||
122 | DRM_AUTH), | ||
123 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_STOLEN_MEMORY, psb_stolen_memory_ioctl, | ||
124 | DRM_AUTH), | ||
125 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GAMMA, psb_gamma_ioctl, DRM_AUTH), | ||
126 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH), | ||
127 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID, | ||
128 | psb_intel_get_pipe_from_crtc_id, 0), | ||
129 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_CREATE, psb_gem_create_ioctl, | ||
130 | DRM_UNLOCKED | DRM_AUTH), | ||
131 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_MMAP, psb_gem_mmap_ioctl, | ||
132 | DRM_UNLOCKED | DRM_AUTH), | ||
133 | }; | ||
134 | |||
135 | static void psb_lastclose(struct drm_device *dev) | ||
136 | { | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | static void psb_do_takedown(struct drm_device *dev) | ||
141 | { | ||
142 | } | ||
143 | |||
144 | static int psb_do_init(struct drm_device *dev) | ||
145 | { | ||
146 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
147 | struct psb_gtt *pg = &dev_priv->gtt; | ||
148 | |||
149 | uint32_t stolen_gtt; | ||
150 | |||
151 | int ret = -ENOMEM; | ||
152 | |||
153 | if (pg->mmu_gatt_start & 0x0FFFFFFF) { | ||
154 | dev_err(dev->dev, "Gatt must be 256M aligned. This is a bug.\n"); | ||
155 | ret = -EINVAL; | ||
156 | goto out_err; | ||
157 | } | ||
158 | |||
159 | |||
160 | stolen_gtt = (pg->stolen_size >> PAGE_SHIFT) * 4; | ||
161 | stolen_gtt = (stolen_gtt + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
162 | stolen_gtt = | ||
163 | (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; | ||
164 | |||
165 | dev_priv->gatt_free_offset = pg->mmu_gatt_start + | ||
166 | (stolen_gtt << PAGE_SHIFT) * 1024; | ||
167 | |||
168 | if (1 || drm_debug) { | ||
169 | uint32_t core_id = PSB_RSGX32(PSB_CR_CORE_ID); | ||
170 | uint32_t core_rev = PSB_RSGX32(PSB_CR_CORE_REVISION); | ||
171 | DRM_INFO("SGX core id = 0x%08x\n", core_id); | ||
172 | DRM_INFO("SGX core rev major = 0x%02x, minor = 0x%02x\n", | ||
173 | (core_rev & _PSB_CC_REVISION_MAJOR_MASK) >> | ||
174 | _PSB_CC_REVISION_MAJOR_SHIFT, | ||
175 | (core_rev & _PSB_CC_REVISION_MINOR_MASK) >> | ||
176 | _PSB_CC_REVISION_MINOR_SHIFT); | ||
177 | DRM_INFO | ||
178 | ("SGX core rev maintenance = 0x%02x, designer = 0x%02x\n", | ||
179 | (core_rev & _PSB_CC_REVISION_MAINTENANCE_MASK) >> | ||
180 | _PSB_CC_REVISION_MAINTENANCE_SHIFT, | ||
181 | (core_rev & _PSB_CC_REVISION_DESIGNER_MASK) >> | ||
182 | _PSB_CC_REVISION_DESIGNER_SHIFT); | ||
183 | } | ||
184 | |||
185 | |||
186 | spin_lock_init(&dev_priv->irqmask_lock); | ||
187 | spin_lock_init(&dev_priv->lock_2d); | ||
188 | |||
189 | PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK0); | ||
190 | PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK1); | ||
191 | PSB_RSGX32(PSB_CR_BIF_BANK1); | ||
192 | PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_MMU_ER_MASK, | ||
193 | PSB_CR_BIF_CTRL); | ||
194 | psb_spank(dev_priv); | ||
195 | |||
196 | /* mmu_gatt ?? */ | ||
197 | PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); | ||
198 | return 0; | ||
199 | out_err: | ||
200 | psb_do_takedown(dev); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | static int psb_driver_unload(struct drm_device *dev) | ||
205 | { | ||
206 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
207 | |||
208 | /* Kill vblank etc here */ | ||
209 | |||
210 | gma_backlight_exit(dev); | ||
211 | |||
212 | psb_modeset_cleanup(dev); | ||
213 | |||
214 | if (dev_priv) { | ||
215 | psb_lid_timer_takedown(dev_priv); | ||
216 | gma_intel_opregion_exit(dev); | ||
217 | |||
218 | if (dev_priv->ops->chip_teardown) | ||
219 | dev_priv->ops->chip_teardown(dev); | ||
220 | psb_do_takedown(dev); | ||
221 | |||
222 | |||
223 | if (dev_priv->pf_pd) { | ||
224 | psb_mmu_free_pagedir(dev_priv->pf_pd); | ||
225 | dev_priv->pf_pd = NULL; | ||
226 | } | ||
227 | if (dev_priv->mmu) { | ||
228 | struct psb_gtt *pg = &dev_priv->gtt; | ||
229 | |||
230 | down_read(&pg->sem); | ||
231 | psb_mmu_remove_pfn_sequence( | ||
232 | psb_mmu_get_default_pd | ||
233 | (dev_priv->mmu), | ||
234 | pg->mmu_gatt_start, | ||
235 | dev_priv->vram_stolen_size >> PAGE_SHIFT); | ||
236 | up_read(&pg->sem); | ||
237 | psb_mmu_driver_takedown(dev_priv->mmu); | ||
238 | dev_priv->mmu = NULL; | ||
239 | } | ||
240 | psb_gtt_takedown(dev); | ||
241 | if (dev_priv->scratch_page) { | ||
242 | __free_page(dev_priv->scratch_page); | ||
243 | dev_priv->scratch_page = NULL; | ||
244 | } | ||
245 | if (dev_priv->vdc_reg) { | ||
246 | iounmap(dev_priv->vdc_reg); | ||
247 | dev_priv->vdc_reg = NULL; | ||
248 | } | ||
249 | if (dev_priv->sgx_reg) { | ||
250 | iounmap(dev_priv->sgx_reg); | ||
251 | dev_priv->sgx_reg = NULL; | ||
252 | } | ||
253 | |||
254 | kfree(dev_priv); | ||
255 | dev->dev_private = NULL; | ||
256 | |||
257 | /*destroy VBT data*/ | ||
258 | psb_intel_destroy_bios(dev); | ||
259 | } | ||
260 | |||
261 | gma_power_uninit(dev); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | |||
267 | static int psb_driver_load(struct drm_device *dev, unsigned long chipset) | ||
268 | { | ||
269 | struct drm_psb_private *dev_priv; | ||
270 | unsigned long resource_start; | ||
271 | struct psb_gtt *pg; | ||
272 | unsigned long irqflags; | ||
273 | int ret = -ENOMEM; | ||
274 | uint32_t tt_pages; | ||
275 | struct drm_connector *connector; | ||
276 | struct psb_intel_encoder *psb_intel_encoder; | ||
277 | |||
278 | dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); | ||
279 | if (dev_priv == NULL) | ||
280 | return -ENOMEM; | ||
281 | |||
282 | dev_priv->ops = (struct psb_ops *)chipset; | ||
283 | dev_priv->dev = dev; | ||
284 | dev->dev_private = (void *) dev_priv; | ||
285 | |||
286 | if (!IS_PSB(dev)) { | ||
287 | if (pci_enable_msi(dev->pdev)) | ||
288 | dev_warn(dev->dev, "Enabling MSI failed!\n"); | ||
289 | } | ||
290 | |||
291 | dev_priv->num_pipe = dev_priv->ops->pipes; | ||
292 | |||
293 | resource_start = pci_resource_start(dev->pdev, PSB_MMIO_RESOURCE); | ||
294 | |||
295 | dev_priv->vdc_reg = | ||
296 | ioremap(resource_start + PSB_VDC_OFFSET, PSB_VDC_SIZE); | ||
297 | if (!dev_priv->vdc_reg) | ||
298 | goto out_err; | ||
299 | |||
300 | dev_priv->sgx_reg = ioremap(resource_start + dev_priv->ops->sgx_offset, | ||
301 | PSB_SGX_SIZE); | ||
302 | if (!dev_priv->sgx_reg) | ||
303 | goto out_err; | ||
304 | |||
305 | ret = dev_priv->ops->chip_setup(dev); | ||
306 | if (ret) | ||
307 | goto out_err; | ||
308 | |||
309 | /* Init OSPM support */ | ||
310 | gma_power_init(dev); | ||
311 | |||
312 | ret = -ENOMEM; | ||
313 | |||
314 | dev_priv->scratch_page = alloc_page(GFP_DMA32 | __GFP_ZERO); | ||
315 | if (!dev_priv->scratch_page) | ||
316 | goto out_err; | ||
317 | |||
318 | set_pages_uc(dev_priv->scratch_page, 1); | ||
319 | |||
320 | ret = psb_gtt_init(dev, 0); | ||
321 | if (ret) | ||
322 | goto out_err; | ||
323 | |||
324 | dev_priv->mmu = psb_mmu_driver_init((void *)0, | ||
325 | drm_psb_trap_pagefaults, 0, | ||
326 | dev_priv); | ||
327 | if (!dev_priv->mmu) | ||
328 | goto out_err; | ||
329 | |||
330 | pg = &dev_priv->gtt; | ||
331 | |||
332 | tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ? | ||
333 | (pg->gatt_pages) : PSB_TT_PRIV0_PLIMIT; | ||
334 | |||
335 | |||
336 | dev_priv->pf_pd = psb_mmu_alloc_pd(dev_priv->mmu, 1, 0); | ||
337 | if (!dev_priv->pf_pd) | ||
338 | goto out_err; | ||
339 | |||
340 | psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0); | ||
341 | psb_mmu_set_pd_context(dev_priv->pf_pd, 1); | ||
342 | |||
343 | ret = psb_do_init(dev); | ||
344 | if (ret) | ||
345 | return ret; | ||
346 | |||
347 | PSB_WSGX32(0x20000000, PSB_CR_PDS_EXEC_BASE); | ||
348 | PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE); | ||
349 | |||
350 | /* igd_opregion_init(&dev_priv->opregion_dev); */ | ||
351 | acpi_video_register(); | ||
352 | if (dev_priv->lid_state) | ||
353 | psb_lid_timer_init(dev_priv); | ||
354 | |||
355 | ret = drm_vblank_init(dev, dev_priv->num_pipe); | ||
356 | if (ret) | ||
357 | goto out_err; | ||
358 | |||
359 | /* | ||
360 | * Install interrupt handlers prior to powering off SGX or else we will | ||
361 | * crash. | ||
362 | */ | ||
363 | dev_priv->vdc_irq_mask = 0; | ||
364 | dev_priv->pipestat[0] = 0; | ||
365 | dev_priv->pipestat[1] = 0; | ||
366 | dev_priv->pipestat[2] = 0; | ||
367 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
368 | PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); | ||
369 | PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); | ||
370 | PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R); | ||
371 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
372 | if (IS_PSB(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) | ||
373 | drm_irq_install(dev); | ||
374 | |||
375 | dev->vblank_disable_allowed = 1; | ||
376 | |||
377 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | ||
378 | |||
379 | dev->driver->get_vblank_counter = psb_get_vblank_counter; | ||
380 | |||
381 | psb_modeset_init(dev); | ||
382 | psb_fbdev_init(dev); | ||
383 | drm_kms_helper_poll_init(dev); | ||
384 | |||
385 | /* Only add backlight support if we have LVDS output */ | ||
386 | list_for_each_entry(connector, &dev->mode_config.connector_list, | ||
387 | head) { | ||
388 | psb_intel_encoder = psb_intel_attached_encoder(connector); | ||
389 | |||
390 | switch (psb_intel_encoder->type) { | ||
391 | case INTEL_OUTPUT_LVDS: | ||
392 | case INTEL_OUTPUT_MIPI: | ||
393 | ret = gma_backlight_init(dev); | ||
394 | break; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | if (ret) | ||
399 | return ret; | ||
400 | #if 0 | ||
401 | /*enable runtime pm at last*/ | ||
402 | pm_runtime_enable(&dev->pdev->dev); | ||
403 | pm_runtime_set_active(&dev->pdev->dev); | ||
404 | #endif | ||
405 | /*Intel drm driver load is done, continue doing pvr load*/ | ||
406 | return 0; | ||
407 | out_err: | ||
408 | psb_driver_unload(dev); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | int psb_driver_device_is_agp(struct drm_device *dev) | ||
413 | { | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static inline void get_brightness(struct backlight_device *bd) | ||
418 | { | ||
419 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
420 | if (bd) { | ||
421 | bd->props.brightness = bd->ops->get_brightness(bd); | ||
422 | backlight_update_status(bd); | ||
423 | } | ||
424 | #endif | ||
425 | } | ||
426 | |||
427 | static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, | ||
428 | struct drm_file *file_priv) | ||
429 | { | ||
430 | struct drm_psb_private *dev_priv = psb_priv(dev); | ||
431 | uint32_t *arg = data; | ||
432 | |||
433 | dev_priv->blc_adj2 = *arg; | ||
434 | get_brightness(dev_priv->backlight_device); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int psb_adb_ioctl(struct drm_device *dev, void *data, | ||
439 | struct drm_file *file_priv) | ||
440 | { | ||
441 | struct drm_psb_private *dev_priv = psb_priv(dev); | ||
442 | uint32_t *arg = data; | ||
443 | |||
444 | dev_priv->blc_adj1 = *arg; | ||
445 | get_brightness(dev_priv->backlight_device); | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int psb_gamma_ioctl(struct drm_device *dev, void *data, | ||
450 | struct drm_file *file_priv) | ||
451 | { | ||
452 | struct drm_psb_dpst_lut_arg *lut_arg = data; | ||
453 | struct drm_mode_object *obj; | ||
454 | struct drm_crtc *crtc; | ||
455 | struct drm_connector *connector; | ||
456 | struct psb_intel_crtc *psb_intel_crtc; | ||
457 | int i = 0; | ||
458 | int32_t obj_id; | ||
459 | |||
460 | obj_id = lut_arg->output_id; | ||
461 | obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR); | ||
462 | if (!obj) { | ||
463 | dev_dbg(dev->dev, "Invalid Connector object.\n"); | ||
464 | return -EINVAL; | ||
465 | } | ||
466 | |||
467 | connector = obj_to_connector(obj); | ||
468 | crtc = connector->encoder->crtc; | ||
469 | psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
470 | |||
471 | for (i = 0; i < 256; i++) | ||
472 | psb_intel_crtc->lut_adj[i] = lut_arg->lut[i]; | ||
473 | |||
474 | psb_intel_crtc_load_lut(crtc); | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, | ||
480 | struct drm_file *file_priv) | ||
481 | { | ||
482 | uint32_t obj_id; | ||
483 | uint16_t op; | ||
484 | struct drm_mode_modeinfo *umode; | ||
485 | struct drm_display_mode *mode = NULL; | ||
486 | struct drm_psb_mode_operation_arg *arg; | ||
487 | struct drm_mode_object *obj; | ||
488 | struct drm_connector *connector; | ||
489 | struct drm_connector_helper_funcs *connector_funcs; | ||
490 | int ret = 0; | ||
491 | int resp = MODE_OK; | ||
492 | |||
493 | arg = (struct drm_psb_mode_operation_arg *)data; | ||
494 | obj_id = arg->obj_id; | ||
495 | op = arg->operation; | ||
496 | |||
497 | switch (op) { | ||
498 | case PSB_MODE_OPERATION_MODE_VALID: | ||
499 | umode = &arg->mode; | ||
500 | |||
501 | mutex_lock(&dev->mode_config.mutex); | ||
502 | |||
503 | obj = drm_mode_object_find(dev, obj_id, | ||
504 | DRM_MODE_OBJECT_CONNECTOR); | ||
505 | if (!obj) { | ||
506 | ret = -EINVAL; | ||
507 | goto mode_op_out; | ||
508 | } | ||
509 | |||
510 | connector = obj_to_connector(obj); | ||
511 | |||
512 | mode = drm_mode_create(dev); | ||
513 | if (!mode) { | ||
514 | ret = -ENOMEM; | ||
515 | goto mode_op_out; | ||
516 | } | ||
517 | |||
518 | /* drm_crtc_convert_umode(mode, umode); */ | ||
519 | { | ||
520 | mode->clock = umode->clock; | ||
521 | mode->hdisplay = umode->hdisplay; | ||
522 | mode->hsync_start = umode->hsync_start; | ||
523 | mode->hsync_end = umode->hsync_end; | ||
524 | mode->htotal = umode->htotal; | ||
525 | mode->hskew = umode->hskew; | ||
526 | mode->vdisplay = umode->vdisplay; | ||
527 | mode->vsync_start = umode->vsync_start; | ||
528 | mode->vsync_end = umode->vsync_end; | ||
529 | mode->vtotal = umode->vtotal; | ||
530 | mode->vscan = umode->vscan; | ||
531 | mode->vrefresh = umode->vrefresh; | ||
532 | mode->flags = umode->flags; | ||
533 | mode->type = umode->type; | ||
534 | strncpy(mode->name, umode->name, DRM_DISPLAY_MODE_LEN); | ||
535 | mode->name[DRM_DISPLAY_MODE_LEN-1] = 0; | ||
536 | } | ||
537 | |||
538 | connector_funcs = (struct drm_connector_helper_funcs *) | ||
539 | connector->helper_private; | ||
540 | |||
541 | if (connector_funcs->mode_valid) { | ||
542 | resp = connector_funcs->mode_valid(connector, mode); | ||
543 | arg->data = resp; | ||
544 | } | ||
545 | |||
546 | /*do some clean up work*/ | ||
547 | if (mode) | ||
548 | drm_mode_destroy(dev, mode); | ||
549 | mode_op_out: | ||
550 | mutex_unlock(&dev->mode_config.mutex); | ||
551 | return ret; | ||
552 | |||
553 | default: | ||
554 | dev_dbg(dev->dev, "Unsupported psb mode operation\n"); | ||
555 | return -EOPNOTSUPP; | ||
556 | } | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, | ||
562 | struct drm_file *file_priv) | ||
563 | { | ||
564 | struct drm_psb_private *dev_priv = psb_priv(dev); | ||
565 | struct drm_psb_stolen_memory_arg *arg = data; | ||
566 | |||
567 | arg->base = dev_priv->stolen_base; | ||
568 | arg->size = dev_priv->vram_stolen_size; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int psb_driver_open(struct drm_device *dev, struct drm_file *priv) | ||
574 | { | ||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static void psb_driver_close(struct drm_device *dev, struct drm_file *priv) | ||
579 | { | ||
580 | } | ||
581 | |||
582 | static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, | ||
583 | unsigned long arg) | ||
584 | { | ||
585 | struct drm_file *file_priv = filp->private_data; | ||
586 | struct drm_device *dev = file_priv->minor->dev; | ||
587 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
588 | static unsigned int runtime_allowed; | ||
589 | |||
590 | if (runtime_allowed == 1 && dev_priv->is_lvds_on) { | ||
591 | runtime_allowed++; | ||
592 | pm_runtime_allow(&dev->pdev->dev); | ||
593 | dev_priv->rpm_enabled = 1; | ||
594 | } | ||
595 | return drm_ioctl(filp, cmd, arg); | ||
596 | /* FIXME: do we need to wrap the other side of this */ | ||
597 | } | ||
598 | |||
599 | |||
600 | /* When a client dies: | ||
601 | * - Check for and clean up flipped page state | ||
602 | */ | ||
603 | void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv) | ||
604 | { | ||
605 | } | ||
606 | |||
607 | static void psb_remove(struct pci_dev *pdev) | ||
608 | { | ||
609 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
610 | drm_put_dev(dev); | ||
611 | } | ||
612 | |||
613 | static const struct dev_pm_ops psb_pm_ops = { | ||
614 | .resume = gma_power_resume, | ||
615 | .suspend = gma_power_suspend, | ||
616 | .runtime_suspend = psb_runtime_suspend, | ||
617 | .runtime_resume = psb_runtime_resume, | ||
618 | .runtime_idle = psb_runtime_idle, | ||
619 | }; | ||
620 | |||
621 | static struct vm_operations_struct psb_gem_vm_ops = { | ||
622 | .fault = psb_gem_fault, | ||
623 | .open = drm_gem_vm_open, | ||
624 | .close = drm_gem_vm_close, | ||
625 | }; | ||
626 | |||
627 | static const struct file_operations psb_gem_fops = { | ||
628 | .owner = THIS_MODULE, | ||
629 | .open = drm_open, | ||
630 | .release = drm_release, | ||
631 | .unlocked_ioctl = psb_unlocked_ioctl, | ||
632 | .mmap = drm_gem_mmap, | ||
633 | .poll = drm_poll, | ||
634 | .fasync = drm_fasync, | ||
635 | .read = drm_read, | ||
636 | }; | ||
637 | |||
638 | static struct drm_driver driver = { | ||
639 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | \ | ||
640 | DRIVER_IRQ_VBL | DRIVER_MODESET | DRIVER_GEM , | ||
641 | .load = psb_driver_load, | ||
642 | .unload = psb_driver_unload, | ||
643 | |||
644 | .ioctls = psb_ioctls, | ||
645 | .num_ioctls = DRM_ARRAY_SIZE(psb_ioctls), | ||
646 | .device_is_agp = psb_driver_device_is_agp, | ||
647 | .irq_preinstall = psb_irq_preinstall, | ||
648 | .irq_postinstall = psb_irq_postinstall, | ||
649 | .irq_uninstall = psb_irq_uninstall, | ||
650 | .irq_handler = psb_irq_handler, | ||
651 | .enable_vblank = psb_enable_vblank, | ||
652 | .disable_vblank = psb_disable_vblank, | ||
653 | .get_vblank_counter = psb_get_vblank_counter, | ||
654 | .lastclose = psb_lastclose, | ||
655 | .open = psb_driver_open, | ||
656 | .preclose = psb_driver_preclose, | ||
657 | .postclose = psb_driver_close, | ||
658 | .reclaim_buffers = drm_core_reclaim_buffers, | ||
659 | |||
660 | .gem_init_object = psb_gem_init_object, | ||
661 | .gem_free_object = psb_gem_free_object, | ||
662 | .gem_vm_ops = &psb_gem_vm_ops, | ||
663 | .dumb_create = psb_gem_dumb_create, | ||
664 | .dumb_map_offset = psb_gem_dumb_map_gtt, | ||
665 | .dumb_destroy = psb_gem_dumb_destroy, | ||
666 | .fops = &psb_gem_fops, | ||
667 | .name = DRIVER_NAME, | ||
668 | .desc = DRIVER_DESC, | ||
669 | .date = PSB_DRM_DRIVER_DATE, | ||
670 | .major = PSB_DRM_DRIVER_MAJOR, | ||
671 | .minor = PSB_DRM_DRIVER_MINOR, | ||
672 | .patchlevel = PSB_DRM_DRIVER_PATCHLEVEL | ||
673 | }; | ||
674 | |||
675 | static struct pci_driver psb_pci_driver = { | ||
676 | .name = DRIVER_NAME, | ||
677 | .id_table = pciidlist, | ||
678 | .probe = psb_probe, | ||
679 | .remove = psb_remove, | ||
680 | .driver.pm = &psb_pm_ops, | ||
681 | }; | ||
682 | |||
683 | static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
684 | { | ||
685 | return drm_get_pci_dev(pdev, ent, &driver); | ||
686 | } | ||
687 | |||
688 | static int __init psb_init(void) | ||
689 | { | ||
690 | return drm_pci_init(&driver, &psb_pci_driver); | ||
691 | } | ||
692 | |||
693 | static void __exit psb_exit(void) | ||
694 | { | ||
695 | drm_pci_exit(&driver, &psb_pci_driver); | ||
696 | } | ||
697 | |||
698 | late_initcall(psb_init); | ||
699 | module_exit(psb_exit); | ||
700 | |||
701 | MODULE_AUTHOR("Alan Cox <alan@linux.intel.com> and others"); | ||
702 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
703 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h new file mode 100644 index 00000000000..eb1568a0da9 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_drv.h | |||
@@ -0,0 +1,956 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007-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 | #ifndef _PSB_DRV_H_ | ||
21 | #define _PSB_DRV_H_ | ||
22 | |||
23 | #include <linux/kref.h> | ||
24 | |||
25 | #include <drm/drmP.h> | ||
26 | #include "drm_global.h" | ||
27 | #include "gem_glue.h" | ||
28 | #include "gma_drm.h" | ||
29 | #include "psb_reg.h" | ||
30 | #include "psb_intel_drv.h" | ||
31 | #include "gtt.h" | ||
32 | #include "power.h" | ||
33 | #include "oaktrail.h" | ||
34 | |||
35 | /* Append new drm mode definition here, align with libdrm definition */ | ||
36 | #define DRM_MODE_SCALE_NO_SCALE 2 | ||
37 | |||
38 | enum { | ||
39 | CHIP_PSB_8108 = 0, /* Poulsbo */ | ||
40 | CHIP_PSB_8109 = 1, /* Poulsbo */ | ||
41 | CHIP_MRST_4100 = 2, /* Moorestown/Oaktrail */ | ||
42 | CHIP_MFLD_0130 = 3, /* Medfield */ | ||
43 | }; | ||
44 | |||
45 | #define IS_PSB(dev) (((dev)->pci_device & 0xfffe) == 0x8108) | ||
46 | #define IS_MRST(dev) (((dev)->pci_device & 0xfffc) == 0x4100) | ||
47 | #define IS_MFLD(dev) (((dev)->pci_device & 0xfff8) == 0x0130) | ||
48 | |||
49 | /* | ||
50 | * Driver definitions | ||
51 | */ | ||
52 | |||
53 | #define DRIVER_NAME "gma500" | ||
54 | #define DRIVER_DESC "DRM driver for the Intel GMA500" | ||
55 | |||
56 | #define PSB_DRM_DRIVER_DATE "2011-06-06" | ||
57 | #define PSB_DRM_DRIVER_MAJOR 1 | ||
58 | #define PSB_DRM_DRIVER_MINOR 0 | ||
59 | #define PSB_DRM_DRIVER_PATCHLEVEL 0 | ||
60 | |||
61 | /* | ||
62 | * Hardware offsets | ||
63 | */ | ||
64 | #define PSB_VDC_OFFSET 0x00000000 | ||
65 | #define PSB_VDC_SIZE 0x000080000 | ||
66 | #define MRST_MMIO_SIZE 0x0000C0000 | ||
67 | #define MDFLD_MMIO_SIZE 0x000100000 | ||
68 | #define PSB_SGX_SIZE 0x8000 | ||
69 | #define PSB_SGX_OFFSET 0x00040000 | ||
70 | #define MRST_SGX_OFFSET 0x00080000 | ||
71 | /* | ||
72 | * PCI resource identifiers | ||
73 | */ | ||
74 | #define PSB_MMIO_RESOURCE 0 | ||
75 | #define PSB_GATT_RESOURCE 2 | ||
76 | #define PSB_GTT_RESOURCE 3 | ||
77 | /* | ||
78 | * PCI configuration | ||
79 | */ | ||
80 | #define PSB_GMCH_CTRL 0x52 | ||
81 | #define PSB_BSM 0x5C | ||
82 | #define _PSB_GMCH_ENABLED 0x4 | ||
83 | #define PSB_PGETBL_CTL 0x2020 | ||
84 | #define _PSB_PGETBL_ENABLED 0x00000001 | ||
85 | #define PSB_SGX_2D_SLAVE_PORT 0x4000 | ||
86 | |||
87 | /* To get rid of */ | ||
88 | #define PSB_TT_PRIV0_LIMIT (256*1024*1024) | ||
89 | #define PSB_TT_PRIV0_PLIMIT (PSB_TT_PRIV0_LIMIT >> PAGE_SHIFT) | ||
90 | |||
91 | /* | ||
92 | * SGX side MMU definitions (these can probably go) | ||
93 | */ | ||
94 | |||
95 | /* | ||
96 | * Flags for external memory type field. | ||
97 | */ | ||
98 | #define PSB_MMU_CACHED_MEMORY 0x0001 /* Bind to MMU only */ | ||
99 | #define PSB_MMU_RO_MEMORY 0x0002 /* MMU RO memory */ | ||
100 | #define PSB_MMU_WO_MEMORY 0x0004 /* MMU WO memory */ | ||
101 | /* | ||
102 | * PTE's and PDE's | ||
103 | */ | ||
104 | #define PSB_PDE_MASK 0x003FFFFF | ||
105 | #define PSB_PDE_SHIFT 22 | ||
106 | #define PSB_PTE_SHIFT 12 | ||
107 | /* | ||
108 | * Cache control | ||
109 | */ | ||
110 | #define PSB_PTE_VALID 0x0001 /* PTE / PDE valid */ | ||
111 | #define PSB_PTE_WO 0x0002 /* Write only */ | ||
112 | #define PSB_PTE_RO 0x0004 /* Read only */ | ||
113 | #define PSB_PTE_CACHED 0x0008 /* CPU cache coherent */ | ||
114 | |||
115 | /* | ||
116 | * VDC registers and bits | ||
117 | */ | ||
118 | #define PSB_MSVDX_CLOCKGATING 0x2064 | ||
119 | #define PSB_TOPAZ_CLOCKGATING 0x2068 | ||
120 | #define PSB_HWSTAM 0x2098 | ||
121 | #define PSB_INSTPM 0x20C0 | ||
122 | #define PSB_INT_IDENTITY_R 0x20A4 | ||
123 | #define _MDFLD_PIPEC_EVENT_FLAG (1<<2) | ||
124 | #define _MDFLD_PIPEC_VBLANK_FLAG (1<<3) | ||
125 | #define _PSB_DPST_PIPEB_FLAG (1<<4) | ||
126 | #define _MDFLD_PIPEB_EVENT_FLAG (1<<4) | ||
127 | #define _PSB_VSYNC_PIPEB_FLAG (1<<5) | ||
128 | #define _PSB_DPST_PIPEA_FLAG (1<<6) | ||
129 | #define _PSB_PIPEA_EVENT_FLAG (1<<6) | ||
130 | #define _PSB_VSYNC_PIPEA_FLAG (1<<7) | ||
131 | #define _MDFLD_MIPIA_FLAG (1<<16) | ||
132 | #define _MDFLD_MIPIC_FLAG (1<<17) | ||
133 | #define _PSB_IRQ_SGX_FLAG (1<<18) | ||
134 | #define _PSB_IRQ_MSVDX_FLAG (1<<19) | ||
135 | #define _LNC_IRQ_TOPAZ_FLAG (1<<20) | ||
136 | |||
137 | #define _PSB_PIPE_EVENT_FLAG (_PSB_VSYNC_PIPEA_FLAG | \ | ||
138 | _PSB_VSYNC_PIPEB_FLAG) | ||
139 | |||
140 | /* This flag includes all the display IRQ bits excepts the vblank irqs. */ | ||
141 | #define _MDFLD_DISP_ALL_IRQ_FLAG (_MDFLD_PIPEC_EVENT_FLAG | \ | ||
142 | _MDFLD_PIPEB_EVENT_FLAG | \ | ||
143 | _PSB_PIPEA_EVENT_FLAG | \ | ||
144 | _PSB_VSYNC_PIPEA_FLAG | \ | ||
145 | _MDFLD_MIPIA_FLAG | \ | ||
146 | _MDFLD_MIPIC_FLAG) | ||
147 | #define PSB_INT_IDENTITY_R 0x20A4 | ||
148 | #define PSB_INT_MASK_R 0x20A8 | ||
149 | #define PSB_INT_ENABLE_R 0x20A0 | ||
150 | |||
151 | #define _PSB_MMU_ER_MASK 0x0001FF00 | ||
152 | #define _PSB_MMU_ER_HOST (1 << 16) | ||
153 | #define GPIOA 0x5010 | ||
154 | #define GPIOB 0x5014 | ||
155 | #define GPIOC 0x5018 | ||
156 | #define GPIOD 0x501c | ||
157 | #define GPIOE 0x5020 | ||
158 | #define GPIOF 0x5024 | ||
159 | #define GPIOG 0x5028 | ||
160 | #define GPIOH 0x502c | ||
161 | #define GPIO_CLOCK_DIR_MASK (1 << 0) | ||
162 | #define GPIO_CLOCK_DIR_IN (0 << 1) | ||
163 | #define GPIO_CLOCK_DIR_OUT (1 << 1) | ||
164 | #define GPIO_CLOCK_VAL_MASK (1 << 2) | ||
165 | #define GPIO_CLOCK_VAL_OUT (1 << 3) | ||
166 | #define GPIO_CLOCK_VAL_IN (1 << 4) | ||
167 | #define GPIO_CLOCK_PULLUP_DISABLE (1 << 5) | ||
168 | #define GPIO_DATA_DIR_MASK (1 << 8) | ||
169 | #define GPIO_DATA_DIR_IN (0 << 9) | ||
170 | #define GPIO_DATA_DIR_OUT (1 << 9) | ||
171 | #define GPIO_DATA_VAL_MASK (1 << 10) | ||
172 | #define GPIO_DATA_VAL_OUT (1 << 11) | ||
173 | #define GPIO_DATA_VAL_IN (1 << 12) | ||
174 | #define GPIO_DATA_PULLUP_DISABLE (1 << 13) | ||
175 | |||
176 | #define VCLK_DIVISOR_VGA0 0x6000 | ||
177 | #define VCLK_DIVISOR_VGA1 0x6004 | ||
178 | #define VCLK_POST_DIV 0x6010 | ||
179 | |||
180 | #define PSB_COMM_2D (PSB_ENGINE_2D << 4) | ||
181 | #define PSB_COMM_3D (PSB_ENGINE_3D << 4) | ||
182 | #define PSB_COMM_TA (PSB_ENGINE_TA << 4) | ||
183 | #define PSB_COMM_HP (PSB_ENGINE_HP << 4) | ||
184 | #define PSB_COMM_USER_IRQ (1024 >> 2) | ||
185 | #define PSB_COMM_USER_IRQ_LOST (PSB_COMM_USER_IRQ + 1) | ||
186 | #define PSB_COMM_FW (2048 >> 2) | ||
187 | |||
188 | #define PSB_UIRQ_VISTEST 1 | ||
189 | #define PSB_UIRQ_OOM_REPLY 2 | ||
190 | #define PSB_UIRQ_FIRE_TA_REPLY 3 | ||
191 | #define PSB_UIRQ_FIRE_RASTER_REPLY 4 | ||
192 | |||
193 | #define PSB_2D_SIZE (256*1024*1024) | ||
194 | #define PSB_MAX_RELOC_PAGES 1024 | ||
195 | |||
196 | #define PSB_LOW_REG_OFFS 0x0204 | ||
197 | #define PSB_HIGH_REG_OFFS 0x0600 | ||
198 | |||
199 | #define PSB_NUM_VBLANKS 2 | ||
200 | |||
201 | |||
202 | #define PSB_2D_SIZE (256*1024*1024) | ||
203 | #define PSB_MAX_RELOC_PAGES 1024 | ||
204 | |||
205 | #define PSB_LOW_REG_OFFS 0x0204 | ||
206 | #define PSB_HIGH_REG_OFFS 0x0600 | ||
207 | |||
208 | #define PSB_NUM_VBLANKS 2 | ||
209 | #define PSB_WATCHDOG_DELAY (DRM_HZ * 2) | ||
210 | #define PSB_LID_DELAY (DRM_HZ / 10) | ||
211 | |||
212 | #define MDFLD_PNW_B0 0x04 | ||
213 | #define MDFLD_PNW_C0 0x08 | ||
214 | |||
215 | #define MDFLD_DSR_2D_3D_0 (1 << 0) | ||
216 | #define MDFLD_DSR_2D_3D_2 (1 << 1) | ||
217 | #define MDFLD_DSR_CURSOR_0 (1 << 2) | ||
218 | #define MDFLD_DSR_CURSOR_2 (1 << 3) | ||
219 | #define MDFLD_DSR_OVERLAY_0 (1 << 4) | ||
220 | #define MDFLD_DSR_OVERLAY_2 (1 << 5) | ||
221 | #define MDFLD_DSR_MIPI_CONTROL (1 << 6) | ||
222 | #define MDFLD_DSR_DAMAGE_MASK_0 ((1 << 0) | (1 << 2) | (1 << 4)) | ||
223 | #define MDFLD_DSR_DAMAGE_MASK_2 ((1 << 1) | (1 << 3) | (1 << 5)) | ||
224 | #define MDFLD_DSR_2D_3D (MDFLD_DSR_2D_3D_0 | MDFLD_DSR_2D_3D_2) | ||
225 | |||
226 | #define MDFLD_DSR_RR 45 | ||
227 | #define MDFLD_DPU_ENABLE (1 << 31) | ||
228 | #define MDFLD_DSR_FULLSCREEN (1 << 30) | ||
229 | #define MDFLD_DSR_DELAY (DRM_HZ / MDFLD_DSR_RR) | ||
230 | |||
231 | #define PSB_PWR_STATE_ON 1 | ||
232 | #define PSB_PWR_STATE_OFF 2 | ||
233 | |||
234 | #define PSB_PMPOLICY_NOPM 0 | ||
235 | #define PSB_PMPOLICY_CLOCKGATING 1 | ||
236 | #define PSB_PMPOLICY_POWERDOWN 2 | ||
237 | |||
238 | #define PSB_PMSTATE_POWERUP 0 | ||
239 | #define PSB_PMSTATE_CLOCKGATED 1 | ||
240 | #define PSB_PMSTATE_POWERDOWN 2 | ||
241 | #define PSB_PCIx_MSI_ADDR_LOC 0x94 | ||
242 | #define PSB_PCIx_MSI_DATA_LOC 0x98 | ||
243 | |||
244 | /* Medfield crystal settings */ | ||
245 | #define KSEL_CRYSTAL_19 1 | ||
246 | #define KSEL_BYPASS_19 5 | ||
247 | #define KSEL_BYPASS_25 6 | ||
248 | #define KSEL_BYPASS_83_100 7 | ||
249 | |||
250 | struct opregion_header; | ||
251 | struct opregion_acpi; | ||
252 | struct opregion_swsci; | ||
253 | struct opregion_asle; | ||
254 | |||
255 | struct psb_intel_opregion { | ||
256 | struct opregion_header *header; | ||
257 | struct opregion_acpi *acpi; | ||
258 | struct opregion_swsci *swsci; | ||
259 | struct opregion_asle *asle; | ||
260 | int enabled; | ||
261 | }; | ||
262 | |||
263 | struct sdvo_device_mapping { | ||
264 | u8 initialized; | ||
265 | u8 dvo_port; | ||
266 | u8 slave_addr; | ||
267 | u8 dvo_wiring; | ||
268 | u8 i2c_pin; | ||
269 | u8 i2c_speed; | ||
270 | u8 ddc_pin; | ||
271 | }; | ||
272 | |||
273 | struct intel_gmbus { | ||
274 | struct i2c_adapter adapter; | ||
275 | struct i2c_adapter *force_bit; | ||
276 | u32 reg0; | ||
277 | }; | ||
278 | |||
279 | struct psb_ops; | ||
280 | |||
281 | #define PSB_NUM_PIPE 3 | ||
282 | |||
283 | struct drm_psb_private { | ||
284 | struct drm_device *dev; | ||
285 | const struct psb_ops *ops; | ||
286 | |||
287 | struct psb_gtt gtt; | ||
288 | |||
289 | /* GTT Memory manager */ | ||
290 | struct psb_gtt_mm *gtt_mm; | ||
291 | struct page *scratch_page; | ||
292 | u32 *gtt_map; | ||
293 | uint32_t stolen_base; | ||
294 | void *vram_addr; | ||
295 | unsigned long vram_stolen_size; | ||
296 | int gtt_initialized; | ||
297 | u16 gmch_ctrl; /* Saved GTT setup */ | ||
298 | u32 pge_ctl; | ||
299 | |||
300 | struct mutex gtt_mutex; | ||
301 | struct resource *gtt_mem; /* Our PCI resource */ | ||
302 | |||
303 | struct psb_mmu_driver *mmu; | ||
304 | struct psb_mmu_pd *pf_pd; | ||
305 | |||
306 | /* | ||
307 | * Register base | ||
308 | */ | ||
309 | |||
310 | uint8_t *sgx_reg; | ||
311 | uint8_t *vdc_reg; | ||
312 | uint32_t gatt_free_offset; | ||
313 | |||
314 | /* | ||
315 | * Fencing / irq. | ||
316 | */ | ||
317 | |||
318 | uint32_t vdc_irq_mask; | ||
319 | uint32_t pipestat[PSB_NUM_PIPE]; | ||
320 | |||
321 | spinlock_t irqmask_lock; | ||
322 | |||
323 | /* | ||
324 | * Power | ||
325 | */ | ||
326 | |||
327 | bool suspended; | ||
328 | bool display_power; | ||
329 | int display_count; | ||
330 | |||
331 | /* | ||
332 | * Modesetting | ||
333 | */ | ||
334 | struct psb_intel_mode_device mode_dev; | ||
335 | |||
336 | struct drm_crtc *plane_to_crtc_mapping[PSB_NUM_PIPE]; | ||
337 | struct drm_crtc *pipe_to_crtc_mapping[PSB_NUM_PIPE]; | ||
338 | uint32_t num_pipe; | ||
339 | |||
340 | /* | ||
341 | * OSPM info (Power management base) (can go ?) | ||
342 | */ | ||
343 | uint32_t ospm_base; | ||
344 | |||
345 | /* | ||
346 | * Sizes info | ||
347 | */ | ||
348 | |||
349 | u32 fuse_reg_value; | ||
350 | u32 video_device_fuse; | ||
351 | |||
352 | /* PCI revision ID for B0:D2:F0 */ | ||
353 | uint8_t platform_rev_id; | ||
354 | |||
355 | /* gmbus */ | ||
356 | struct intel_gmbus *gmbus; | ||
357 | |||
358 | /* Used by SDVO */ | ||
359 | int crt_ddc_pin; | ||
360 | /* FIXME: The mappings should be parsed from bios but for now we can | ||
361 | pretend there are no mappings available */ | ||
362 | struct sdvo_device_mapping sdvo_mappings[2]; | ||
363 | u32 hotplug_supported_mask; | ||
364 | struct drm_property *broadcast_rgb_property; | ||
365 | struct drm_property *force_audio_property; | ||
366 | |||
367 | /* | ||
368 | * LVDS info | ||
369 | */ | ||
370 | int backlight_duty_cycle; /* restore backlight to this value */ | ||
371 | bool panel_wants_dither; | ||
372 | struct drm_display_mode *panel_fixed_mode; | ||
373 | struct drm_display_mode *lfp_lvds_vbt_mode; | ||
374 | struct drm_display_mode *sdvo_lvds_vbt_mode; | ||
375 | |||
376 | struct bdb_lvds_backlight *lvds_bl; /* LVDS backlight info from VBT */ | ||
377 | struct psb_intel_i2c_chan *lvds_i2c_bus; /* FIXME: Remove this? */ | ||
378 | |||
379 | /* Feature bits from the VBIOS */ | ||
380 | unsigned int int_tv_support:1; | ||
381 | unsigned int lvds_dither:1; | ||
382 | unsigned int lvds_vbt:1; | ||
383 | unsigned int int_crt_support:1; | ||
384 | unsigned int lvds_use_ssc:1; | ||
385 | int lvds_ssc_freq; | ||
386 | bool is_lvds_on; | ||
387 | bool is_mipi_on; | ||
388 | u32 mipi_ctrl_display; | ||
389 | |||
390 | unsigned int core_freq; | ||
391 | uint32_t iLVDS_enable; | ||
392 | |||
393 | /* Runtime PM state */ | ||
394 | int rpm_enabled; | ||
395 | |||
396 | /* MID specific */ | ||
397 | struct oaktrail_vbt vbt_data; | ||
398 | struct oaktrail_gct_data gct_data; | ||
399 | |||
400 | /* MIPI Panel type etc */ | ||
401 | int panel_id; | ||
402 | bool dual_mipi; /* dual display - DPI & DBI */ | ||
403 | bool dpi_panel_on; /* The DPI panel power is on */ | ||
404 | bool dpi_panel_on2; /* The DPI panel power is on */ | ||
405 | bool dbi_panel_on; /* The DBI panel power is on */ | ||
406 | bool dbi_panel_on2; /* The DBI panel power is on */ | ||
407 | u32 dsr_fb_update; /* DSR FB update counter */ | ||
408 | |||
409 | /* Moorestown HDMI state */ | ||
410 | struct oaktrail_hdmi_dev *hdmi_priv; | ||
411 | |||
412 | /* Moorestown pipe config register value cache */ | ||
413 | uint32_t pipeconf; | ||
414 | uint32_t pipeconf1; | ||
415 | uint32_t pipeconf2; | ||
416 | |||
417 | /* Moorestown plane control register value cache */ | ||
418 | uint32_t dspcntr; | ||
419 | uint32_t dspcntr1; | ||
420 | uint32_t dspcntr2; | ||
421 | |||
422 | /* Moorestown MM backlight cache */ | ||
423 | uint8_t saveBKLTCNT; | ||
424 | uint8_t saveBKLTREQ; | ||
425 | uint8_t saveBKLTBRTL; | ||
426 | |||
427 | /* | ||
428 | * Register state | ||
429 | */ | ||
430 | uint32_t saveDSPACNTR; | ||
431 | uint32_t saveDSPBCNTR; | ||
432 | uint32_t savePIPEACONF; | ||
433 | uint32_t savePIPEBCONF; | ||
434 | uint32_t savePIPEASRC; | ||
435 | uint32_t savePIPEBSRC; | ||
436 | uint32_t saveFPA0; | ||
437 | uint32_t saveFPA1; | ||
438 | uint32_t saveDPLL_A; | ||
439 | uint32_t saveDPLL_A_MD; | ||
440 | uint32_t saveHTOTAL_A; | ||
441 | uint32_t saveHBLANK_A; | ||
442 | uint32_t saveHSYNC_A; | ||
443 | uint32_t saveVTOTAL_A; | ||
444 | uint32_t saveVBLANK_A; | ||
445 | uint32_t saveVSYNC_A; | ||
446 | uint32_t saveDSPASTRIDE; | ||
447 | uint32_t saveDSPASIZE; | ||
448 | uint32_t saveDSPAPOS; | ||
449 | uint32_t saveDSPABASE; | ||
450 | uint32_t saveDSPASURF; | ||
451 | uint32_t saveDSPASTATUS; | ||
452 | uint32_t saveFPB0; | ||
453 | uint32_t saveFPB1; | ||
454 | uint32_t saveDPLL_B; | ||
455 | uint32_t saveDPLL_B_MD; | ||
456 | uint32_t saveHTOTAL_B; | ||
457 | uint32_t saveHBLANK_B; | ||
458 | uint32_t saveHSYNC_B; | ||
459 | uint32_t saveVTOTAL_B; | ||
460 | uint32_t saveVBLANK_B; | ||
461 | uint32_t saveVSYNC_B; | ||
462 | uint32_t saveDSPBSTRIDE; | ||
463 | uint32_t saveDSPBSIZE; | ||
464 | uint32_t saveDSPBPOS; | ||
465 | uint32_t saveDSPBBASE; | ||
466 | uint32_t saveDSPBSURF; | ||
467 | uint32_t saveDSPBSTATUS; | ||
468 | uint32_t saveVCLK_DIVISOR_VGA0; | ||
469 | uint32_t saveVCLK_DIVISOR_VGA1; | ||
470 | uint32_t saveVCLK_POST_DIV; | ||
471 | uint32_t saveVGACNTRL; | ||
472 | uint32_t saveADPA; | ||
473 | uint32_t saveLVDS; | ||
474 | uint32_t saveDVOA; | ||
475 | uint32_t saveDVOB; | ||
476 | uint32_t saveDVOC; | ||
477 | uint32_t savePP_ON; | ||
478 | uint32_t savePP_OFF; | ||
479 | uint32_t savePP_CONTROL; | ||
480 | uint32_t savePP_CYCLE; | ||
481 | uint32_t savePFIT_CONTROL; | ||
482 | uint32_t savePaletteA[256]; | ||
483 | uint32_t savePaletteB[256]; | ||
484 | uint32_t saveBLC_PWM_CTL2; | ||
485 | uint32_t saveBLC_PWM_CTL; | ||
486 | uint32_t saveCLOCKGATING; | ||
487 | uint32_t saveDSPARB; | ||
488 | uint32_t saveDSPATILEOFF; | ||
489 | uint32_t saveDSPBTILEOFF; | ||
490 | uint32_t saveDSPAADDR; | ||
491 | uint32_t saveDSPBADDR; | ||
492 | uint32_t savePFIT_AUTO_RATIOS; | ||
493 | uint32_t savePFIT_PGM_RATIOS; | ||
494 | uint32_t savePP_ON_DELAYS; | ||
495 | uint32_t savePP_OFF_DELAYS; | ||
496 | uint32_t savePP_DIVISOR; | ||
497 | uint32_t saveBSM; | ||
498 | uint32_t saveVBT; | ||
499 | uint32_t saveBCLRPAT_A; | ||
500 | uint32_t saveBCLRPAT_B; | ||
501 | uint32_t saveDSPALINOFF; | ||
502 | uint32_t saveDSPBLINOFF; | ||
503 | uint32_t savePERF_MODE; | ||
504 | uint32_t saveDSPFW1; | ||
505 | uint32_t saveDSPFW2; | ||
506 | uint32_t saveDSPFW3; | ||
507 | uint32_t saveDSPFW4; | ||
508 | uint32_t saveDSPFW5; | ||
509 | uint32_t saveDSPFW6; | ||
510 | uint32_t saveCHICKENBIT; | ||
511 | uint32_t saveDSPACURSOR_CTRL; | ||
512 | uint32_t saveDSPBCURSOR_CTRL; | ||
513 | uint32_t saveDSPACURSOR_BASE; | ||
514 | uint32_t saveDSPBCURSOR_BASE; | ||
515 | uint32_t saveDSPACURSOR_POS; | ||
516 | uint32_t saveDSPBCURSOR_POS; | ||
517 | uint32_t save_palette_a[256]; | ||
518 | uint32_t save_palette_b[256]; | ||
519 | uint32_t saveOV_OVADD; | ||
520 | uint32_t saveOV_OGAMC0; | ||
521 | uint32_t saveOV_OGAMC1; | ||
522 | uint32_t saveOV_OGAMC2; | ||
523 | uint32_t saveOV_OGAMC3; | ||
524 | uint32_t saveOV_OGAMC4; | ||
525 | uint32_t saveOV_OGAMC5; | ||
526 | uint32_t saveOVC_OVADD; | ||
527 | uint32_t saveOVC_OGAMC0; | ||
528 | uint32_t saveOVC_OGAMC1; | ||
529 | uint32_t saveOVC_OGAMC2; | ||
530 | uint32_t saveOVC_OGAMC3; | ||
531 | uint32_t saveOVC_OGAMC4; | ||
532 | uint32_t saveOVC_OGAMC5; | ||
533 | |||
534 | /* MSI reg save */ | ||
535 | uint32_t msi_addr; | ||
536 | uint32_t msi_data; | ||
537 | |||
538 | /* Medfield specific register save state */ | ||
539 | uint32_t saveHDMIPHYMISCCTL; | ||
540 | uint32_t saveHDMIB_CONTROL; | ||
541 | uint32_t saveDSPCCNTR; | ||
542 | uint32_t savePIPECCONF; | ||
543 | uint32_t savePIPECSRC; | ||
544 | uint32_t saveHTOTAL_C; | ||
545 | uint32_t saveHBLANK_C; | ||
546 | uint32_t saveHSYNC_C; | ||
547 | uint32_t saveVTOTAL_C; | ||
548 | uint32_t saveVBLANK_C; | ||
549 | uint32_t saveVSYNC_C; | ||
550 | uint32_t saveDSPCSTRIDE; | ||
551 | uint32_t saveDSPCSIZE; | ||
552 | uint32_t saveDSPCPOS; | ||
553 | uint32_t saveDSPCSURF; | ||
554 | uint32_t saveDSPCSTATUS; | ||
555 | uint32_t saveDSPCLINOFF; | ||
556 | uint32_t saveDSPCTILEOFF; | ||
557 | uint32_t saveDSPCCURSOR_CTRL; | ||
558 | uint32_t saveDSPCCURSOR_BASE; | ||
559 | uint32_t saveDSPCCURSOR_POS; | ||
560 | uint32_t save_palette_c[256]; | ||
561 | uint32_t saveOV_OVADD_C; | ||
562 | uint32_t saveOV_OGAMC0_C; | ||
563 | uint32_t saveOV_OGAMC1_C; | ||
564 | uint32_t saveOV_OGAMC2_C; | ||
565 | uint32_t saveOV_OGAMC3_C; | ||
566 | uint32_t saveOV_OGAMC4_C; | ||
567 | uint32_t saveOV_OGAMC5_C; | ||
568 | |||
569 | /* DSI register save */ | ||
570 | uint32_t saveDEVICE_READY_REG; | ||
571 | uint32_t saveINTR_EN_REG; | ||
572 | uint32_t saveDSI_FUNC_PRG_REG; | ||
573 | uint32_t saveHS_TX_TIMEOUT_REG; | ||
574 | uint32_t saveLP_RX_TIMEOUT_REG; | ||
575 | uint32_t saveTURN_AROUND_TIMEOUT_REG; | ||
576 | uint32_t saveDEVICE_RESET_REG; | ||
577 | uint32_t saveDPI_RESOLUTION_REG; | ||
578 | uint32_t saveHORIZ_SYNC_PAD_COUNT_REG; | ||
579 | uint32_t saveHORIZ_BACK_PORCH_COUNT_REG; | ||
580 | uint32_t saveHORIZ_FRONT_PORCH_COUNT_REG; | ||
581 | uint32_t saveHORIZ_ACTIVE_AREA_COUNT_REG; | ||
582 | uint32_t saveVERT_SYNC_PAD_COUNT_REG; | ||
583 | uint32_t saveVERT_BACK_PORCH_COUNT_REG; | ||
584 | uint32_t saveVERT_FRONT_PORCH_COUNT_REG; | ||
585 | uint32_t saveHIGH_LOW_SWITCH_COUNT_REG; | ||
586 | uint32_t saveINIT_COUNT_REG; | ||
587 | uint32_t saveMAX_RET_PAK_REG; | ||
588 | uint32_t saveVIDEO_FMT_REG; | ||
589 | uint32_t saveEOT_DISABLE_REG; | ||
590 | uint32_t saveLP_BYTECLK_REG; | ||
591 | uint32_t saveHS_LS_DBI_ENABLE_REG; | ||
592 | uint32_t saveTXCLKESC_REG; | ||
593 | uint32_t saveDPHY_PARAM_REG; | ||
594 | uint32_t saveMIPI_CONTROL_REG; | ||
595 | uint32_t saveMIPI; | ||
596 | uint32_t saveMIPI_C; | ||
597 | |||
598 | /* DPST register save */ | ||
599 | uint32_t saveHISTOGRAM_INT_CONTROL_REG; | ||
600 | uint32_t saveHISTOGRAM_LOGIC_CONTROL_REG; | ||
601 | uint32_t savePWM_CONTROL_LOGIC; | ||
602 | |||
603 | /* | ||
604 | * DSI info. | ||
605 | */ | ||
606 | void * dbi_dsr_info; | ||
607 | void * dbi_dpu_info; | ||
608 | void * dsi_configs[2]; | ||
609 | /* | ||
610 | * LID-Switch | ||
611 | */ | ||
612 | spinlock_t lid_lock; | ||
613 | struct timer_list lid_timer; | ||
614 | struct psb_intel_opregion opregion; | ||
615 | u32 *lid_state; | ||
616 | u32 lid_last_state; | ||
617 | |||
618 | /* | ||
619 | * Watchdog | ||
620 | */ | ||
621 | |||
622 | uint32_t apm_reg; | ||
623 | uint16_t apm_base; | ||
624 | |||
625 | /* | ||
626 | * Used for modifying backlight from | ||
627 | * xrandr -- consider removing and using HAL instead | ||
628 | */ | ||
629 | struct backlight_device *backlight_device; | ||
630 | struct drm_property *backlight_property; | ||
631 | uint32_t blc_adj1; | ||
632 | uint32_t blc_adj2; | ||
633 | |||
634 | void *fbdev; | ||
635 | |||
636 | /* 2D acceleration */ | ||
637 | spinlock_t lock_2d; | ||
638 | }; | ||
639 | |||
640 | |||
641 | /* | ||
642 | * Operations for each board type | ||
643 | */ | ||
644 | |||
645 | struct psb_ops { | ||
646 | const char *name; | ||
647 | unsigned int accel_2d:1; | ||
648 | int pipes; /* Number of output pipes */ | ||
649 | int crtcs; /* Number of CRTCs */ | ||
650 | int sgx_offset; /* Base offset of SGX device */ | ||
651 | |||
652 | /* Sub functions */ | ||
653 | struct drm_crtc_helper_funcs const *crtc_helper; | ||
654 | struct drm_crtc_funcs const *crtc_funcs; | ||
655 | |||
656 | /* Setup hooks */ | ||
657 | int (*chip_setup)(struct drm_device *dev); | ||
658 | void (*chip_teardown)(struct drm_device *dev); | ||
659 | |||
660 | /* Display management hooks */ | ||
661 | int (*output_init)(struct drm_device *dev); | ||
662 | /* Power management hooks */ | ||
663 | void (*init_pm)(struct drm_device *dev); | ||
664 | int (*save_regs)(struct drm_device *dev); | ||
665 | int (*restore_regs)(struct drm_device *dev); | ||
666 | int (*power_up)(struct drm_device *dev); | ||
667 | int (*power_down)(struct drm_device *dev); | ||
668 | |||
669 | void (*lvds_bl_power)(struct drm_device *dev, bool on); | ||
670 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
671 | /* Backlight */ | ||
672 | int (*backlight_init)(struct drm_device *dev); | ||
673 | #endif | ||
674 | int i2c_bus; /* I2C bus identifier for Moorestown */ | ||
675 | }; | ||
676 | |||
677 | |||
678 | |||
679 | struct psb_mmu_driver; | ||
680 | |||
681 | extern int drm_crtc_probe_output_modes(struct drm_device *dev, int, int); | ||
682 | extern int drm_pick_crtcs(struct drm_device *dev); | ||
683 | |||
684 | static inline struct drm_psb_private *psb_priv(struct drm_device *dev) | ||
685 | { | ||
686 | return (struct drm_psb_private *) dev->dev_private; | ||
687 | } | ||
688 | |||
689 | /* | ||
690 | * MMU stuff. | ||
691 | */ | ||
692 | |||
693 | extern struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, | ||
694 | int trap_pagefaults, | ||
695 | int invalid_type, | ||
696 | struct drm_psb_private *dev_priv); | ||
697 | extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); | ||
698 | extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver | ||
699 | *driver); | ||
700 | extern void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, uint32_t mmu_offset, | ||
701 | uint32_t gtt_start, uint32_t gtt_pages); | ||
702 | extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, | ||
703 | int trap_pagefaults, | ||
704 | int invalid_type); | ||
705 | extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); | ||
706 | extern void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot); | ||
707 | extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, | ||
708 | unsigned long address, | ||
709 | uint32_t num_pages); | ||
710 | extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, | ||
711 | uint32_t start_pfn, | ||
712 | unsigned long address, | ||
713 | uint32_t num_pages, int type); | ||
714 | extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, | ||
715 | unsigned long *pfn); | ||
716 | |||
717 | /* | ||
718 | * Enable / disable MMU for different requestors. | ||
719 | */ | ||
720 | |||
721 | |||
722 | extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context); | ||
723 | extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, | ||
724 | unsigned long address, uint32_t num_pages, | ||
725 | uint32_t desired_tile_stride, | ||
726 | uint32_t hw_tile_stride, int type); | ||
727 | extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd, | ||
728 | unsigned long address, uint32_t num_pages, | ||
729 | uint32_t desired_tile_stride, | ||
730 | uint32_t hw_tile_stride); | ||
731 | /* | ||
732 | *psb_irq.c | ||
733 | */ | ||
734 | |||
735 | extern irqreturn_t psb_irq_handler(DRM_IRQ_ARGS); | ||
736 | extern int psb_irq_enable_dpst(struct drm_device *dev); | ||
737 | extern int psb_irq_disable_dpst(struct drm_device *dev); | ||
738 | extern void psb_irq_preinstall(struct drm_device *dev); | ||
739 | extern int psb_irq_postinstall(struct drm_device *dev); | ||
740 | extern void psb_irq_uninstall(struct drm_device *dev); | ||
741 | extern void psb_irq_turn_on_dpst(struct drm_device *dev); | ||
742 | extern void psb_irq_turn_off_dpst(struct drm_device *dev); | ||
743 | |||
744 | extern void psb_irq_uninstall_islands(struct drm_device *dev, int hw_islands); | ||
745 | extern int psb_vblank_wait2(struct drm_device *dev, unsigned int *sequence); | ||
746 | extern int psb_vblank_wait(struct drm_device *dev, unsigned int *sequence); | ||
747 | extern int psb_enable_vblank(struct drm_device *dev, int crtc); | ||
748 | extern void psb_disable_vblank(struct drm_device *dev, int crtc); | ||
749 | void | ||
750 | psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); | ||
751 | |||
752 | void | ||
753 | psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); | ||
754 | |||
755 | extern u32 psb_get_vblank_counter(struct drm_device *dev, int crtc); | ||
756 | |||
757 | /* | ||
758 | * intel_opregion.c | ||
759 | */ | ||
760 | extern int gma_intel_opregion_init(struct drm_device *dev); | ||
761 | extern int gma_intel_opregion_exit(struct drm_device *dev); | ||
762 | |||
763 | /* | ||
764 | * framebuffer.c | ||
765 | */ | ||
766 | extern int psbfb_probed(struct drm_device *dev); | ||
767 | extern int psbfb_remove(struct drm_device *dev, | ||
768 | struct drm_framebuffer *fb); | ||
769 | /* | ||
770 | * accel_2d.c | ||
771 | */ | ||
772 | extern void psbfb_copyarea(struct fb_info *info, | ||
773 | const struct fb_copyarea *region); | ||
774 | extern int psbfb_sync(struct fb_info *info); | ||
775 | extern void psb_spank(struct drm_psb_private *dev_priv); | ||
776 | |||
777 | /* | ||
778 | * psb_reset.c | ||
779 | */ | ||
780 | |||
781 | extern void psb_lid_timer_init(struct drm_psb_private *dev_priv); | ||
782 | extern void psb_lid_timer_takedown(struct drm_psb_private *dev_priv); | ||
783 | extern void psb_print_pagefault(struct drm_psb_private *dev_priv); | ||
784 | |||
785 | /* modesetting */ | ||
786 | extern void psb_modeset_init(struct drm_device *dev); | ||
787 | extern void psb_modeset_cleanup(struct drm_device *dev); | ||
788 | extern int psb_fbdev_init(struct drm_device *dev); | ||
789 | |||
790 | /* backlight.c */ | ||
791 | int gma_backlight_init(struct drm_device *dev); | ||
792 | void gma_backlight_exit(struct drm_device *dev); | ||
793 | |||
794 | /* oaktrail_crtc.c */ | ||
795 | extern const struct drm_crtc_helper_funcs oaktrail_helper_funcs; | ||
796 | |||
797 | /* oaktrail_lvds.c */ | ||
798 | extern void oaktrail_lvds_init(struct drm_device *dev, | ||
799 | struct psb_intel_mode_device *mode_dev); | ||
800 | |||
801 | /* psb_intel_display.c */ | ||
802 | extern const struct drm_crtc_helper_funcs psb_intel_helper_funcs; | ||
803 | extern const struct drm_crtc_funcs psb_intel_crtc_funcs; | ||
804 | |||
805 | /* psb_intel_lvds.c */ | ||
806 | extern const struct drm_connector_helper_funcs | ||
807 | psb_intel_lvds_connector_helper_funcs; | ||
808 | extern const struct drm_connector_funcs psb_intel_lvds_connector_funcs; | ||
809 | |||
810 | /* gem.c */ | ||
811 | extern int psb_gem_init_object(struct drm_gem_object *obj); | ||
812 | extern void psb_gem_free_object(struct drm_gem_object *obj); | ||
813 | extern int psb_gem_get_aperture(struct drm_device *dev, void *data, | ||
814 | struct drm_file *file); | ||
815 | extern int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, | ||
816 | struct drm_mode_create_dumb *args); | ||
817 | extern int psb_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, | ||
818 | uint32_t handle); | ||
819 | extern int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, | ||
820 | uint32_t handle, uint64_t *offset); | ||
821 | extern int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); | ||
822 | extern int psb_gem_create_ioctl(struct drm_device *dev, void *data, | ||
823 | struct drm_file *file); | ||
824 | extern int psb_gem_mmap_ioctl(struct drm_device *dev, void *data, | ||
825 | struct drm_file *file); | ||
826 | |||
827 | /* psb_device.c */ | ||
828 | extern const struct psb_ops psb_chip_ops; | ||
829 | |||
830 | /* oaktrail_device.c */ | ||
831 | extern const struct psb_ops oaktrail_chip_ops; | ||
832 | |||
833 | /* cdv_device.c */ | ||
834 | extern const struct psb_ops cdv_chip_ops; | ||
835 | |||
836 | /* | ||
837 | * Debug print bits setting | ||
838 | */ | ||
839 | #define PSB_D_GENERAL (1 << 0) | ||
840 | #define PSB_D_INIT (1 << 1) | ||
841 | #define PSB_D_IRQ (1 << 2) | ||
842 | #define PSB_D_ENTRY (1 << 3) | ||
843 | /* debug the get H/V BP/FP count */ | ||
844 | #define PSB_D_HV (1 << 4) | ||
845 | #define PSB_D_DBI_BF (1 << 5) | ||
846 | #define PSB_D_PM (1 << 6) | ||
847 | #define PSB_D_RENDER (1 << 7) | ||
848 | #define PSB_D_REG (1 << 8) | ||
849 | #define PSB_D_MSVDX (1 << 9) | ||
850 | #define PSB_D_TOPAZ (1 << 10) | ||
851 | |||
852 | extern int drm_psb_no_fb; | ||
853 | extern int drm_idle_check_interval; | ||
854 | |||
855 | /* | ||
856 | * Utilities | ||
857 | */ | ||
858 | |||
859 | static inline u32 MRST_MSG_READ32(uint port, uint offset) | ||
860 | { | ||
861 | int mcr = (0xD0<<24) | (port << 16) | (offset << 8); | ||
862 | uint32_t ret_val = 0; | ||
863 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | ||
864 | pci_write_config_dword(pci_root, 0xD0, mcr); | ||
865 | pci_read_config_dword(pci_root, 0xD4, &ret_val); | ||
866 | pci_dev_put(pci_root); | ||
867 | return ret_val; | ||
868 | } | ||
869 | static inline void MRST_MSG_WRITE32(uint port, uint offset, u32 value) | ||
870 | { | ||
871 | int mcr = (0xE0<<24) | (port << 16) | (offset << 8) | 0xF0; | ||
872 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | ||
873 | pci_write_config_dword(pci_root, 0xD4, value); | ||
874 | pci_write_config_dword(pci_root, 0xD0, mcr); | ||
875 | pci_dev_put(pci_root); | ||
876 | } | ||
877 | static inline u32 MDFLD_MSG_READ32(uint port, uint offset) | ||
878 | { | ||
879 | int mcr = (0x10<<24) | (port << 16) | (offset << 8); | ||
880 | uint32_t ret_val = 0; | ||
881 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | ||
882 | pci_write_config_dword(pci_root, 0xD0, mcr); | ||
883 | pci_read_config_dword(pci_root, 0xD4, &ret_val); | ||
884 | pci_dev_put(pci_root); | ||
885 | return ret_val; | ||
886 | } | ||
887 | static inline void MDFLD_MSG_WRITE32(uint port, uint offset, u32 value) | ||
888 | { | ||
889 | int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0; | ||
890 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | ||
891 | pci_write_config_dword(pci_root, 0xD4, value); | ||
892 | pci_write_config_dword(pci_root, 0xD0, mcr); | ||
893 | pci_dev_put(pci_root); | ||
894 | } | ||
895 | |||
896 | static inline uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg) | ||
897 | { | ||
898 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
899 | return ioread32(dev_priv->vdc_reg + reg); | ||
900 | } | ||
901 | |||
902 | #define REG_READ(reg) REGISTER_READ(dev, (reg)) | ||
903 | |||
904 | static inline void REGISTER_WRITE(struct drm_device *dev, uint32_t reg, | ||
905 | uint32_t val) | ||
906 | { | ||
907 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
908 | iowrite32((val), dev_priv->vdc_reg + (reg)); | ||
909 | } | ||
910 | |||
911 | #define REG_WRITE(reg, val) REGISTER_WRITE(dev, (reg), (val)) | ||
912 | |||
913 | static inline void REGISTER_WRITE16(struct drm_device *dev, | ||
914 | uint32_t reg, uint32_t val) | ||
915 | { | ||
916 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
917 | iowrite16((val), dev_priv->vdc_reg + (reg)); | ||
918 | } | ||
919 | |||
920 | #define REG_WRITE16(reg, val) REGISTER_WRITE16(dev, (reg), (val)) | ||
921 | |||
922 | static inline void REGISTER_WRITE8(struct drm_device *dev, | ||
923 | uint32_t reg, uint32_t val) | ||
924 | { | ||
925 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
926 | iowrite8((val), dev_priv->vdc_reg + (reg)); | ||
927 | } | ||
928 | |||
929 | #define REG_WRITE8(reg, val) REGISTER_WRITE8(dev, (reg), (val)) | ||
930 | |||
931 | #define PSB_WVDC32(_val, _offs) iowrite32(_val, dev_priv->vdc_reg + (_offs)) | ||
932 | #define PSB_RVDC32(_offs) ioread32(dev_priv->vdc_reg + (_offs)) | ||
933 | |||
934 | /* #define TRAP_SGX_PM_FAULT 1 */ | ||
935 | #ifdef TRAP_SGX_PM_FAULT | ||
936 | #define PSB_RSGX32(_offs) \ | ||
937 | ({ \ | ||
938 | if (inl(dev_priv->apm_base + PSB_APM_STS) & 0x3) { \ | ||
939 | printk(KERN_ERR \ | ||
940 | "access sgx when it's off!! (READ) %s, %d\n", \ | ||
941 | __FILE__, __LINE__); \ | ||
942 | melay(1000); \ | ||
943 | } \ | ||
944 | ioread32(dev_priv->sgx_reg + (_offs)); \ | ||
945 | }) | ||
946 | #else | ||
947 | #define PSB_RSGX32(_offs) ioread32(dev_priv->sgx_reg + (_offs)) | ||
948 | #endif | ||
949 | #define PSB_WSGX32(_val, _offs) iowrite32(_val, dev_priv->sgx_reg + (_offs)) | ||
950 | |||
951 | #define MSVDX_REG_DUMP 0 | ||
952 | |||
953 | #define PSB_WMSVDX32(_val, _offs) iowrite32(_val, dev_priv->msvdx_reg + (_offs)) | ||
954 | #define PSB_RMSVDX32(_offs) ioread32(dev_priv->msvdx_reg + (_offs)) | ||
955 | |||
956 | #endif | ||
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c new file mode 100644 index 00000000000..49e983508d5 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_intel_display.c | |||
@@ -0,0 +1,1446 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2011 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | |||
24 | #include <drm/drmP.h> | ||
25 | #include "framebuffer.h" | ||
26 | #include "psb_drv.h" | ||
27 | #include "psb_intel_drv.h" | ||
28 | #include "psb_intel_reg.h" | ||
29 | #include "psb_intel_display.h" | ||
30 | #include "power.h" | ||
31 | |||
32 | struct psb_intel_clock_t { | ||
33 | /* given values */ | ||
34 | int n; | ||
35 | int m1, m2; | ||
36 | int p1, p2; | ||
37 | /* derived values */ | ||
38 | int dot; | ||
39 | int vco; | ||
40 | int m; | ||
41 | int p; | ||
42 | }; | ||
43 | |||
44 | struct psb_intel_range_t { | ||
45 | int min, max; | ||
46 | }; | ||
47 | |||
48 | struct psb_intel_p2_t { | ||
49 | int dot_limit; | ||
50 | int p2_slow, p2_fast; | ||
51 | }; | ||
52 | |||
53 | #define INTEL_P2_NUM 2 | ||
54 | |||
55 | struct psb_intel_limit_t { | ||
56 | struct psb_intel_range_t dot, vco, n, m, m1, m2, p, p1; | ||
57 | struct psb_intel_p2_t p2; | ||
58 | }; | ||
59 | |||
60 | #define I8XX_DOT_MIN 25000 | ||
61 | #define I8XX_DOT_MAX 350000 | ||
62 | #define I8XX_VCO_MIN 930000 | ||
63 | #define I8XX_VCO_MAX 1400000 | ||
64 | #define I8XX_N_MIN 3 | ||
65 | #define I8XX_N_MAX 16 | ||
66 | #define I8XX_M_MIN 96 | ||
67 | #define I8XX_M_MAX 140 | ||
68 | #define I8XX_M1_MIN 18 | ||
69 | #define I8XX_M1_MAX 26 | ||
70 | #define I8XX_M2_MIN 6 | ||
71 | #define I8XX_M2_MAX 16 | ||
72 | #define I8XX_P_MIN 4 | ||
73 | #define I8XX_P_MAX 128 | ||
74 | #define I8XX_P1_MIN 2 | ||
75 | #define I8XX_P1_MAX 33 | ||
76 | #define I8XX_P1_LVDS_MIN 1 | ||
77 | #define I8XX_P1_LVDS_MAX 6 | ||
78 | #define I8XX_P2_SLOW 4 | ||
79 | #define I8XX_P2_FAST 2 | ||
80 | #define I8XX_P2_LVDS_SLOW 14 | ||
81 | #define I8XX_P2_LVDS_FAST 14 /* No fast option */ | ||
82 | #define I8XX_P2_SLOW_LIMIT 165000 | ||
83 | |||
84 | #define I9XX_DOT_MIN 20000 | ||
85 | #define I9XX_DOT_MAX 400000 | ||
86 | #define I9XX_VCO_MIN 1400000 | ||
87 | #define I9XX_VCO_MAX 2800000 | ||
88 | #define I9XX_N_MIN 3 | ||
89 | #define I9XX_N_MAX 8 | ||
90 | #define I9XX_M_MIN 70 | ||
91 | #define I9XX_M_MAX 120 | ||
92 | #define I9XX_M1_MIN 10 | ||
93 | #define I9XX_M1_MAX 20 | ||
94 | #define I9XX_M2_MIN 5 | ||
95 | #define I9XX_M2_MAX 9 | ||
96 | #define I9XX_P_SDVO_DAC_MIN 5 | ||
97 | #define I9XX_P_SDVO_DAC_MAX 80 | ||
98 | #define I9XX_P_LVDS_MIN 7 | ||
99 | #define I9XX_P_LVDS_MAX 98 | ||
100 | #define I9XX_P1_MIN 1 | ||
101 | #define I9XX_P1_MAX 8 | ||
102 | #define I9XX_P2_SDVO_DAC_SLOW 10 | ||
103 | #define I9XX_P2_SDVO_DAC_FAST 5 | ||
104 | #define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000 | ||
105 | #define I9XX_P2_LVDS_SLOW 14 | ||
106 | #define I9XX_P2_LVDS_FAST 7 | ||
107 | #define I9XX_P2_LVDS_SLOW_LIMIT 112000 | ||
108 | |||
109 | #define INTEL_LIMIT_I8XX_DVO_DAC 0 | ||
110 | #define INTEL_LIMIT_I8XX_LVDS 1 | ||
111 | #define INTEL_LIMIT_I9XX_SDVO_DAC 2 | ||
112 | #define INTEL_LIMIT_I9XX_LVDS 3 | ||
113 | |||
114 | static const struct psb_intel_limit_t psb_intel_limits[] = { | ||
115 | { /* INTEL_LIMIT_I8XX_DVO_DAC */ | ||
116 | .dot = {.min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX}, | ||
117 | .vco = {.min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX}, | ||
118 | .n = {.min = I8XX_N_MIN, .max = I8XX_N_MAX}, | ||
119 | .m = {.min = I8XX_M_MIN, .max = I8XX_M_MAX}, | ||
120 | .m1 = {.min = I8XX_M1_MIN, .max = I8XX_M1_MAX}, | ||
121 | .m2 = {.min = I8XX_M2_MIN, .max = I8XX_M2_MAX}, | ||
122 | .p = {.min = I8XX_P_MIN, .max = I8XX_P_MAX}, | ||
123 | .p1 = {.min = I8XX_P1_MIN, .max = I8XX_P1_MAX}, | ||
124 | .p2 = {.dot_limit = I8XX_P2_SLOW_LIMIT, | ||
125 | .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST}, | ||
126 | }, | ||
127 | { /* INTEL_LIMIT_I8XX_LVDS */ | ||
128 | .dot = {.min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX}, | ||
129 | .vco = {.min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX}, | ||
130 | .n = {.min = I8XX_N_MIN, .max = I8XX_N_MAX}, | ||
131 | .m = {.min = I8XX_M_MIN, .max = I8XX_M_MAX}, | ||
132 | .m1 = {.min = I8XX_M1_MIN, .max = I8XX_M1_MAX}, | ||
133 | .m2 = {.min = I8XX_M2_MIN, .max = I8XX_M2_MAX}, | ||
134 | .p = {.min = I8XX_P_MIN, .max = I8XX_P_MAX}, | ||
135 | .p1 = {.min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX}, | ||
136 | .p2 = {.dot_limit = I8XX_P2_SLOW_LIMIT, | ||
137 | .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST}, | ||
138 | }, | ||
139 | { /* INTEL_LIMIT_I9XX_SDVO_DAC */ | ||
140 | .dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, | ||
141 | .vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX}, | ||
142 | .n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX}, | ||
143 | .m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX}, | ||
144 | .m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX}, | ||
145 | .m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX}, | ||
146 | .p = {.min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX}, | ||
147 | .p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX}, | ||
148 | .p2 = {.dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, | ||
149 | .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = | ||
150 | I9XX_P2_SDVO_DAC_FAST}, | ||
151 | }, | ||
152 | { /* INTEL_LIMIT_I9XX_LVDS */ | ||
153 | .dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, | ||
154 | .vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX}, | ||
155 | .n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX}, | ||
156 | .m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX}, | ||
157 | .m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX}, | ||
158 | .m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX}, | ||
159 | .p = {.min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX}, | ||
160 | .p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX}, | ||
161 | /* The single-channel range is 25-112Mhz, and dual-channel | ||
162 | * is 80-224Mhz. Prefer single channel as much as possible. | ||
163 | */ | ||
164 | .p2 = {.dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, | ||
165 | .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST}, | ||
166 | }, | ||
167 | }; | ||
168 | |||
169 | static const struct psb_intel_limit_t *psb_intel_limit(struct drm_crtc *crtc) | ||
170 | { | ||
171 | const struct psb_intel_limit_t *limit; | ||
172 | |||
173 | if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) | ||
174 | limit = &psb_intel_limits[INTEL_LIMIT_I9XX_LVDS]; | ||
175 | else | ||
176 | limit = &psb_intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; | ||
177 | return limit; | ||
178 | } | ||
179 | |||
180 | /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ | ||
181 | |||
182 | static void i8xx_clock(int refclk, struct psb_intel_clock_t *clock) | ||
183 | { | ||
184 | clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | ||
185 | clock->p = clock->p1 * clock->p2; | ||
186 | clock->vco = refclk * clock->m / (clock->n + 2); | ||
187 | clock->dot = clock->vco / clock->p; | ||
188 | } | ||
189 | |||
190 | /** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ | ||
191 | |||
192 | static void i9xx_clock(int refclk, struct psb_intel_clock_t *clock) | ||
193 | { | ||
194 | clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | ||
195 | clock->p = clock->p1 * clock->p2; | ||
196 | clock->vco = refclk * clock->m / (clock->n + 2); | ||
197 | clock->dot = clock->vco / clock->p; | ||
198 | } | ||
199 | |||
200 | static void psb_intel_clock(struct drm_device *dev, int refclk, | ||
201 | struct psb_intel_clock_t *clock) | ||
202 | { | ||
203 | return i9xx_clock(refclk, clock); | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * Returns whether any output on the specified pipe is of the specified type | ||
208 | */ | ||
209 | bool psb_intel_pipe_has_type(struct drm_crtc *crtc, int type) | ||
210 | { | ||
211 | struct drm_device *dev = crtc->dev; | ||
212 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
213 | struct drm_connector *l_entry; | ||
214 | |||
215 | list_for_each_entry(l_entry, &mode_config->connector_list, head) { | ||
216 | if (l_entry->encoder && l_entry->encoder->crtc == crtc) { | ||
217 | struct psb_intel_encoder *psb_intel_encoder = | ||
218 | psb_intel_attached_encoder(l_entry); | ||
219 | if (psb_intel_encoder->type == type) | ||
220 | return true; | ||
221 | } | ||
222 | } | ||
223 | return false; | ||
224 | } | ||
225 | |||
226 | #define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } | ||
227 | /** | ||
228 | * Returns whether the given set of divisors are valid for a given refclk with | ||
229 | * the given connectors. | ||
230 | */ | ||
231 | |||
232 | static bool psb_intel_PLL_is_valid(struct drm_crtc *crtc, | ||
233 | struct psb_intel_clock_t *clock) | ||
234 | { | ||
235 | const struct psb_intel_limit_t *limit = psb_intel_limit(crtc); | ||
236 | |||
237 | if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) | ||
238 | INTELPllInvalid("p1 out of range\n"); | ||
239 | if (clock->p < limit->p.min || limit->p.max < clock->p) | ||
240 | INTELPllInvalid("p out of range\n"); | ||
241 | if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) | ||
242 | INTELPllInvalid("m2 out of range\n"); | ||
243 | if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) | ||
244 | INTELPllInvalid("m1 out of range\n"); | ||
245 | if (clock->m1 <= clock->m2) | ||
246 | INTELPllInvalid("m1 <= m2\n"); | ||
247 | if (clock->m < limit->m.min || limit->m.max < clock->m) | ||
248 | INTELPllInvalid("m out of range\n"); | ||
249 | if (clock->n < limit->n.min || limit->n.max < clock->n) | ||
250 | INTELPllInvalid("n out of range\n"); | ||
251 | if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) | ||
252 | INTELPllInvalid("vco out of range\n"); | ||
253 | /* XXX: We may need to be checking "Dot clock" | ||
254 | * depending on the multiplier, connector, etc., | ||
255 | * rather than just a single range. | ||
256 | */ | ||
257 | if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) | ||
258 | INTELPllInvalid("dot out of range\n"); | ||
259 | |||
260 | return true; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * Returns a set of divisors for the desired target clock with the given | ||
265 | * refclk, or FALSE. The returned values represent the clock equation: | ||
266 | * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. | ||
267 | */ | ||
268 | static bool psb_intel_find_best_PLL(struct drm_crtc *crtc, int target, | ||
269 | int refclk, | ||
270 | struct psb_intel_clock_t *best_clock) | ||
271 | { | ||
272 | struct drm_device *dev = crtc->dev; | ||
273 | struct psb_intel_clock_t clock; | ||
274 | const struct psb_intel_limit_t *limit = psb_intel_limit(crtc); | ||
275 | int err = target; | ||
276 | |||
277 | if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && | ||
278 | (REG_READ(LVDS) & LVDS_PORT_EN) != 0) { | ||
279 | /* | ||
280 | * For LVDS, if the panel is on, just rely on its current | ||
281 | * settings for dual-channel. We haven't figured out how to | ||
282 | * reliably set up different single/dual channel state, if we | ||
283 | * even can. | ||
284 | */ | ||
285 | if ((REG_READ(LVDS) & LVDS_CLKB_POWER_MASK) == | ||
286 | LVDS_CLKB_POWER_UP) | ||
287 | clock.p2 = limit->p2.p2_fast; | ||
288 | else | ||
289 | clock.p2 = limit->p2.p2_slow; | ||
290 | } else { | ||
291 | if (target < limit->p2.dot_limit) | ||
292 | clock.p2 = limit->p2.p2_slow; | ||
293 | else | ||
294 | clock.p2 = limit->p2.p2_fast; | ||
295 | } | ||
296 | |||
297 | memset(best_clock, 0, sizeof(*best_clock)); | ||
298 | |||
299 | for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; | ||
300 | clock.m1++) { | ||
301 | for (clock.m2 = limit->m2.min; | ||
302 | clock.m2 < clock.m1 && clock.m2 <= limit->m2.max; | ||
303 | clock.m2++) { | ||
304 | for (clock.n = limit->n.min; | ||
305 | clock.n <= limit->n.max; clock.n++) { | ||
306 | for (clock.p1 = limit->p1.min; | ||
307 | clock.p1 <= limit->p1.max; | ||
308 | clock.p1++) { | ||
309 | int this_err; | ||
310 | |||
311 | psb_intel_clock(dev, refclk, &clock); | ||
312 | |||
313 | if (!psb_intel_PLL_is_valid | ||
314 | (crtc, &clock)) | ||
315 | continue; | ||
316 | |||
317 | this_err = abs(clock.dot - target); | ||
318 | if (this_err < err) { | ||
319 | *best_clock = clock; | ||
320 | err = this_err; | ||
321 | } | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return err != target; | ||
328 | } | ||
329 | |||
330 | void psb_intel_wait_for_vblank(struct drm_device *dev) | ||
331 | { | ||
332 | /* Wait for 20ms, i.e. one cycle at 50hz. */ | ||
333 | mdelay(20); | ||
334 | } | ||
335 | |||
336 | int psb_intel_pipe_set_base(struct drm_crtc *crtc, | ||
337 | int x, int y, struct drm_framebuffer *old_fb) | ||
338 | { | ||
339 | struct drm_device *dev = crtc->dev; | ||
340 | /* struct drm_i915_master_private *master_priv; */ | ||
341 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
342 | struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); | ||
343 | int pipe = psb_intel_crtc->pipe; | ||
344 | unsigned long start, offset; | ||
345 | int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); | ||
346 | int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); | ||
347 | int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; | ||
348 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
349 | u32 dspcntr; | ||
350 | int ret = 0; | ||
351 | |||
352 | if (!gma_power_begin(dev, true)) | ||
353 | return 0; | ||
354 | |||
355 | /* no fb bound */ | ||
356 | if (!crtc->fb) { | ||
357 | dev_dbg(dev->dev, "No FB bound\n"); | ||
358 | goto psb_intel_pipe_cleaner; | ||
359 | } | ||
360 | |||
361 | /* We are displaying this buffer, make sure it is actually loaded | ||
362 | into the GTT */ | ||
363 | ret = psb_gtt_pin(psbfb->gtt); | ||
364 | if (ret < 0) | ||
365 | goto psb_intel_pipe_set_base_exit; | ||
366 | start = psbfb->gtt->offset; | ||
367 | |||
368 | offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); | ||
369 | |||
370 | REG_WRITE(dspstride, crtc->fb->pitches[0]); | ||
371 | |||
372 | dspcntr = REG_READ(dspcntr_reg); | ||
373 | dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; | ||
374 | |||
375 | switch (crtc->fb->bits_per_pixel) { | ||
376 | case 8: | ||
377 | dspcntr |= DISPPLANE_8BPP; | ||
378 | break; | ||
379 | case 16: | ||
380 | if (crtc->fb->depth == 15) | ||
381 | dspcntr |= DISPPLANE_15_16BPP; | ||
382 | else | ||
383 | dspcntr |= DISPPLANE_16BPP; | ||
384 | break; | ||
385 | case 24: | ||
386 | case 32: | ||
387 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | ||
388 | break; | ||
389 | default: | ||
390 | dev_err(dev->dev, "Unknown color depth\n"); | ||
391 | ret = -EINVAL; | ||
392 | psb_gtt_unpin(psbfb->gtt); | ||
393 | goto psb_intel_pipe_set_base_exit; | ||
394 | } | ||
395 | REG_WRITE(dspcntr_reg, dspcntr); | ||
396 | |||
397 | |||
398 | if (0 /* FIXMEAC - check what PSB needs */) { | ||
399 | REG_WRITE(dspbase, offset); | ||
400 | REG_READ(dspbase); | ||
401 | REG_WRITE(dspsurf, start); | ||
402 | REG_READ(dspsurf); | ||
403 | } else { | ||
404 | REG_WRITE(dspbase, start + offset); | ||
405 | REG_READ(dspbase); | ||
406 | } | ||
407 | |||
408 | psb_intel_pipe_cleaner: | ||
409 | /* If there was a previous display we can now unpin it */ | ||
410 | if (old_fb) | ||
411 | psb_gtt_unpin(to_psb_fb(old_fb)->gtt); | ||
412 | |||
413 | psb_intel_pipe_set_base_exit: | ||
414 | gma_power_end(dev); | ||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * Sets the power management mode of the pipe and plane. | ||
420 | * | ||
421 | * This code should probably grow support for turning the cursor off and back | ||
422 | * on appropriately at the same time as we're turning the pipe off/on. | ||
423 | */ | ||
424 | static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
425 | { | ||
426 | struct drm_device *dev = crtc->dev; | ||
427 | /* struct drm_i915_master_private *master_priv; */ | ||
428 | /* struct drm_i915_private *dev_priv = dev->dev_private; */ | ||
429 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
430 | int pipe = psb_intel_crtc->pipe; | ||
431 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
432 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
433 | int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE; | ||
434 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
435 | u32 temp; | ||
436 | bool enabled; | ||
437 | |||
438 | /* XXX: When our outputs are all unaware of DPMS modes other than off | ||
439 | * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. | ||
440 | */ | ||
441 | switch (mode) { | ||
442 | case DRM_MODE_DPMS_ON: | ||
443 | case DRM_MODE_DPMS_STANDBY: | ||
444 | case DRM_MODE_DPMS_SUSPEND: | ||
445 | /* Enable the DPLL */ | ||
446 | temp = REG_READ(dpll_reg); | ||
447 | if ((temp & DPLL_VCO_ENABLE) == 0) { | ||
448 | REG_WRITE(dpll_reg, temp); | ||
449 | REG_READ(dpll_reg); | ||
450 | /* Wait for the clocks to stabilize. */ | ||
451 | udelay(150); | ||
452 | REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
453 | REG_READ(dpll_reg); | ||
454 | /* Wait for the clocks to stabilize. */ | ||
455 | udelay(150); | ||
456 | REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
457 | REG_READ(dpll_reg); | ||
458 | /* Wait for the clocks to stabilize. */ | ||
459 | udelay(150); | ||
460 | } | ||
461 | |||
462 | /* Enable the pipe */ | ||
463 | temp = REG_READ(pipeconf_reg); | ||
464 | if ((temp & PIPEACONF_ENABLE) == 0) | ||
465 | REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); | ||
466 | |||
467 | /* Enable the plane */ | ||
468 | temp = REG_READ(dspcntr_reg); | ||
469 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
470 | REG_WRITE(dspcntr_reg, | ||
471 | temp | DISPLAY_PLANE_ENABLE); | ||
472 | /* Flush the plane changes */ | ||
473 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
474 | } | ||
475 | |||
476 | psb_intel_crtc_load_lut(crtc); | ||
477 | |||
478 | /* Give the overlay scaler a chance to enable | ||
479 | * if it's on this pipe */ | ||
480 | /* psb_intel_crtc_dpms_video(crtc, true); TODO */ | ||
481 | break; | ||
482 | case DRM_MODE_DPMS_OFF: | ||
483 | /* Give the overlay scaler a chance to disable | ||
484 | * if it's on this pipe */ | ||
485 | /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */ | ||
486 | |||
487 | /* Disable the VGA plane that we never use */ | ||
488 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
489 | |||
490 | /* Disable display plane */ | ||
491 | temp = REG_READ(dspcntr_reg); | ||
492 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
493 | REG_WRITE(dspcntr_reg, | ||
494 | temp & ~DISPLAY_PLANE_ENABLE); | ||
495 | /* Flush the plane changes */ | ||
496 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
497 | REG_READ(dspbase_reg); | ||
498 | } | ||
499 | |||
500 | /* Next, disable display pipes */ | ||
501 | temp = REG_READ(pipeconf_reg); | ||
502 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
503 | REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); | ||
504 | REG_READ(pipeconf_reg); | ||
505 | } | ||
506 | |||
507 | /* Wait for vblank for the disable to take effect. */ | ||
508 | psb_intel_wait_for_vblank(dev); | ||
509 | |||
510 | temp = REG_READ(dpll_reg); | ||
511 | if ((temp & DPLL_VCO_ENABLE) != 0) { | ||
512 | REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); | ||
513 | REG_READ(dpll_reg); | ||
514 | } | ||
515 | |||
516 | /* Wait for the clocks to turn off. */ | ||
517 | udelay(150); | ||
518 | break; | ||
519 | } | ||
520 | |||
521 | enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; | ||
522 | |||
523 | /*Set FIFO Watermarks*/ | ||
524 | REG_WRITE(DSPARB, 0x3F3E); | ||
525 | } | ||
526 | |||
527 | static void psb_intel_crtc_prepare(struct drm_crtc *crtc) | ||
528 | { | ||
529 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
530 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
531 | } | ||
532 | |||
533 | static void psb_intel_crtc_commit(struct drm_crtc *crtc) | ||
534 | { | ||
535 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
536 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
537 | } | ||
538 | |||
539 | void psb_intel_encoder_prepare(struct drm_encoder *encoder) | ||
540 | { | ||
541 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
542 | encoder->helper_private; | ||
543 | /* lvds has its own version of prepare see psb_intel_lvds_prepare */ | ||
544 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
545 | } | ||
546 | |||
547 | void psb_intel_encoder_commit(struct drm_encoder *encoder) | ||
548 | { | ||
549 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
550 | encoder->helper_private; | ||
551 | /* lvds has its own version of commit see psb_intel_lvds_commit */ | ||
552 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
553 | } | ||
554 | |||
555 | void psb_intel_encoder_destroy(struct drm_encoder *encoder) | ||
556 | { | ||
557 | struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder); | ||
558 | |||
559 | drm_encoder_cleanup(encoder); | ||
560 | kfree(intel_encoder); | ||
561 | } | ||
562 | |||
563 | static bool psb_intel_crtc_mode_fixup(struct drm_crtc *crtc, | ||
564 | struct drm_display_mode *mode, | ||
565 | struct drm_display_mode *adjusted_mode) | ||
566 | { | ||
567 | return true; | ||
568 | } | ||
569 | |||
570 | |||
571 | /** | ||
572 | * Return the pipe currently connected to the panel fitter, | ||
573 | * or -1 if the panel fitter is not present or not in use | ||
574 | */ | ||
575 | static int psb_intel_panel_fitter_pipe(struct drm_device *dev) | ||
576 | { | ||
577 | u32 pfit_control; | ||
578 | |||
579 | pfit_control = REG_READ(PFIT_CONTROL); | ||
580 | |||
581 | /* See if the panel fitter is in use */ | ||
582 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
583 | return -1; | ||
584 | /* Must be on PIPE 1 for PSB */ | ||
585 | return 1; | ||
586 | } | ||
587 | |||
588 | static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, | ||
589 | struct drm_display_mode *mode, | ||
590 | struct drm_display_mode *adjusted_mode, | ||
591 | int x, int y, | ||
592 | struct drm_framebuffer *old_fb) | ||
593 | { | ||
594 | struct drm_device *dev = crtc->dev; | ||
595 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
596 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
597 | int pipe = psb_intel_crtc->pipe; | ||
598 | int fp_reg = (pipe == 0) ? FPA0 : FPB0; | ||
599 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
600 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
601 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
602 | int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; | ||
603 | int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; | ||
604 | int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; | ||
605 | int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; | ||
606 | int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; | ||
607 | int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; | ||
608 | int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; | ||
609 | int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; | ||
610 | int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; | ||
611 | int refclk; | ||
612 | struct psb_intel_clock_t clock; | ||
613 | u32 dpll = 0, fp = 0, dspcntr, pipeconf; | ||
614 | bool ok, is_sdvo = false, is_dvo = false; | ||
615 | bool is_crt = false, is_lvds = false, is_tv = false; | ||
616 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
617 | struct drm_connector *connector; | ||
618 | |||
619 | /* No scan out no play */ | ||
620 | if (crtc->fb == NULL) { | ||
621 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | list_for_each_entry(connector, &mode_config->connector_list, head) { | ||
626 | struct psb_intel_encoder *psb_intel_encoder = | ||
627 | psb_intel_attached_encoder(connector); | ||
628 | |||
629 | if (!connector->encoder | ||
630 | || connector->encoder->crtc != crtc) | ||
631 | continue; | ||
632 | |||
633 | switch (psb_intel_encoder->type) { | ||
634 | case INTEL_OUTPUT_LVDS: | ||
635 | is_lvds = true; | ||
636 | break; | ||
637 | case INTEL_OUTPUT_SDVO: | ||
638 | is_sdvo = true; | ||
639 | break; | ||
640 | case INTEL_OUTPUT_DVO: | ||
641 | is_dvo = true; | ||
642 | break; | ||
643 | case INTEL_OUTPUT_TVOUT: | ||
644 | is_tv = true; | ||
645 | break; | ||
646 | case INTEL_OUTPUT_ANALOG: | ||
647 | is_crt = true; | ||
648 | break; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | refclk = 96000; | ||
653 | |||
654 | ok = psb_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, | ||
655 | &clock); | ||
656 | if (!ok) { | ||
657 | dev_err(dev->dev, "Couldn't find PLL settings for mode!\n"); | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | fp = clock.n << 16 | clock.m1 << 8 | clock.m2; | ||
662 | |||
663 | dpll = DPLL_VGA_MODE_DIS; | ||
664 | if (is_lvds) { | ||
665 | dpll |= DPLLB_MODE_LVDS; | ||
666 | dpll |= DPLL_DVO_HIGH_SPEED; | ||
667 | } else | ||
668 | dpll |= DPLLB_MODE_DAC_SERIAL; | ||
669 | if (is_sdvo) { | ||
670 | int sdvo_pixel_multiply = | ||
671 | adjusted_mode->clock / mode->clock; | ||
672 | dpll |= DPLL_DVO_HIGH_SPEED; | ||
673 | dpll |= | ||
674 | (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; | ||
675 | } | ||
676 | |||
677 | /* compute bitmask from p1 value */ | ||
678 | dpll |= (1 << (clock.p1 - 1)) << 16; | ||
679 | switch (clock.p2) { | ||
680 | case 5: | ||
681 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; | ||
682 | break; | ||
683 | case 7: | ||
684 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; | ||
685 | break; | ||
686 | case 10: | ||
687 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; | ||
688 | break; | ||
689 | case 14: | ||
690 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; | ||
691 | break; | ||
692 | } | ||
693 | |||
694 | if (is_tv) { | ||
695 | /* XXX: just matching BIOS for now */ | ||
696 | /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ | ||
697 | dpll |= 3; | ||
698 | } | ||
699 | dpll |= PLL_REF_INPUT_DREFCLK; | ||
700 | |||
701 | /* setup pipeconf */ | ||
702 | pipeconf = REG_READ(pipeconf_reg); | ||
703 | |||
704 | /* Set up the display plane register */ | ||
705 | dspcntr = DISPPLANE_GAMMA_ENABLE; | ||
706 | |||
707 | if (pipe == 0) | ||
708 | dspcntr |= DISPPLANE_SEL_PIPE_A; | ||
709 | else | ||
710 | dspcntr |= DISPPLANE_SEL_PIPE_B; | ||
711 | |||
712 | dspcntr |= DISPLAY_PLANE_ENABLE; | ||
713 | pipeconf |= PIPEACONF_ENABLE; | ||
714 | dpll |= DPLL_VCO_ENABLE; | ||
715 | |||
716 | |||
717 | /* Disable the panel fitter if it was on our pipe */ | ||
718 | if (psb_intel_panel_fitter_pipe(dev) == pipe) | ||
719 | REG_WRITE(PFIT_CONTROL, 0); | ||
720 | |||
721 | drm_mode_debug_printmodeline(mode); | ||
722 | |||
723 | if (dpll & DPLL_VCO_ENABLE) { | ||
724 | REG_WRITE(fp_reg, fp); | ||
725 | REG_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); | ||
726 | REG_READ(dpll_reg); | ||
727 | udelay(150); | ||
728 | } | ||
729 | |||
730 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. | ||
731 | * This is an exception to the general rule that mode_set doesn't turn | ||
732 | * things on. | ||
733 | */ | ||
734 | if (is_lvds) { | ||
735 | u32 lvds = REG_READ(LVDS); | ||
736 | |||
737 | lvds &= ~LVDS_PIPEB_SELECT; | ||
738 | if (pipe == 1) | ||
739 | lvds |= LVDS_PIPEB_SELECT; | ||
740 | |||
741 | lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; | ||
742 | /* Set the B0-B3 data pairs corresponding to | ||
743 | * whether we're going to | ||
744 | * set the DPLLs for dual-channel mode or not. | ||
745 | */ | ||
746 | lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); | ||
747 | if (clock.p2 == 7) | ||
748 | lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; | ||
749 | |||
750 | /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) | ||
751 | * appropriately here, but we need to look more | ||
752 | * thoroughly into how panels behave in the two modes. | ||
753 | */ | ||
754 | |||
755 | REG_WRITE(LVDS, lvds); | ||
756 | REG_READ(LVDS); | ||
757 | } | ||
758 | |||
759 | REG_WRITE(fp_reg, fp); | ||
760 | REG_WRITE(dpll_reg, dpll); | ||
761 | REG_READ(dpll_reg); | ||
762 | /* Wait for the clocks to stabilize. */ | ||
763 | udelay(150); | ||
764 | |||
765 | /* write it again -- the BIOS does, after all */ | ||
766 | REG_WRITE(dpll_reg, dpll); | ||
767 | |||
768 | REG_READ(dpll_reg); | ||
769 | /* Wait for the clocks to stabilize. */ | ||
770 | udelay(150); | ||
771 | |||
772 | REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | | ||
773 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
774 | REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | | ||
775 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
776 | REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | | ||
777 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
778 | REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | | ||
779 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
780 | REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | | ||
781 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
782 | REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | | ||
783 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
784 | /* pipesrc and dspsize control the size that is scaled from, | ||
785 | * which should always be the user's requested size. | ||
786 | */ | ||
787 | REG_WRITE(dspsize_reg, | ||
788 | ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); | ||
789 | REG_WRITE(dsppos_reg, 0); | ||
790 | REG_WRITE(pipesrc_reg, | ||
791 | ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); | ||
792 | REG_WRITE(pipeconf_reg, pipeconf); | ||
793 | REG_READ(pipeconf_reg); | ||
794 | |||
795 | psb_intel_wait_for_vblank(dev); | ||
796 | |||
797 | REG_WRITE(dspcntr_reg, dspcntr); | ||
798 | |||
799 | /* Flush the plane changes */ | ||
800 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); | ||
801 | |||
802 | psb_intel_wait_for_vblank(dev); | ||
803 | |||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | /** Loads the palette/gamma unit for the CRTC with the prepared values */ | ||
808 | void psb_intel_crtc_load_lut(struct drm_crtc *crtc) | ||
809 | { | ||
810 | struct drm_device *dev = crtc->dev; | ||
811 | struct drm_psb_private *dev_priv = | ||
812 | (struct drm_psb_private *)dev->dev_private; | ||
813 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
814 | int palreg = PALETTE_A; | ||
815 | int i; | ||
816 | |||
817 | /* The clocks have to be on to load the palette. */ | ||
818 | if (!crtc->enabled) | ||
819 | return; | ||
820 | |||
821 | switch (psb_intel_crtc->pipe) { | ||
822 | case 0: | ||
823 | break; | ||
824 | case 1: | ||
825 | palreg = PALETTE_B; | ||
826 | break; | ||
827 | case 2: | ||
828 | palreg = PALETTE_C; | ||
829 | break; | ||
830 | default: | ||
831 | dev_err(dev->dev, "Illegal Pipe Number.\n"); | ||
832 | return; | ||
833 | } | ||
834 | |||
835 | if (gma_power_begin(dev, false)) { | ||
836 | for (i = 0; i < 256; i++) { | ||
837 | REG_WRITE(palreg + 4 * i, | ||
838 | ((psb_intel_crtc->lut_r[i] + | ||
839 | psb_intel_crtc->lut_adj[i]) << 16) | | ||
840 | ((psb_intel_crtc->lut_g[i] + | ||
841 | psb_intel_crtc->lut_adj[i]) << 8) | | ||
842 | (psb_intel_crtc->lut_b[i] + | ||
843 | psb_intel_crtc->lut_adj[i])); | ||
844 | } | ||
845 | gma_power_end(dev); | ||
846 | } else { | ||
847 | for (i = 0; i < 256; i++) { | ||
848 | dev_priv->save_palette_a[i] = | ||
849 | ((psb_intel_crtc->lut_r[i] + | ||
850 | psb_intel_crtc->lut_adj[i]) << 16) | | ||
851 | ((psb_intel_crtc->lut_g[i] + | ||
852 | psb_intel_crtc->lut_adj[i]) << 8) | | ||
853 | (psb_intel_crtc->lut_b[i] + | ||
854 | psb_intel_crtc->lut_adj[i]); | ||
855 | } | ||
856 | |||
857 | } | ||
858 | } | ||
859 | |||
860 | /** | ||
861 | * Save HW states of giving crtc | ||
862 | */ | ||
863 | static void psb_intel_crtc_save(struct drm_crtc *crtc) | ||
864 | { | ||
865 | struct drm_device *dev = crtc->dev; | ||
866 | /* struct drm_psb_private *dev_priv = | ||
867 | (struct drm_psb_private *)dev->dev_private; */ | ||
868 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
869 | struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state; | ||
870 | int pipeA = (psb_intel_crtc->pipe == 0); | ||
871 | uint32_t paletteReg; | ||
872 | int i; | ||
873 | |||
874 | if (!crtc_state) { | ||
875 | dev_err(dev->dev, "No CRTC state found\n"); | ||
876 | return; | ||
877 | } | ||
878 | |||
879 | crtc_state->saveDSPCNTR = REG_READ(pipeA ? DSPACNTR : DSPBCNTR); | ||
880 | crtc_state->savePIPECONF = REG_READ(pipeA ? PIPEACONF : PIPEBCONF); | ||
881 | crtc_state->savePIPESRC = REG_READ(pipeA ? PIPEASRC : PIPEBSRC); | ||
882 | crtc_state->saveFP0 = REG_READ(pipeA ? FPA0 : FPB0); | ||
883 | crtc_state->saveFP1 = REG_READ(pipeA ? FPA1 : FPB1); | ||
884 | crtc_state->saveDPLL = REG_READ(pipeA ? DPLL_A : DPLL_B); | ||
885 | crtc_state->saveHTOTAL = REG_READ(pipeA ? HTOTAL_A : HTOTAL_B); | ||
886 | crtc_state->saveHBLANK = REG_READ(pipeA ? HBLANK_A : HBLANK_B); | ||
887 | crtc_state->saveHSYNC = REG_READ(pipeA ? HSYNC_A : HSYNC_B); | ||
888 | crtc_state->saveVTOTAL = REG_READ(pipeA ? VTOTAL_A : VTOTAL_B); | ||
889 | crtc_state->saveVBLANK = REG_READ(pipeA ? VBLANK_A : VBLANK_B); | ||
890 | crtc_state->saveVSYNC = REG_READ(pipeA ? VSYNC_A : VSYNC_B); | ||
891 | crtc_state->saveDSPSTRIDE = REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE); | ||
892 | |||
893 | /*NOTE: DSPSIZE DSPPOS only for psb*/ | ||
894 | crtc_state->saveDSPSIZE = REG_READ(pipeA ? DSPASIZE : DSPBSIZE); | ||
895 | crtc_state->saveDSPPOS = REG_READ(pipeA ? DSPAPOS : DSPBPOS); | ||
896 | |||
897 | crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE); | ||
898 | |||
899 | paletteReg = pipeA ? PALETTE_A : PALETTE_B; | ||
900 | for (i = 0; i < 256; ++i) | ||
901 | crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2)); | ||
902 | } | ||
903 | |||
904 | /** | ||
905 | * Restore HW states of giving crtc | ||
906 | */ | ||
907 | static void psb_intel_crtc_restore(struct drm_crtc *crtc) | ||
908 | { | ||
909 | struct drm_device *dev = crtc->dev; | ||
910 | /* struct drm_psb_private * dev_priv = | ||
911 | (struct drm_psb_private *)dev->dev_private; */ | ||
912 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
913 | struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state; | ||
914 | /* struct drm_crtc_helper_funcs * crtc_funcs = crtc->helper_private; */ | ||
915 | int pipeA = (psb_intel_crtc->pipe == 0); | ||
916 | uint32_t paletteReg; | ||
917 | int i; | ||
918 | |||
919 | if (!crtc_state) { | ||
920 | dev_err(dev->dev, "No crtc state\n"); | ||
921 | return; | ||
922 | } | ||
923 | |||
924 | if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) { | ||
925 | REG_WRITE(pipeA ? DPLL_A : DPLL_B, | ||
926 | crtc_state->saveDPLL & ~DPLL_VCO_ENABLE); | ||
927 | REG_READ(pipeA ? DPLL_A : DPLL_B); | ||
928 | udelay(150); | ||
929 | } | ||
930 | |||
931 | REG_WRITE(pipeA ? FPA0 : FPB0, crtc_state->saveFP0); | ||
932 | REG_READ(pipeA ? FPA0 : FPB0); | ||
933 | |||
934 | REG_WRITE(pipeA ? FPA1 : FPB1, crtc_state->saveFP1); | ||
935 | REG_READ(pipeA ? FPA1 : FPB1); | ||
936 | |||
937 | REG_WRITE(pipeA ? DPLL_A : DPLL_B, crtc_state->saveDPLL); | ||
938 | REG_READ(pipeA ? DPLL_A : DPLL_B); | ||
939 | udelay(150); | ||
940 | |||
941 | REG_WRITE(pipeA ? HTOTAL_A : HTOTAL_B, crtc_state->saveHTOTAL); | ||
942 | REG_WRITE(pipeA ? HBLANK_A : HBLANK_B, crtc_state->saveHBLANK); | ||
943 | REG_WRITE(pipeA ? HSYNC_A : HSYNC_B, crtc_state->saveHSYNC); | ||
944 | REG_WRITE(pipeA ? VTOTAL_A : VTOTAL_B, crtc_state->saveVTOTAL); | ||
945 | REG_WRITE(pipeA ? VBLANK_A : VBLANK_B, crtc_state->saveVBLANK); | ||
946 | REG_WRITE(pipeA ? VSYNC_A : VSYNC_B, crtc_state->saveVSYNC); | ||
947 | REG_WRITE(pipeA ? DSPASTRIDE : DSPBSTRIDE, crtc_state->saveDSPSTRIDE); | ||
948 | |||
949 | REG_WRITE(pipeA ? DSPASIZE : DSPBSIZE, crtc_state->saveDSPSIZE); | ||
950 | REG_WRITE(pipeA ? DSPAPOS : DSPBPOS, crtc_state->saveDSPPOS); | ||
951 | |||
952 | REG_WRITE(pipeA ? PIPEASRC : PIPEBSRC, crtc_state->savePIPESRC); | ||
953 | REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE); | ||
954 | REG_WRITE(pipeA ? PIPEACONF : PIPEBCONF, crtc_state->savePIPECONF); | ||
955 | |||
956 | psb_intel_wait_for_vblank(dev); | ||
957 | |||
958 | REG_WRITE(pipeA ? DSPACNTR : DSPBCNTR, crtc_state->saveDSPCNTR); | ||
959 | REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE); | ||
960 | |||
961 | psb_intel_wait_for_vblank(dev); | ||
962 | |||
963 | paletteReg = pipeA ? PALETTE_A : PALETTE_B; | ||
964 | for (i = 0; i < 256; ++i) | ||
965 | REG_WRITE(paletteReg + (i << 2), crtc_state->savePalette[i]); | ||
966 | } | ||
967 | |||
968 | static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, | ||
969 | struct drm_file *file_priv, | ||
970 | uint32_t handle, | ||
971 | uint32_t width, uint32_t height) | ||
972 | { | ||
973 | struct drm_device *dev = crtc->dev; | ||
974 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
975 | int pipe = psb_intel_crtc->pipe; | ||
976 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; | ||
977 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; | ||
978 | uint32_t temp; | ||
979 | size_t addr = 0; | ||
980 | struct gtt_range *gt; | ||
981 | struct drm_gem_object *obj; | ||
982 | int ret; | ||
983 | |||
984 | /* if we want to turn of the cursor ignore width and height */ | ||
985 | if (!handle) { | ||
986 | /* turn off the cursor */ | ||
987 | temp = CURSOR_MODE_DISABLE; | ||
988 | |||
989 | if (gma_power_begin(dev, false)) { | ||
990 | REG_WRITE(control, temp); | ||
991 | REG_WRITE(base, 0); | ||
992 | gma_power_end(dev); | ||
993 | } | ||
994 | |||
995 | /* Unpin the old GEM object */ | ||
996 | if (psb_intel_crtc->cursor_obj) { | ||
997 | gt = container_of(psb_intel_crtc->cursor_obj, | ||
998 | struct gtt_range, gem); | ||
999 | psb_gtt_unpin(gt); | ||
1000 | drm_gem_object_unreference(psb_intel_crtc->cursor_obj); | ||
1001 | psb_intel_crtc->cursor_obj = NULL; | ||
1002 | } | ||
1003 | |||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | /* Currently we only support 64x64 cursors */ | ||
1008 | if (width != 64 || height != 64) { | ||
1009 | dev_dbg(dev->dev, "we currently only support 64x64 cursors\n"); | ||
1010 | return -EINVAL; | ||
1011 | } | ||
1012 | |||
1013 | obj = drm_gem_object_lookup(dev, file_priv, handle); | ||
1014 | if (!obj) | ||
1015 | return -ENOENT; | ||
1016 | |||
1017 | if (obj->size < width * height * 4) { | ||
1018 | dev_dbg(dev->dev, "buffer is to small\n"); | ||
1019 | return -ENOMEM; | ||
1020 | } | ||
1021 | |||
1022 | gt = container_of(obj, struct gtt_range, gem); | ||
1023 | |||
1024 | /* Pin the memory into the GTT */ | ||
1025 | ret = psb_gtt_pin(gt); | ||
1026 | if (ret) { | ||
1027 | dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); | ||
1028 | return ret; | ||
1029 | } | ||
1030 | |||
1031 | |||
1032 | addr = gt->offset; /* Or resource.start ??? */ | ||
1033 | |||
1034 | psb_intel_crtc->cursor_addr = addr; | ||
1035 | |||
1036 | temp = 0; | ||
1037 | /* set the pipe for the cursor */ | ||
1038 | temp |= (pipe << 28); | ||
1039 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | ||
1040 | |||
1041 | if (gma_power_begin(dev, false)) { | ||
1042 | REG_WRITE(control, temp); | ||
1043 | REG_WRITE(base, addr); | ||
1044 | gma_power_end(dev); | ||
1045 | } | ||
1046 | |||
1047 | /* unpin the old bo */ | ||
1048 | if (psb_intel_crtc->cursor_obj) { | ||
1049 | gt = container_of(psb_intel_crtc->cursor_obj, | ||
1050 | struct gtt_range, gem); | ||
1051 | psb_gtt_unpin(gt); | ||
1052 | drm_gem_object_unreference(psb_intel_crtc->cursor_obj); | ||
1053 | psb_intel_crtc->cursor_obj = obj; | ||
1054 | } | ||
1055 | return 0; | ||
1056 | } | ||
1057 | |||
1058 | static int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | ||
1059 | { | ||
1060 | struct drm_device *dev = crtc->dev; | ||
1061 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1062 | int pipe = psb_intel_crtc->pipe; | ||
1063 | uint32_t temp = 0; | ||
1064 | uint32_t addr; | ||
1065 | |||
1066 | |||
1067 | if (x < 0) { | ||
1068 | temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); | ||
1069 | x = -x; | ||
1070 | } | ||
1071 | if (y < 0) { | ||
1072 | temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); | ||
1073 | y = -y; | ||
1074 | } | ||
1075 | |||
1076 | temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); | ||
1077 | temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); | ||
1078 | |||
1079 | addr = psb_intel_crtc->cursor_addr; | ||
1080 | |||
1081 | if (gma_power_begin(dev, false)) { | ||
1082 | REG_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); | ||
1083 | REG_WRITE((pipe == 0) ? CURABASE : CURBBASE, addr); | ||
1084 | gma_power_end(dev); | ||
1085 | } | ||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, | ||
1090 | u16 *green, u16 *blue, uint32_t type, uint32_t size) | ||
1091 | { | ||
1092 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1093 | int i; | ||
1094 | |||
1095 | if (size != 256) | ||
1096 | return; | ||
1097 | |||
1098 | for (i = 0; i < 256; i++) { | ||
1099 | psb_intel_crtc->lut_r[i] = red[i] >> 8; | ||
1100 | psb_intel_crtc->lut_g[i] = green[i] >> 8; | ||
1101 | psb_intel_crtc->lut_b[i] = blue[i] >> 8; | ||
1102 | } | ||
1103 | |||
1104 | psb_intel_crtc_load_lut(crtc); | ||
1105 | } | ||
1106 | |||
1107 | static int psb_crtc_set_config(struct drm_mode_set *set) | ||
1108 | { | ||
1109 | int ret; | ||
1110 | struct drm_device *dev = set->crtc->dev; | ||
1111 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1112 | |||
1113 | if (!dev_priv->rpm_enabled) | ||
1114 | return drm_crtc_helper_set_config(set); | ||
1115 | |||
1116 | pm_runtime_forbid(&dev->pdev->dev); | ||
1117 | ret = drm_crtc_helper_set_config(set); | ||
1118 | pm_runtime_allow(&dev->pdev->dev); | ||
1119 | return ret; | ||
1120 | } | ||
1121 | |||
1122 | /* Returns the clock of the currently programmed mode of the given pipe. */ | ||
1123 | static int psb_intel_crtc_clock_get(struct drm_device *dev, | ||
1124 | struct drm_crtc *crtc) | ||
1125 | { | ||
1126 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1127 | int pipe = psb_intel_crtc->pipe; | ||
1128 | u32 dpll; | ||
1129 | u32 fp; | ||
1130 | struct psb_intel_clock_t clock; | ||
1131 | bool is_lvds; | ||
1132 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1133 | |||
1134 | if (gma_power_begin(dev, false)) { | ||
1135 | dpll = REG_READ((pipe == 0) ? DPLL_A : DPLL_B); | ||
1136 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) | ||
1137 | fp = REG_READ((pipe == 0) ? FPA0 : FPB0); | ||
1138 | else | ||
1139 | fp = REG_READ((pipe == 0) ? FPA1 : FPB1); | ||
1140 | is_lvds = (pipe == 1) && (REG_READ(LVDS) & LVDS_PORT_EN); | ||
1141 | gma_power_end(dev); | ||
1142 | } else { | ||
1143 | dpll = (pipe == 0) ? | ||
1144 | dev_priv->saveDPLL_A : dev_priv->saveDPLL_B; | ||
1145 | |||
1146 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) | ||
1147 | fp = (pipe == 0) ? | ||
1148 | dev_priv->saveFPA0 : | ||
1149 | dev_priv->saveFPB0; | ||
1150 | else | ||
1151 | fp = (pipe == 0) ? | ||
1152 | dev_priv->saveFPA1 : | ||
1153 | dev_priv->saveFPB1; | ||
1154 | |||
1155 | is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN); | ||
1156 | } | ||
1157 | |||
1158 | clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; | ||
1159 | clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; | ||
1160 | clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; | ||
1161 | |||
1162 | if (is_lvds) { | ||
1163 | clock.p1 = | ||
1164 | ffs((dpll & | ||
1165 | DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> | ||
1166 | DPLL_FPA01_P1_POST_DIV_SHIFT); | ||
1167 | clock.p2 = 14; | ||
1168 | |||
1169 | if ((dpll & PLL_REF_INPUT_MASK) == | ||
1170 | PLLB_REF_INPUT_SPREADSPECTRUMIN) { | ||
1171 | /* XXX: might not be 66MHz */ | ||
1172 | i8xx_clock(66000, &clock); | ||
1173 | } else | ||
1174 | i8xx_clock(48000, &clock); | ||
1175 | } else { | ||
1176 | if (dpll & PLL_P1_DIVIDE_BY_TWO) | ||
1177 | clock.p1 = 2; | ||
1178 | else { | ||
1179 | clock.p1 = | ||
1180 | ((dpll & | ||
1181 | DPLL_FPA01_P1_POST_DIV_MASK_I830) >> | ||
1182 | DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; | ||
1183 | } | ||
1184 | if (dpll & PLL_P2_DIVIDE_BY_4) | ||
1185 | clock.p2 = 4; | ||
1186 | else | ||
1187 | clock.p2 = 2; | ||
1188 | |||
1189 | i8xx_clock(48000, &clock); | ||
1190 | } | ||
1191 | |||
1192 | /* XXX: It would be nice to validate the clocks, but we can't reuse | ||
1193 | * i830PllIsValid() because it relies on the xf86_config connector | ||
1194 | * configuration being accurate, which it isn't necessarily. | ||
1195 | */ | ||
1196 | |||
1197 | return clock.dot; | ||
1198 | } | ||
1199 | |||
1200 | /** Returns the currently programmed mode of the given pipe. */ | ||
1201 | struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, | ||
1202 | struct drm_crtc *crtc) | ||
1203 | { | ||
1204 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1205 | int pipe = psb_intel_crtc->pipe; | ||
1206 | struct drm_display_mode *mode; | ||
1207 | int htot; | ||
1208 | int hsync; | ||
1209 | int vtot; | ||
1210 | int vsync; | ||
1211 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1212 | |||
1213 | if (gma_power_begin(dev, false)) { | ||
1214 | htot = REG_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); | ||
1215 | hsync = REG_READ((pipe == 0) ? HSYNC_A : HSYNC_B); | ||
1216 | vtot = REG_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); | ||
1217 | vsync = REG_READ((pipe == 0) ? VSYNC_A : VSYNC_B); | ||
1218 | gma_power_end(dev); | ||
1219 | } else { | ||
1220 | htot = (pipe == 0) ? | ||
1221 | dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B; | ||
1222 | hsync = (pipe == 0) ? | ||
1223 | dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B; | ||
1224 | vtot = (pipe == 0) ? | ||
1225 | dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B; | ||
1226 | vsync = (pipe == 0) ? | ||
1227 | dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B; | ||
1228 | } | ||
1229 | |||
1230 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
1231 | if (!mode) | ||
1232 | return NULL; | ||
1233 | |||
1234 | mode->clock = psb_intel_crtc_clock_get(dev, crtc); | ||
1235 | mode->hdisplay = (htot & 0xffff) + 1; | ||
1236 | mode->htotal = ((htot & 0xffff0000) >> 16) + 1; | ||
1237 | mode->hsync_start = (hsync & 0xffff) + 1; | ||
1238 | mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; | ||
1239 | mode->vdisplay = (vtot & 0xffff) + 1; | ||
1240 | mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; | ||
1241 | mode->vsync_start = (vsync & 0xffff) + 1; | ||
1242 | mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; | ||
1243 | |||
1244 | drm_mode_set_name(mode); | ||
1245 | drm_mode_set_crtcinfo(mode, 0); | ||
1246 | |||
1247 | return mode; | ||
1248 | } | ||
1249 | |||
1250 | void psb_intel_crtc_destroy(struct drm_crtc *crtc) | ||
1251 | { | ||
1252 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1253 | struct gtt_range *gt; | ||
1254 | |||
1255 | /* Unpin the old GEM object */ | ||
1256 | if (psb_intel_crtc->cursor_obj) { | ||
1257 | gt = container_of(psb_intel_crtc->cursor_obj, | ||
1258 | struct gtt_range, gem); | ||
1259 | psb_gtt_unpin(gt); | ||
1260 | drm_gem_object_unreference(psb_intel_crtc->cursor_obj); | ||
1261 | psb_intel_crtc->cursor_obj = NULL; | ||
1262 | } | ||
1263 | kfree(psb_intel_crtc->crtc_state); | ||
1264 | drm_crtc_cleanup(crtc); | ||
1265 | kfree(psb_intel_crtc); | ||
1266 | } | ||
1267 | |||
1268 | const struct drm_crtc_helper_funcs psb_intel_helper_funcs = { | ||
1269 | .dpms = psb_intel_crtc_dpms, | ||
1270 | .mode_fixup = psb_intel_crtc_mode_fixup, | ||
1271 | .mode_set = psb_intel_crtc_mode_set, | ||
1272 | .mode_set_base = psb_intel_pipe_set_base, | ||
1273 | .prepare = psb_intel_crtc_prepare, | ||
1274 | .commit = psb_intel_crtc_commit, | ||
1275 | }; | ||
1276 | |||
1277 | const struct drm_crtc_funcs psb_intel_crtc_funcs = { | ||
1278 | .save = psb_intel_crtc_save, | ||
1279 | .restore = psb_intel_crtc_restore, | ||
1280 | .cursor_set = psb_intel_crtc_cursor_set, | ||
1281 | .cursor_move = psb_intel_crtc_cursor_move, | ||
1282 | .gamma_set = psb_intel_crtc_gamma_set, | ||
1283 | .set_config = psb_crtc_set_config, | ||
1284 | .destroy = psb_intel_crtc_destroy, | ||
1285 | }; | ||
1286 | |||
1287 | /* | ||
1288 | * Set the default value of cursor control and base register | ||
1289 | * to zero. This is a workaround for h/w defect on Oaktrail | ||
1290 | */ | ||
1291 | static void psb_intel_cursor_init(struct drm_device *dev, int pipe) | ||
1292 | { | ||
1293 | u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR }; | ||
1294 | u32 base[3] = { CURABASE, CURBBASE, CURCBASE }; | ||
1295 | |||
1296 | REG_WRITE(control[pipe], 0); | ||
1297 | REG_WRITE(base[pipe], 0); | ||
1298 | } | ||
1299 | |||
1300 | void psb_intel_crtc_init(struct drm_device *dev, int pipe, | ||
1301 | struct psb_intel_mode_device *mode_dev) | ||
1302 | { | ||
1303 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1304 | struct psb_intel_crtc *psb_intel_crtc; | ||
1305 | int i; | ||
1306 | uint16_t *r_base, *g_base, *b_base; | ||
1307 | |||
1308 | /* We allocate a extra array of drm_connector pointers | ||
1309 | * for fbdev after the crtc */ | ||
1310 | psb_intel_crtc = | ||
1311 | kzalloc(sizeof(struct psb_intel_crtc) + | ||
1312 | (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), | ||
1313 | GFP_KERNEL); | ||
1314 | if (psb_intel_crtc == NULL) | ||
1315 | return; | ||
1316 | |||
1317 | psb_intel_crtc->crtc_state = | ||
1318 | kzalloc(sizeof(struct psb_intel_crtc_state), GFP_KERNEL); | ||
1319 | if (!psb_intel_crtc->crtc_state) { | ||
1320 | dev_err(dev->dev, "Crtc state error: No memory\n"); | ||
1321 | kfree(psb_intel_crtc); | ||
1322 | return; | ||
1323 | } | ||
1324 | |||
1325 | /* Set the CRTC operations from the chip specific data */ | ||
1326 | drm_crtc_init(dev, &psb_intel_crtc->base, dev_priv->ops->crtc_funcs); | ||
1327 | |||
1328 | drm_mode_crtc_set_gamma_size(&psb_intel_crtc->base, 256); | ||
1329 | psb_intel_crtc->pipe = pipe; | ||
1330 | psb_intel_crtc->plane = pipe; | ||
1331 | |||
1332 | r_base = psb_intel_crtc->base.gamma_store; | ||
1333 | g_base = r_base + 256; | ||
1334 | b_base = g_base + 256; | ||
1335 | for (i = 0; i < 256; i++) { | ||
1336 | psb_intel_crtc->lut_r[i] = i; | ||
1337 | psb_intel_crtc->lut_g[i] = i; | ||
1338 | psb_intel_crtc->lut_b[i] = i; | ||
1339 | r_base[i] = i << 8; | ||
1340 | g_base[i] = i << 8; | ||
1341 | b_base[i] = i << 8; | ||
1342 | |||
1343 | psb_intel_crtc->lut_adj[i] = 0; | ||
1344 | } | ||
1345 | |||
1346 | psb_intel_crtc->mode_dev = mode_dev; | ||
1347 | psb_intel_crtc->cursor_addr = 0; | ||
1348 | |||
1349 | drm_crtc_helper_add(&psb_intel_crtc->base, | ||
1350 | dev_priv->ops->crtc_helper); | ||
1351 | |||
1352 | /* Setup the array of drm_connector pointer array */ | ||
1353 | psb_intel_crtc->mode_set.crtc = &psb_intel_crtc->base; | ||
1354 | BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || | ||
1355 | dev_priv->plane_to_crtc_mapping[psb_intel_crtc->plane] != NULL); | ||
1356 | dev_priv->plane_to_crtc_mapping[psb_intel_crtc->plane] = | ||
1357 | &psb_intel_crtc->base; | ||
1358 | dev_priv->pipe_to_crtc_mapping[psb_intel_crtc->pipe] = | ||
1359 | &psb_intel_crtc->base; | ||
1360 | psb_intel_crtc->mode_set.connectors = | ||
1361 | (struct drm_connector **) (psb_intel_crtc + 1); | ||
1362 | psb_intel_crtc->mode_set.num_connectors = 0; | ||
1363 | psb_intel_cursor_init(dev, pipe); | ||
1364 | } | ||
1365 | |||
1366 | int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, | ||
1367 | struct drm_file *file_priv) | ||
1368 | { | ||
1369 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1370 | struct drm_psb_get_pipe_from_crtc_id_arg *pipe_from_crtc_id = data; | ||
1371 | struct drm_mode_object *drmmode_obj; | ||
1372 | struct psb_intel_crtc *crtc; | ||
1373 | |||
1374 | if (!dev_priv) { | ||
1375 | dev_err(dev->dev, "called with no initialization\n"); | ||
1376 | return -EINVAL; | ||
1377 | } | ||
1378 | |||
1379 | drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id, | ||
1380 | DRM_MODE_OBJECT_CRTC); | ||
1381 | |||
1382 | if (!drmmode_obj) { | ||
1383 | dev_err(dev->dev, "no such CRTC id\n"); | ||
1384 | return -EINVAL; | ||
1385 | } | ||
1386 | |||
1387 | crtc = to_psb_intel_crtc(obj_to_crtc(drmmode_obj)); | ||
1388 | pipe_from_crtc_id->pipe = crtc->pipe; | ||
1389 | |||
1390 | return 0; | ||
1391 | } | ||
1392 | |||
1393 | struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) | ||
1394 | { | ||
1395 | struct drm_crtc *crtc = NULL; | ||
1396 | |||
1397 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
1398 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
1399 | if (psb_intel_crtc->pipe == pipe) | ||
1400 | break; | ||
1401 | } | ||
1402 | return crtc; | ||
1403 | } | ||
1404 | |||
1405 | int psb_intel_connector_clones(struct drm_device *dev, int type_mask) | ||
1406 | { | ||
1407 | int index_mask = 0; | ||
1408 | struct drm_connector *connector; | ||
1409 | int entry = 0; | ||
1410 | |||
1411 | list_for_each_entry(connector, &dev->mode_config.connector_list, | ||
1412 | head) { | ||
1413 | struct psb_intel_encoder *psb_intel_encoder = | ||
1414 | psb_intel_attached_encoder(connector); | ||
1415 | if (type_mask & (1 << psb_intel_encoder->type)) | ||
1416 | index_mask |= (1 << entry); | ||
1417 | entry++; | ||
1418 | } | ||
1419 | return index_mask; | ||
1420 | } | ||
1421 | |||
1422 | |||
1423 | void psb_intel_modeset_cleanup(struct drm_device *dev) | ||
1424 | { | ||
1425 | drm_mode_config_cleanup(dev); | ||
1426 | } | ||
1427 | |||
1428 | |||
1429 | /* current intel driver doesn't take advantage of encoders | ||
1430 | always give back the encoder for the connector | ||
1431 | */ | ||
1432 | struct drm_encoder *psb_intel_best_encoder(struct drm_connector *connector) | ||
1433 | { | ||
1434 | struct psb_intel_encoder *psb_intel_encoder = | ||
1435 | psb_intel_attached_encoder(connector); | ||
1436 | |||
1437 | return &psb_intel_encoder->base; | ||
1438 | } | ||
1439 | |||
1440 | void psb_intel_connector_attach_encoder(struct psb_intel_connector *connector, | ||
1441 | struct psb_intel_encoder *encoder) | ||
1442 | { | ||
1443 | connector->encoder = encoder; | ||
1444 | drm_mode_connector_attach_encoder(&connector->base, | ||
1445 | &encoder->base); | ||
1446 | } | ||
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.h b/drivers/gpu/drm/gma500/psb_intel_display.h new file mode 100644 index 00000000000..535b49a5e40 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_intel_display.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* copyright (c) 2008, Intel Corporation | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify it | ||
4 | * under the terms and conditions of the GNU General Public License, | ||
5 | * version 2, as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
8 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
9 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
10 | * more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License along with | ||
13 | * this program; if not, write to the Free Software Foundation, Inc., | ||
14 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
15 | * | ||
16 | * Authors: | ||
17 | * Eric Anholt <eric@anholt.net> | ||
18 | */ | ||
19 | |||
20 | #ifndef _INTEL_DISPLAY_H_ | ||
21 | #define _INTEL_DISPLAY_H_ | ||
22 | |||
23 | bool psb_intel_pipe_has_type(struct drm_crtc *crtc, int type); | ||
24 | void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, | ||
25 | u16 *green, u16 *blue, uint32_t type, uint32_t size); | ||
26 | void psb_intel_crtc_destroy(struct drm_crtc *crtc); | ||
27 | |||
28 | #endif | ||
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h new file mode 100644 index 00000000000..f40535e5668 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h | |||
@@ -0,0 +1,289 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2009-2011, Intel Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef __INTEL_DRV_H__ | ||
20 | #define __INTEL_DRV_H__ | ||
21 | |||
22 | #include <linux/i2c.h> | ||
23 | #include <linux/i2c-algo-bit.h> | ||
24 | #include <drm/drm_crtc.h> | ||
25 | #include <drm/drm_crtc_helper.h> | ||
26 | #include <linux/gpio.h> | ||
27 | |||
28 | /* | ||
29 | * Display related stuff | ||
30 | */ | ||
31 | |||
32 | /* store information about an Ixxx DVO */ | ||
33 | /* The i830->i865 use multiple DVOs with multiple i2cs */ | ||
34 | /* the i915, i945 have a single sDVO i2c bus - which is different */ | ||
35 | #define MAX_OUTPUTS 6 | ||
36 | /* maximum connectors per crtcs in the mode set */ | ||
37 | #define INTELFB_CONN_LIMIT 4 | ||
38 | |||
39 | #define INTEL_I2C_BUS_DVO 1 | ||
40 | #define INTEL_I2C_BUS_SDVO 2 | ||
41 | |||
42 | /* Intel Pipe Clone Bit */ | ||
43 | #define INTEL_HDMIB_CLONE_BIT 1 | ||
44 | #define INTEL_HDMIC_CLONE_BIT 2 | ||
45 | #define INTEL_HDMID_CLONE_BIT 3 | ||
46 | #define INTEL_HDMIE_CLONE_BIT 4 | ||
47 | #define INTEL_HDMIF_CLONE_BIT 5 | ||
48 | #define INTEL_SDVO_NON_TV_CLONE_BIT 6 | ||
49 | #define INTEL_SDVO_TV_CLONE_BIT 7 | ||
50 | #define INTEL_SDVO_LVDS_CLONE_BIT 8 | ||
51 | #define INTEL_ANALOG_CLONE_BIT 9 | ||
52 | #define INTEL_TV_CLONE_BIT 10 | ||
53 | #define INTEL_DP_B_CLONE_BIT 11 | ||
54 | #define INTEL_DP_C_CLONE_BIT 12 | ||
55 | #define INTEL_DP_D_CLONE_BIT 13 | ||
56 | #define INTEL_LVDS_CLONE_BIT 14 | ||
57 | #define INTEL_DVO_TMDS_CLONE_BIT 15 | ||
58 | #define INTEL_DVO_LVDS_CLONE_BIT 16 | ||
59 | #define INTEL_EDP_CLONE_BIT 17 | ||
60 | |||
61 | /* these are outputs from the chip - integrated only | ||
62 | * external chips are via DVO or SDVO output */ | ||
63 | #define INTEL_OUTPUT_UNUSED 0 | ||
64 | #define INTEL_OUTPUT_ANALOG 1 | ||
65 | #define INTEL_OUTPUT_DVO 2 | ||
66 | #define INTEL_OUTPUT_SDVO 3 | ||
67 | #define INTEL_OUTPUT_LVDS 4 | ||
68 | #define INTEL_OUTPUT_TVOUT 5 | ||
69 | #define INTEL_OUTPUT_HDMI 6 | ||
70 | #define INTEL_OUTPUT_MIPI 7 | ||
71 | #define INTEL_OUTPUT_MIPI2 8 | ||
72 | |||
73 | #define INTEL_DVO_CHIP_NONE 0 | ||
74 | #define INTEL_DVO_CHIP_LVDS 1 | ||
75 | #define INTEL_DVO_CHIP_TMDS 2 | ||
76 | #define INTEL_DVO_CHIP_TVOUT 4 | ||
77 | |||
78 | #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) | ||
79 | #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) | ||
80 | |||
81 | static inline void | ||
82 | psb_intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, | ||
83 | int multiplier) | ||
84 | { | ||
85 | mode->clock *= multiplier; | ||
86 | mode->private_flags |= multiplier; | ||
87 | } | ||
88 | |||
89 | static inline int | ||
90 | psb_intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) | ||
91 | { | ||
92 | return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) | ||
93 | >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT; | ||
94 | } | ||
95 | |||
96 | |||
97 | /* | ||
98 | * Hold information useally put on the device driver privates here, | ||
99 | * since it needs to be shared across multiple of devices drivers privates. | ||
100 | */ | ||
101 | struct psb_intel_mode_device { | ||
102 | |||
103 | /* | ||
104 | * Abstracted memory manager operations | ||
105 | */ | ||
106 | size_t(*bo_offset) (struct drm_device *dev, void *bo); | ||
107 | |||
108 | /* | ||
109 | * Cursor (Can go ?) | ||
110 | */ | ||
111 | int cursor_needs_physical; | ||
112 | |||
113 | /* | ||
114 | * LVDS info | ||
115 | */ | ||
116 | int backlight_duty_cycle; /* restore backlight to this value */ | ||
117 | bool panel_wants_dither; | ||
118 | struct drm_display_mode *panel_fixed_mode; | ||
119 | struct drm_display_mode *panel_fixed_mode2; | ||
120 | struct drm_display_mode *vbt_mode; /* if any */ | ||
121 | |||
122 | uint32_t saveBLC_PWM_CTL; | ||
123 | }; | ||
124 | |||
125 | struct psb_intel_i2c_chan { | ||
126 | /* for getting at dev. private (mmio etc.) */ | ||
127 | struct drm_device *drm_dev; | ||
128 | u32 reg; /* GPIO reg */ | ||
129 | struct i2c_adapter adapter; | ||
130 | struct i2c_algo_bit_data algo; | ||
131 | u8 slave_addr; | ||
132 | }; | ||
133 | |||
134 | struct psb_intel_encoder { | ||
135 | struct drm_encoder base; | ||
136 | int type; | ||
137 | bool needs_tv_clock; | ||
138 | void (*hot_plug)(struct psb_intel_encoder *); | ||
139 | int crtc_mask; | ||
140 | int clone_mask; | ||
141 | void *dev_priv; /* For sdvo_priv, lvds_priv, etc... */ | ||
142 | |||
143 | /* FIXME: Either make SDVO and LVDS store it's i2c here or give CDV it's | ||
144 | own set of output privates */ | ||
145 | struct psb_intel_i2c_chan *i2c_bus; | ||
146 | struct psb_intel_i2c_chan *ddc_bus; | ||
147 | }; | ||
148 | |||
149 | struct psb_intel_connector { | ||
150 | struct drm_connector base; | ||
151 | struct psb_intel_encoder *encoder; | ||
152 | }; | ||
153 | |||
154 | struct psb_intel_crtc_state { | ||
155 | uint32_t saveDSPCNTR; | ||
156 | uint32_t savePIPECONF; | ||
157 | uint32_t savePIPESRC; | ||
158 | uint32_t saveDPLL; | ||
159 | uint32_t saveFP0; | ||
160 | uint32_t saveFP1; | ||
161 | uint32_t saveHTOTAL; | ||
162 | uint32_t saveHBLANK; | ||
163 | uint32_t saveHSYNC; | ||
164 | uint32_t saveVTOTAL; | ||
165 | uint32_t saveVBLANK; | ||
166 | uint32_t saveVSYNC; | ||
167 | uint32_t saveDSPSTRIDE; | ||
168 | uint32_t saveDSPSIZE; | ||
169 | uint32_t saveDSPPOS; | ||
170 | uint32_t saveDSPBASE; | ||
171 | uint32_t savePalette[256]; | ||
172 | }; | ||
173 | |||
174 | struct psb_intel_crtc { | ||
175 | struct drm_crtc base; | ||
176 | int pipe; | ||
177 | int plane; | ||
178 | uint32_t cursor_addr; | ||
179 | u8 lut_r[256], lut_g[256], lut_b[256]; | ||
180 | u8 lut_adj[256]; | ||
181 | struct psb_intel_framebuffer *fbdev_fb; | ||
182 | /* a mode_set for fbdev users on this crtc */ | ||
183 | struct drm_mode_set mode_set; | ||
184 | |||
185 | /* GEM object that holds our cursor */ | ||
186 | struct drm_gem_object *cursor_obj; | ||
187 | |||
188 | struct drm_display_mode saved_mode; | ||
189 | struct drm_display_mode saved_adjusted_mode; | ||
190 | |||
191 | struct psb_intel_mode_device *mode_dev; | ||
192 | |||
193 | /*crtc mode setting flags*/ | ||
194 | u32 mode_flags; | ||
195 | |||
196 | /* Saved Crtc HW states */ | ||
197 | struct psb_intel_crtc_state *crtc_state; | ||
198 | }; | ||
199 | |||
200 | #define to_psb_intel_crtc(x) \ | ||
201 | container_of(x, struct psb_intel_crtc, base) | ||
202 | #define to_psb_intel_connector(x) \ | ||
203 | container_of(x, struct psb_intel_connector, base) | ||
204 | #define to_psb_intel_encoder(x) \ | ||
205 | container_of(x, struct psb_intel_encoder, base) | ||
206 | #define to_psb_intel_framebuffer(x) \ | ||
207 | container_of(x, struct psb_intel_framebuffer, base) | ||
208 | |||
209 | struct psb_intel_i2c_chan *psb_intel_i2c_create(struct drm_device *dev, | ||
210 | const u32 reg, const char *name); | ||
211 | void psb_intel_i2c_destroy(struct psb_intel_i2c_chan *chan); | ||
212 | int psb_intel_ddc_get_modes(struct drm_connector *connector, | ||
213 | struct i2c_adapter *adapter); | ||
214 | extern bool psb_intel_ddc_probe(struct i2c_adapter *adapter); | ||
215 | |||
216 | extern void psb_intel_crtc_init(struct drm_device *dev, int pipe, | ||
217 | struct psb_intel_mode_device *mode_dev); | ||
218 | extern void psb_intel_crt_init(struct drm_device *dev); | ||
219 | extern bool psb_intel_sdvo_init(struct drm_device *dev, int output_device); | ||
220 | extern void psb_intel_dvo_init(struct drm_device *dev); | ||
221 | extern void psb_intel_tv_init(struct drm_device *dev); | ||
222 | extern void psb_intel_lvds_init(struct drm_device *dev, | ||
223 | struct psb_intel_mode_device *mode_dev); | ||
224 | extern void psb_intel_lvds_set_brightness(struct drm_device *dev, int level); | ||
225 | extern void oaktrail_lvds_init(struct drm_device *dev, | ||
226 | struct psb_intel_mode_device *mode_dev); | ||
227 | extern void oaktrail_wait_for_INTR_PKT_SENT(struct drm_device *dev); | ||
228 | extern void oaktrail_dsi_init(struct drm_device *dev, | ||
229 | struct psb_intel_mode_device *mode_dev); | ||
230 | extern void mid_dsi_init(struct drm_device *dev, | ||
231 | struct psb_intel_mode_device *mode_dev, int dsi_num); | ||
232 | |||
233 | extern void psb_intel_crtc_load_lut(struct drm_crtc *crtc); | ||
234 | extern void psb_intel_encoder_prepare(struct drm_encoder *encoder); | ||
235 | extern void psb_intel_encoder_commit(struct drm_encoder *encoder); | ||
236 | extern void psb_intel_encoder_destroy(struct drm_encoder *encoder); | ||
237 | |||
238 | static inline struct psb_intel_encoder *psb_intel_attached_encoder( | ||
239 | struct drm_connector *connector) | ||
240 | { | ||
241 | return to_psb_intel_connector(connector)->encoder; | ||
242 | } | ||
243 | |||
244 | extern void psb_intel_connector_attach_encoder( | ||
245 | struct psb_intel_connector *connector, | ||
246 | struct psb_intel_encoder *encoder); | ||
247 | |||
248 | extern struct drm_encoder *psb_intel_best_encoder(struct drm_connector | ||
249 | *connector); | ||
250 | |||
251 | extern struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, | ||
252 | struct drm_crtc *crtc); | ||
253 | extern void psb_intel_wait_for_vblank(struct drm_device *dev); | ||
254 | extern int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, | ||
255 | struct drm_file *file_priv); | ||
256 | extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, | ||
257 | int pipe); | ||
258 | extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev, | ||
259 | int sdvoB); | ||
260 | extern int psb_intel_sdvo_supports_hotplug(struct drm_connector *connector); | ||
261 | extern void psb_intel_sdvo_set_hotplug(struct drm_connector *connector, | ||
262 | int enable); | ||
263 | extern int intelfb_probe(struct drm_device *dev); | ||
264 | extern int intelfb_remove(struct drm_device *dev, | ||
265 | struct drm_framebuffer *fb); | ||
266 | extern struct drm_framebuffer *psb_intel_framebuffer_create(struct drm_device | ||
267 | *dev, struct | ||
268 | drm_mode_fb_cmd | ||
269 | *mode_cmd, | ||
270 | void *mm_private); | ||
271 | extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, | ||
272 | struct drm_display_mode *mode, | ||
273 | struct drm_display_mode *adjusted_mode); | ||
274 | extern int psb_intel_lvds_mode_valid(struct drm_connector *connector, | ||
275 | struct drm_display_mode *mode); | ||
276 | extern int psb_intel_lvds_set_property(struct drm_connector *connector, | ||
277 | struct drm_property *property, | ||
278 | uint64_t value); | ||
279 | extern void psb_intel_lvds_destroy(struct drm_connector *connector); | ||
280 | extern const struct drm_encoder_funcs psb_intel_lvds_enc_funcs; | ||
281 | |||
282 | /* intel_gmbus.c */ | ||
283 | extern void gma_intel_i2c_reset(struct drm_device *dev); | ||
284 | extern int gma_intel_setup_gmbus(struct drm_device *dev); | ||
285 | extern void gma_intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed); | ||
286 | extern void gma_intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit); | ||
287 | extern void gma_intel_teardown_gmbus(struct drm_device *dev); | ||
288 | |||
289 | #endif /* __INTEL_DRV_H__ */ | ||
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c new file mode 100644 index 00000000000..a25e4ca5e91 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c | |||
@@ -0,0 +1,868 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | * Dave Airlie <airlied@linux.ie> | ||
20 | * Jesse Barnes <jesse.barnes@intel.com> | ||
21 | */ | ||
22 | |||
23 | #include <linux/i2c.h> | ||
24 | #include <drm/drmP.h> | ||
25 | |||
26 | #include "intel_bios.h" | ||
27 | #include "psb_drv.h" | ||
28 | #include "psb_intel_drv.h" | ||
29 | #include "psb_intel_reg.h" | ||
30 | #include "power.h" | ||
31 | #include <linux/pm_runtime.h> | ||
32 | |||
33 | /* | ||
34 | * LVDS I2C backlight control macros | ||
35 | */ | ||
36 | #define BRIGHTNESS_MAX_LEVEL 100 | ||
37 | #define BRIGHTNESS_MASK 0xFF | ||
38 | #define BLC_I2C_TYPE 0x01 | ||
39 | #define BLC_PWM_TYPT 0x02 | ||
40 | |||
41 | #define BLC_POLARITY_NORMAL 0 | ||
42 | #define BLC_POLARITY_INVERSE 1 | ||
43 | |||
44 | #define PSB_BLC_MAX_PWM_REG_FREQ (0xFFFE) | ||
45 | #define PSB_BLC_MIN_PWM_REG_FREQ (0x2) | ||
46 | #define PSB_BLC_PWM_PRECISION_FACTOR (10) | ||
47 | #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) | ||
48 | #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) | ||
49 | |||
50 | struct psb_intel_lvds_priv { | ||
51 | /* | ||
52 | * Saved LVDO output states | ||
53 | */ | ||
54 | uint32_t savePP_ON; | ||
55 | uint32_t savePP_OFF; | ||
56 | uint32_t saveLVDS; | ||
57 | uint32_t savePP_CONTROL; | ||
58 | uint32_t savePP_CYCLE; | ||
59 | uint32_t savePFIT_CONTROL; | ||
60 | uint32_t savePFIT_PGM_RATIOS; | ||
61 | uint32_t saveBLC_PWM_CTL; | ||
62 | |||
63 | struct psb_intel_i2c_chan *i2c_bus; | ||
64 | struct psb_intel_i2c_chan *ddc_bus; | ||
65 | }; | ||
66 | |||
67 | |||
68 | /* | ||
69 | * Returns the maximum level of the backlight duty cycle field. | ||
70 | */ | ||
71 | static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev) | ||
72 | { | ||
73 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
74 | u32 ret; | ||
75 | |||
76 | if (gma_power_begin(dev, false)) { | ||
77 | ret = REG_READ(BLC_PWM_CTL); | ||
78 | gma_power_end(dev); | ||
79 | } else /* Powered off, use the saved value */ | ||
80 | ret = dev_priv->saveBLC_PWM_CTL; | ||
81 | |||
82 | /* Top 15bits hold the frequency mask */ | ||
83 | ret = (ret & BACKLIGHT_MODULATION_FREQ_MASK) >> | ||
84 | BACKLIGHT_MODULATION_FREQ_SHIFT; | ||
85 | |||
86 | ret *= 2; /* Return a 16bit range as needed for setting */ | ||
87 | if (ret == 0) | ||
88 | dev_err(dev->dev, "BL bug: Reg %08x save %08X\n", | ||
89 | REG_READ(BLC_PWM_CTL), dev_priv->saveBLC_PWM_CTL); | ||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Set LVDS backlight level by I2C command | ||
95 | * | ||
96 | * FIXME: at some point we need to both track this for PM and also | ||
97 | * disable runtime pm on MRST if the brightness is nil (ie blanked) | ||
98 | */ | ||
99 | static int psb_lvds_i2c_set_brightness(struct drm_device *dev, | ||
100 | unsigned int level) | ||
101 | { | ||
102 | struct drm_psb_private *dev_priv = | ||
103 | (struct drm_psb_private *)dev->dev_private; | ||
104 | |||
105 | struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; | ||
106 | u8 out_buf[2]; | ||
107 | unsigned int blc_i2c_brightness; | ||
108 | |||
109 | struct i2c_msg msgs[] = { | ||
110 | { | ||
111 | .addr = lvds_i2c_bus->slave_addr, | ||
112 | .flags = 0, | ||
113 | .len = 2, | ||
114 | .buf = out_buf, | ||
115 | } | ||
116 | }; | ||
117 | |||
118 | blc_i2c_brightness = BRIGHTNESS_MASK & ((unsigned int)level * | ||
119 | BRIGHTNESS_MASK / | ||
120 | BRIGHTNESS_MAX_LEVEL); | ||
121 | |||
122 | if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) | ||
123 | blc_i2c_brightness = BRIGHTNESS_MASK - blc_i2c_brightness; | ||
124 | |||
125 | out_buf[0] = dev_priv->lvds_bl->brightnesscmd; | ||
126 | out_buf[1] = (u8)blc_i2c_brightness; | ||
127 | |||
128 | if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) { | ||
129 | dev_dbg(dev->dev, "I2C set brightness.(command, value) (%d, %d)\n", | ||
130 | dev_priv->lvds_bl->brightnesscmd, | ||
131 | blc_i2c_brightness); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | dev_err(dev->dev, "I2C transfer error\n"); | ||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | |||
140 | static int psb_lvds_pwm_set_brightness(struct drm_device *dev, int level) | ||
141 | { | ||
142 | struct drm_psb_private *dev_priv = | ||
143 | (struct drm_psb_private *)dev->dev_private; | ||
144 | |||
145 | u32 max_pwm_blc; | ||
146 | u32 blc_pwm_duty_cycle; | ||
147 | |||
148 | max_pwm_blc = psb_intel_lvds_get_max_backlight(dev); | ||
149 | |||
150 | /*BLC_PWM_CTL Should be initiated while backlight device init*/ | ||
151 | BUG_ON(max_pwm_blc == 0); | ||
152 | |||
153 | blc_pwm_duty_cycle = level * max_pwm_blc / BRIGHTNESS_MAX_LEVEL; | ||
154 | |||
155 | if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) | ||
156 | blc_pwm_duty_cycle = max_pwm_blc - blc_pwm_duty_cycle; | ||
157 | |||
158 | blc_pwm_duty_cycle &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; | ||
159 | REG_WRITE(BLC_PWM_CTL, | ||
160 | (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) | | ||
161 | (blc_pwm_duty_cycle)); | ||
162 | |||
163 | dev_info(dev->dev, "Backlight lvds set brightness %08x\n", | ||
164 | (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) | | ||
165 | (blc_pwm_duty_cycle)); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Set LVDS backlight level either by I2C or PWM | ||
172 | */ | ||
173 | void psb_intel_lvds_set_brightness(struct drm_device *dev, int level) | ||
174 | { | ||
175 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
176 | |||
177 | dev_dbg(dev->dev, "backlight level is %d\n", level); | ||
178 | |||
179 | if (!dev_priv->lvds_bl) { | ||
180 | dev_err(dev->dev, "NO LVDS backlight info\n"); | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | if (dev_priv->lvds_bl->type == BLC_I2C_TYPE) | ||
185 | psb_lvds_i2c_set_brightness(dev, level); | ||
186 | else | ||
187 | psb_lvds_pwm_set_brightness(dev, level); | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Sets the backlight level. | ||
192 | * | ||
193 | * level: backlight level, from 0 to psb_intel_lvds_get_max_backlight(). | ||
194 | */ | ||
195 | static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level) | ||
196 | { | ||
197 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
198 | u32 blc_pwm_ctl; | ||
199 | |||
200 | if (gma_power_begin(dev, false)) { | ||
201 | blc_pwm_ctl = REG_READ(BLC_PWM_CTL); | ||
202 | blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; | ||
203 | REG_WRITE(BLC_PWM_CTL, | ||
204 | (blc_pwm_ctl | | ||
205 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); | ||
206 | dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl | | ||
207 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); | ||
208 | gma_power_end(dev); | ||
209 | } else { | ||
210 | blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL & | ||
211 | ~BACKLIGHT_DUTY_CYCLE_MASK; | ||
212 | dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl | | ||
213 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Sets the power state for the panel. | ||
219 | */ | ||
220 | static void psb_intel_lvds_set_power(struct drm_device *dev, bool on) | ||
221 | { | ||
222 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
223 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
224 | u32 pp_status; | ||
225 | |||
226 | if (!gma_power_begin(dev, true)) { | ||
227 | dev_err(dev->dev, "set power, chip off!\n"); | ||
228 | return; | ||
229 | } | ||
230 | |||
231 | if (on) { | ||
232 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | | ||
233 | POWER_TARGET_ON); | ||
234 | do { | ||
235 | pp_status = REG_READ(PP_STATUS); | ||
236 | } while ((pp_status & PP_ON) == 0); | ||
237 | |||
238 | psb_intel_lvds_set_backlight(dev, | ||
239 | mode_dev->backlight_duty_cycle); | ||
240 | } else { | ||
241 | psb_intel_lvds_set_backlight(dev, 0); | ||
242 | |||
243 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & | ||
244 | ~POWER_TARGET_ON); | ||
245 | do { | ||
246 | pp_status = REG_READ(PP_STATUS); | ||
247 | } while (pp_status & PP_ON); | ||
248 | } | ||
249 | |||
250 | gma_power_end(dev); | ||
251 | } | ||
252 | |||
253 | static void psb_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
254 | { | ||
255 | struct drm_device *dev = encoder->dev; | ||
256 | |||
257 | if (mode == DRM_MODE_DPMS_ON) | ||
258 | psb_intel_lvds_set_power(dev, true); | ||
259 | else | ||
260 | psb_intel_lvds_set_power(dev, false); | ||
261 | |||
262 | /* XXX: We never power down the LVDS pairs. */ | ||
263 | } | ||
264 | |||
265 | static void psb_intel_lvds_save(struct drm_connector *connector) | ||
266 | { | ||
267 | struct drm_device *dev = connector->dev; | ||
268 | struct drm_psb_private *dev_priv = | ||
269 | (struct drm_psb_private *)dev->dev_private; | ||
270 | struct psb_intel_encoder *psb_intel_encoder = | ||
271 | psb_intel_attached_encoder(connector); | ||
272 | struct psb_intel_lvds_priv *lvds_priv = | ||
273 | (struct psb_intel_lvds_priv *)psb_intel_encoder->dev_priv; | ||
274 | |||
275 | lvds_priv->savePP_ON = REG_READ(LVDSPP_ON); | ||
276 | lvds_priv->savePP_OFF = REG_READ(LVDSPP_OFF); | ||
277 | lvds_priv->saveLVDS = REG_READ(LVDS); | ||
278 | lvds_priv->savePP_CONTROL = REG_READ(PP_CONTROL); | ||
279 | lvds_priv->savePP_CYCLE = REG_READ(PP_CYCLE); | ||
280 | /*lvds_priv->savePP_DIVISOR = REG_READ(PP_DIVISOR);*/ | ||
281 | lvds_priv->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); | ||
282 | lvds_priv->savePFIT_CONTROL = REG_READ(PFIT_CONTROL); | ||
283 | lvds_priv->savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS); | ||
284 | |||
285 | /*TODO: move backlight_duty_cycle to psb_intel_lvds_priv*/ | ||
286 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & | ||
287 | BACKLIGHT_DUTY_CYCLE_MASK); | ||
288 | |||
289 | /* | ||
290 | * If the light is off at server startup, | ||
291 | * just make it full brightness | ||
292 | */ | ||
293 | if (dev_priv->backlight_duty_cycle == 0) | ||
294 | dev_priv->backlight_duty_cycle = | ||
295 | psb_intel_lvds_get_max_backlight(dev); | ||
296 | |||
297 | dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", | ||
298 | lvds_priv->savePP_ON, | ||
299 | lvds_priv->savePP_OFF, | ||
300 | lvds_priv->saveLVDS, | ||
301 | lvds_priv->savePP_CONTROL, | ||
302 | lvds_priv->savePP_CYCLE, | ||
303 | lvds_priv->saveBLC_PWM_CTL); | ||
304 | } | ||
305 | |||
306 | static void psb_intel_lvds_restore(struct drm_connector *connector) | ||
307 | { | ||
308 | struct drm_device *dev = connector->dev; | ||
309 | u32 pp_status; | ||
310 | struct psb_intel_encoder *psb_intel_encoder = | ||
311 | psb_intel_attached_encoder(connector); | ||
312 | struct psb_intel_lvds_priv *lvds_priv = | ||
313 | (struct psb_intel_lvds_priv *)psb_intel_encoder->dev_priv; | ||
314 | |||
315 | dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", | ||
316 | lvds_priv->savePP_ON, | ||
317 | lvds_priv->savePP_OFF, | ||
318 | lvds_priv->saveLVDS, | ||
319 | lvds_priv->savePP_CONTROL, | ||
320 | lvds_priv->savePP_CYCLE, | ||
321 | lvds_priv->saveBLC_PWM_CTL); | ||
322 | |||
323 | REG_WRITE(BLC_PWM_CTL, lvds_priv->saveBLC_PWM_CTL); | ||
324 | REG_WRITE(PFIT_CONTROL, lvds_priv->savePFIT_CONTROL); | ||
325 | REG_WRITE(PFIT_PGM_RATIOS, lvds_priv->savePFIT_PGM_RATIOS); | ||
326 | REG_WRITE(LVDSPP_ON, lvds_priv->savePP_ON); | ||
327 | REG_WRITE(LVDSPP_OFF, lvds_priv->savePP_OFF); | ||
328 | /*REG_WRITE(PP_DIVISOR, lvds_priv->savePP_DIVISOR);*/ | ||
329 | REG_WRITE(PP_CYCLE, lvds_priv->savePP_CYCLE); | ||
330 | REG_WRITE(PP_CONTROL, lvds_priv->savePP_CONTROL); | ||
331 | REG_WRITE(LVDS, lvds_priv->saveLVDS); | ||
332 | |||
333 | if (lvds_priv->savePP_CONTROL & POWER_TARGET_ON) { | ||
334 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | | ||
335 | POWER_TARGET_ON); | ||
336 | do { | ||
337 | pp_status = REG_READ(PP_STATUS); | ||
338 | } while ((pp_status & PP_ON) == 0); | ||
339 | } else { | ||
340 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & | ||
341 | ~POWER_TARGET_ON); | ||
342 | do { | ||
343 | pp_status = REG_READ(PP_STATUS); | ||
344 | } while (pp_status & PP_ON); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | int psb_intel_lvds_mode_valid(struct drm_connector *connector, | ||
349 | struct drm_display_mode *mode) | ||
350 | { | ||
351 | struct drm_psb_private *dev_priv = connector->dev->dev_private; | ||
352 | struct psb_intel_encoder *psb_intel_encoder = | ||
353 | psb_intel_attached_encoder(connector); | ||
354 | struct drm_display_mode *fixed_mode = | ||
355 | dev_priv->mode_dev.panel_fixed_mode; | ||
356 | |||
357 | if (psb_intel_encoder->type == INTEL_OUTPUT_MIPI2) | ||
358 | fixed_mode = dev_priv->mode_dev.panel_fixed_mode2; | ||
359 | |||
360 | /* just in case */ | ||
361 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
362 | return MODE_NO_DBLESCAN; | ||
363 | |||
364 | /* just in case */ | ||
365 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
366 | return MODE_NO_INTERLACE; | ||
367 | |||
368 | if (fixed_mode) { | ||
369 | if (mode->hdisplay > fixed_mode->hdisplay) | ||
370 | return MODE_PANEL; | ||
371 | if (mode->vdisplay > fixed_mode->vdisplay) | ||
372 | return MODE_PANEL; | ||
373 | } | ||
374 | return MODE_OK; | ||
375 | } | ||
376 | |||
377 | bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, | ||
378 | struct drm_display_mode *mode, | ||
379 | struct drm_display_mode *adjusted_mode) | ||
380 | { | ||
381 | struct drm_device *dev = encoder->dev; | ||
382 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
383 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
384 | struct psb_intel_crtc *psb_intel_crtc = | ||
385 | to_psb_intel_crtc(encoder->crtc); | ||
386 | struct drm_encoder *tmp_encoder; | ||
387 | struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; | ||
388 | struct psb_intel_encoder *psb_intel_encoder = | ||
389 | to_psb_intel_encoder(encoder); | ||
390 | |||
391 | if (psb_intel_encoder->type == INTEL_OUTPUT_MIPI2) | ||
392 | panel_fixed_mode = mode_dev->panel_fixed_mode2; | ||
393 | |||
394 | /* PSB requires the LVDS is on pipe B, MRST has only one pipe anyway */ | ||
395 | if (!IS_MRST(dev) && psb_intel_crtc->pipe == 0) { | ||
396 | printk(KERN_ERR "Can't support LVDS on pipe A\n"); | ||
397 | return false; | ||
398 | } | ||
399 | if (IS_MRST(dev) && psb_intel_crtc->pipe != 0) { | ||
400 | printk(KERN_ERR "Must use PIPE A\n"); | ||
401 | return false; | ||
402 | } | ||
403 | /* Should never happen!! */ | ||
404 | list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, | ||
405 | head) { | ||
406 | if (tmp_encoder != encoder | ||
407 | && tmp_encoder->crtc == encoder->crtc) { | ||
408 | printk(KERN_ERR "Can't enable LVDS and another " | ||
409 | "encoder on the same pipe\n"); | ||
410 | return false; | ||
411 | } | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * If we have timings from the BIOS for the panel, put them in | ||
416 | * to the adjusted mode. The CRTC will be set up for this mode, | ||
417 | * with the panel scaling set up to source from the H/VDisplay | ||
418 | * of the original mode. | ||
419 | */ | ||
420 | if (panel_fixed_mode != NULL) { | ||
421 | adjusted_mode->hdisplay = panel_fixed_mode->hdisplay; | ||
422 | adjusted_mode->hsync_start = panel_fixed_mode->hsync_start; | ||
423 | adjusted_mode->hsync_end = panel_fixed_mode->hsync_end; | ||
424 | adjusted_mode->htotal = panel_fixed_mode->htotal; | ||
425 | adjusted_mode->vdisplay = panel_fixed_mode->vdisplay; | ||
426 | adjusted_mode->vsync_start = panel_fixed_mode->vsync_start; | ||
427 | adjusted_mode->vsync_end = panel_fixed_mode->vsync_end; | ||
428 | adjusted_mode->vtotal = panel_fixed_mode->vtotal; | ||
429 | adjusted_mode->clock = panel_fixed_mode->clock; | ||
430 | drm_mode_set_crtcinfo(adjusted_mode, | ||
431 | CRTC_INTERLACE_HALVE_V); | ||
432 | } | ||
433 | |||
434 | /* | ||
435 | * XXX: It would be nice to support lower refresh rates on the | ||
436 | * panels to reduce power consumption, and perhaps match the | ||
437 | * user's requested refresh rate. | ||
438 | */ | ||
439 | |||
440 | return true; | ||
441 | } | ||
442 | |||
443 | static void psb_intel_lvds_prepare(struct drm_encoder *encoder) | ||
444 | { | ||
445 | struct drm_device *dev = encoder->dev; | ||
446 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
447 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
448 | |||
449 | if (!gma_power_begin(dev, true)) | ||
450 | return; | ||
451 | |||
452 | mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); | ||
453 | mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & | ||
454 | BACKLIGHT_DUTY_CYCLE_MASK); | ||
455 | |||
456 | psb_intel_lvds_set_power(dev, false); | ||
457 | |||
458 | gma_power_end(dev); | ||
459 | } | ||
460 | |||
461 | static void psb_intel_lvds_commit(struct drm_encoder *encoder) | ||
462 | { | ||
463 | struct drm_device *dev = encoder->dev; | ||
464 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
465 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
466 | |||
467 | if (mode_dev->backlight_duty_cycle == 0) | ||
468 | mode_dev->backlight_duty_cycle = | ||
469 | psb_intel_lvds_get_max_backlight(dev); | ||
470 | |||
471 | psb_intel_lvds_set_power(dev, true); | ||
472 | } | ||
473 | |||
474 | static void psb_intel_lvds_mode_set(struct drm_encoder *encoder, | ||
475 | struct drm_display_mode *mode, | ||
476 | struct drm_display_mode *adjusted_mode) | ||
477 | { | ||
478 | struct drm_device *dev = encoder->dev; | ||
479 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
480 | u32 pfit_control; | ||
481 | |||
482 | /* | ||
483 | * The LVDS pin pair will already have been turned on in the | ||
484 | * psb_intel_crtc_mode_set since it has a large impact on the DPLL | ||
485 | * settings. | ||
486 | */ | ||
487 | |||
488 | /* | ||
489 | * Enable automatic panel scaling so that non-native modes fill the | ||
490 | * screen. Should be enabled before the pipe is enabled, according to | ||
491 | * register description and PRM. | ||
492 | */ | ||
493 | if (mode->hdisplay != adjusted_mode->hdisplay || | ||
494 | mode->vdisplay != adjusted_mode->vdisplay) | ||
495 | pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | | ||
496 | HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | | ||
497 | HORIZ_INTERP_BILINEAR); | ||
498 | else | ||
499 | pfit_control = 0; | ||
500 | |||
501 | if (dev_priv->lvds_dither) | ||
502 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; | ||
503 | |||
504 | REG_WRITE(PFIT_CONTROL, pfit_control); | ||
505 | } | ||
506 | |||
507 | /* | ||
508 | * Detect the LVDS connection. | ||
509 | * | ||
510 | * This always returns CONNECTOR_STATUS_CONNECTED. | ||
511 | * This connector should only have | ||
512 | * been set up if the LVDS was actually connected anyway. | ||
513 | */ | ||
514 | static enum drm_connector_status psb_intel_lvds_detect(struct drm_connector | ||
515 | *connector, bool force) | ||
516 | { | ||
517 | return connector_status_connected; | ||
518 | } | ||
519 | |||
520 | /* | ||
521 | * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. | ||
522 | */ | ||
523 | static int psb_intel_lvds_get_modes(struct drm_connector *connector) | ||
524 | { | ||
525 | struct drm_device *dev = connector->dev; | ||
526 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
527 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | ||
528 | struct psb_intel_encoder *psb_intel_encoder = | ||
529 | psb_intel_attached_encoder(connector); | ||
530 | struct psb_intel_lvds_priv *lvds_priv = psb_intel_encoder->dev_priv; | ||
531 | int ret = 0; | ||
532 | |||
533 | if (!IS_MRST(dev)) | ||
534 | ret = psb_intel_ddc_get_modes(connector, &lvds_priv->i2c_bus->adapter); | ||
535 | |||
536 | if (ret) | ||
537 | return ret; | ||
538 | |||
539 | /* Didn't get an EDID, so | ||
540 | * Set wide sync ranges so we get all modes | ||
541 | * handed to valid_mode for checking | ||
542 | */ | ||
543 | connector->display_info.min_vfreq = 0; | ||
544 | connector->display_info.max_vfreq = 200; | ||
545 | connector->display_info.min_hfreq = 0; | ||
546 | connector->display_info.max_hfreq = 200; | ||
547 | |||
548 | if (mode_dev->panel_fixed_mode != NULL) { | ||
549 | struct drm_display_mode *mode = | ||
550 | drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); | ||
551 | drm_mode_probed_add(connector, mode); | ||
552 | return 1; | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /** | ||
559 | * psb_intel_lvds_destroy - unregister and free LVDS structures | ||
560 | * @connector: connector to free | ||
561 | * | ||
562 | * Unregister the DDC bus for this connector then free the driver private | ||
563 | * structure. | ||
564 | */ | ||
565 | void psb_intel_lvds_destroy(struct drm_connector *connector) | ||
566 | { | ||
567 | struct psb_intel_encoder *psb_intel_encoder = | ||
568 | psb_intel_attached_encoder(connector); | ||
569 | struct psb_intel_lvds_priv *lvds_priv = psb_intel_encoder->dev_priv; | ||
570 | |||
571 | if (lvds_priv->ddc_bus) | ||
572 | psb_intel_i2c_destroy(lvds_priv->ddc_bus); | ||
573 | drm_sysfs_connector_remove(connector); | ||
574 | drm_connector_cleanup(connector); | ||
575 | kfree(connector); | ||
576 | } | ||
577 | |||
578 | int psb_intel_lvds_set_property(struct drm_connector *connector, | ||
579 | struct drm_property *property, | ||
580 | uint64_t value) | ||
581 | { | ||
582 | struct drm_encoder *encoder = connector->encoder; | ||
583 | |||
584 | if (!encoder) | ||
585 | return -1; | ||
586 | |||
587 | if (!strcmp(property->name, "scaling mode")) { | ||
588 | struct psb_intel_crtc *crtc = | ||
589 | to_psb_intel_crtc(encoder->crtc); | ||
590 | uint64_t curval; | ||
591 | |||
592 | if (!crtc) | ||
593 | goto set_prop_error; | ||
594 | |||
595 | switch (value) { | ||
596 | case DRM_MODE_SCALE_FULLSCREEN: | ||
597 | break; | ||
598 | case DRM_MODE_SCALE_NO_SCALE: | ||
599 | break; | ||
600 | case DRM_MODE_SCALE_ASPECT: | ||
601 | break; | ||
602 | default: | ||
603 | goto set_prop_error; | ||
604 | } | ||
605 | |||
606 | if (drm_connector_property_get_value(connector, | ||
607 | property, | ||
608 | &curval)) | ||
609 | goto set_prop_error; | ||
610 | |||
611 | if (curval == value) | ||
612 | goto set_prop_done; | ||
613 | |||
614 | if (drm_connector_property_set_value(connector, | ||
615 | property, | ||
616 | value)) | ||
617 | goto set_prop_error; | ||
618 | |||
619 | if (crtc->saved_mode.hdisplay != 0 && | ||
620 | crtc->saved_mode.vdisplay != 0) { | ||
621 | if (!drm_crtc_helper_set_mode(encoder->crtc, | ||
622 | &crtc->saved_mode, | ||
623 | encoder->crtc->x, | ||
624 | encoder->crtc->y, | ||
625 | encoder->crtc->fb)) | ||
626 | goto set_prop_error; | ||
627 | } | ||
628 | } else if (!strcmp(property->name, "backlight")) { | ||
629 | if (drm_connector_property_set_value(connector, | ||
630 | property, | ||
631 | value)) | ||
632 | goto set_prop_error; | ||
633 | else { | ||
634 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
635 | struct drm_psb_private *devp = | ||
636 | encoder->dev->dev_private; | ||
637 | struct backlight_device *bd = devp->backlight_device; | ||
638 | if (bd) { | ||
639 | bd->props.brightness = value; | ||
640 | backlight_update_status(bd); | ||
641 | } | ||
642 | #endif | ||
643 | } | ||
644 | } else if (!strcmp(property->name, "DPMS")) { | ||
645 | struct drm_encoder_helper_funcs *hfuncs | ||
646 | = encoder->helper_private; | ||
647 | hfuncs->dpms(encoder, value); | ||
648 | } | ||
649 | |||
650 | set_prop_done: | ||
651 | return 0; | ||
652 | set_prop_error: | ||
653 | return -1; | ||
654 | } | ||
655 | |||
656 | static const struct drm_encoder_helper_funcs psb_intel_lvds_helper_funcs = { | ||
657 | .dpms = psb_intel_lvds_encoder_dpms, | ||
658 | .mode_fixup = psb_intel_lvds_mode_fixup, | ||
659 | .prepare = psb_intel_lvds_prepare, | ||
660 | .mode_set = psb_intel_lvds_mode_set, | ||
661 | .commit = psb_intel_lvds_commit, | ||
662 | }; | ||
663 | |||
664 | const struct drm_connector_helper_funcs | ||
665 | psb_intel_lvds_connector_helper_funcs = { | ||
666 | .get_modes = psb_intel_lvds_get_modes, | ||
667 | .mode_valid = psb_intel_lvds_mode_valid, | ||
668 | .best_encoder = psb_intel_best_encoder, | ||
669 | }; | ||
670 | |||
671 | const struct drm_connector_funcs psb_intel_lvds_connector_funcs = { | ||
672 | .dpms = drm_helper_connector_dpms, | ||
673 | .save = psb_intel_lvds_save, | ||
674 | .restore = psb_intel_lvds_restore, | ||
675 | .detect = psb_intel_lvds_detect, | ||
676 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
677 | .set_property = psb_intel_lvds_set_property, | ||
678 | .destroy = psb_intel_lvds_destroy, | ||
679 | }; | ||
680 | |||
681 | |||
682 | static void psb_intel_lvds_enc_destroy(struct drm_encoder *encoder) | ||
683 | { | ||
684 | drm_encoder_cleanup(encoder); | ||
685 | } | ||
686 | |||
687 | const struct drm_encoder_funcs psb_intel_lvds_enc_funcs = { | ||
688 | .destroy = psb_intel_lvds_enc_destroy, | ||
689 | }; | ||
690 | |||
691 | |||
692 | |||
693 | /** | ||
694 | * psb_intel_lvds_init - setup LVDS connectors on this device | ||
695 | * @dev: drm device | ||
696 | * | ||
697 | * Create the connector, register the LVDS DDC bus, and try to figure out what | ||
698 | * modes we can display on the LVDS panel (if present). | ||
699 | */ | ||
700 | void psb_intel_lvds_init(struct drm_device *dev, | ||
701 | struct psb_intel_mode_device *mode_dev) | ||
702 | { | ||
703 | struct psb_intel_encoder *psb_intel_encoder; | ||
704 | struct psb_intel_connector *psb_intel_connector; | ||
705 | struct psb_intel_lvds_priv *lvds_priv; | ||
706 | struct drm_connector *connector; | ||
707 | struct drm_encoder *encoder; | ||
708 | struct drm_display_mode *scan; /* *modes, *bios_mode; */ | ||
709 | struct drm_crtc *crtc; | ||
710 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
711 | u32 lvds; | ||
712 | int pipe; | ||
713 | |||
714 | psb_intel_encoder = | ||
715 | kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); | ||
716 | |||
717 | if (!psb_intel_encoder) { | ||
718 | dev_err(dev->dev, "psb_intel_encoder allocation error\n"); | ||
719 | return; | ||
720 | } | ||
721 | |||
722 | psb_intel_connector = | ||
723 | kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); | ||
724 | |||
725 | if (!psb_intel_connector) { | ||
726 | kfree(psb_intel_encoder); | ||
727 | dev_err(dev->dev, "psb_intel_connector allocation error\n"); | ||
728 | } | ||
729 | |||
730 | lvds_priv = kzalloc(sizeof(struct psb_intel_lvds_priv), GFP_KERNEL); | ||
731 | if (!lvds_priv) { | ||
732 | dev_err(dev->dev, "LVDS private allocation error\n"); | ||
733 | goto failed_connector; | ||
734 | } | ||
735 | |||
736 | psb_intel_encoder->dev_priv = lvds_priv; | ||
737 | |||
738 | connector = &psb_intel_connector->base; | ||
739 | encoder = &psb_intel_encoder->base; | ||
740 | drm_connector_init(dev, connector, | ||
741 | &psb_intel_lvds_connector_funcs, | ||
742 | DRM_MODE_CONNECTOR_LVDS); | ||
743 | |||
744 | drm_encoder_init(dev, encoder, | ||
745 | &psb_intel_lvds_enc_funcs, | ||
746 | DRM_MODE_ENCODER_LVDS); | ||
747 | |||
748 | psb_intel_connector_attach_encoder(psb_intel_connector, | ||
749 | psb_intel_encoder); | ||
750 | psb_intel_encoder->type = INTEL_OUTPUT_LVDS; | ||
751 | |||
752 | drm_encoder_helper_add(encoder, &psb_intel_lvds_helper_funcs); | ||
753 | drm_connector_helper_add(connector, | ||
754 | &psb_intel_lvds_connector_helper_funcs); | ||
755 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
756 | connector->interlace_allowed = false; | ||
757 | connector->doublescan_allowed = false; | ||
758 | |||
759 | /*Attach connector properties*/ | ||
760 | drm_connector_attach_property(connector, | ||
761 | dev->mode_config.scaling_mode_property, | ||
762 | DRM_MODE_SCALE_FULLSCREEN); | ||
763 | drm_connector_attach_property(connector, | ||
764 | dev_priv->backlight_property, | ||
765 | BRIGHTNESS_MAX_LEVEL); | ||
766 | |||
767 | /* | ||
768 | * Set up I2C bus | ||
769 | * FIXME: distroy i2c_bus when exit | ||
770 | */ | ||
771 | lvds_priv->i2c_bus = psb_intel_i2c_create(dev, GPIOB, "LVDSBLC_B"); | ||
772 | if (!lvds_priv->i2c_bus) { | ||
773 | dev_printk(KERN_ERR, | ||
774 | &dev->pdev->dev, "I2C bus registration failed.\n"); | ||
775 | goto failed_blc_i2c; | ||
776 | } | ||
777 | lvds_priv->i2c_bus->slave_addr = 0x2C; | ||
778 | dev_priv->lvds_i2c_bus = lvds_priv->i2c_bus; | ||
779 | |||
780 | /* | ||
781 | * LVDS discovery: | ||
782 | * 1) check for EDID on DDC | ||
783 | * 2) check for VBT data | ||
784 | * 3) check to see if LVDS is already on | ||
785 | * if none of the above, no panel | ||
786 | * 4) make sure lid is open | ||
787 | * if closed, act like it's not there for now | ||
788 | */ | ||
789 | |||
790 | /* Set up the DDC bus. */ | ||
791 | lvds_priv->ddc_bus = psb_intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); | ||
792 | if (!lvds_priv->ddc_bus) { | ||
793 | dev_printk(KERN_ERR, &dev->pdev->dev, | ||
794 | "DDC bus registration " "failed.\n"); | ||
795 | goto failed_ddc; | ||
796 | } | ||
797 | |||
798 | /* | ||
799 | * Attempt to get the fixed panel mode from DDC. Assume that the | ||
800 | * preferred mode is the right one. | ||
801 | */ | ||
802 | psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->adapter); | ||
803 | list_for_each_entry(scan, &connector->probed_modes, head) { | ||
804 | if (scan->type & DRM_MODE_TYPE_PREFERRED) { | ||
805 | mode_dev->panel_fixed_mode = | ||
806 | drm_mode_duplicate(dev, scan); | ||
807 | goto out; /* FIXME: check for quirks */ | ||
808 | } | ||
809 | } | ||
810 | |||
811 | /* Failed to get EDID, what about VBT? do we need this? */ | ||
812 | if (mode_dev->vbt_mode) | ||
813 | mode_dev->panel_fixed_mode = | ||
814 | drm_mode_duplicate(dev, mode_dev->vbt_mode); | ||
815 | |||
816 | if (!mode_dev->panel_fixed_mode) | ||
817 | if (dev_priv->lfp_lvds_vbt_mode) | ||
818 | mode_dev->panel_fixed_mode = | ||
819 | drm_mode_duplicate(dev, | ||
820 | dev_priv->lfp_lvds_vbt_mode); | ||
821 | |||
822 | /* | ||
823 | * If we didn't get EDID, try checking if the panel is already turned | ||
824 | * on. If so, assume that whatever is currently programmed is the | ||
825 | * correct mode. | ||
826 | */ | ||
827 | lvds = REG_READ(LVDS); | ||
828 | pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; | ||
829 | crtc = psb_intel_get_crtc_from_pipe(dev, pipe); | ||
830 | |||
831 | if (crtc && (lvds & LVDS_PORT_EN)) { | ||
832 | mode_dev->panel_fixed_mode = | ||
833 | psb_intel_crtc_mode_get(dev, crtc); | ||
834 | if (mode_dev->panel_fixed_mode) { | ||
835 | mode_dev->panel_fixed_mode->type |= | ||
836 | DRM_MODE_TYPE_PREFERRED; | ||
837 | goto out; /* FIXME: check for quirks */ | ||
838 | } | ||
839 | } | ||
840 | |||
841 | /* If we still don't have a mode after all that, give up. */ | ||
842 | if (!mode_dev->panel_fixed_mode) { | ||
843 | dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); | ||
844 | goto failed_find; | ||
845 | } | ||
846 | |||
847 | /* | ||
848 | * Blacklist machines with BIOSes that list an LVDS panel without | ||
849 | * actually having one. | ||
850 | */ | ||
851 | out: | ||
852 | drm_sysfs_connector_add(connector); | ||
853 | return; | ||
854 | |||
855 | failed_find: | ||
856 | if (lvds_priv->ddc_bus) | ||
857 | psb_intel_i2c_destroy(lvds_priv->ddc_bus); | ||
858 | failed_ddc: | ||
859 | if (lvds_priv->i2c_bus) | ||
860 | psb_intel_i2c_destroy(lvds_priv->i2c_bus); | ||
861 | failed_blc_i2c: | ||
862 | drm_encoder_cleanup(encoder); | ||
863 | drm_connector_cleanup(connector); | ||
864 | failed_connector: | ||
865 | if (psb_intel_connector) | ||
866 | kfree(psb_intel_connector); | ||
867 | } | ||
868 | |||
diff --git a/drivers/gpu/drm/gma500/psb_intel_modes.c b/drivers/gpu/drm/gma500/psb_intel_modes.c new file mode 100644 index 00000000000..4fca0d6feeb --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_intel_modes.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authers: Jesse Barnes <jesse.barnes@intel.com> | ||
18 | */ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/fb.h> | ||
22 | #include <drm/drmP.h> | ||
23 | #include "psb_intel_drv.h" | ||
24 | |||
25 | /** | ||
26 | * psb_intel_ddc_probe | ||
27 | * | ||
28 | */ | ||
29 | bool psb_intel_ddc_probe(struct i2c_adapter *adapter) | ||
30 | { | ||
31 | u8 out_buf[] = { 0x0, 0x0 }; | ||
32 | u8 buf[2]; | ||
33 | int ret; | ||
34 | struct i2c_msg msgs[] = { | ||
35 | { | ||
36 | .addr = 0x50, | ||
37 | .flags = 0, | ||
38 | .len = 1, | ||
39 | .buf = out_buf, | ||
40 | }, | ||
41 | { | ||
42 | .addr = 0x50, | ||
43 | .flags = I2C_M_RD, | ||
44 | .len = 1, | ||
45 | .buf = buf, | ||
46 | } | ||
47 | }; | ||
48 | |||
49 | ret = i2c_transfer(adapter, msgs, 2); | ||
50 | if (ret == 2) | ||
51 | return true; | ||
52 | |||
53 | return false; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * psb_intel_ddc_get_modes - get modelist from monitor | ||
58 | * @connector: DRM connector device to use | ||
59 | * | ||
60 | * Fetch the EDID information from @connector using the DDC bus. | ||
61 | */ | ||
62 | int psb_intel_ddc_get_modes(struct drm_connector *connector, | ||
63 | struct i2c_adapter *adapter) | ||
64 | { | ||
65 | struct edid *edid; | ||
66 | int ret = 0; | ||
67 | |||
68 | edid = drm_get_edid(connector, adapter); | ||
69 | if (edid) { | ||
70 | drm_mode_connector_update_edid_property(connector, edid); | ||
71 | ret = drm_add_edid_modes(connector, edid); | ||
72 | kfree(edid); | ||
73 | } | ||
74 | return ret; | ||
75 | } | ||
diff --git a/drivers/gpu/drm/gma500/psb_intel_reg.h b/drivers/gpu/drm/gma500/psb_intel_reg.h new file mode 100644 index 00000000000..fcc0af03d68 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_intel_reg.h | |||
@@ -0,0 +1,1309 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2009, Intel Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | */ | ||
17 | #ifndef __PSB_INTEL_REG_H__ | ||
18 | #define __PSB_INTEL_REG_H__ | ||
19 | |||
20 | /* | ||
21 | * GPIO regs | ||
22 | */ | ||
23 | #define GPIOA 0x5010 | ||
24 | #define GPIOB 0x5014 | ||
25 | #define GPIOC 0x5018 | ||
26 | #define GPIOD 0x501c | ||
27 | #define GPIOE 0x5020 | ||
28 | #define GPIOF 0x5024 | ||
29 | #define GPIOG 0x5028 | ||
30 | #define GPIOH 0x502c | ||
31 | # define GPIO_CLOCK_DIR_MASK (1 << 0) | ||
32 | # define GPIO_CLOCK_DIR_IN (0 << 1) | ||
33 | # define GPIO_CLOCK_DIR_OUT (1 << 1) | ||
34 | # define GPIO_CLOCK_VAL_MASK (1 << 2) | ||
35 | # define GPIO_CLOCK_VAL_OUT (1 << 3) | ||
36 | # define GPIO_CLOCK_VAL_IN (1 << 4) | ||
37 | # define GPIO_CLOCK_PULLUP_DISABLE (1 << 5) | ||
38 | # define GPIO_DATA_DIR_MASK (1 << 8) | ||
39 | # define GPIO_DATA_DIR_IN (0 << 9) | ||
40 | # define GPIO_DATA_DIR_OUT (1 << 9) | ||
41 | # define GPIO_DATA_VAL_MASK (1 << 10) | ||
42 | # define GPIO_DATA_VAL_OUT (1 << 11) | ||
43 | # define GPIO_DATA_VAL_IN (1 << 12) | ||
44 | # define GPIO_DATA_PULLUP_DISABLE (1 << 13) | ||
45 | |||
46 | #define GMBUS0 0x5100 /* clock/port select */ | ||
47 | #define GMBUS_RATE_100KHZ (0<<8) | ||
48 | #define GMBUS_RATE_50KHZ (1<<8) | ||
49 | #define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */ | ||
50 | #define GMBUS_RATE_1MHZ (3<<8) /* reserved on Pineview */ | ||
51 | #define GMBUS_HOLD_EXT (1<<7) /* 300ns hold time, rsvd on Pineview */ | ||
52 | #define GMBUS_PORT_DISABLED 0 | ||
53 | #define GMBUS_PORT_SSC 1 | ||
54 | #define GMBUS_PORT_VGADDC 2 | ||
55 | #define GMBUS_PORT_PANEL 3 | ||
56 | #define GMBUS_PORT_DPC 4 /* HDMIC */ | ||
57 | #define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */ | ||
58 | /* 6 reserved */ | ||
59 | #define GMBUS_PORT_DPD 7 /* HDMID */ | ||
60 | #define GMBUS_NUM_PORTS 8 | ||
61 | #define GMBUS1 0x5104 /* command/status */ | ||
62 | #define GMBUS_SW_CLR_INT (1<<31) | ||
63 | #define GMBUS_SW_RDY (1<<30) | ||
64 | #define GMBUS_ENT (1<<29) /* enable timeout */ | ||
65 | #define GMBUS_CYCLE_NONE (0<<25) | ||
66 | #define GMBUS_CYCLE_WAIT (1<<25) | ||
67 | #define GMBUS_CYCLE_INDEX (2<<25) | ||
68 | #define GMBUS_CYCLE_STOP (4<<25) | ||
69 | #define GMBUS_BYTE_COUNT_SHIFT 16 | ||
70 | #define GMBUS_SLAVE_INDEX_SHIFT 8 | ||
71 | #define GMBUS_SLAVE_ADDR_SHIFT 1 | ||
72 | #define GMBUS_SLAVE_READ (1<<0) | ||
73 | #define GMBUS_SLAVE_WRITE (0<<0) | ||
74 | #define GMBUS2 0x5108 /* status */ | ||
75 | #define GMBUS_INUSE (1<<15) | ||
76 | #define GMBUS_HW_WAIT_PHASE (1<<14) | ||
77 | #define GMBUS_STALL_TIMEOUT (1<<13) | ||
78 | #define GMBUS_INT (1<<12) | ||
79 | #define GMBUS_HW_RDY (1<<11) | ||
80 | #define GMBUS_SATOER (1<<10) | ||
81 | #define GMBUS_ACTIVE (1<<9) | ||
82 | #define GMBUS3 0x510c /* data buffer bytes 3-0 */ | ||
83 | #define GMBUS4 0x5110 /* interrupt mask (Pineview+) */ | ||
84 | #define GMBUS_SLAVE_TIMEOUT_EN (1<<4) | ||
85 | #define GMBUS_NAK_EN (1<<3) | ||
86 | #define GMBUS_IDLE_EN (1<<2) | ||
87 | #define GMBUS_HW_WAIT_EN (1<<1) | ||
88 | #define GMBUS_HW_RDY_EN (1<<0) | ||
89 | #define GMBUS5 0x5120 /* byte index */ | ||
90 | #define GMBUS_2BYTE_INDEX_EN (1<<31) | ||
91 | |||
92 | #define BLC_PWM_CTL 0x61254 | ||
93 | #define BLC_PWM_CTL2 0x61250 | ||
94 | #define BLC_PWM_CTL_C 0x62254 | ||
95 | #define BLC_PWM_CTL2_C 0x62250 | ||
96 | #define BACKLIGHT_MODULATION_FREQ_SHIFT (17) | ||
97 | /* | ||
98 | * This is the most significant 15 bits of the number of backlight cycles in a | ||
99 | * complete cycle of the modulated backlight control. | ||
100 | * | ||
101 | * The actual value is this field multiplied by two. | ||
102 | */ | ||
103 | #define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) | ||
104 | #define BLM_LEGACY_MODE (1 << 16) | ||
105 | /* | ||
106 | * This is the number of cycles out of the backlight modulation cycle for which | ||
107 | * the backlight is on. | ||
108 | * | ||
109 | * This field must be no greater than the number of cycles in the complete | ||
110 | * backlight modulation cycle. | ||
111 | */ | ||
112 | #define BACKLIGHT_DUTY_CYCLE_SHIFT (0) | ||
113 | #define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) | ||
114 | |||
115 | #define I915_GCFGC 0xf0 | ||
116 | #define I915_LOW_FREQUENCY_ENABLE (1 << 7) | ||
117 | #define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4) | ||
118 | #define I915_DISPLAY_CLOCK_333_MHZ (4 << 4) | ||
119 | #define I915_DISPLAY_CLOCK_MASK (7 << 4) | ||
120 | |||
121 | #define I855_HPLLCC 0xc0 | ||
122 | #define I855_CLOCK_CONTROL_MASK (3 << 0) | ||
123 | #define I855_CLOCK_133_200 (0 << 0) | ||
124 | #define I855_CLOCK_100_200 (1 << 0) | ||
125 | #define I855_CLOCK_100_133 (2 << 0) | ||
126 | #define I855_CLOCK_166_250 (3 << 0) | ||
127 | |||
128 | /* I830 CRTC registers */ | ||
129 | #define HTOTAL_A 0x60000 | ||
130 | #define HBLANK_A 0x60004 | ||
131 | #define HSYNC_A 0x60008 | ||
132 | #define VTOTAL_A 0x6000c | ||
133 | #define VBLANK_A 0x60010 | ||
134 | #define VSYNC_A 0x60014 | ||
135 | #define PIPEASRC 0x6001c | ||
136 | #define BCLRPAT_A 0x60020 | ||
137 | #define VSYNCSHIFT_A 0x60028 | ||
138 | |||
139 | #define HTOTAL_B 0x61000 | ||
140 | #define HBLANK_B 0x61004 | ||
141 | #define HSYNC_B 0x61008 | ||
142 | #define VTOTAL_B 0x6100c | ||
143 | #define VBLANK_B 0x61010 | ||
144 | #define VSYNC_B 0x61014 | ||
145 | #define PIPEBSRC 0x6101c | ||
146 | #define BCLRPAT_B 0x61020 | ||
147 | #define VSYNCSHIFT_B 0x61028 | ||
148 | |||
149 | #define HTOTAL_C 0x62000 | ||
150 | #define HBLANK_C 0x62004 | ||
151 | #define HSYNC_C 0x62008 | ||
152 | #define VTOTAL_C 0x6200c | ||
153 | #define VBLANK_C 0x62010 | ||
154 | #define VSYNC_C 0x62014 | ||
155 | #define PIPECSRC 0x6201c | ||
156 | #define BCLRPAT_C 0x62020 | ||
157 | #define VSYNCSHIFT_C 0x62028 | ||
158 | |||
159 | #define PP_STATUS 0x61200 | ||
160 | # define PP_ON (1 << 31) | ||
161 | /* | ||
162 | * Indicates that all dependencies of the panel are on: | ||
163 | * | ||
164 | * - PLL enabled | ||
165 | * - pipe enabled | ||
166 | * - LVDS/DVOB/DVOC on | ||
167 | */ | ||
168 | #define PP_READY (1 << 30) | ||
169 | #define PP_SEQUENCE_NONE (0 << 28) | ||
170 | #define PP_SEQUENCE_ON (1 << 28) | ||
171 | #define PP_SEQUENCE_OFF (2 << 28) | ||
172 | #define PP_SEQUENCE_MASK 0x30000000 | ||
173 | #define PP_CONTROL 0x61204 | ||
174 | #define POWER_TARGET_ON (1 << 0) | ||
175 | |||
176 | #define LVDSPP_ON 0x61208 | ||
177 | #define LVDSPP_OFF 0x6120c | ||
178 | #define PP_CYCLE 0x61210 | ||
179 | |||
180 | #define PFIT_CONTROL 0x61230 | ||
181 | #define PFIT_ENABLE (1 << 31) | ||
182 | #define PFIT_PIPE_MASK (3 << 29) | ||
183 | #define PFIT_PIPE_SHIFT 29 | ||
184 | #define PFIT_SCALING_MODE_PILLARBOX (1 << 27) | ||
185 | #define PFIT_SCALING_MODE_LETTERBOX (3 << 26) | ||
186 | #define VERT_INTERP_DISABLE (0 << 10) | ||
187 | #define VERT_INTERP_BILINEAR (1 << 10) | ||
188 | #define VERT_INTERP_MASK (3 << 10) | ||
189 | #define VERT_AUTO_SCALE (1 << 9) | ||
190 | #define HORIZ_INTERP_DISABLE (0 << 6) | ||
191 | #define HORIZ_INTERP_BILINEAR (1 << 6) | ||
192 | #define HORIZ_INTERP_MASK (3 << 6) | ||
193 | #define HORIZ_AUTO_SCALE (1 << 5) | ||
194 | #define PANEL_8TO6_DITHER_ENABLE (1 << 3) | ||
195 | |||
196 | #define PFIT_PGM_RATIOS 0x61234 | ||
197 | #define PFIT_VERT_SCALE_MASK 0xfff00000 | ||
198 | #define PFIT_HORIZ_SCALE_MASK 0x0000fff0 | ||
199 | |||
200 | #define PFIT_AUTO_RATIOS 0x61238 | ||
201 | |||
202 | #define DPLL_A 0x06014 | ||
203 | #define DPLL_B 0x06018 | ||
204 | #define DPLL_VCO_ENABLE (1 << 31) | ||
205 | #define DPLL_DVO_HIGH_SPEED (1 << 30) | ||
206 | #define DPLL_SYNCLOCK_ENABLE (1 << 29) | ||
207 | #define DPLL_VGA_MODE_DIS (1 << 28) | ||
208 | #define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ | ||
209 | #define DPLLB_MODE_LVDS (2 << 26) /* i915 */ | ||
210 | #define DPLL_MODE_MASK (3 << 26) | ||
211 | #define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ | ||
212 | #define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ | ||
213 | #define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ | ||
214 | #define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ | ||
215 | #define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ | ||
216 | #define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ | ||
217 | #define DPLL_LOCK (1 << 15) /* CDV */ | ||
218 | |||
219 | /* | ||
220 | * The i830 generation, in DAC/serial mode, defines p1 as two plus this | ||
221 | * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set. | ||
222 | */ | ||
223 | # define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 | ||
224 | /* | ||
225 | * The i830 generation, in LVDS mode, defines P1 as the bit number set within | ||
226 | * this field (only one bit may be set). | ||
227 | */ | ||
228 | #define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 | ||
229 | #define DPLL_FPA01_P1_POST_DIV_SHIFT 16 | ||
230 | #define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required | ||
231 | * in DVO non-gang */ | ||
232 | # define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ | ||
233 | #define PLL_REF_INPUT_DREFCLK (0 << 13) | ||
234 | #define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ | ||
235 | #define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO | ||
236 | * TVCLKIN */ | ||
237 | #define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) | ||
238 | #define PLL_REF_INPUT_MASK (3 << 13) | ||
239 | #define PLL_LOAD_PULSE_PHASE_SHIFT 9 | ||
240 | /* | ||
241 | * Parallel to Serial Load Pulse phase selection. | ||
242 | * Selects the phase for the 10X DPLL clock for the PCIe | ||
243 | * digital display port. The range is 4 to 13; 10 or more | ||
244 | * is just a flip delay. The default is 6 | ||
245 | */ | ||
246 | #define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) | ||
247 | #define DISPLAY_RATE_SELECT_FPA1 (1 << 8) | ||
248 | |||
249 | /* | ||
250 | * SDVO multiplier for 945G/GM. Not used on 965. | ||
251 | * | ||
252 | * DPLL_MD_UDI_MULTIPLIER_MASK | ||
253 | */ | ||
254 | #define SDVO_MULTIPLIER_MASK 0x000000ff | ||
255 | #define SDVO_MULTIPLIER_SHIFT_HIRES 4 | ||
256 | #define SDVO_MULTIPLIER_SHIFT_VGA 0 | ||
257 | |||
258 | /* | ||
259 | * PLL_MD | ||
260 | */ | ||
261 | /* Pipe A SDVO/UDI clock multiplier/divider register for G965. */ | ||
262 | #define DPLL_A_MD 0x0601c | ||
263 | /* Pipe B SDVO/UDI clock multiplier/divider register for G965. */ | ||
264 | #define DPLL_B_MD 0x06020 | ||
265 | /* | ||
266 | * UDI pixel divider, controlling how many pixels are stuffed into a packet. | ||
267 | * | ||
268 | * Value is pixels minus 1. Must be set to 1 pixel for SDVO. | ||
269 | */ | ||
270 | #define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 | ||
271 | #define DPLL_MD_UDI_DIVIDER_SHIFT 24 | ||
272 | /* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ | ||
273 | #define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 | ||
274 | #define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 | ||
275 | /* | ||
276 | * SDVO/UDI pixel multiplier. | ||
277 | * | ||
278 | * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus | ||
279 | * clock rate is 10 times the DPLL clock. At low resolution/refresh rate | ||
280 | * modes, the bus rate would be below the limits, so SDVO allows for stuffing | ||
281 | * dummy bytes in the datastream at an increased clock rate, with both sides of | ||
282 | * the link knowing how many bytes are fill. | ||
283 | * | ||
284 | * So, for a mode with a dotclock of 65Mhz, we would want to double the clock | ||
285 | * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be | ||
286 | * set to 130Mhz, and the SDVO multiplier set to 2x in this register and | ||
287 | * through an SDVO command. | ||
288 | * | ||
289 | * This register field has values of multiplication factor minus 1, with | ||
290 | * a maximum multiplier of 5 for SDVO. | ||
291 | */ | ||
292 | #define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 | ||
293 | #define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 | ||
294 | /* | ||
295 | * SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. | ||
296 | * This best be set to the default value (3) or the CRT won't work. No, | ||
297 | * I don't entirely understand what this does... | ||
298 | */ | ||
299 | #define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f | ||
300 | #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 | ||
301 | |||
302 | #define DPLL_TEST 0x606c | ||
303 | #define DPLLB_TEST_SDVO_DIV_1 (0 << 22) | ||
304 | #define DPLLB_TEST_SDVO_DIV_2 (1 << 22) | ||
305 | #define DPLLB_TEST_SDVO_DIV_4 (2 << 22) | ||
306 | #define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) | ||
307 | #define DPLLB_TEST_N_BYPASS (1 << 19) | ||
308 | #define DPLLB_TEST_M_BYPASS (1 << 18) | ||
309 | #define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) | ||
310 | #define DPLLA_TEST_N_BYPASS (1 << 3) | ||
311 | #define DPLLA_TEST_M_BYPASS (1 << 2) | ||
312 | #define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) | ||
313 | |||
314 | #define ADPA 0x61100 | ||
315 | #define ADPA_DAC_ENABLE (1 << 31) | ||
316 | #define ADPA_DAC_DISABLE 0 | ||
317 | #define ADPA_PIPE_SELECT_MASK (1 << 30) | ||
318 | #define ADPA_PIPE_A_SELECT 0 | ||
319 | #define ADPA_PIPE_B_SELECT (1 << 30) | ||
320 | #define ADPA_USE_VGA_HVPOLARITY (1 << 15) | ||
321 | #define ADPA_SETS_HVPOLARITY 0 | ||
322 | #define ADPA_VSYNC_CNTL_DISABLE (1 << 11) | ||
323 | #define ADPA_VSYNC_CNTL_ENABLE 0 | ||
324 | #define ADPA_HSYNC_CNTL_DISABLE (1 << 10) | ||
325 | #define ADPA_HSYNC_CNTL_ENABLE 0 | ||
326 | #define ADPA_VSYNC_ACTIVE_HIGH (1 << 4) | ||
327 | #define ADPA_VSYNC_ACTIVE_LOW 0 | ||
328 | #define ADPA_HSYNC_ACTIVE_HIGH (1 << 3) | ||
329 | #define ADPA_HSYNC_ACTIVE_LOW 0 | ||
330 | |||
331 | #define FPA0 0x06040 | ||
332 | #define FPA1 0x06044 | ||
333 | #define FPB0 0x06048 | ||
334 | #define FPB1 0x0604c | ||
335 | #define FP_N_DIV_MASK 0x003f0000 | ||
336 | #define FP_N_DIV_SHIFT 16 | ||
337 | #define FP_M1_DIV_MASK 0x00003f00 | ||
338 | #define FP_M1_DIV_SHIFT 8 | ||
339 | #define FP_M2_DIV_MASK 0x0000003f | ||
340 | #define FP_M2_DIV_SHIFT 0 | ||
341 | |||
342 | #define PORT_HOTPLUG_EN 0x61110 | ||
343 | #define SDVOB_HOTPLUG_INT_EN (1 << 26) | ||
344 | #define SDVOC_HOTPLUG_INT_EN (1 << 25) | ||
345 | #define TV_HOTPLUG_INT_EN (1 << 18) | ||
346 | #define CRT_HOTPLUG_INT_EN (1 << 9) | ||
347 | #define CRT_HOTPLUG_FORCE_DETECT (1 << 3) | ||
348 | /* CDV.. */ | ||
349 | #define CRT_HOTPLUG_ACTIVATION_PERIOD_64 (1 << 8) | ||
350 | #define CRT_HOTPLUG_DAC_ON_TIME_2M (0 << 7) | ||
351 | #define CRT_HOTPLUG_DAC_ON_TIME_4M (1 << 7) | ||
352 | #define CRT_HOTPLUG_VOLTAGE_COMPARE_40 (0 << 5) | ||
353 | #define CRT_HOTPLUG_VOLTAGE_COMPARE_50 (1 << 5) | ||
354 | #define CRT_HOTPLUG_VOLTAGE_COMPARE_60 (2 << 5) | ||
355 | #define CRT_HOTPLUG_VOLTAGE_COMPARE_70 (3 << 5) | ||
356 | #define CRT_HOTPLUG_VOLTAGE_COMPARE_MASK (3 << 5) | ||
357 | #define CRT_HOTPLUG_DETECT_DELAY_1G (0 << 4) | ||
358 | #define CRT_HOTPLUG_DETECT_DELAY_2G (1 << 4) | ||
359 | #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) | ||
360 | #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) | ||
361 | #define CRT_HOTPLUG_DETECT_MASK 0x000000F8 | ||
362 | |||
363 | #define PORT_HOTPLUG_STAT 0x61114 | ||
364 | #define CRT_HOTPLUG_INT_STATUS (1 << 11) | ||
365 | #define TV_HOTPLUG_INT_STATUS (1 << 10) | ||
366 | #define CRT_HOTPLUG_MONITOR_MASK (3 << 8) | ||
367 | #define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) | ||
368 | #define CRT_HOTPLUG_MONITOR_MONO (2 << 8) | ||
369 | #define CRT_HOTPLUG_MONITOR_NONE (0 << 8) | ||
370 | #define SDVOC_HOTPLUG_INT_STATUS (1 << 7) | ||
371 | #define SDVOB_HOTPLUG_INT_STATUS (1 << 6) | ||
372 | |||
373 | #define SDVOB 0x61140 | ||
374 | #define SDVOC 0x61160 | ||
375 | #define SDVO_ENABLE (1 << 31) | ||
376 | #define SDVO_PIPE_B_SELECT (1 << 30) | ||
377 | #define SDVO_STALL_SELECT (1 << 29) | ||
378 | #define SDVO_INTERRUPT_ENABLE (1 << 26) | ||
379 | #define SDVO_COLOR_RANGE_16_235 (1 << 8) | ||
380 | #define SDVO_AUDIO_ENABLE (1 << 6) | ||
381 | |||
382 | /** | ||
383 | * 915G/GM SDVO pixel multiplier. | ||
384 | * | ||
385 | * Programmed value is multiplier - 1, up to 5x. | ||
386 | * | ||
387 | * DPLL_MD_UDI_MULTIPLIER_MASK | ||
388 | */ | ||
389 | #define SDVO_PORT_MULTIPLY_MASK (7 << 23) | ||
390 | #define SDVO_PORT_MULTIPLY_SHIFT 23 | ||
391 | #define SDVO_PHASE_SELECT_MASK (15 << 19) | ||
392 | #define SDVO_PHASE_SELECT_DEFAULT (6 << 19) | ||
393 | #define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) | ||
394 | #define SDVOC_GANG_MODE (1 << 16) | ||
395 | #define SDVO_BORDER_ENABLE (1 << 7) | ||
396 | #define SDVOB_PCIE_CONCURRENCY (1 << 3) | ||
397 | #define SDVO_DETECTED (1 << 2) | ||
398 | /* Bits to be preserved when writing */ | ||
399 | #define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14)) | ||
400 | #define SDVOC_PRESERVE_MASK (1 << 17) | ||
401 | |||
402 | /* | ||
403 | * This register controls the LVDS output enable, pipe selection, and data | ||
404 | * format selection. | ||
405 | * | ||
406 | * All of the clock/data pairs are force powered down by power sequencing. | ||
407 | */ | ||
408 | #define LVDS 0x61180 | ||
409 | /* | ||
410 | * Enables the LVDS port. This bit must be set before DPLLs are enabled, as | ||
411 | * the DPLL semantics change when the LVDS is assigned to that pipe. | ||
412 | */ | ||
413 | #define LVDS_PORT_EN (1 << 31) | ||
414 | /* Selects pipe B for LVDS data. Must be set on pre-965. */ | ||
415 | #define LVDS_PIPEB_SELECT (1 << 30) | ||
416 | |||
417 | /* Turns on border drawing to allow centered display. */ | ||
418 | #define LVDS_BORDER_EN (1 << 15) | ||
419 | |||
420 | /* | ||
421 | * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per | ||
422 | * pixel. | ||
423 | */ | ||
424 | #define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) | ||
425 | #define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) | ||
426 | #define LVDS_A0A2_CLKA_POWER_UP (3 << 8) | ||
427 | /* | ||
428 | * Controls the A3 data pair, which contains the additional LSBs for 24 bit | ||
429 | * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be | ||
430 | * on. | ||
431 | */ | ||
432 | #define LVDS_A3_POWER_MASK (3 << 6) | ||
433 | #define LVDS_A3_POWER_DOWN (0 << 6) | ||
434 | #define LVDS_A3_POWER_UP (3 << 6) | ||
435 | /* | ||
436 | * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP | ||
437 | * is set. | ||
438 | */ | ||
439 | #define LVDS_CLKB_POWER_MASK (3 << 4) | ||
440 | #define LVDS_CLKB_POWER_DOWN (0 << 4) | ||
441 | #define LVDS_CLKB_POWER_UP (3 << 4) | ||
442 | /* | ||
443 | * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 | ||
444 | * setting for whether we are in dual-channel mode. The B3 pair will | ||
445 | * additionally only be powered up when LVDS_A3_POWER_UP is set. | ||
446 | */ | ||
447 | #define LVDS_B0B3_POWER_MASK (3 << 2) | ||
448 | #define LVDS_B0B3_POWER_DOWN (0 << 2) | ||
449 | #define LVDS_B0B3_POWER_UP (3 << 2) | ||
450 | |||
451 | #define PIPEACONF 0x70008 | ||
452 | #define PIPEACONF_ENABLE (1 << 31) | ||
453 | #define PIPEACONF_DISABLE 0 | ||
454 | #define PIPEACONF_DOUBLE_WIDE (1 << 30) | ||
455 | #define PIPECONF_ACTIVE (1 << 30) | ||
456 | #define I965_PIPECONF_ACTIVE (1 << 30) | ||
457 | #define PIPECONF_DSIPLL_LOCK (1 << 29) | ||
458 | #define PIPEACONF_SINGLE_WIDE 0 | ||
459 | #define PIPEACONF_PIPE_UNLOCKED 0 | ||
460 | #define PIPEACONF_DSR (1 << 26) | ||
461 | #define PIPEACONF_PIPE_LOCKED (1 << 25) | ||
462 | #define PIPEACONF_PALETTE 0 | ||
463 | #define PIPECONF_FORCE_BORDER (1 << 25) | ||
464 | #define PIPEACONF_GAMMA (1 << 24) | ||
465 | #define PIPECONF_PROGRESSIVE (0 << 21) | ||
466 | #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) | ||
467 | #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) | ||
468 | #define PIPECONF_PLANE_OFF (1 << 19) | ||
469 | #define PIPECONF_CURSOR_OFF (1 << 18) | ||
470 | |||
471 | #define PIPEBCONF 0x71008 | ||
472 | #define PIPEBCONF_ENABLE (1 << 31) | ||
473 | #define PIPEBCONF_DISABLE 0 | ||
474 | #define PIPEBCONF_DOUBLE_WIDE (1 << 30) | ||
475 | #define PIPEBCONF_DISABLE 0 | ||
476 | #define PIPEBCONF_GAMMA (1 << 24) | ||
477 | #define PIPEBCONF_PALETTE 0 | ||
478 | |||
479 | #define PIPECCONF 0x72008 | ||
480 | |||
481 | #define PIPEBGCMAXRED 0x71010 | ||
482 | #define PIPEBGCMAXGREEN 0x71014 | ||
483 | #define PIPEBGCMAXBLUE 0x71018 | ||
484 | |||
485 | #define PIPEASTAT 0x70024 | ||
486 | #define PIPEBSTAT 0x71024 | ||
487 | #define PIPECSTAT 0x72024 | ||
488 | #define PIPE_VBLANK_INTERRUPT_STATUS (1UL << 1) | ||
489 | #define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL << 2) | ||
490 | #define PIPE_VBLANK_CLEAR (1 << 1) | ||
491 | #define PIPE_VBLANK_STATUS (1 << 1) | ||
492 | #define PIPE_TE_STATUS (1UL << 6) | ||
493 | #define PIPE_DPST_EVENT_STATUS (1UL << 7) | ||
494 | #define PIPE_VSYNC_CLEAR (1UL << 9) | ||
495 | #define PIPE_VSYNC_STATUS (1UL << 9) | ||
496 | #define PIPE_HDMI_AUDIO_UNDERRUN_STATUS (1UL << 10) | ||
497 | #define PIPE_HDMI_AUDIO_BUFFER_DONE_STATUS (1UL << 11) | ||
498 | #define PIPE_VBLANK_INTERRUPT_ENABLE (1UL << 17) | ||
499 | #define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL << 18) | ||
500 | #define PIPE_TE_ENABLE (1UL << 22) | ||
501 | #define PIPE_DPST_EVENT_ENABLE (1UL << 23) | ||
502 | #define PIPE_VSYNC_ENABL (1UL << 25) | ||
503 | #define PIPE_HDMI_AUDIO_UNDERRUN (1UL << 26) | ||
504 | #define PIPE_HDMI_AUDIO_BUFFER_DONE (1UL << 27) | ||
505 | #define PIPE_HDMI_AUDIO_INT_MASK (PIPE_HDMI_AUDIO_UNDERRUN | \ | ||
506 | PIPE_HDMI_AUDIO_BUFFER_DONE) | ||
507 | #define PIPE_EVENT_MASK ((1 << 29)|(1 << 28)|(1 << 27)|(1 << 26)|(1 << 24)|(1 << 23)|(1 << 22)|(1 << 21)|(1 << 20)|(1 << 16)) | ||
508 | #define PIPE_VBLANK_MASK ((1 << 25)|(1 << 24)|(1 << 18)|(1 << 17)) | ||
509 | #define HISTOGRAM_INT_CONTROL 0x61268 | ||
510 | #define HISTOGRAM_BIN_DATA 0X61264 | ||
511 | #define HISTOGRAM_LOGIC_CONTROL 0x61260 | ||
512 | #define PWM_CONTROL_LOGIC 0x61250 | ||
513 | #define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL << 10) | ||
514 | #define HISTOGRAM_INTERRUPT_ENABLE (1UL << 31) | ||
515 | #define HISTOGRAM_LOGIC_ENABLE (1UL << 31) | ||
516 | #define PWM_LOGIC_ENABLE (1UL << 31) | ||
517 | #define PWM_PHASEIN_ENABLE (1UL << 25) | ||
518 | #define PWM_PHASEIN_INT_ENABLE (1UL << 24) | ||
519 | #define PWM_PHASEIN_VB_COUNT 0x00001f00 | ||
520 | #define PWM_PHASEIN_INC 0x0000001f | ||
521 | #define HISTOGRAM_INT_CTRL_CLEAR (1UL << 30) | ||
522 | #define DPST_YUV_LUMA_MODE 0 | ||
523 | |||
524 | struct dpst_ie_histogram_control { | ||
525 | union { | ||
526 | uint32_t data; | ||
527 | struct { | ||
528 | uint32_t bin_reg_index:7; | ||
529 | uint32_t reserved:4; | ||
530 | uint32_t bin_reg_func_select:1; | ||
531 | uint32_t sync_to_phase_in:1; | ||
532 | uint32_t alt_enhancement_mode:2; | ||
533 | uint32_t reserved1:1; | ||
534 | uint32_t sync_to_phase_in_count:8; | ||
535 | uint32_t histogram_mode_select:1; | ||
536 | uint32_t reserved2:4; | ||
537 | uint32_t ie_pipe_assignment:1; | ||
538 | uint32_t ie_mode_table_enabled:1; | ||
539 | uint32_t ie_histogram_enable:1; | ||
540 | }; | ||
541 | }; | ||
542 | }; | ||
543 | |||
544 | struct dpst_guardband { | ||
545 | union { | ||
546 | uint32_t data; | ||
547 | struct { | ||
548 | uint32_t guardband:22; | ||
549 | uint32_t guardband_interrupt_delay:8; | ||
550 | uint32_t interrupt_status:1; | ||
551 | uint32_t interrupt_enable:1; | ||
552 | }; | ||
553 | }; | ||
554 | }; | ||
555 | |||
556 | #define PIPEAFRAMEHIGH 0x70040 | ||
557 | #define PIPEAFRAMEPIXEL 0x70044 | ||
558 | #define PIPEBFRAMEHIGH 0x71040 | ||
559 | #define PIPEBFRAMEPIXEL 0x71044 | ||
560 | #define PIPECFRAMEHIGH 0x72040 | ||
561 | #define PIPECFRAMEPIXEL 0x72044 | ||
562 | #define PIPE_FRAME_HIGH_MASK 0x0000ffff | ||
563 | #define PIPE_FRAME_HIGH_SHIFT 0 | ||
564 | #define PIPE_FRAME_LOW_MASK 0xff000000 | ||
565 | #define PIPE_FRAME_LOW_SHIFT 24 | ||
566 | #define PIPE_PIXEL_MASK 0x00ffffff | ||
567 | #define PIPE_PIXEL_SHIFT 0 | ||
568 | |||
569 | #define DSPARB 0x70030 | ||
570 | #define DSPFW1 0x70034 | ||
571 | #define DSPFW2 0x70038 | ||
572 | #define DSPFW3 0x7003c | ||
573 | #define DSPFW4 0x70050 | ||
574 | #define DSPFW5 0x70054 | ||
575 | #define DSPFW6 0x70058 | ||
576 | #define DSPCHICKENBIT 0x70400 | ||
577 | #define DSPACNTR 0x70180 | ||
578 | #define DSPBCNTR 0x71180 | ||
579 | #define DSPCCNTR 0x72180 | ||
580 | #define DISPLAY_PLANE_ENABLE (1 << 31) | ||
581 | #define DISPLAY_PLANE_DISABLE 0 | ||
582 | #define DISPPLANE_GAMMA_ENABLE (1 << 30) | ||
583 | #define DISPPLANE_GAMMA_DISABLE 0 | ||
584 | #define DISPPLANE_PIXFORMAT_MASK (0xf << 26) | ||
585 | #define DISPPLANE_8BPP (0x2 << 26) | ||
586 | #define DISPPLANE_15_16BPP (0x4 << 26) | ||
587 | #define DISPPLANE_16BPP (0x5 << 26) | ||
588 | #define DISPPLANE_32BPP_NO_ALPHA (0x6 << 26) | ||
589 | #define DISPPLANE_32BPP (0x7 << 26) | ||
590 | #define DISPPLANE_STEREO_ENABLE (1 << 25) | ||
591 | #define DISPPLANE_STEREO_DISABLE 0 | ||
592 | #define DISPPLANE_SEL_PIPE_MASK (1 << 24) | ||
593 | #define DISPPLANE_SEL_PIPE_POS 24 | ||
594 | #define DISPPLANE_SEL_PIPE_A 0 | ||
595 | #define DISPPLANE_SEL_PIPE_B (1 << 24) | ||
596 | #define DISPPLANE_SRC_KEY_ENABLE (1 << 22) | ||
597 | #define DISPPLANE_SRC_KEY_DISABLE 0 | ||
598 | #define DISPPLANE_LINE_DOUBLE (1 << 20) | ||
599 | #define DISPPLANE_NO_LINE_DOUBLE 0 | ||
600 | #define DISPPLANE_STEREO_POLARITY_FIRST 0 | ||
601 | #define DISPPLANE_STEREO_POLARITY_SECOND (1 << 18) | ||
602 | /* plane B only */ | ||
603 | #define DISPPLANE_ALPHA_TRANS_ENABLE (1 << 15) | ||
604 | #define DISPPLANE_ALPHA_TRANS_DISABLE 0 | ||
605 | #define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 | ||
606 | #define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) | ||
607 | #define DISPPLANE_BOTTOM (4) | ||
608 | |||
609 | #define DSPABASE 0x70184 | ||
610 | #define DSPALINOFF 0x70184 | ||
611 | #define DSPASTRIDE 0x70188 | ||
612 | |||
613 | #define DSPBBASE 0x71184 | ||
614 | #define DSPBLINOFF 0X71184 | ||
615 | #define DSPBADDR DSPBBASE | ||
616 | #define DSPBSTRIDE 0x71188 | ||
617 | |||
618 | #define DSPCBASE 0x72184 | ||
619 | #define DSPCLINOFF 0x72184 | ||
620 | #define DSPCSTRIDE 0x72188 | ||
621 | |||
622 | #define DSPAKEYVAL 0x70194 | ||
623 | #define DSPAKEYMASK 0x70198 | ||
624 | |||
625 | #define DSPAPOS 0x7018C /* reserved */ | ||
626 | #define DSPASIZE 0x70190 | ||
627 | #define DSPBPOS 0x7118C | ||
628 | #define DSPBSIZE 0x71190 | ||
629 | #define DSPCPOS 0x7218C | ||
630 | #define DSPCSIZE 0x72190 | ||
631 | |||
632 | #define DSPASURF 0x7019C | ||
633 | #define DSPATILEOFF 0x701A4 | ||
634 | |||
635 | #define DSPBSURF 0x7119C | ||
636 | #define DSPBTILEOFF 0x711A4 | ||
637 | |||
638 | #define DSPCSURF 0x7219C | ||
639 | #define DSPCTILEOFF 0x721A4 | ||
640 | #define DSPCKEYMAXVAL 0x721A0 | ||
641 | #define DSPCKEYMINVAL 0x72194 | ||
642 | #define DSPCKEYMSK 0x72198 | ||
643 | |||
644 | #define VGACNTRL 0x71400 | ||
645 | #define VGA_DISP_DISABLE (1 << 31) | ||
646 | #define VGA_2X_MODE (1 << 30) | ||
647 | #define VGA_PIPE_B_SELECT (1 << 29) | ||
648 | |||
649 | /* | ||
650 | * Overlay registers | ||
651 | */ | ||
652 | #define OV_C_OFFSET 0x08000 | ||
653 | #define OV_OVADD 0x30000 | ||
654 | #define OV_DOVASTA 0x30008 | ||
655 | # define OV_PIPE_SELECT ((1 << 6)|(1 << 7)) | ||
656 | # define OV_PIPE_SELECT_POS 6 | ||
657 | # define OV_PIPE_A 0 | ||
658 | # define OV_PIPE_C 1 | ||
659 | #define OV_OGAMC5 0x30010 | ||
660 | #define OV_OGAMC4 0x30014 | ||
661 | #define OV_OGAMC3 0x30018 | ||
662 | #define OV_OGAMC2 0x3001C | ||
663 | #define OV_OGAMC1 0x30020 | ||
664 | #define OV_OGAMC0 0x30024 | ||
665 | #define OVC_OVADD 0x38000 | ||
666 | #define OVC_DOVCSTA 0x38008 | ||
667 | #define OVC_OGAMC5 0x38010 | ||
668 | #define OVC_OGAMC4 0x38014 | ||
669 | #define OVC_OGAMC3 0x38018 | ||
670 | #define OVC_OGAMC2 0x3801C | ||
671 | #define OVC_OGAMC1 0x38020 | ||
672 | #define OVC_OGAMC0 0x38024 | ||
673 | |||
674 | /* | ||
675 | * Some BIOS scratch area registers. The 845 (and 830?) store the amount | ||
676 | * of video memory available to the BIOS in SWF1. | ||
677 | */ | ||
678 | #define SWF0 0x71410 | ||
679 | #define SWF1 0x71414 | ||
680 | #define SWF2 0x71418 | ||
681 | #define SWF3 0x7141c | ||
682 | #define SWF4 0x71420 | ||
683 | #define SWF5 0x71424 | ||
684 | #define SWF6 0x71428 | ||
685 | |||
686 | /* | ||
687 | * 855 scratch registers. | ||
688 | */ | ||
689 | #define SWF00 0x70410 | ||
690 | #define SWF01 0x70414 | ||
691 | #define SWF02 0x70418 | ||
692 | #define SWF03 0x7041c | ||
693 | #define SWF04 0x70420 | ||
694 | #define SWF05 0x70424 | ||
695 | #define SWF06 0x70428 | ||
696 | |||
697 | #define SWF10 SWF0 | ||
698 | #define SWF11 SWF1 | ||
699 | #define SWF12 SWF2 | ||
700 | #define SWF13 SWF3 | ||
701 | #define SWF14 SWF4 | ||
702 | #define SWF15 SWF5 | ||
703 | #define SWF16 SWF6 | ||
704 | |||
705 | #define SWF30 0x72414 | ||
706 | #define SWF31 0x72418 | ||
707 | #define SWF32 0x7241c | ||
708 | |||
709 | |||
710 | /* | ||
711 | * Palette registers | ||
712 | */ | ||
713 | #define PALETTE_A 0x0a000 | ||
714 | #define PALETTE_B 0x0a800 | ||
715 | #define PALETTE_C 0x0ac00 | ||
716 | |||
717 | /* Cursor A & B regs */ | ||
718 | #define CURACNTR 0x70080 | ||
719 | #define CURSOR_MODE_DISABLE 0x00 | ||
720 | #define CURSOR_MODE_64_32B_AX 0x07 | ||
721 | #define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) | ||
722 | #define MCURSOR_GAMMA_ENABLE (1 << 26) | ||
723 | #define CURABASE 0x70084 | ||
724 | #define CURAPOS 0x70088 | ||
725 | #define CURSOR_POS_MASK 0x007FF | ||
726 | #define CURSOR_POS_SIGN 0x8000 | ||
727 | #define CURSOR_X_SHIFT 0 | ||
728 | #define CURSOR_Y_SHIFT 16 | ||
729 | #define CURBCNTR 0x700c0 | ||
730 | #define CURBBASE 0x700c4 | ||
731 | #define CURBPOS 0x700c8 | ||
732 | #define CURCCNTR 0x700e0 | ||
733 | #define CURCBASE 0x700e4 | ||
734 | #define CURCPOS 0x700e8 | ||
735 | |||
736 | /* | ||
737 | * Interrupt Registers | ||
738 | */ | ||
739 | #define IER 0x020a0 | ||
740 | #define IIR 0x020a4 | ||
741 | #define IMR 0x020a8 | ||
742 | #define ISR 0x020ac | ||
743 | |||
744 | /* | ||
745 | * MOORESTOWN delta registers | ||
746 | */ | ||
747 | #define MRST_DPLL_A 0x0f014 | ||
748 | #define MDFLD_DPLL_B 0x0f018 | ||
749 | #define MDFLD_INPUT_REF_SEL (1 << 14) | ||
750 | #define MDFLD_VCO_SEL (1 << 16) | ||
751 | #define DPLLA_MODE_LVDS (2 << 26) /* mrst */ | ||
752 | #define MDFLD_PLL_LATCHEN (1 << 28) | ||
753 | #define MDFLD_PWR_GATE_EN (1 << 30) | ||
754 | #define MDFLD_P1_MASK (0x1FF << 17) | ||
755 | #define MRST_FPA0 0x0f040 | ||
756 | #define MRST_FPA1 0x0f044 | ||
757 | #define MDFLD_DPLL_DIV0 0x0f048 | ||
758 | #define MDFLD_DPLL_DIV1 0x0f04c | ||
759 | #define MRST_PERF_MODE 0x020f4 | ||
760 | |||
761 | /* | ||
762 | * MEDFIELD HDMI registers | ||
763 | */ | ||
764 | #define HDMIPHYMISCCTL 0x61134 | ||
765 | #define HDMI_PHY_POWER_DOWN 0x7f | ||
766 | #define HDMIB_CONTROL 0x61140 | ||
767 | #define HDMIB_PORT_EN (1 << 31) | ||
768 | #define HDMIB_PIPE_B_SELECT (1 << 30) | ||
769 | #define HDMIB_NULL_PACKET (1 << 9) | ||
770 | #define HDMIB_HDCP_PORT (1 << 5) | ||
771 | |||
772 | /* #define LVDS 0x61180 */ | ||
773 | #define MRST_PANEL_8TO6_DITHER_ENABLE (1 << 25) | ||
774 | #define MRST_PANEL_24_DOT_1_FORMAT (1 << 24) | ||
775 | #define LVDS_A3_POWER_UP_0_OUTPUT (1 << 6) | ||
776 | |||
777 | #define MIPI 0x61190 | ||
778 | #define MIPI_C 0x62190 | ||
779 | #define MIPI_PORT_EN (1 << 31) | ||
780 | /* Turns on border drawing to allow centered display. */ | ||
781 | #define SEL_FLOPPED_HSTX (1 << 23) | ||
782 | #define PASS_FROM_SPHY_TO_AFE (1 << 16) | ||
783 | #define MIPI_BORDER_EN (1 << 15) | ||
784 | #define MIPIA_3LANE_MIPIC_1LANE 0x1 | ||
785 | #define MIPIA_2LANE_MIPIC_2LANE 0x2 | ||
786 | #define TE_TRIGGER_DSI_PROTOCOL (1 << 2) | ||
787 | #define TE_TRIGGER_GPIO_PIN (1 << 3) | ||
788 | #define MIPI_TE_COUNT 0x61194 | ||
789 | |||
790 | /* #define PP_CONTROL 0x61204 */ | ||
791 | #define POWER_DOWN_ON_RESET (1 << 1) | ||
792 | |||
793 | /* #define PFIT_CONTROL 0x61230 */ | ||
794 | #define PFIT_PIPE_SELECT (3 << 29) | ||
795 | #define PFIT_PIPE_SELECT_SHIFT (29) | ||
796 | |||
797 | /* #define BLC_PWM_CTL 0x61254 */ | ||
798 | #define MRST_BACKLIGHT_MODULATION_FREQ_SHIFT (16) | ||
799 | #define MRST_BACKLIGHT_MODULATION_FREQ_MASK (0xffff << 16) | ||
800 | |||
801 | /* #define PIPEACONF 0x70008 */ | ||
802 | #define PIPEACONF_PIPE_STATE (1 << 30) | ||
803 | /* #define DSPACNTR 0x70180 */ | ||
804 | |||
805 | #define MRST_DSPABASE 0x7019c | ||
806 | #define MRST_DSPBBASE 0x7119c | ||
807 | #define MDFLD_DSPCBASE 0x7219c | ||
808 | |||
809 | /* | ||
810 | * Moorestown registers. | ||
811 | */ | ||
812 | |||
813 | /* | ||
814 | * MIPI IP registers | ||
815 | */ | ||
816 | #define MIPIC_REG_OFFSET 0x800 | ||
817 | |||
818 | #define DEVICE_READY_REG 0xb000 | ||
819 | #define LP_OUTPUT_HOLD (1 << 16) | ||
820 | #define EXIT_ULPS_DEV_READY 0x3 | ||
821 | #define LP_OUTPUT_HOLD_RELEASE 0x810000 | ||
822 | # define ENTERING_ULPS (2 << 1) | ||
823 | # define EXITING_ULPS (1 << 1) | ||
824 | # define ULPS_MASK (3 << 1) | ||
825 | # define BUS_POSSESSION (1 << 3) | ||
826 | #define INTR_STAT_REG 0xb004 | ||
827 | #define RX_SOT_ERROR (1 << 0) | ||
828 | #define RX_SOT_SYNC_ERROR (1 << 1) | ||
829 | #define RX_ESCAPE_MODE_ENTRY_ERROR (1 << 3) | ||
830 | #define RX_LP_TX_SYNC_ERROR (1 << 4) | ||
831 | #define RX_HS_RECEIVE_TIMEOUT_ERROR (1 << 5) | ||
832 | #define RX_FALSE_CONTROL_ERROR (1 << 6) | ||
833 | #define RX_ECC_SINGLE_BIT_ERROR (1 << 7) | ||
834 | #define RX_ECC_MULTI_BIT_ERROR (1 << 8) | ||
835 | #define RX_CHECKSUM_ERROR (1 << 9) | ||
836 | #define RX_DSI_DATA_TYPE_NOT_RECOGNIZED (1 << 10) | ||
837 | #define RX_DSI_VC_ID_INVALID (1 << 11) | ||
838 | #define TX_FALSE_CONTROL_ERROR (1 << 12) | ||
839 | #define TX_ECC_SINGLE_BIT_ERROR (1 << 13) | ||
840 | #define TX_ECC_MULTI_BIT_ERROR (1 << 14) | ||
841 | #define TX_CHECKSUM_ERROR (1 << 15) | ||
842 | #define TX_DSI_DATA_TYPE_NOT_RECOGNIZED (1 << 16) | ||
843 | #define TX_DSI_VC_ID_INVALID (1 << 17) | ||
844 | #define HIGH_CONTENTION (1 << 18) | ||
845 | #define LOW_CONTENTION (1 << 19) | ||
846 | #define DPI_FIFO_UNDER_RUN (1 << 20) | ||
847 | #define HS_TX_TIMEOUT (1 << 21) | ||
848 | #define LP_RX_TIMEOUT (1 << 22) | ||
849 | #define TURN_AROUND_ACK_TIMEOUT (1 << 23) | ||
850 | #define ACK_WITH_NO_ERROR (1 << 24) | ||
851 | #define HS_GENERIC_WR_FIFO_FULL (1 << 27) | ||
852 | #define LP_GENERIC_WR_FIFO_FULL (1 << 28) | ||
853 | #define SPL_PKT_SENT (1 << 30) | ||
854 | #define INTR_EN_REG 0xb008 | ||
855 | #define DSI_FUNC_PRG_REG 0xb00c | ||
856 | #define DPI_CHANNEL_NUMBER_POS 0x03 | ||
857 | #define DBI_CHANNEL_NUMBER_POS 0x05 | ||
858 | #define FMT_DPI_POS 0x07 | ||
859 | #define FMT_DBI_POS 0x0A | ||
860 | #define DBI_DATA_WIDTH_POS 0x0D | ||
861 | |||
862 | /* DPI PIXEL FORMATS */ | ||
863 | #define RGB_565_FMT 0x01 /* RGB 565 FORMAT */ | ||
864 | #define RGB_666_FMT 0x02 /* RGB 666 FORMAT */ | ||
865 | #define LRGB_666_FMT 0x03 /* RGB LOOSELY PACKED | ||
866 | * 666 FORMAT | ||
867 | */ | ||
868 | #define RGB_888_FMT 0x04 /* RGB 888 FORMAT */ | ||
869 | #define VIRTUAL_CHANNEL_NUMBER_0 0x00 /* Virtual channel 0 */ | ||
870 | #define VIRTUAL_CHANNEL_NUMBER_1 0x01 /* Virtual channel 1 */ | ||
871 | #define VIRTUAL_CHANNEL_NUMBER_2 0x02 /* Virtual channel 2 */ | ||
872 | #define VIRTUAL_CHANNEL_NUMBER_3 0x03 /* Virtual channel 3 */ | ||
873 | |||
874 | #define DBI_NOT_SUPPORTED 0x00 /* command mode | ||
875 | * is not supported | ||
876 | */ | ||
877 | #define DBI_DATA_WIDTH_16BIT 0x01 /* 16 bit data */ | ||
878 | #define DBI_DATA_WIDTH_9BIT 0x02 /* 9 bit data */ | ||
879 | #define DBI_DATA_WIDTH_8BIT 0x03 /* 8 bit data */ | ||
880 | #define DBI_DATA_WIDTH_OPT1 0x04 /* option 1 */ | ||
881 | #define DBI_DATA_WIDTH_OPT2 0x05 /* option 2 */ | ||
882 | |||
883 | #define HS_TX_TIMEOUT_REG 0xb010 | ||
884 | #define LP_RX_TIMEOUT_REG 0xb014 | ||
885 | #define TURN_AROUND_TIMEOUT_REG 0xb018 | ||
886 | #define DEVICE_RESET_REG 0xb01C | ||
887 | #define DPI_RESOLUTION_REG 0xb020 | ||
888 | #define RES_V_POS 0x10 | ||
889 | #define DBI_RESOLUTION_REG 0xb024 /* Reserved for MDFLD */ | ||
890 | #define HORIZ_SYNC_PAD_COUNT_REG 0xb028 | ||
891 | #define HORIZ_BACK_PORCH_COUNT_REG 0xb02C | ||
892 | #define HORIZ_FRONT_PORCH_COUNT_REG 0xb030 | ||
893 | #define HORIZ_ACTIVE_AREA_COUNT_REG 0xb034 | ||
894 | #define VERT_SYNC_PAD_COUNT_REG 0xb038 | ||
895 | #define VERT_BACK_PORCH_COUNT_REG 0xb03c | ||
896 | #define VERT_FRONT_PORCH_COUNT_REG 0xb040 | ||
897 | #define HIGH_LOW_SWITCH_COUNT_REG 0xb044 | ||
898 | #define DPI_CONTROL_REG 0xb048 | ||
899 | #define DPI_SHUT_DOWN (1 << 0) | ||
900 | #define DPI_TURN_ON (1 << 1) | ||
901 | #define DPI_COLOR_MODE_ON (1 << 2) | ||
902 | #define DPI_COLOR_MODE_OFF (1 << 3) | ||
903 | #define DPI_BACK_LIGHT_ON (1 << 4) | ||
904 | #define DPI_BACK_LIGHT_OFF (1 << 5) | ||
905 | #define DPI_LP (1 << 6) | ||
906 | #define DPI_DATA_REG 0xb04c | ||
907 | #define DPI_BACK_LIGHT_ON_DATA 0x07 | ||
908 | #define DPI_BACK_LIGHT_OFF_DATA 0x17 | ||
909 | #define INIT_COUNT_REG 0xb050 | ||
910 | #define MAX_RET_PAK_REG 0xb054 | ||
911 | #define VIDEO_FMT_REG 0xb058 | ||
912 | #define COMPLETE_LAST_PCKT (1 << 2) | ||
913 | #define EOT_DISABLE_REG 0xb05c | ||
914 | #define ENABLE_CLOCK_STOPPING (1 << 1) | ||
915 | #define LP_BYTECLK_REG 0xb060 | ||
916 | #define LP_GEN_DATA_REG 0xb064 | ||
917 | #define HS_GEN_DATA_REG 0xb068 | ||
918 | #define LP_GEN_CTRL_REG 0xb06C | ||
919 | #define HS_GEN_CTRL_REG 0xb070 | ||
920 | #define DCS_CHANNEL_NUMBER_POS 0x6 | ||
921 | #define MCS_COMMANDS_POS 0x8 | ||
922 | #define WORD_COUNTS_POS 0x8 | ||
923 | #define MCS_PARAMETER_POS 0x10 | ||
924 | #define GEN_FIFO_STAT_REG 0xb074 | ||
925 | #define HS_DATA_FIFO_FULL (1 << 0) | ||
926 | #define HS_DATA_FIFO_HALF_EMPTY (1 << 1) | ||
927 | #define HS_DATA_FIFO_EMPTY (1 << 2) | ||
928 | #define LP_DATA_FIFO_FULL (1 << 8) | ||
929 | #define LP_DATA_FIFO_HALF_EMPTY (1 << 9) | ||
930 | #define LP_DATA_FIFO_EMPTY (1 << 10) | ||
931 | #define HS_CTRL_FIFO_FULL (1 << 16) | ||
932 | #define HS_CTRL_FIFO_HALF_EMPTY (1 << 17) | ||
933 | #define HS_CTRL_FIFO_EMPTY (1 << 18) | ||
934 | #define LP_CTRL_FIFO_FULL (1 << 24) | ||
935 | #define LP_CTRL_FIFO_HALF_EMPTY (1 << 25) | ||
936 | #define LP_CTRL_FIFO_EMPTY (1 << 26) | ||
937 | #define DBI_FIFO_EMPTY (1 << 27) | ||
938 | #define DPI_FIFO_EMPTY (1 << 28) | ||
939 | #define HS_LS_DBI_ENABLE_REG 0xb078 | ||
940 | #define TXCLKESC_REG 0xb07c | ||
941 | #define DPHY_PARAM_REG 0xb080 | ||
942 | #define DBI_BW_CTRL_REG 0xb084 | ||
943 | #define CLK_LANE_SWT_REG 0xb088 | ||
944 | |||
945 | /* | ||
946 | * MIPI Adapter registers | ||
947 | */ | ||
948 | #define MIPI_CONTROL_REG 0xb104 | ||
949 | #define MIPI_2X_CLOCK_BITS ((1 << 0) | (1 << 1)) | ||
950 | #define MIPI_DATA_ADDRESS_REG 0xb108 | ||
951 | #define MIPI_DATA_LENGTH_REG 0xb10C | ||
952 | #define MIPI_COMMAND_ADDRESS_REG 0xb110 | ||
953 | #define MIPI_COMMAND_LENGTH_REG 0xb114 | ||
954 | #define MIPI_READ_DATA_RETURN_REG0 0xb118 | ||
955 | #define MIPI_READ_DATA_RETURN_REG1 0xb11C | ||
956 | #define MIPI_READ_DATA_RETURN_REG2 0xb120 | ||
957 | #define MIPI_READ_DATA_RETURN_REG3 0xb124 | ||
958 | #define MIPI_READ_DATA_RETURN_REG4 0xb128 | ||
959 | #define MIPI_READ_DATA_RETURN_REG5 0xb12C | ||
960 | #define MIPI_READ_DATA_RETURN_REG6 0xb130 | ||
961 | #define MIPI_READ_DATA_RETURN_REG7 0xb134 | ||
962 | #define MIPI_READ_DATA_VALID_REG 0xb138 | ||
963 | |||
964 | /* DBI COMMANDS */ | ||
965 | #define soft_reset 0x01 | ||
966 | /* | ||
967 | * The display module performs a software reset. | ||
968 | * Registers are written with their SW Reset default values. | ||
969 | */ | ||
970 | #define get_power_mode 0x0a | ||
971 | /* | ||
972 | * The display module returns the current power mode | ||
973 | */ | ||
974 | #define get_address_mode 0x0b | ||
975 | /* | ||
976 | * The display module returns the current status. | ||
977 | */ | ||
978 | #define get_pixel_format 0x0c | ||
979 | /* | ||
980 | * This command gets the pixel format for the RGB image data | ||
981 | * used by the interface. | ||
982 | */ | ||
983 | #define get_display_mode 0x0d | ||
984 | /* | ||
985 | * The display module returns the Display Image Mode status. | ||
986 | */ | ||
987 | #define get_signal_mode 0x0e | ||
988 | /* | ||
989 | * The display module returns the Display Signal Mode. | ||
990 | */ | ||
991 | #define get_diagnostic_result 0x0f | ||
992 | /* | ||
993 | * The display module returns the self-diagnostic results following | ||
994 | * a Sleep Out command. | ||
995 | */ | ||
996 | #define enter_sleep_mode 0x10 | ||
997 | /* | ||
998 | * This command causes the display module to enter the Sleep mode. | ||
999 | * In this mode, all unnecessary blocks inside the display module are | ||
1000 | * disabled except interface communication. This is the lowest power | ||
1001 | * mode the display module supports. | ||
1002 | */ | ||
1003 | #define exit_sleep_mode 0x11 | ||
1004 | /* | ||
1005 | * This command causes the display module to exit Sleep mode. | ||
1006 | * All blocks inside the display module are enabled. | ||
1007 | */ | ||
1008 | #define enter_partial_mode 0x12 | ||
1009 | /* | ||
1010 | * This command causes the display module to enter the Partial Display | ||
1011 | * Mode. The Partial Display Mode window is described by the | ||
1012 | * set_partial_area command. | ||
1013 | */ | ||
1014 | #define enter_normal_mode 0x13 | ||
1015 | /* | ||
1016 | * This command causes the display module to enter the Normal mode. | ||
1017 | * Normal Mode is defined as Partial Display mode and Scroll mode are off | ||
1018 | */ | ||
1019 | #define exit_invert_mode 0x20 | ||
1020 | /* | ||
1021 | * This command causes the display module to stop inverting the image | ||
1022 | * data on the display device. The frame memory contents remain unchanged. | ||
1023 | * No status bits are changed. | ||
1024 | */ | ||
1025 | #define enter_invert_mode 0x21 | ||
1026 | /* | ||
1027 | * This command causes the display module to invert the image data only on | ||
1028 | * the display device. The frame memory contents remain unchanged. | ||
1029 | * No status bits are changed. | ||
1030 | */ | ||
1031 | #define set_gamma_curve 0x26 | ||
1032 | /* | ||
1033 | * This command selects the desired gamma curve for the display device. | ||
1034 | * Four fixed gamma curves are defined in section DCS spec. | ||
1035 | */ | ||
1036 | #define set_display_off 0x28 | ||
1037 | /* ************************************************************************* *\ | ||
1038 | This command causes the display module to stop displaying the image data | ||
1039 | on the display device. The frame memory contents remain unchanged. | ||
1040 | No status bits are changed. | ||
1041 | \* ************************************************************************* */ | ||
1042 | #define set_display_on 0x29 | ||
1043 | /* ************************************************************************* *\ | ||
1044 | This command causes the display module to start displaying the image data | ||
1045 | on the display device. The frame memory contents remain unchanged. | ||
1046 | No status bits are changed. | ||
1047 | \* ************************************************************************* */ | ||
1048 | #define set_column_address 0x2a | ||
1049 | /* | ||
1050 | * This command defines the column extent of the frame memory accessed by | ||
1051 | * the hostprocessor with the read_memory_continue and | ||
1052 | * write_memory_continue commands. | ||
1053 | * No status bits are changed. | ||
1054 | */ | ||
1055 | #define set_page_addr 0x2b | ||
1056 | /* | ||
1057 | * This command defines the page extent of the frame memory accessed by | ||
1058 | * the host processor with the write_memory_continue and | ||
1059 | * read_memory_continue command. | ||
1060 | * No status bits are changed. | ||
1061 | */ | ||
1062 | #define write_mem_start 0x2c | ||
1063 | /* | ||
1064 | * This command transfers image data from the host processor to the | ||
1065 | * display modules frame memory starting at the pixel location specified | ||
1066 | * by preceding set_column_address and set_page_address commands. | ||
1067 | */ | ||
1068 | #define set_partial_area 0x30 | ||
1069 | /* | ||
1070 | * This command defines the Partial Display mode s display area. | ||
1071 | * There are two parameters associated with this command, the first | ||
1072 | * defines the Start Row (SR) and the second the End Row (ER). SR and ER | ||
1073 | * refer to the Frame Memory Line Pointer. | ||
1074 | */ | ||
1075 | #define set_scroll_area 0x33 | ||
1076 | /* | ||
1077 | * This command defines the display modules Vertical Scrolling Area. | ||
1078 | */ | ||
1079 | #define set_tear_off 0x34 | ||
1080 | /* | ||
1081 | * This command turns off the display modules Tearing Effect output | ||
1082 | * signal on the TE signal line. | ||
1083 | */ | ||
1084 | #define set_tear_on 0x35 | ||
1085 | /* | ||
1086 | * This command turns on the display modules Tearing Effect output signal | ||
1087 | * on the TE signal line. | ||
1088 | */ | ||
1089 | #define set_address_mode 0x36 | ||
1090 | /* | ||
1091 | * This command sets the data order for transfers from the host processor | ||
1092 | * to display modules frame memory,bits B[7:5] and B3, and from the | ||
1093 | * display modules frame memory to the display device, bits B[2:0] and B4. | ||
1094 | */ | ||
1095 | #define set_scroll_start 0x37 | ||
1096 | /* | ||
1097 | * This command sets the start of the vertical scrolling area in the frame | ||
1098 | * memory. The vertical scrolling area is fully defined when this command | ||
1099 | * is used with the set_scroll_area command The set_scroll_start command | ||
1100 | * has one parameter, the Vertical Scroll Pointer. The VSP defines the | ||
1101 | * line in the frame memory that is written to the display device as the | ||
1102 | * first line of the vertical scroll area. | ||
1103 | */ | ||
1104 | #define exit_idle_mode 0x38 | ||
1105 | /* | ||
1106 | * This command causes the display module to exit Idle mode. | ||
1107 | */ | ||
1108 | #define enter_idle_mode 0x39 | ||
1109 | /* | ||
1110 | * This command causes the display module to enter Idle Mode. | ||
1111 | * In Idle Mode, color expression is reduced. Colors are shown on the | ||
1112 | * display device using the MSB of each of the R, G and B color | ||
1113 | * components in the frame memory | ||
1114 | */ | ||
1115 | #define set_pixel_format 0x3a | ||
1116 | /* | ||
1117 | * This command sets the pixel format for the RGB image data used by the | ||
1118 | * interface. | ||
1119 | * Bits D[6:4] DPI Pixel Format Definition | ||
1120 | * Bits D[2:0] DBI Pixel Format Definition | ||
1121 | * Bits D7 and D3 are not used. | ||
1122 | */ | ||
1123 | #define DCS_PIXEL_FORMAT_3bpp 0x1 | ||
1124 | #define DCS_PIXEL_FORMAT_8bpp 0x2 | ||
1125 | #define DCS_PIXEL_FORMAT_12bpp 0x3 | ||
1126 | #define DCS_PIXEL_FORMAT_16bpp 0x5 | ||
1127 | #define DCS_PIXEL_FORMAT_18bpp 0x6 | ||
1128 | #define DCS_PIXEL_FORMAT_24bpp 0x7 | ||
1129 | |||
1130 | #define write_mem_cont 0x3c | ||
1131 | |||
1132 | /* | ||
1133 | * This command transfers image data from the host processor to the | ||
1134 | * display module's frame memory continuing from the pixel location | ||
1135 | * following the previous write_memory_continue or write_memory_start | ||
1136 | * command. | ||
1137 | */ | ||
1138 | #define set_tear_scanline 0x44 | ||
1139 | /* | ||
1140 | * This command turns on the display modules Tearing Effect output signal | ||
1141 | * on the TE signal line when the display module reaches line N. | ||
1142 | */ | ||
1143 | #define get_scanline 0x45 | ||
1144 | /* | ||
1145 | * The display module returns the current scanline, N, used to update the | ||
1146 | * display device. The total number of scanlines on a display device is | ||
1147 | * defined as VSYNC + VBP + VACT + VFP.The first scanline is defined as | ||
1148 | * the first line of V Sync and is denoted as Line 0. | ||
1149 | * When in Sleep Mode, the value returned by get_scanline is undefined. | ||
1150 | */ | ||
1151 | |||
1152 | /* MCS or Generic COMMANDS */ | ||
1153 | /* MCS/generic data type */ | ||
1154 | #define GEN_SHORT_WRITE_0 0x03 /* generic short write, no parameters */ | ||
1155 | #define GEN_SHORT_WRITE_1 0x13 /* generic short write, 1 parameters */ | ||
1156 | #define GEN_SHORT_WRITE_2 0x23 /* generic short write, 2 parameters */ | ||
1157 | #define GEN_READ_0 0x04 /* generic read, no parameters */ | ||
1158 | #define GEN_READ_1 0x14 /* generic read, 1 parameters */ | ||
1159 | #define GEN_READ_2 0x24 /* generic read, 2 parameters */ | ||
1160 | #define GEN_LONG_WRITE 0x29 /* generic long write */ | ||
1161 | #define MCS_SHORT_WRITE_0 0x05 /* MCS short write, no parameters */ | ||
1162 | #define MCS_SHORT_WRITE_1 0x15 /* MCS short write, 1 parameters */ | ||
1163 | #define MCS_READ 0x06 /* MCS read, no parameters */ | ||
1164 | #define MCS_LONG_WRITE 0x39 /* MCS long write */ | ||
1165 | /* MCS/generic commands */ | ||
1166 | /* TPO MCS */ | ||
1167 | #define write_display_profile 0x50 | ||
1168 | #define write_display_brightness 0x51 | ||
1169 | #define write_ctrl_display 0x53 | ||
1170 | #define write_ctrl_cabc 0x55 | ||
1171 | #define UI_IMAGE 0x01 | ||
1172 | #define STILL_IMAGE 0x02 | ||
1173 | #define MOVING_IMAGE 0x03 | ||
1174 | #define write_hysteresis 0x57 | ||
1175 | #define write_gamma_setting 0x58 | ||
1176 | #define write_cabc_min_bright 0x5e | ||
1177 | #define write_kbbc_profile 0x60 | ||
1178 | /* TMD MCS */ | ||
1179 | #define tmd_write_display_brightness 0x8c | ||
1180 | |||
1181 | /* | ||
1182 | * This command is used to control ambient light, panel backlight | ||
1183 | * brightness and gamma settings. | ||
1184 | */ | ||
1185 | #define BRIGHT_CNTL_BLOCK_ON (1 << 5) | ||
1186 | #define AMBIENT_LIGHT_SENSE_ON (1 << 4) | ||
1187 | #define DISPLAY_DIMMING_ON (1 << 3) | ||
1188 | #define BACKLIGHT_ON (1 << 2) | ||
1189 | #define DISPLAY_BRIGHTNESS_AUTO (1 << 1) | ||
1190 | #define GAMMA_AUTO (1 << 0) | ||
1191 | |||
1192 | /* DCS Interface Pixel Formats */ | ||
1193 | #define DCS_PIXEL_FORMAT_3BPP 0x1 | ||
1194 | #define DCS_PIXEL_FORMAT_8BPP 0x2 | ||
1195 | #define DCS_PIXEL_FORMAT_12BPP 0x3 | ||
1196 | #define DCS_PIXEL_FORMAT_16BPP 0x5 | ||
1197 | #define DCS_PIXEL_FORMAT_18BPP 0x6 | ||
1198 | #define DCS_PIXEL_FORMAT_24BPP 0x7 | ||
1199 | /* ONE PARAMETER READ DATA */ | ||
1200 | #define addr_mode_data 0xfc | ||
1201 | #define diag_res_data 0x00 | ||
1202 | #define disp_mode_data 0x23 | ||
1203 | #define pxl_fmt_data 0x77 | ||
1204 | #define pwr_mode_data 0x74 | ||
1205 | #define sig_mode_data 0x00 | ||
1206 | /* TWO PARAMETERS READ DATA */ | ||
1207 | #define scanline_data1 0xff | ||
1208 | #define scanline_data2 0xff | ||
1209 | #define NON_BURST_MODE_SYNC_PULSE 0x01 /* Non Burst Mode | ||
1210 | * with Sync Pulse | ||
1211 | */ | ||
1212 | #define NON_BURST_MODE_SYNC_EVENTS 0x02 /* Non Burst Mode | ||
1213 | * with Sync events | ||
1214 | */ | ||
1215 | #define BURST_MODE 0x03 /* Burst Mode */ | ||
1216 | #define DBI_COMMAND_BUFFER_SIZE 0x240 /* 0x32 */ /* 0x120 */ | ||
1217 | /* Allocate at least | ||
1218 | * 0x100 Byte with 32 | ||
1219 | * byte alignment | ||
1220 | */ | ||
1221 | #define DBI_DATA_BUFFER_SIZE 0x120 /* Allocate at least | ||
1222 | * 0x100 Byte with 32 | ||
1223 | * byte alignment | ||
1224 | */ | ||
1225 | #define DBI_CB_TIME_OUT 0xFFFF | ||
1226 | |||
1227 | #define GEN_FB_TIME_OUT 2000 | ||
1228 | |||
1229 | #define SKU_83 0x01 | ||
1230 | #define SKU_100 0x02 | ||
1231 | #define SKU_100L 0x04 | ||
1232 | #define SKU_BYPASS 0x08 | ||
1233 | |||
1234 | /* Some handy macros for playing with bitfields. */ | ||
1235 | #define PSB_MASK(high, low) (((1<<((high)-(low)+1))-1)<<(low)) | ||
1236 | #define SET_FIELD(value, field) (((value) << field ## _SHIFT) & field ## _MASK) | ||
1237 | #define GET_FIELD(word, field) (((word) & field ## _MASK) >> field ## _SHIFT) | ||
1238 | |||
1239 | #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) | ||
1240 | |||
1241 | /* PCI config space */ | ||
1242 | |||
1243 | #define SB_PCKT 0x02100 /* cedarview */ | ||
1244 | # define SB_OPCODE_MASK PSB_MASK(31, 16) | ||
1245 | # define SB_OPCODE_SHIFT 16 | ||
1246 | # define SB_OPCODE_READ 0 | ||
1247 | # define SB_OPCODE_WRITE 1 | ||
1248 | # define SB_DEST_MASK PSB_MASK(15, 8) | ||
1249 | # define SB_DEST_SHIFT 8 | ||
1250 | # define SB_DEST_DPLL 0x88 | ||
1251 | # define SB_BYTE_ENABLE_MASK PSB_MASK(7, 4) | ||
1252 | # define SB_BYTE_ENABLE_SHIFT 4 | ||
1253 | # define SB_BUSY (1 << 0) | ||
1254 | |||
1255 | |||
1256 | /* 32-bit value read/written from the DPIO reg. */ | ||
1257 | #define SB_DATA 0x02104 /* cedarview */ | ||
1258 | /* 32-bit address of the DPIO reg to be read/written. */ | ||
1259 | #define SB_ADDR 0x02108 /* cedarview */ | ||
1260 | #define DPIO_CFG 0x02110 /* cedarview */ | ||
1261 | # define DPIO_MODE_SELECT_1 (1 << 3) | ||
1262 | # define DPIO_MODE_SELECT_0 (1 << 2) | ||
1263 | # define DPIO_SFR_BYPASS (1 << 1) | ||
1264 | /* reset is active low */ | ||
1265 | # define DPIO_CMN_RESET_N (1 << 0) | ||
1266 | |||
1267 | /* Cedarview sideband registers */ | ||
1268 | #define _SB_M_A 0x8008 | ||
1269 | #define _SB_M_B 0x8028 | ||
1270 | #define SB_M(pipe) _PIPE(pipe, _SB_M_A, _SB_M_B) | ||
1271 | # define SB_M_DIVIDER_MASK (0xFF << 24) | ||
1272 | # define SB_M_DIVIDER_SHIFT 24 | ||
1273 | |||
1274 | #define _SB_N_VCO_A 0x8014 | ||
1275 | #define _SB_N_VCO_B 0x8034 | ||
1276 | #define SB_N_VCO(pipe) _PIPE(pipe, _SB_N_VCO_A, _SB_N_VCO_B) | ||
1277 | #define SB_N_VCO_SEL_MASK PSB_MASK(31, 30) | ||
1278 | #define SB_N_VCO_SEL_SHIFT 30 | ||
1279 | #define SB_N_DIVIDER_MASK PSB_MASK(29, 26) | ||
1280 | #define SB_N_DIVIDER_SHIFT 26 | ||
1281 | #define SB_N_CB_TUNE_MASK PSB_MASK(25, 24) | ||
1282 | #define SB_N_CB_TUNE_SHIFT 24 | ||
1283 | |||
1284 | #define _SB_REF_A 0x8018 | ||
1285 | #define _SB_REF_B 0x8038 | ||
1286 | #define SB_REF_SFR(pipe) _PIPE(pipe, _SB_REF_A, _SB_REF_B) | ||
1287 | |||
1288 | #define _SB_P_A 0x801c | ||
1289 | #define _SB_P_B 0x803c | ||
1290 | #define SB_P(pipe) _PIPE(pipe, _SB_P_A, _SB_P_B) | ||
1291 | #define SB_P2_DIVIDER_MASK PSB_MASK(31, 30) | ||
1292 | #define SB_P2_DIVIDER_SHIFT 30 | ||
1293 | #define SB_P2_10 0 /* HDMI, DP, DAC */ | ||
1294 | #define SB_P2_5 1 /* DAC */ | ||
1295 | #define SB_P2_14 2 /* LVDS single */ | ||
1296 | #define SB_P2_7 3 /* LVDS double */ | ||
1297 | #define SB_P1_DIVIDER_MASK PSB_MASK(15, 12) | ||
1298 | #define SB_P1_DIVIDER_SHIFT 12 | ||
1299 | |||
1300 | #define PSB_LANE0 0x120 | ||
1301 | #define PSB_LANE1 0x220 | ||
1302 | #define PSB_LANE2 0x2320 | ||
1303 | #define PSB_LANE3 0x2420 | ||
1304 | |||
1305 | #define LANE_PLL_MASK (0x7 << 20) | ||
1306 | #define LANE_PLL_ENABLE (0x3 << 20) | ||
1307 | |||
1308 | |||
1309 | #endif | ||
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c new file mode 100644 index 00000000000..4882b29119e --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c | |||
@@ -0,0 +1,2617 @@ | |||
1 | /* | ||
2 | * Copyright 2006 Dave Airlie <airlied@linux.ie> | ||
3 | * Copyright © 2006-2007 Intel Corporation | ||
4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the next | ||
14 | * paragraph) shall be included in all copies or substantial portions of the | ||
15 | * Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
23 | * DEALINGS IN THE SOFTWARE. | ||
24 | * | ||
25 | * Authors: | ||
26 | * Eric Anholt <eric@anholt.net> | ||
27 | */ | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include "drmP.h" | ||
33 | #include "drm.h" | ||
34 | #include "drm_crtc.h" | ||
35 | #include "drm_edid.h" | ||
36 | #include "psb_intel_drv.h" | ||
37 | #include "gma_drm.h" | ||
38 | #include "psb_drv.h" | ||
39 | #include "psb_intel_sdvo_regs.h" | ||
40 | #include "psb_intel_reg.h" | ||
41 | |||
42 | #define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1) | ||
43 | #define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1) | ||
44 | #define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1) | ||
45 | #define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0) | ||
46 | |||
47 | #define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\ | ||
48 | SDVO_TV_MASK) | ||
49 | |||
50 | #define IS_TV(c) (c->output_flag & SDVO_TV_MASK) | ||
51 | #define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK) | ||
52 | #define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) | ||
53 | #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) | ||
54 | |||
55 | |||
56 | static const char *tv_format_names[] = { | ||
57 | "NTSC_M" , "NTSC_J" , "NTSC_443", | ||
58 | "PAL_B" , "PAL_D" , "PAL_G" , | ||
59 | "PAL_H" , "PAL_I" , "PAL_M" , | ||
60 | "PAL_N" , "PAL_NC" , "PAL_60" , | ||
61 | "SECAM_B" , "SECAM_D" , "SECAM_G" , | ||
62 | "SECAM_K" , "SECAM_K1", "SECAM_L" , | ||
63 | "SECAM_60" | ||
64 | }; | ||
65 | |||
66 | #define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names)) | ||
67 | |||
68 | struct psb_intel_sdvo { | ||
69 | struct psb_intel_encoder base; | ||
70 | |||
71 | struct i2c_adapter *i2c; | ||
72 | u8 slave_addr; | ||
73 | |||
74 | struct i2c_adapter ddc; | ||
75 | |||
76 | /* Register for the SDVO device: SDVOB or SDVOC */ | ||
77 | int sdvo_reg; | ||
78 | |||
79 | /* Active outputs controlled by this SDVO output */ | ||
80 | uint16_t controlled_output; | ||
81 | |||
82 | /* | ||
83 | * Capabilities of the SDVO device returned by | ||
84 | * i830_sdvo_get_capabilities() | ||
85 | */ | ||
86 | struct psb_intel_sdvo_caps caps; | ||
87 | |||
88 | /* Pixel clock limitations reported by the SDVO device, in kHz */ | ||
89 | int pixel_clock_min, pixel_clock_max; | ||
90 | |||
91 | /* | ||
92 | * For multiple function SDVO device, | ||
93 | * this is for current attached outputs. | ||
94 | */ | ||
95 | uint16_t attached_output; | ||
96 | |||
97 | /** | ||
98 | * This is used to select the color range of RBG outputs in HDMI mode. | ||
99 | * It is only valid when using TMDS encoding and 8 bit per color mode. | ||
100 | */ | ||
101 | uint32_t color_range; | ||
102 | |||
103 | /** | ||
104 | * This is set if we're going to treat the device as TV-out. | ||
105 | * | ||
106 | * While we have these nice friendly flags for output types that ought | ||
107 | * to decide this for us, the S-Video output on our HDMI+S-Video card | ||
108 | * shows up as RGB1 (VGA). | ||
109 | */ | ||
110 | bool is_tv; | ||
111 | |||
112 | /* This is for current tv format name */ | ||
113 | int tv_format_index; | ||
114 | |||
115 | /** | ||
116 | * This is set if we treat the device as HDMI, instead of DVI. | ||
117 | */ | ||
118 | bool is_hdmi; | ||
119 | bool has_hdmi_monitor; | ||
120 | bool has_hdmi_audio; | ||
121 | |||
122 | /** | ||
123 | * This is set if we detect output of sdvo device as LVDS and | ||
124 | * have a valid fixed mode to use with the panel. | ||
125 | */ | ||
126 | bool is_lvds; | ||
127 | |||
128 | /** | ||
129 | * This is sdvo fixed pannel mode pointer | ||
130 | */ | ||
131 | struct drm_display_mode *sdvo_lvds_fixed_mode; | ||
132 | |||
133 | /* DDC bus used by this SDVO encoder */ | ||
134 | uint8_t ddc_bus; | ||
135 | |||
136 | /* Input timings for adjusted_mode */ | ||
137 | struct psb_intel_sdvo_dtd input_dtd; | ||
138 | }; | ||
139 | |||
140 | struct psb_intel_sdvo_connector { | ||
141 | struct psb_intel_connector base; | ||
142 | |||
143 | /* Mark the type of connector */ | ||
144 | uint16_t output_flag; | ||
145 | |||
146 | int force_audio; | ||
147 | |||
148 | /* This contains all current supported TV format */ | ||
149 | u8 tv_format_supported[TV_FORMAT_NUM]; | ||
150 | int format_supported_num; | ||
151 | struct drm_property *tv_format; | ||
152 | |||
153 | /* add the property for the SDVO-TV */ | ||
154 | struct drm_property *left; | ||
155 | struct drm_property *right; | ||
156 | struct drm_property *top; | ||
157 | struct drm_property *bottom; | ||
158 | struct drm_property *hpos; | ||
159 | struct drm_property *vpos; | ||
160 | struct drm_property *contrast; | ||
161 | struct drm_property *saturation; | ||
162 | struct drm_property *hue; | ||
163 | struct drm_property *sharpness; | ||
164 | struct drm_property *flicker_filter; | ||
165 | struct drm_property *flicker_filter_adaptive; | ||
166 | struct drm_property *flicker_filter_2d; | ||
167 | struct drm_property *tv_chroma_filter; | ||
168 | struct drm_property *tv_luma_filter; | ||
169 | struct drm_property *dot_crawl; | ||
170 | |||
171 | /* add the property for the SDVO-TV/LVDS */ | ||
172 | struct drm_property *brightness; | ||
173 | |||
174 | /* Add variable to record current setting for the above property */ | ||
175 | u32 left_margin, right_margin, top_margin, bottom_margin; | ||
176 | |||
177 | /* this is to get the range of margin.*/ | ||
178 | u32 max_hscan, max_vscan; | ||
179 | u32 max_hpos, cur_hpos; | ||
180 | u32 max_vpos, cur_vpos; | ||
181 | u32 cur_brightness, max_brightness; | ||
182 | u32 cur_contrast, max_contrast; | ||
183 | u32 cur_saturation, max_saturation; | ||
184 | u32 cur_hue, max_hue; | ||
185 | u32 cur_sharpness, max_sharpness; | ||
186 | u32 cur_flicker_filter, max_flicker_filter; | ||
187 | u32 cur_flicker_filter_adaptive, max_flicker_filter_adaptive; | ||
188 | u32 cur_flicker_filter_2d, max_flicker_filter_2d; | ||
189 | u32 cur_tv_chroma_filter, max_tv_chroma_filter; | ||
190 | u32 cur_tv_luma_filter, max_tv_luma_filter; | ||
191 | u32 cur_dot_crawl, max_dot_crawl; | ||
192 | }; | ||
193 | |||
194 | static struct psb_intel_sdvo *to_psb_intel_sdvo(struct drm_encoder *encoder) | ||
195 | { | ||
196 | return container_of(encoder, struct psb_intel_sdvo, base.base); | ||
197 | } | ||
198 | |||
199 | static struct psb_intel_sdvo *intel_attached_sdvo(struct drm_connector *connector) | ||
200 | { | ||
201 | return container_of(psb_intel_attached_encoder(connector), | ||
202 | struct psb_intel_sdvo, base); | ||
203 | } | ||
204 | |||
205 | static struct psb_intel_sdvo_connector *to_psb_intel_sdvo_connector(struct drm_connector *connector) | ||
206 | { | ||
207 | return container_of(to_psb_intel_connector(connector), struct psb_intel_sdvo_connector, base); | ||
208 | } | ||
209 | |||
210 | static bool | ||
211 | psb_intel_sdvo_output_setup(struct psb_intel_sdvo *psb_intel_sdvo, uint16_t flags); | ||
212 | static bool | ||
213 | psb_intel_sdvo_tv_create_property(struct psb_intel_sdvo *psb_intel_sdvo, | ||
214 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector, | ||
215 | int type); | ||
216 | static bool | ||
217 | psb_intel_sdvo_create_enhance_property(struct psb_intel_sdvo *psb_intel_sdvo, | ||
218 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector); | ||
219 | |||
220 | /** | ||
221 | * Writes the SDVOB or SDVOC with the given value, but always writes both | ||
222 | * SDVOB and SDVOC to work around apparent hardware issues (according to | ||
223 | * comments in the BIOS). | ||
224 | */ | ||
225 | static void psb_intel_sdvo_write_sdvox(struct psb_intel_sdvo *psb_intel_sdvo, u32 val) | ||
226 | { | ||
227 | struct drm_device *dev = psb_intel_sdvo->base.base.dev; | ||
228 | u32 bval = val, cval = val; | ||
229 | int i; | ||
230 | |||
231 | if (psb_intel_sdvo->sdvo_reg == SDVOB) { | ||
232 | cval = REG_READ(SDVOC); | ||
233 | } else { | ||
234 | bval = REG_READ(SDVOB); | ||
235 | } | ||
236 | /* | ||
237 | * Write the registers twice for luck. Sometimes, | ||
238 | * writing them only once doesn't appear to 'stick'. | ||
239 | * The BIOS does this too. Yay, magic | ||
240 | */ | ||
241 | for (i = 0; i < 2; i++) | ||
242 | { | ||
243 | REG_WRITE(SDVOB, bval); | ||
244 | REG_READ(SDVOB); | ||
245 | REG_WRITE(SDVOC, cval); | ||
246 | REG_READ(SDVOC); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static bool psb_intel_sdvo_read_byte(struct psb_intel_sdvo *psb_intel_sdvo, u8 addr, u8 *ch) | ||
251 | { | ||
252 | struct i2c_msg msgs[] = { | ||
253 | { | ||
254 | .addr = psb_intel_sdvo->slave_addr, | ||
255 | .flags = 0, | ||
256 | .len = 1, | ||
257 | .buf = &addr, | ||
258 | }, | ||
259 | { | ||
260 | .addr = psb_intel_sdvo->slave_addr, | ||
261 | .flags = I2C_M_RD, | ||
262 | .len = 1, | ||
263 | .buf = ch, | ||
264 | } | ||
265 | }; | ||
266 | int ret; | ||
267 | |||
268 | if ((ret = i2c_transfer(psb_intel_sdvo->i2c, msgs, 2)) == 2) | ||
269 | return true; | ||
270 | |||
271 | DRM_DEBUG_KMS("i2c transfer returned %d\n", ret); | ||
272 | return false; | ||
273 | } | ||
274 | |||
275 | #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} | ||
276 | /** Mapping of command numbers to names, for debug output */ | ||
277 | static const struct _sdvo_cmd_name { | ||
278 | u8 cmd; | ||
279 | const char *name; | ||
280 | } sdvo_cmd_names[] = { | ||
281 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), | ||
282 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), | ||
283 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV), | ||
284 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS), | ||
285 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS), | ||
286 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS), | ||
287 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP), | ||
288 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP), | ||
289 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS), | ||
290 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), | ||
291 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), | ||
292 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), | ||
293 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), | ||
294 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), | ||
295 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), | ||
296 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), | ||
297 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2), | ||
298 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), | ||
299 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2), | ||
300 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), | ||
301 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1), | ||
302 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2), | ||
303 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1), | ||
304 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2), | ||
305 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING), | ||
306 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1), | ||
307 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2), | ||
308 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE), | ||
309 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE), | ||
310 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS), | ||
311 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT), | ||
312 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT), | ||
313 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS), | ||
314 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT), | ||
315 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT), | ||
316 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES), | ||
317 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POWER_STATE), | ||
318 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE), | ||
319 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DISPLAY_POWER_STATE), | ||
320 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), | ||
321 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT), | ||
322 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT), | ||
323 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS), | ||
324 | |||
325 | /* Add the op code for SDVO enhancements */ | ||
326 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HPOS), | ||
327 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HPOS), | ||
328 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HPOS), | ||
329 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_VPOS), | ||
330 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_VPOS), | ||
331 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_VPOS), | ||
332 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SATURATION), | ||
333 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SATURATION), | ||
334 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SATURATION), | ||
335 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HUE), | ||
336 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HUE), | ||
337 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HUE), | ||
338 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_CONTRAST), | ||
339 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CONTRAST), | ||
340 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTRAST), | ||
341 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_BRIGHTNESS), | ||
342 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_BRIGHTNESS), | ||
343 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_BRIGHTNESS), | ||
344 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_H), | ||
345 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_H), | ||
346 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_H), | ||
347 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_V), | ||
348 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_V), | ||
349 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_V), | ||
350 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER), | ||
351 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER), | ||
352 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER), | ||
353 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE), | ||
354 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE), | ||
355 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE), | ||
356 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_2D), | ||
357 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_2D), | ||
358 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_2D), | ||
359 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SHARPNESS), | ||
360 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SHARPNESS), | ||
361 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SHARPNESS), | ||
362 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DOT_CRAWL), | ||
363 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DOT_CRAWL), | ||
364 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_CHROMA_FILTER), | ||
365 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_CHROMA_FILTER), | ||
366 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_CHROMA_FILTER), | ||
367 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_LUMA_FILTER), | ||
368 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_LUMA_FILTER), | ||
369 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_LUMA_FILTER), | ||
370 | |||
371 | /* HDMI op code */ | ||
372 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE), | ||
373 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE), | ||
374 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODE), | ||
375 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_PIXEL_REPLI), | ||
376 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PIXEL_REPLI), | ||
377 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY_CAP), | ||
378 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_COLORIMETRY), | ||
379 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY), | ||
380 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER), | ||
381 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_AUDIO_STAT), | ||
382 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_STAT), | ||
383 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INDEX), | ||
384 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_INDEX), | ||
385 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INFO), | ||
386 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_AV_SPLIT), | ||
387 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_AV_SPLIT), | ||
388 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_TXRATE), | ||
389 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_TXRATE), | ||
390 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_DATA), | ||
391 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA), | ||
392 | }; | ||
393 | |||
394 | #define IS_SDVOB(reg) (reg == SDVOB) | ||
395 | #define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC") | ||
396 | |||
397 | static void psb_intel_sdvo_debug_write(struct psb_intel_sdvo *psb_intel_sdvo, u8 cmd, | ||
398 | const void *args, int args_len) | ||
399 | { | ||
400 | int i; | ||
401 | |||
402 | DRM_DEBUG_KMS("%s: W: %02X ", | ||
403 | SDVO_NAME(psb_intel_sdvo), cmd); | ||
404 | for (i = 0; i < args_len; i++) | ||
405 | DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); | ||
406 | for (; i < 8; i++) | ||
407 | DRM_LOG_KMS(" "); | ||
408 | for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) { | ||
409 | if (cmd == sdvo_cmd_names[i].cmd) { | ||
410 | DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name); | ||
411 | break; | ||
412 | } | ||
413 | } | ||
414 | if (i == ARRAY_SIZE(sdvo_cmd_names)) | ||
415 | DRM_LOG_KMS("(%02X)", cmd); | ||
416 | DRM_LOG_KMS("\n"); | ||
417 | } | ||
418 | |||
419 | static const char *cmd_status_names[] = { | ||
420 | "Power on", | ||
421 | "Success", | ||
422 | "Not supported", | ||
423 | "Invalid arg", | ||
424 | "Pending", | ||
425 | "Target not specified", | ||
426 | "Scaling not supported" | ||
427 | }; | ||
428 | |||
429 | static bool psb_intel_sdvo_write_cmd(struct psb_intel_sdvo *psb_intel_sdvo, u8 cmd, | ||
430 | const void *args, int args_len) | ||
431 | { | ||
432 | u8 buf[args_len*2 + 2], status; | ||
433 | struct i2c_msg msgs[args_len + 3]; | ||
434 | int i, ret; | ||
435 | |||
436 | psb_intel_sdvo_debug_write(psb_intel_sdvo, cmd, args, args_len); | ||
437 | |||
438 | for (i = 0; i < args_len; i++) { | ||
439 | msgs[i].addr = psb_intel_sdvo->slave_addr; | ||
440 | msgs[i].flags = 0; | ||
441 | msgs[i].len = 2; | ||
442 | msgs[i].buf = buf + 2 *i; | ||
443 | buf[2*i + 0] = SDVO_I2C_ARG_0 - i; | ||
444 | buf[2*i + 1] = ((u8*)args)[i]; | ||
445 | } | ||
446 | msgs[i].addr = psb_intel_sdvo->slave_addr; | ||
447 | msgs[i].flags = 0; | ||
448 | msgs[i].len = 2; | ||
449 | msgs[i].buf = buf + 2*i; | ||
450 | buf[2*i + 0] = SDVO_I2C_OPCODE; | ||
451 | buf[2*i + 1] = cmd; | ||
452 | |||
453 | /* the following two are to read the response */ | ||
454 | status = SDVO_I2C_CMD_STATUS; | ||
455 | msgs[i+1].addr = psb_intel_sdvo->slave_addr; | ||
456 | msgs[i+1].flags = 0; | ||
457 | msgs[i+1].len = 1; | ||
458 | msgs[i+1].buf = &status; | ||
459 | |||
460 | msgs[i+2].addr = psb_intel_sdvo->slave_addr; | ||
461 | msgs[i+2].flags = I2C_M_RD; | ||
462 | msgs[i+2].len = 1; | ||
463 | msgs[i+2].buf = &status; | ||
464 | |||
465 | ret = i2c_transfer(psb_intel_sdvo->i2c, msgs, i+3); | ||
466 | if (ret < 0) { | ||
467 | DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); | ||
468 | return false; | ||
469 | } | ||
470 | if (ret != i+3) { | ||
471 | /* failure in I2C transfer */ | ||
472 | DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3); | ||
473 | return false; | ||
474 | } | ||
475 | |||
476 | return true; | ||
477 | } | ||
478 | |||
479 | static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo, | ||
480 | void *response, int response_len) | ||
481 | { | ||
482 | u8 retry = 5; | ||
483 | u8 status; | ||
484 | int i; | ||
485 | |||
486 | DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(psb_intel_sdvo)); | ||
487 | |||
488 | /* | ||
489 | * The documentation states that all commands will be | ||
490 | * processed within 15µs, and that we need only poll | ||
491 | * the status byte a maximum of 3 times in order for the | ||
492 | * command to be complete. | ||
493 | * | ||
494 | * Check 5 times in case the hardware failed to read the docs. | ||
495 | */ | ||
496 | if (!psb_intel_sdvo_read_byte(psb_intel_sdvo, | ||
497 | SDVO_I2C_CMD_STATUS, | ||
498 | &status)) | ||
499 | goto log_fail; | ||
500 | |||
501 | while (status == SDVO_CMD_STATUS_PENDING && retry--) { | ||
502 | udelay(15); | ||
503 | if (!psb_intel_sdvo_read_byte(psb_intel_sdvo, | ||
504 | SDVO_I2C_CMD_STATUS, | ||
505 | &status)) | ||
506 | goto log_fail; | ||
507 | } | ||
508 | |||
509 | if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) | ||
510 | DRM_LOG_KMS("(%s)", cmd_status_names[status]); | ||
511 | else | ||
512 | DRM_LOG_KMS("(??? %d)", status); | ||
513 | |||
514 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
515 | goto log_fail; | ||
516 | |||
517 | /* Read the command response */ | ||
518 | for (i = 0; i < response_len; i++) { | ||
519 | if (!psb_intel_sdvo_read_byte(psb_intel_sdvo, | ||
520 | SDVO_I2C_RETURN_0 + i, | ||
521 | &((u8 *)response)[i])) | ||
522 | goto log_fail; | ||
523 | DRM_LOG_KMS(" %02X", ((u8 *)response)[i]); | ||
524 | } | ||
525 | DRM_LOG_KMS("\n"); | ||
526 | return true; | ||
527 | |||
528 | log_fail: | ||
529 | DRM_LOG_KMS("... failed\n"); | ||
530 | return false; | ||
531 | } | ||
532 | |||
533 | static int psb_intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) | ||
534 | { | ||
535 | if (mode->clock >= 100000) | ||
536 | return 1; | ||
537 | else if (mode->clock >= 50000) | ||
538 | return 2; | ||
539 | else | ||
540 | return 4; | ||
541 | } | ||
542 | |||
543 | static bool psb_intel_sdvo_set_control_bus_switch(struct psb_intel_sdvo *psb_intel_sdvo, | ||
544 | u8 ddc_bus) | ||
545 | { | ||
546 | /* This must be the immediately preceding write before the i2c xfer */ | ||
547 | return psb_intel_sdvo_write_cmd(psb_intel_sdvo, | ||
548 | SDVO_CMD_SET_CONTROL_BUS_SWITCH, | ||
549 | &ddc_bus, 1); | ||
550 | } | ||
551 | |||
552 | static bool psb_intel_sdvo_set_value(struct psb_intel_sdvo *psb_intel_sdvo, u8 cmd, const void *data, int len) | ||
553 | { | ||
554 | if (!psb_intel_sdvo_write_cmd(psb_intel_sdvo, cmd, data, len)) | ||
555 | return false; | ||
556 | |||
557 | return psb_intel_sdvo_read_response(psb_intel_sdvo, NULL, 0); | ||
558 | } | ||
559 | |||
560 | static bool | ||
561 | psb_intel_sdvo_get_value(struct psb_intel_sdvo *psb_intel_sdvo, u8 cmd, void *value, int len) | ||
562 | { | ||
563 | if (!psb_intel_sdvo_write_cmd(psb_intel_sdvo, cmd, NULL, 0)) | ||
564 | return false; | ||
565 | |||
566 | return psb_intel_sdvo_read_response(psb_intel_sdvo, value, len); | ||
567 | } | ||
568 | |||
569 | static bool psb_intel_sdvo_set_target_input(struct psb_intel_sdvo *psb_intel_sdvo) | ||
570 | { | ||
571 | struct psb_intel_sdvo_set_target_input_args targets = {0}; | ||
572 | return psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
573 | SDVO_CMD_SET_TARGET_INPUT, | ||
574 | &targets, sizeof(targets)); | ||
575 | } | ||
576 | |||
577 | /** | ||
578 | * Return whether each input is trained. | ||
579 | * | ||
580 | * This function is making an assumption about the layout of the response, | ||
581 | * which should be checked against the docs. | ||
582 | */ | ||
583 | static bool psb_intel_sdvo_get_trained_inputs(struct psb_intel_sdvo *psb_intel_sdvo, bool *input_1, bool *input_2) | ||
584 | { | ||
585 | struct psb_intel_sdvo_get_trained_inputs_response response; | ||
586 | |||
587 | BUILD_BUG_ON(sizeof(response) != 1); | ||
588 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, | ||
589 | &response, sizeof(response))) | ||
590 | return false; | ||
591 | |||
592 | *input_1 = response.input0_trained; | ||
593 | *input_2 = response.input1_trained; | ||
594 | return true; | ||
595 | } | ||
596 | |||
597 | static bool psb_intel_sdvo_set_active_outputs(struct psb_intel_sdvo *psb_intel_sdvo, | ||
598 | u16 outputs) | ||
599 | { | ||
600 | return psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
601 | SDVO_CMD_SET_ACTIVE_OUTPUTS, | ||
602 | &outputs, sizeof(outputs)); | ||
603 | } | ||
604 | |||
605 | static bool psb_intel_sdvo_set_encoder_power_state(struct psb_intel_sdvo *psb_intel_sdvo, | ||
606 | int mode) | ||
607 | { | ||
608 | u8 state = SDVO_ENCODER_STATE_ON; | ||
609 | |||
610 | switch (mode) { | ||
611 | case DRM_MODE_DPMS_ON: | ||
612 | state = SDVO_ENCODER_STATE_ON; | ||
613 | break; | ||
614 | case DRM_MODE_DPMS_STANDBY: | ||
615 | state = SDVO_ENCODER_STATE_STANDBY; | ||
616 | break; | ||
617 | case DRM_MODE_DPMS_SUSPEND: | ||
618 | state = SDVO_ENCODER_STATE_SUSPEND; | ||
619 | break; | ||
620 | case DRM_MODE_DPMS_OFF: | ||
621 | state = SDVO_ENCODER_STATE_OFF; | ||
622 | break; | ||
623 | } | ||
624 | |||
625 | return psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
626 | SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state)); | ||
627 | } | ||
628 | |||
629 | static bool psb_intel_sdvo_get_input_pixel_clock_range(struct psb_intel_sdvo *psb_intel_sdvo, | ||
630 | int *clock_min, | ||
631 | int *clock_max) | ||
632 | { | ||
633 | struct psb_intel_sdvo_pixel_clock_range clocks; | ||
634 | |||
635 | BUILD_BUG_ON(sizeof(clocks) != 4); | ||
636 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
637 | SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, | ||
638 | &clocks, sizeof(clocks))) | ||
639 | return false; | ||
640 | |||
641 | /* Convert the values from units of 10 kHz to kHz. */ | ||
642 | *clock_min = clocks.min * 10; | ||
643 | *clock_max = clocks.max * 10; | ||
644 | return true; | ||
645 | } | ||
646 | |||
647 | static bool psb_intel_sdvo_set_target_output(struct psb_intel_sdvo *psb_intel_sdvo, | ||
648 | u16 outputs) | ||
649 | { | ||
650 | return psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
651 | SDVO_CMD_SET_TARGET_OUTPUT, | ||
652 | &outputs, sizeof(outputs)); | ||
653 | } | ||
654 | |||
655 | static bool psb_intel_sdvo_set_timing(struct psb_intel_sdvo *psb_intel_sdvo, u8 cmd, | ||
656 | struct psb_intel_sdvo_dtd *dtd) | ||
657 | { | ||
658 | return psb_intel_sdvo_set_value(psb_intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) && | ||
659 | psb_intel_sdvo_set_value(psb_intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); | ||
660 | } | ||
661 | |||
662 | static bool psb_intel_sdvo_set_input_timing(struct psb_intel_sdvo *psb_intel_sdvo, | ||
663 | struct psb_intel_sdvo_dtd *dtd) | ||
664 | { | ||
665 | return psb_intel_sdvo_set_timing(psb_intel_sdvo, | ||
666 | SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); | ||
667 | } | ||
668 | |||
669 | static bool psb_intel_sdvo_set_output_timing(struct psb_intel_sdvo *psb_intel_sdvo, | ||
670 | struct psb_intel_sdvo_dtd *dtd) | ||
671 | { | ||
672 | return psb_intel_sdvo_set_timing(psb_intel_sdvo, | ||
673 | SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); | ||
674 | } | ||
675 | |||
676 | static bool | ||
677 | psb_intel_sdvo_create_preferred_input_timing(struct psb_intel_sdvo *psb_intel_sdvo, | ||
678 | uint16_t clock, | ||
679 | uint16_t width, | ||
680 | uint16_t height) | ||
681 | { | ||
682 | struct psb_intel_sdvo_preferred_input_timing_args args; | ||
683 | |||
684 | memset(&args, 0, sizeof(args)); | ||
685 | args.clock = clock; | ||
686 | args.width = width; | ||
687 | args.height = height; | ||
688 | args.interlace = 0; | ||
689 | |||
690 | if (psb_intel_sdvo->is_lvds && | ||
691 | (psb_intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width || | ||
692 | psb_intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height)) | ||
693 | args.scaled = 1; | ||
694 | |||
695 | return psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
696 | SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, | ||
697 | &args, sizeof(args)); | ||
698 | } | ||
699 | |||
700 | static bool psb_intel_sdvo_get_preferred_input_timing(struct psb_intel_sdvo *psb_intel_sdvo, | ||
701 | struct psb_intel_sdvo_dtd *dtd) | ||
702 | { | ||
703 | BUILD_BUG_ON(sizeof(dtd->part1) != 8); | ||
704 | BUILD_BUG_ON(sizeof(dtd->part2) != 8); | ||
705 | return psb_intel_sdvo_get_value(psb_intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, | ||
706 | &dtd->part1, sizeof(dtd->part1)) && | ||
707 | psb_intel_sdvo_get_value(psb_intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, | ||
708 | &dtd->part2, sizeof(dtd->part2)); | ||
709 | } | ||
710 | |||
711 | static bool psb_intel_sdvo_set_clock_rate_mult(struct psb_intel_sdvo *psb_intel_sdvo, u8 val) | ||
712 | { | ||
713 | return psb_intel_sdvo_set_value(psb_intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); | ||
714 | } | ||
715 | |||
716 | static void psb_intel_sdvo_get_dtd_from_mode(struct psb_intel_sdvo_dtd *dtd, | ||
717 | const struct drm_display_mode *mode) | ||
718 | { | ||
719 | uint16_t width, height; | ||
720 | uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len; | ||
721 | uint16_t h_sync_offset, v_sync_offset; | ||
722 | |||
723 | width = mode->crtc_hdisplay; | ||
724 | height = mode->crtc_vdisplay; | ||
725 | |||
726 | /* do some mode translations */ | ||
727 | h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; | ||
728 | h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; | ||
729 | |||
730 | v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; | ||
731 | v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; | ||
732 | |||
733 | h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; | ||
734 | v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; | ||
735 | |||
736 | dtd->part1.clock = mode->clock / 10; | ||
737 | dtd->part1.h_active = width & 0xff; | ||
738 | dtd->part1.h_blank = h_blank_len & 0xff; | ||
739 | dtd->part1.h_high = (((width >> 8) & 0xf) << 4) | | ||
740 | ((h_blank_len >> 8) & 0xf); | ||
741 | dtd->part1.v_active = height & 0xff; | ||
742 | dtd->part1.v_blank = v_blank_len & 0xff; | ||
743 | dtd->part1.v_high = (((height >> 8) & 0xf) << 4) | | ||
744 | ((v_blank_len >> 8) & 0xf); | ||
745 | |||
746 | dtd->part2.h_sync_off = h_sync_offset & 0xff; | ||
747 | dtd->part2.h_sync_width = h_sync_len & 0xff; | ||
748 | dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | | ||
749 | (v_sync_len & 0xf); | ||
750 | dtd->part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | | ||
751 | ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | | ||
752 | ((v_sync_len & 0x30) >> 4); | ||
753 | |||
754 | dtd->part2.dtd_flags = 0x18; | ||
755 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
756 | dtd->part2.dtd_flags |= 0x2; | ||
757 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
758 | dtd->part2.dtd_flags |= 0x4; | ||
759 | |||
760 | dtd->part2.sdvo_flags = 0; | ||
761 | dtd->part2.v_sync_off_high = v_sync_offset & 0xc0; | ||
762 | dtd->part2.reserved = 0; | ||
763 | } | ||
764 | |||
765 | static void psb_intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, | ||
766 | const struct psb_intel_sdvo_dtd *dtd) | ||
767 | { | ||
768 | mode->hdisplay = dtd->part1.h_active; | ||
769 | mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8; | ||
770 | mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off; | ||
771 | mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2; | ||
772 | mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width; | ||
773 | mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4; | ||
774 | mode->htotal = mode->hdisplay + dtd->part1.h_blank; | ||
775 | mode->htotal += (dtd->part1.h_high & 0xf) << 8; | ||
776 | |||
777 | mode->vdisplay = dtd->part1.v_active; | ||
778 | mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8; | ||
779 | mode->vsync_start = mode->vdisplay; | ||
780 | mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf; | ||
781 | mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2; | ||
782 | mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0; | ||
783 | mode->vsync_end = mode->vsync_start + | ||
784 | (dtd->part2.v_sync_off_width & 0xf); | ||
785 | mode->vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4; | ||
786 | mode->vtotal = mode->vdisplay + dtd->part1.v_blank; | ||
787 | mode->vtotal += (dtd->part1.v_high & 0xf) << 8; | ||
788 | |||
789 | mode->clock = dtd->part1.clock * 10; | ||
790 | |||
791 | mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); | ||
792 | if (dtd->part2.dtd_flags & 0x2) | ||
793 | mode->flags |= DRM_MODE_FLAG_PHSYNC; | ||
794 | if (dtd->part2.dtd_flags & 0x4) | ||
795 | mode->flags |= DRM_MODE_FLAG_PVSYNC; | ||
796 | } | ||
797 | |||
798 | static bool psb_intel_sdvo_check_supp_encode(struct psb_intel_sdvo *psb_intel_sdvo) | ||
799 | { | ||
800 | struct psb_intel_sdvo_encode encode; | ||
801 | |||
802 | BUILD_BUG_ON(sizeof(encode) != 2); | ||
803 | return psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
804 | SDVO_CMD_GET_SUPP_ENCODE, | ||
805 | &encode, sizeof(encode)); | ||
806 | } | ||
807 | |||
808 | static bool psb_intel_sdvo_set_encode(struct psb_intel_sdvo *psb_intel_sdvo, | ||
809 | uint8_t mode) | ||
810 | { | ||
811 | return psb_intel_sdvo_set_value(psb_intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1); | ||
812 | } | ||
813 | |||
814 | static bool psb_intel_sdvo_set_colorimetry(struct psb_intel_sdvo *psb_intel_sdvo, | ||
815 | uint8_t mode) | ||
816 | { | ||
817 | return psb_intel_sdvo_set_value(psb_intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); | ||
818 | } | ||
819 | |||
820 | #if 0 | ||
821 | static void psb_intel_sdvo_dump_hdmi_buf(struct psb_intel_sdvo *psb_intel_sdvo) | ||
822 | { | ||
823 | int i, j; | ||
824 | uint8_t set_buf_index[2]; | ||
825 | uint8_t av_split; | ||
826 | uint8_t buf_size; | ||
827 | uint8_t buf[48]; | ||
828 | uint8_t *pos; | ||
829 | |||
830 | psb_intel_sdvo_get_value(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, &av_split, 1); | ||
831 | |||
832 | for (i = 0; i <= av_split; i++) { | ||
833 | set_buf_index[0] = i; set_buf_index[1] = 0; | ||
834 | psb_intel_sdvo_write_cmd(encoder, SDVO_CMD_SET_HBUF_INDEX, | ||
835 | set_buf_index, 2); | ||
836 | psb_intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_INFO, NULL, 0); | ||
837 | psb_intel_sdvo_read_response(encoder, &buf_size, 1); | ||
838 | |||
839 | pos = buf; | ||
840 | for (j = 0; j <= buf_size; j += 8) { | ||
841 | psb_intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_DATA, | ||
842 | NULL, 0); | ||
843 | psb_intel_sdvo_read_response(encoder, pos, 8); | ||
844 | pos += 8; | ||
845 | } | ||
846 | } | ||
847 | } | ||
848 | #endif | ||
849 | |||
850 | static bool psb_intel_sdvo_set_avi_infoframe(struct psb_intel_sdvo *psb_intel_sdvo) | ||
851 | { | ||
852 | DRM_INFO("HDMI is not supported yet"); | ||
853 | |||
854 | return false; | ||
855 | #if 0 | ||
856 | struct dip_infoframe avi_if = { | ||
857 | .type = DIP_TYPE_AVI, | ||
858 | .ver = DIP_VERSION_AVI, | ||
859 | .len = DIP_LEN_AVI, | ||
860 | }; | ||
861 | uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; | ||
862 | uint8_t set_buf_index[2] = { 1, 0 }; | ||
863 | uint64_t *data = (uint64_t *)&avi_if; | ||
864 | unsigned i; | ||
865 | |||
866 | intel_dip_infoframe_csum(&avi_if); | ||
867 | |||
868 | if (!psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
869 | SDVO_CMD_SET_HBUF_INDEX, | ||
870 | set_buf_index, 2)) | ||
871 | return false; | ||
872 | |||
873 | for (i = 0; i < sizeof(avi_if); i += 8) { | ||
874 | if (!psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
875 | SDVO_CMD_SET_HBUF_DATA, | ||
876 | data, 8)) | ||
877 | return false; | ||
878 | data++; | ||
879 | } | ||
880 | |||
881 | return psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
882 | SDVO_CMD_SET_HBUF_TXRATE, | ||
883 | &tx_rate, 1); | ||
884 | #endif | ||
885 | } | ||
886 | |||
887 | static bool psb_intel_sdvo_set_tv_format(struct psb_intel_sdvo *psb_intel_sdvo) | ||
888 | { | ||
889 | struct psb_intel_sdvo_tv_format format; | ||
890 | uint32_t format_map; | ||
891 | |||
892 | format_map = 1 << psb_intel_sdvo->tv_format_index; | ||
893 | memset(&format, 0, sizeof(format)); | ||
894 | memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); | ||
895 | |||
896 | BUILD_BUG_ON(sizeof(format) != 6); | ||
897 | return psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
898 | SDVO_CMD_SET_TV_FORMAT, | ||
899 | &format, sizeof(format)); | ||
900 | } | ||
901 | |||
902 | static bool | ||
903 | psb_intel_sdvo_set_output_timings_from_mode(struct psb_intel_sdvo *psb_intel_sdvo, | ||
904 | struct drm_display_mode *mode) | ||
905 | { | ||
906 | struct psb_intel_sdvo_dtd output_dtd; | ||
907 | |||
908 | if (!psb_intel_sdvo_set_target_output(psb_intel_sdvo, | ||
909 | psb_intel_sdvo->attached_output)) | ||
910 | return false; | ||
911 | |||
912 | psb_intel_sdvo_get_dtd_from_mode(&output_dtd, mode); | ||
913 | if (!psb_intel_sdvo_set_output_timing(psb_intel_sdvo, &output_dtd)) | ||
914 | return false; | ||
915 | |||
916 | return true; | ||
917 | } | ||
918 | |||
919 | static bool | ||
920 | psb_intel_sdvo_set_input_timings_for_mode(struct psb_intel_sdvo *psb_intel_sdvo, | ||
921 | struct drm_display_mode *mode, | ||
922 | struct drm_display_mode *adjusted_mode) | ||
923 | { | ||
924 | /* Reset the input timing to the screen. Assume always input 0. */ | ||
925 | if (!psb_intel_sdvo_set_target_input(psb_intel_sdvo)) | ||
926 | return false; | ||
927 | |||
928 | if (!psb_intel_sdvo_create_preferred_input_timing(psb_intel_sdvo, | ||
929 | mode->clock / 10, | ||
930 | mode->hdisplay, | ||
931 | mode->vdisplay)) | ||
932 | return false; | ||
933 | |||
934 | if (!psb_intel_sdvo_get_preferred_input_timing(psb_intel_sdvo, | ||
935 | &psb_intel_sdvo->input_dtd)) | ||
936 | return false; | ||
937 | |||
938 | psb_intel_sdvo_get_mode_from_dtd(adjusted_mode, &psb_intel_sdvo->input_dtd); | ||
939 | |||
940 | drm_mode_set_crtcinfo(adjusted_mode, 0); | ||
941 | return true; | ||
942 | } | ||
943 | |||
944 | static bool psb_intel_sdvo_mode_fixup(struct drm_encoder *encoder, | ||
945 | struct drm_display_mode *mode, | ||
946 | struct drm_display_mode *adjusted_mode) | ||
947 | { | ||
948 | struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(encoder); | ||
949 | int multiplier; | ||
950 | |||
951 | /* We need to construct preferred input timings based on our | ||
952 | * output timings. To do that, we have to set the output | ||
953 | * timings, even though this isn't really the right place in | ||
954 | * the sequence to do it. Oh well. | ||
955 | */ | ||
956 | if (psb_intel_sdvo->is_tv) { | ||
957 | if (!psb_intel_sdvo_set_output_timings_from_mode(psb_intel_sdvo, mode)) | ||
958 | return false; | ||
959 | |||
960 | (void) psb_intel_sdvo_set_input_timings_for_mode(psb_intel_sdvo, | ||
961 | mode, | ||
962 | adjusted_mode); | ||
963 | } else if (psb_intel_sdvo->is_lvds) { | ||
964 | if (!psb_intel_sdvo_set_output_timings_from_mode(psb_intel_sdvo, | ||
965 | psb_intel_sdvo->sdvo_lvds_fixed_mode)) | ||
966 | return false; | ||
967 | |||
968 | (void) psb_intel_sdvo_set_input_timings_for_mode(psb_intel_sdvo, | ||
969 | mode, | ||
970 | adjusted_mode); | ||
971 | } | ||
972 | |||
973 | /* Make the CRTC code factor in the SDVO pixel multiplier. The | ||
974 | * SDVO device will factor out the multiplier during mode_set. | ||
975 | */ | ||
976 | multiplier = psb_intel_sdvo_get_pixel_multiplier(adjusted_mode); | ||
977 | psb_intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); | ||
978 | |||
979 | return true; | ||
980 | } | ||
981 | |||
982 | static void psb_intel_sdvo_mode_set(struct drm_encoder *encoder, | ||
983 | struct drm_display_mode *mode, | ||
984 | struct drm_display_mode *adjusted_mode) | ||
985 | { | ||
986 | struct drm_device *dev = encoder->dev; | ||
987 | struct drm_crtc *crtc = encoder->crtc; | ||
988 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
989 | struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(encoder); | ||
990 | u32 sdvox; | ||
991 | struct psb_intel_sdvo_in_out_map in_out; | ||
992 | struct psb_intel_sdvo_dtd input_dtd; | ||
993 | int pixel_multiplier = psb_intel_mode_get_pixel_multiplier(adjusted_mode); | ||
994 | int rate; | ||
995 | |||
996 | if (!mode) | ||
997 | return; | ||
998 | |||
999 | /* First, set the input mapping for the first input to our controlled | ||
1000 | * output. This is only correct if we're a single-input device, in | ||
1001 | * which case the first input is the output from the appropriate SDVO | ||
1002 | * channel on the motherboard. In a two-input device, the first input | ||
1003 | * will be SDVOB and the second SDVOC. | ||
1004 | */ | ||
1005 | in_out.in0 = psb_intel_sdvo->attached_output; | ||
1006 | in_out.in1 = 0; | ||
1007 | |||
1008 | psb_intel_sdvo_set_value(psb_intel_sdvo, | ||
1009 | SDVO_CMD_SET_IN_OUT_MAP, | ||
1010 | &in_out, sizeof(in_out)); | ||
1011 | |||
1012 | /* Set the output timings to the screen */ | ||
1013 | if (!psb_intel_sdvo_set_target_output(psb_intel_sdvo, | ||
1014 | psb_intel_sdvo->attached_output)) | ||
1015 | return; | ||
1016 | |||
1017 | /* We have tried to get input timing in mode_fixup, and filled into | ||
1018 | * adjusted_mode. | ||
1019 | */ | ||
1020 | if (psb_intel_sdvo->is_tv || psb_intel_sdvo->is_lvds) { | ||
1021 | input_dtd = psb_intel_sdvo->input_dtd; | ||
1022 | } else { | ||
1023 | /* Set the output timing to the screen */ | ||
1024 | if (!psb_intel_sdvo_set_target_output(psb_intel_sdvo, | ||
1025 | psb_intel_sdvo->attached_output)) | ||
1026 | return; | ||
1027 | |||
1028 | psb_intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); | ||
1029 | (void) psb_intel_sdvo_set_output_timing(psb_intel_sdvo, &input_dtd); | ||
1030 | } | ||
1031 | |||
1032 | /* Set the input timing to the screen. Assume always input 0. */ | ||
1033 | if (!psb_intel_sdvo_set_target_input(psb_intel_sdvo)) | ||
1034 | return; | ||
1035 | |||
1036 | if (psb_intel_sdvo->has_hdmi_monitor) { | ||
1037 | psb_intel_sdvo_set_encode(psb_intel_sdvo, SDVO_ENCODE_HDMI); | ||
1038 | psb_intel_sdvo_set_colorimetry(psb_intel_sdvo, | ||
1039 | SDVO_COLORIMETRY_RGB256); | ||
1040 | psb_intel_sdvo_set_avi_infoframe(psb_intel_sdvo); | ||
1041 | } else | ||
1042 | psb_intel_sdvo_set_encode(psb_intel_sdvo, SDVO_ENCODE_DVI); | ||
1043 | |||
1044 | if (psb_intel_sdvo->is_tv && | ||
1045 | !psb_intel_sdvo_set_tv_format(psb_intel_sdvo)) | ||
1046 | return; | ||
1047 | |||
1048 | (void) psb_intel_sdvo_set_input_timing(psb_intel_sdvo, &input_dtd); | ||
1049 | |||
1050 | switch (pixel_multiplier) { | ||
1051 | default: | ||
1052 | case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; | ||
1053 | case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; | ||
1054 | case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break; | ||
1055 | } | ||
1056 | if (!psb_intel_sdvo_set_clock_rate_mult(psb_intel_sdvo, rate)) | ||
1057 | return; | ||
1058 | |||
1059 | /* Set the SDVO control regs. */ | ||
1060 | sdvox = REG_READ(psb_intel_sdvo->sdvo_reg); | ||
1061 | switch (psb_intel_sdvo->sdvo_reg) { | ||
1062 | case SDVOB: | ||
1063 | sdvox &= SDVOB_PRESERVE_MASK; | ||
1064 | break; | ||
1065 | case SDVOC: | ||
1066 | sdvox &= SDVOC_PRESERVE_MASK; | ||
1067 | break; | ||
1068 | } | ||
1069 | sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; | ||
1070 | |||
1071 | if (psb_intel_crtc->pipe == 1) | ||
1072 | sdvox |= SDVO_PIPE_B_SELECT; | ||
1073 | if (psb_intel_sdvo->has_hdmi_audio) | ||
1074 | sdvox |= SDVO_AUDIO_ENABLE; | ||
1075 | |||
1076 | /* FIXME: Check if this is needed for PSB | ||
1077 | sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT; | ||
1078 | */ | ||
1079 | |||
1080 | if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL) | ||
1081 | sdvox |= SDVO_STALL_SELECT; | ||
1082 | psb_intel_sdvo_write_sdvox(psb_intel_sdvo, sdvox); | ||
1083 | } | ||
1084 | |||
1085 | static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode) | ||
1086 | { | ||
1087 | struct drm_device *dev = encoder->dev; | ||
1088 | struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(encoder); | ||
1089 | u32 temp; | ||
1090 | |||
1091 | switch (mode) { | ||
1092 | case DRM_MODE_DPMS_ON: | ||
1093 | DRM_DEBUG("DPMS_ON"); | ||
1094 | break; | ||
1095 | case DRM_MODE_DPMS_OFF: | ||
1096 | DRM_DEBUG("DPMS_OFF"); | ||
1097 | break; | ||
1098 | default: | ||
1099 | DRM_DEBUG("DPMS: %d", mode); | ||
1100 | } | ||
1101 | |||
1102 | if (mode != DRM_MODE_DPMS_ON) { | ||
1103 | psb_intel_sdvo_set_active_outputs(psb_intel_sdvo, 0); | ||
1104 | if (0) | ||
1105 | psb_intel_sdvo_set_encoder_power_state(psb_intel_sdvo, mode); | ||
1106 | |||
1107 | if (mode == DRM_MODE_DPMS_OFF) { | ||
1108 | temp = REG_READ(psb_intel_sdvo->sdvo_reg); | ||
1109 | if ((temp & SDVO_ENABLE) != 0) { | ||
1110 | psb_intel_sdvo_write_sdvox(psb_intel_sdvo, temp & ~SDVO_ENABLE); | ||
1111 | } | ||
1112 | } | ||
1113 | } else { | ||
1114 | bool input1, input2; | ||
1115 | int i; | ||
1116 | u8 status; | ||
1117 | |||
1118 | temp = REG_READ(psb_intel_sdvo->sdvo_reg); | ||
1119 | if ((temp & SDVO_ENABLE) == 0) | ||
1120 | psb_intel_sdvo_write_sdvox(psb_intel_sdvo, temp | SDVO_ENABLE); | ||
1121 | for (i = 0; i < 2; i++) | ||
1122 | psb_intel_wait_for_vblank(dev); | ||
1123 | |||
1124 | status = psb_intel_sdvo_get_trained_inputs(psb_intel_sdvo, &input1, &input2); | ||
1125 | /* Warn if the device reported failure to sync. | ||
1126 | * A lot of SDVO devices fail to notify of sync, but it's | ||
1127 | * a given it the status is a success, we succeeded. | ||
1128 | */ | ||
1129 | if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { | ||
1130 | DRM_DEBUG_KMS("First %s output reported failure to " | ||
1131 | "sync\n", SDVO_NAME(psb_intel_sdvo)); | ||
1132 | } | ||
1133 | |||
1134 | if (0) | ||
1135 | psb_intel_sdvo_set_encoder_power_state(psb_intel_sdvo, mode); | ||
1136 | psb_intel_sdvo_set_active_outputs(psb_intel_sdvo, psb_intel_sdvo->attached_output); | ||
1137 | } | ||
1138 | return; | ||
1139 | } | ||
1140 | |||
1141 | static int psb_intel_sdvo_mode_valid(struct drm_connector *connector, | ||
1142 | struct drm_display_mode *mode) | ||
1143 | { | ||
1144 | struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); | ||
1145 | |||
1146 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
1147 | return MODE_NO_DBLESCAN; | ||
1148 | |||
1149 | if (psb_intel_sdvo->pixel_clock_min > mode->clock) | ||
1150 | return MODE_CLOCK_LOW; | ||
1151 | |||
1152 | if (psb_intel_sdvo->pixel_clock_max < mode->clock) | ||
1153 | return MODE_CLOCK_HIGH; | ||
1154 | |||
1155 | if (psb_intel_sdvo->is_lvds) { | ||
1156 | if (mode->hdisplay > psb_intel_sdvo->sdvo_lvds_fixed_mode->hdisplay) | ||
1157 | return MODE_PANEL; | ||
1158 | |||
1159 | if (mode->vdisplay > psb_intel_sdvo->sdvo_lvds_fixed_mode->vdisplay) | ||
1160 | return MODE_PANEL; | ||
1161 | } | ||
1162 | |||
1163 | return MODE_OK; | ||
1164 | } | ||
1165 | |||
1166 | static bool psb_intel_sdvo_get_capabilities(struct psb_intel_sdvo *psb_intel_sdvo, struct psb_intel_sdvo_caps *caps) | ||
1167 | { | ||
1168 | BUILD_BUG_ON(sizeof(*caps) != 8); | ||
1169 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
1170 | SDVO_CMD_GET_DEVICE_CAPS, | ||
1171 | caps, sizeof(*caps))) | ||
1172 | return false; | ||
1173 | |||
1174 | DRM_DEBUG_KMS("SDVO capabilities:\n" | ||
1175 | " vendor_id: %d\n" | ||
1176 | " device_id: %d\n" | ||
1177 | " device_rev_id: %d\n" | ||
1178 | " sdvo_version_major: %d\n" | ||
1179 | " sdvo_version_minor: %d\n" | ||
1180 | " sdvo_inputs_mask: %d\n" | ||
1181 | " smooth_scaling: %d\n" | ||
1182 | " sharp_scaling: %d\n" | ||
1183 | " up_scaling: %d\n" | ||
1184 | " down_scaling: %d\n" | ||
1185 | " stall_support: %d\n" | ||
1186 | " output_flags: %d\n", | ||
1187 | caps->vendor_id, | ||
1188 | caps->device_id, | ||
1189 | caps->device_rev_id, | ||
1190 | caps->sdvo_version_major, | ||
1191 | caps->sdvo_version_minor, | ||
1192 | caps->sdvo_inputs_mask, | ||
1193 | caps->smooth_scaling, | ||
1194 | caps->sharp_scaling, | ||
1195 | caps->up_scaling, | ||
1196 | caps->down_scaling, | ||
1197 | caps->stall_support, | ||
1198 | caps->output_flags); | ||
1199 | |||
1200 | return true; | ||
1201 | } | ||
1202 | |||
1203 | /* No use! */ | ||
1204 | #if 0 | ||
1205 | struct drm_connector* psb_intel_sdvo_find(struct drm_device *dev, int sdvoB) | ||
1206 | { | ||
1207 | struct drm_connector *connector = NULL; | ||
1208 | struct psb_intel_sdvo *iout = NULL; | ||
1209 | struct psb_intel_sdvo *sdvo; | ||
1210 | |||
1211 | /* find the sdvo connector */ | ||
1212 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1213 | iout = to_psb_intel_sdvo(connector); | ||
1214 | |||
1215 | if (iout->type != INTEL_OUTPUT_SDVO) | ||
1216 | continue; | ||
1217 | |||
1218 | sdvo = iout->dev_priv; | ||
1219 | |||
1220 | if (sdvo->sdvo_reg == SDVOB && sdvoB) | ||
1221 | return connector; | ||
1222 | |||
1223 | if (sdvo->sdvo_reg == SDVOC && !sdvoB) | ||
1224 | return connector; | ||
1225 | |||
1226 | } | ||
1227 | |||
1228 | return NULL; | ||
1229 | } | ||
1230 | |||
1231 | int psb_intel_sdvo_supports_hotplug(struct drm_connector *connector) | ||
1232 | { | ||
1233 | u8 response[2]; | ||
1234 | u8 status; | ||
1235 | struct psb_intel_sdvo *psb_intel_sdvo; | ||
1236 | DRM_DEBUG_KMS("\n"); | ||
1237 | |||
1238 | if (!connector) | ||
1239 | return 0; | ||
1240 | |||
1241 | psb_intel_sdvo = to_psb_intel_sdvo(connector); | ||
1242 | |||
1243 | return psb_intel_sdvo_get_value(psb_intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, | ||
1244 | &response, 2) && response[0]; | ||
1245 | } | ||
1246 | |||
1247 | void psb_intel_sdvo_set_hotplug(struct drm_connector *connector, int on) | ||
1248 | { | ||
1249 | u8 response[2]; | ||
1250 | u8 status; | ||
1251 | struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(connector); | ||
1252 | |||
1253 | psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); | ||
1254 | psb_intel_sdvo_read_response(psb_intel_sdvo, &response, 2); | ||
1255 | |||
1256 | if (on) { | ||
1257 | psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); | ||
1258 | status = psb_intel_sdvo_read_response(psb_intel_sdvo, &response, 2); | ||
1259 | |||
1260 | psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); | ||
1261 | } else { | ||
1262 | response[0] = 0; | ||
1263 | response[1] = 0; | ||
1264 | psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); | ||
1265 | } | ||
1266 | |||
1267 | psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); | ||
1268 | psb_intel_sdvo_read_response(psb_intel_sdvo, &response, 2); | ||
1269 | } | ||
1270 | #endif | ||
1271 | |||
1272 | static bool | ||
1273 | psb_intel_sdvo_multifunc_encoder(struct psb_intel_sdvo *psb_intel_sdvo) | ||
1274 | { | ||
1275 | /* Is there more than one type of output? */ | ||
1276 | int caps = psb_intel_sdvo->caps.output_flags & 0xf; | ||
1277 | return caps & -caps; | ||
1278 | } | ||
1279 | |||
1280 | static struct edid * | ||
1281 | psb_intel_sdvo_get_edid(struct drm_connector *connector) | ||
1282 | { | ||
1283 | struct psb_intel_sdvo *sdvo = intel_attached_sdvo(connector); | ||
1284 | return drm_get_edid(connector, &sdvo->ddc); | ||
1285 | } | ||
1286 | |||
1287 | /* Mac mini hack -- use the same DDC as the analog connector */ | ||
1288 | static struct edid * | ||
1289 | psb_intel_sdvo_get_analog_edid(struct drm_connector *connector) | ||
1290 | { | ||
1291 | struct drm_psb_private *dev_priv = connector->dev->dev_private; | ||
1292 | |||
1293 | return drm_get_edid(connector, | ||
1294 | &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); | ||
1295 | return NULL; | ||
1296 | } | ||
1297 | |||
1298 | enum drm_connector_status | ||
1299 | psb_intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) | ||
1300 | { | ||
1301 | struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); | ||
1302 | enum drm_connector_status status; | ||
1303 | struct edid *edid; | ||
1304 | |||
1305 | edid = psb_intel_sdvo_get_edid(connector); | ||
1306 | |||
1307 | if (edid == NULL && psb_intel_sdvo_multifunc_encoder(psb_intel_sdvo)) { | ||
1308 | u8 ddc, saved_ddc = psb_intel_sdvo->ddc_bus; | ||
1309 | |||
1310 | /* | ||
1311 | * Don't use the 1 as the argument of DDC bus switch to get | ||
1312 | * the EDID. It is used for SDVO SPD ROM. | ||
1313 | */ | ||
1314 | for (ddc = psb_intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { | ||
1315 | psb_intel_sdvo->ddc_bus = ddc; | ||
1316 | edid = psb_intel_sdvo_get_edid(connector); | ||
1317 | if (edid) | ||
1318 | break; | ||
1319 | } | ||
1320 | /* | ||
1321 | * If we found the EDID on the other bus, | ||
1322 | * assume that is the correct DDC bus. | ||
1323 | */ | ||
1324 | if (edid == NULL) | ||
1325 | psb_intel_sdvo->ddc_bus = saved_ddc; | ||
1326 | } | ||
1327 | |||
1328 | /* | ||
1329 | * When there is no edid and no monitor is connected with VGA | ||
1330 | * port, try to use the CRT ddc to read the EDID for DVI-connector. | ||
1331 | */ | ||
1332 | if (edid == NULL) | ||
1333 | edid = psb_intel_sdvo_get_analog_edid(connector); | ||
1334 | |||
1335 | status = connector_status_unknown; | ||
1336 | if (edid != NULL) { | ||
1337 | /* DDC bus is shared, match EDID to connector type */ | ||
1338 | if (edid->input & DRM_EDID_INPUT_DIGITAL) { | ||
1339 | status = connector_status_connected; | ||
1340 | if (psb_intel_sdvo->is_hdmi) { | ||
1341 | psb_intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); | ||
1342 | psb_intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); | ||
1343 | } | ||
1344 | } else | ||
1345 | status = connector_status_disconnected; | ||
1346 | connector->display_info.raw_edid = NULL; | ||
1347 | kfree(edid); | ||
1348 | } | ||
1349 | |||
1350 | if (status == connector_status_connected) { | ||
1351 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); | ||
1352 | if (psb_intel_sdvo_connector->force_audio) | ||
1353 | psb_intel_sdvo->has_hdmi_audio = psb_intel_sdvo_connector->force_audio > 0; | ||
1354 | } | ||
1355 | |||
1356 | return status; | ||
1357 | } | ||
1358 | |||
1359 | static enum drm_connector_status | ||
1360 | psb_intel_sdvo_detect(struct drm_connector *connector, bool force) | ||
1361 | { | ||
1362 | uint16_t response; | ||
1363 | struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); | ||
1364 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); | ||
1365 | enum drm_connector_status ret; | ||
1366 | |||
1367 | if (!psb_intel_sdvo_write_cmd(psb_intel_sdvo, | ||
1368 | SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0)) | ||
1369 | return connector_status_unknown; | ||
1370 | |||
1371 | /* add 30ms delay when the output type might be TV */ | ||
1372 | if (psb_intel_sdvo->caps.output_flags & | ||
1373 | (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0)) | ||
1374 | mdelay(30); | ||
1375 | |||
1376 | if (!psb_intel_sdvo_read_response(psb_intel_sdvo, &response, 2)) | ||
1377 | return connector_status_unknown; | ||
1378 | |||
1379 | DRM_DEBUG_KMS("SDVO response %d %d [%x]\n", | ||
1380 | response & 0xff, response >> 8, | ||
1381 | psb_intel_sdvo_connector->output_flag); | ||
1382 | |||
1383 | if (response == 0) | ||
1384 | return connector_status_disconnected; | ||
1385 | |||
1386 | psb_intel_sdvo->attached_output = response; | ||
1387 | |||
1388 | psb_intel_sdvo->has_hdmi_monitor = false; | ||
1389 | psb_intel_sdvo->has_hdmi_audio = false; | ||
1390 | |||
1391 | if ((psb_intel_sdvo_connector->output_flag & response) == 0) | ||
1392 | ret = connector_status_disconnected; | ||
1393 | else if (IS_TMDS(psb_intel_sdvo_connector)) | ||
1394 | ret = psb_intel_sdvo_hdmi_sink_detect(connector); | ||
1395 | else { | ||
1396 | struct edid *edid; | ||
1397 | |||
1398 | /* if we have an edid check it matches the connection */ | ||
1399 | edid = psb_intel_sdvo_get_edid(connector); | ||
1400 | if (edid == NULL) | ||
1401 | edid = psb_intel_sdvo_get_analog_edid(connector); | ||
1402 | if (edid != NULL) { | ||
1403 | if (edid->input & DRM_EDID_INPUT_DIGITAL) | ||
1404 | ret = connector_status_disconnected; | ||
1405 | else | ||
1406 | ret = connector_status_connected; | ||
1407 | connector->display_info.raw_edid = NULL; | ||
1408 | kfree(edid); | ||
1409 | } else | ||
1410 | ret = connector_status_connected; | ||
1411 | } | ||
1412 | |||
1413 | /* May update encoder flag for like clock for SDVO TV, etc.*/ | ||
1414 | if (ret == connector_status_connected) { | ||
1415 | psb_intel_sdvo->is_tv = false; | ||
1416 | psb_intel_sdvo->is_lvds = false; | ||
1417 | psb_intel_sdvo->base.needs_tv_clock = false; | ||
1418 | |||
1419 | if (response & SDVO_TV_MASK) { | ||
1420 | psb_intel_sdvo->is_tv = true; | ||
1421 | psb_intel_sdvo->base.needs_tv_clock = true; | ||
1422 | } | ||
1423 | if (response & SDVO_LVDS_MASK) | ||
1424 | psb_intel_sdvo->is_lvds = psb_intel_sdvo->sdvo_lvds_fixed_mode != NULL; | ||
1425 | } | ||
1426 | |||
1427 | return ret; | ||
1428 | } | ||
1429 | |||
1430 | static void psb_intel_sdvo_get_ddc_modes(struct drm_connector *connector) | ||
1431 | { | ||
1432 | struct edid *edid; | ||
1433 | |||
1434 | /* set the bus switch and get the modes */ | ||
1435 | edid = psb_intel_sdvo_get_edid(connector); | ||
1436 | |||
1437 | /* | ||
1438 | * Mac mini hack. On this device, the DVI-I connector shares one DDC | ||
1439 | * link between analog and digital outputs. So, if the regular SDVO | ||
1440 | * DDC fails, check to see if the analog output is disconnected, in | ||
1441 | * which case we'll look there for the digital DDC data. | ||
1442 | */ | ||
1443 | if (edid == NULL) | ||
1444 | edid = psb_intel_sdvo_get_analog_edid(connector); | ||
1445 | |||
1446 | if (edid != NULL) { | ||
1447 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); | ||
1448 | bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); | ||
1449 | bool connector_is_digital = !!IS_TMDS(psb_intel_sdvo_connector); | ||
1450 | |||
1451 | if (connector_is_digital == monitor_is_digital) { | ||
1452 | drm_mode_connector_update_edid_property(connector, edid); | ||
1453 | drm_add_edid_modes(connector, edid); | ||
1454 | } | ||
1455 | |||
1456 | connector->display_info.raw_edid = NULL; | ||
1457 | kfree(edid); | ||
1458 | } | ||
1459 | } | ||
1460 | |||
1461 | /* | ||
1462 | * Set of SDVO TV modes. | ||
1463 | * Note! This is in reply order (see loop in get_tv_modes). | ||
1464 | * XXX: all 60Hz refresh? | ||
1465 | */ | ||
1466 | static const struct drm_display_mode sdvo_tv_modes[] = { | ||
1467 | { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384, | ||
1468 | 416, 0, 200, 201, 232, 233, 0, | ||
1469 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1470 | { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384, | ||
1471 | 416, 0, 240, 241, 272, 273, 0, | ||
1472 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1473 | { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464, | ||
1474 | 496, 0, 300, 301, 332, 333, 0, | ||
1475 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1476 | { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704, | ||
1477 | 736, 0, 350, 351, 382, 383, 0, | ||
1478 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1479 | { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704, | ||
1480 | 736, 0, 400, 401, 432, 433, 0, | ||
1481 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1482 | { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704, | ||
1483 | 736, 0, 480, 481, 512, 513, 0, | ||
1484 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1485 | { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768, | ||
1486 | 800, 0, 480, 481, 512, 513, 0, | ||
1487 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1488 | { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768, | ||
1489 | 800, 0, 576, 577, 608, 609, 0, | ||
1490 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1491 | { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784, | ||
1492 | 816, 0, 350, 351, 382, 383, 0, | ||
1493 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1494 | { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784, | ||
1495 | 816, 0, 400, 401, 432, 433, 0, | ||
1496 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1497 | { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784, | ||
1498 | 816, 0, 480, 481, 512, 513, 0, | ||
1499 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1500 | { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784, | ||
1501 | 816, 0, 540, 541, 572, 573, 0, | ||
1502 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1503 | { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784, | ||
1504 | 816, 0, 576, 577, 608, 609, 0, | ||
1505 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1506 | { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832, | ||
1507 | 864, 0, 576, 577, 608, 609, 0, | ||
1508 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1509 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864, | ||
1510 | 896, 0, 600, 601, 632, 633, 0, | ||
1511 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1512 | { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896, | ||
1513 | 928, 0, 624, 625, 656, 657, 0, | ||
1514 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1515 | { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984, | ||
1516 | 1016, 0, 766, 767, 798, 799, 0, | ||
1517 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1518 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088, | ||
1519 | 1120, 0, 768, 769, 800, 801, 0, | ||
1520 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1521 | { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344, | ||
1522 | 1376, 0, 1024, 1025, 1056, 1057, 0, | ||
1523 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
1524 | }; | ||
1525 | |||
1526 | static void psb_intel_sdvo_get_tv_modes(struct drm_connector *connector) | ||
1527 | { | ||
1528 | struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); | ||
1529 | struct psb_intel_sdvo_sdtv_resolution_request tv_res; | ||
1530 | uint32_t reply = 0, format_map = 0; | ||
1531 | int i; | ||
1532 | |||
1533 | /* Read the list of supported input resolutions for the selected TV | ||
1534 | * format. | ||
1535 | */ | ||
1536 | format_map = 1 << psb_intel_sdvo->tv_format_index; | ||
1537 | memcpy(&tv_res, &format_map, | ||
1538 | min(sizeof(format_map), sizeof(struct psb_intel_sdvo_sdtv_resolution_request))); | ||
1539 | |||
1540 | if (!psb_intel_sdvo_set_target_output(psb_intel_sdvo, psb_intel_sdvo->attached_output)) | ||
1541 | return; | ||
1542 | |||
1543 | BUILD_BUG_ON(sizeof(tv_res) != 3); | ||
1544 | if (!psb_intel_sdvo_write_cmd(psb_intel_sdvo, | ||
1545 | SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, | ||
1546 | &tv_res, sizeof(tv_res))) | ||
1547 | return; | ||
1548 | if (!psb_intel_sdvo_read_response(psb_intel_sdvo, &reply, 3)) | ||
1549 | return; | ||
1550 | |||
1551 | for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++) | ||
1552 | if (reply & (1 << i)) { | ||
1553 | struct drm_display_mode *nmode; | ||
1554 | nmode = drm_mode_duplicate(connector->dev, | ||
1555 | &sdvo_tv_modes[i]); | ||
1556 | if (nmode) | ||
1557 | drm_mode_probed_add(connector, nmode); | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1561 | static void psb_intel_sdvo_get_lvds_modes(struct drm_connector *connector) | ||
1562 | { | ||
1563 | struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); | ||
1564 | struct drm_psb_private *dev_priv = connector->dev->dev_private; | ||
1565 | struct drm_display_mode *newmode; | ||
1566 | |||
1567 | /* | ||
1568 | * Attempt to get the mode list from DDC. | ||
1569 | * Assume that the preferred modes are | ||
1570 | * arranged in priority order. | ||
1571 | */ | ||
1572 | psb_intel_ddc_get_modes(connector, psb_intel_sdvo->i2c); | ||
1573 | if (list_empty(&connector->probed_modes) == false) | ||
1574 | goto end; | ||
1575 | |||
1576 | /* Fetch modes from VBT */ | ||
1577 | if (dev_priv->sdvo_lvds_vbt_mode != NULL) { | ||
1578 | newmode = drm_mode_duplicate(connector->dev, | ||
1579 | dev_priv->sdvo_lvds_vbt_mode); | ||
1580 | if (newmode != NULL) { | ||
1581 | /* Guarantee the mode is preferred */ | ||
1582 | newmode->type = (DRM_MODE_TYPE_PREFERRED | | ||
1583 | DRM_MODE_TYPE_DRIVER); | ||
1584 | drm_mode_probed_add(connector, newmode); | ||
1585 | } | ||
1586 | } | ||
1587 | |||
1588 | end: | ||
1589 | list_for_each_entry(newmode, &connector->probed_modes, head) { | ||
1590 | if (newmode->type & DRM_MODE_TYPE_PREFERRED) { | ||
1591 | psb_intel_sdvo->sdvo_lvds_fixed_mode = | ||
1592 | drm_mode_duplicate(connector->dev, newmode); | ||
1593 | |||
1594 | drm_mode_set_crtcinfo(psb_intel_sdvo->sdvo_lvds_fixed_mode, | ||
1595 | 0); | ||
1596 | |||
1597 | psb_intel_sdvo->is_lvds = true; | ||
1598 | break; | ||
1599 | } | ||
1600 | } | ||
1601 | |||
1602 | } | ||
1603 | |||
1604 | static int psb_intel_sdvo_get_modes(struct drm_connector *connector) | ||
1605 | { | ||
1606 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); | ||
1607 | |||
1608 | if (IS_TV(psb_intel_sdvo_connector)) | ||
1609 | psb_intel_sdvo_get_tv_modes(connector); | ||
1610 | else if (IS_LVDS(psb_intel_sdvo_connector)) | ||
1611 | psb_intel_sdvo_get_lvds_modes(connector); | ||
1612 | else | ||
1613 | psb_intel_sdvo_get_ddc_modes(connector); | ||
1614 | |||
1615 | return !list_empty(&connector->probed_modes); | ||
1616 | } | ||
1617 | |||
1618 | static void | ||
1619 | psb_intel_sdvo_destroy_enhance_property(struct drm_connector *connector) | ||
1620 | { | ||
1621 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); | ||
1622 | struct drm_device *dev = connector->dev; | ||
1623 | |||
1624 | if (psb_intel_sdvo_connector->left) | ||
1625 | drm_property_destroy(dev, psb_intel_sdvo_connector->left); | ||
1626 | if (psb_intel_sdvo_connector->right) | ||
1627 | drm_property_destroy(dev, psb_intel_sdvo_connector->right); | ||
1628 | if (psb_intel_sdvo_connector->top) | ||
1629 | drm_property_destroy(dev, psb_intel_sdvo_connector->top); | ||
1630 | if (psb_intel_sdvo_connector->bottom) | ||
1631 | drm_property_destroy(dev, psb_intel_sdvo_connector->bottom); | ||
1632 | if (psb_intel_sdvo_connector->hpos) | ||
1633 | drm_property_destroy(dev, psb_intel_sdvo_connector->hpos); | ||
1634 | if (psb_intel_sdvo_connector->vpos) | ||
1635 | drm_property_destroy(dev, psb_intel_sdvo_connector->vpos); | ||
1636 | if (psb_intel_sdvo_connector->saturation) | ||
1637 | drm_property_destroy(dev, psb_intel_sdvo_connector->saturation); | ||
1638 | if (psb_intel_sdvo_connector->contrast) | ||
1639 | drm_property_destroy(dev, psb_intel_sdvo_connector->contrast); | ||
1640 | if (psb_intel_sdvo_connector->hue) | ||
1641 | drm_property_destroy(dev, psb_intel_sdvo_connector->hue); | ||
1642 | if (psb_intel_sdvo_connector->sharpness) | ||
1643 | drm_property_destroy(dev, psb_intel_sdvo_connector->sharpness); | ||
1644 | if (psb_intel_sdvo_connector->flicker_filter) | ||
1645 | drm_property_destroy(dev, psb_intel_sdvo_connector->flicker_filter); | ||
1646 | if (psb_intel_sdvo_connector->flicker_filter_2d) | ||
1647 | drm_property_destroy(dev, psb_intel_sdvo_connector->flicker_filter_2d); | ||
1648 | if (psb_intel_sdvo_connector->flicker_filter_adaptive) | ||
1649 | drm_property_destroy(dev, psb_intel_sdvo_connector->flicker_filter_adaptive); | ||
1650 | if (psb_intel_sdvo_connector->tv_luma_filter) | ||
1651 | drm_property_destroy(dev, psb_intel_sdvo_connector->tv_luma_filter); | ||
1652 | if (psb_intel_sdvo_connector->tv_chroma_filter) | ||
1653 | drm_property_destroy(dev, psb_intel_sdvo_connector->tv_chroma_filter); | ||
1654 | if (psb_intel_sdvo_connector->dot_crawl) | ||
1655 | drm_property_destroy(dev, psb_intel_sdvo_connector->dot_crawl); | ||
1656 | if (psb_intel_sdvo_connector->brightness) | ||
1657 | drm_property_destroy(dev, psb_intel_sdvo_connector->brightness); | ||
1658 | } | ||
1659 | |||
1660 | static void psb_intel_sdvo_destroy(struct drm_connector *connector) | ||
1661 | { | ||
1662 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); | ||
1663 | |||
1664 | if (psb_intel_sdvo_connector->tv_format) | ||
1665 | drm_property_destroy(connector->dev, | ||
1666 | psb_intel_sdvo_connector->tv_format); | ||
1667 | |||
1668 | psb_intel_sdvo_destroy_enhance_property(connector); | ||
1669 | drm_sysfs_connector_remove(connector); | ||
1670 | drm_connector_cleanup(connector); | ||
1671 | kfree(connector); | ||
1672 | } | ||
1673 | |||
1674 | static bool psb_intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) | ||
1675 | { | ||
1676 | struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); | ||
1677 | struct edid *edid; | ||
1678 | bool has_audio = false; | ||
1679 | |||
1680 | if (!psb_intel_sdvo->is_hdmi) | ||
1681 | return false; | ||
1682 | |||
1683 | edid = psb_intel_sdvo_get_edid(connector); | ||
1684 | if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL) | ||
1685 | has_audio = drm_detect_monitor_audio(edid); | ||
1686 | |||
1687 | return has_audio; | ||
1688 | } | ||
1689 | |||
1690 | static int | ||
1691 | psb_intel_sdvo_set_property(struct drm_connector *connector, | ||
1692 | struct drm_property *property, | ||
1693 | uint64_t val) | ||
1694 | { | ||
1695 | struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); | ||
1696 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); | ||
1697 | struct drm_psb_private *dev_priv = connector->dev->dev_private; | ||
1698 | uint16_t temp_value; | ||
1699 | uint8_t cmd; | ||
1700 | int ret; | ||
1701 | |||
1702 | ret = drm_connector_property_set_value(connector, property, val); | ||
1703 | if (ret) | ||
1704 | return ret; | ||
1705 | |||
1706 | if (property == dev_priv->force_audio_property) { | ||
1707 | int i = val; | ||
1708 | bool has_audio; | ||
1709 | |||
1710 | if (i == psb_intel_sdvo_connector->force_audio) | ||
1711 | return 0; | ||
1712 | |||
1713 | psb_intel_sdvo_connector->force_audio = i; | ||
1714 | |||
1715 | if (i == 0) | ||
1716 | has_audio = psb_intel_sdvo_detect_hdmi_audio(connector); | ||
1717 | else | ||
1718 | has_audio = i > 0; | ||
1719 | |||
1720 | if (has_audio == psb_intel_sdvo->has_hdmi_audio) | ||
1721 | return 0; | ||
1722 | |||
1723 | psb_intel_sdvo->has_hdmi_audio = has_audio; | ||
1724 | goto done; | ||
1725 | } | ||
1726 | |||
1727 | if (property == dev_priv->broadcast_rgb_property) { | ||
1728 | if (val == !!psb_intel_sdvo->color_range) | ||
1729 | return 0; | ||
1730 | |||
1731 | psb_intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; | ||
1732 | goto done; | ||
1733 | } | ||
1734 | |||
1735 | #define CHECK_PROPERTY(name, NAME) \ | ||
1736 | if (psb_intel_sdvo_connector->name == property) { \ | ||
1737 | if (psb_intel_sdvo_connector->cur_##name == temp_value) return 0; \ | ||
1738 | if (psb_intel_sdvo_connector->max_##name < temp_value) return -EINVAL; \ | ||
1739 | cmd = SDVO_CMD_SET_##NAME; \ | ||
1740 | psb_intel_sdvo_connector->cur_##name = temp_value; \ | ||
1741 | goto set_value; \ | ||
1742 | } | ||
1743 | |||
1744 | if (property == psb_intel_sdvo_connector->tv_format) { | ||
1745 | if (val >= TV_FORMAT_NUM) | ||
1746 | return -EINVAL; | ||
1747 | |||
1748 | if (psb_intel_sdvo->tv_format_index == | ||
1749 | psb_intel_sdvo_connector->tv_format_supported[val]) | ||
1750 | return 0; | ||
1751 | |||
1752 | psb_intel_sdvo->tv_format_index = psb_intel_sdvo_connector->tv_format_supported[val]; | ||
1753 | goto done; | ||
1754 | } else if (IS_TV_OR_LVDS(psb_intel_sdvo_connector)) { | ||
1755 | temp_value = val; | ||
1756 | if (psb_intel_sdvo_connector->left == property) { | ||
1757 | drm_connector_property_set_value(connector, | ||
1758 | psb_intel_sdvo_connector->right, val); | ||
1759 | if (psb_intel_sdvo_connector->left_margin == temp_value) | ||
1760 | return 0; | ||
1761 | |||
1762 | psb_intel_sdvo_connector->left_margin = temp_value; | ||
1763 | psb_intel_sdvo_connector->right_margin = temp_value; | ||
1764 | temp_value = psb_intel_sdvo_connector->max_hscan - | ||
1765 | psb_intel_sdvo_connector->left_margin; | ||
1766 | cmd = SDVO_CMD_SET_OVERSCAN_H; | ||
1767 | goto set_value; | ||
1768 | } else if (psb_intel_sdvo_connector->right == property) { | ||
1769 | drm_connector_property_set_value(connector, | ||
1770 | psb_intel_sdvo_connector->left, val); | ||
1771 | if (psb_intel_sdvo_connector->right_margin == temp_value) | ||
1772 | return 0; | ||
1773 | |||
1774 | psb_intel_sdvo_connector->left_margin = temp_value; | ||
1775 | psb_intel_sdvo_connector->right_margin = temp_value; | ||
1776 | temp_value = psb_intel_sdvo_connector->max_hscan - | ||
1777 | psb_intel_sdvo_connector->left_margin; | ||
1778 | cmd = SDVO_CMD_SET_OVERSCAN_H; | ||
1779 | goto set_value; | ||
1780 | } else if (psb_intel_sdvo_connector->top == property) { | ||
1781 | drm_connector_property_set_value(connector, | ||
1782 | psb_intel_sdvo_connector->bottom, val); | ||
1783 | if (psb_intel_sdvo_connector->top_margin == temp_value) | ||
1784 | return 0; | ||
1785 | |||
1786 | psb_intel_sdvo_connector->top_margin = temp_value; | ||
1787 | psb_intel_sdvo_connector->bottom_margin = temp_value; | ||
1788 | temp_value = psb_intel_sdvo_connector->max_vscan - | ||
1789 | psb_intel_sdvo_connector->top_margin; | ||
1790 | cmd = SDVO_CMD_SET_OVERSCAN_V; | ||
1791 | goto set_value; | ||
1792 | } else if (psb_intel_sdvo_connector->bottom == property) { | ||
1793 | drm_connector_property_set_value(connector, | ||
1794 | psb_intel_sdvo_connector->top, val); | ||
1795 | if (psb_intel_sdvo_connector->bottom_margin == temp_value) | ||
1796 | return 0; | ||
1797 | |||
1798 | psb_intel_sdvo_connector->top_margin = temp_value; | ||
1799 | psb_intel_sdvo_connector->bottom_margin = temp_value; | ||
1800 | temp_value = psb_intel_sdvo_connector->max_vscan - | ||
1801 | psb_intel_sdvo_connector->top_margin; | ||
1802 | cmd = SDVO_CMD_SET_OVERSCAN_V; | ||
1803 | goto set_value; | ||
1804 | } | ||
1805 | CHECK_PROPERTY(hpos, HPOS) | ||
1806 | CHECK_PROPERTY(vpos, VPOS) | ||
1807 | CHECK_PROPERTY(saturation, SATURATION) | ||
1808 | CHECK_PROPERTY(contrast, CONTRAST) | ||
1809 | CHECK_PROPERTY(hue, HUE) | ||
1810 | CHECK_PROPERTY(brightness, BRIGHTNESS) | ||
1811 | CHECK_PROPERTY(sharpness, SHARPNESS) | ||
1812 | CHECK_PROPERTY(flicker_filter, FLICKER_FILTER) | ||
1813 | CHECK_PROPERTY(flicker_filter_2d, FLICKER_FILTER_2D) | ||
1814 | CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE) | ||
1815 | CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER) | ||
1816 | CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER) | ||
1817 | CHECK_PROPERTY(dot_crawl, DOT_CRAWL) | ||
1818 | } | ||
1819 | |||
1820 | return -EINVAL; /* unknown property */ | ||
1821 | |||
1822 | set_value: | ||
1823 | if (!psb_intel_sdvo_set_value(psb_intel_sdvo, cmd, &temp_value, 2)) | ||
1824 | return -EIO; | ||
1825 | |||
1826 | |||
1827 | done: | ||
1828 | if (psb_intel_sdvo->base.base.crtc) { | ||
1829 | struct drm_crtc *crtc = psb_intel_sdvo->base.base.crtc; | ||
1830 | drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, | ||
1831 | crtc->y, crtc->fb); | ||
1832 | } | ||
1833 | |||
1834 | return 0; | ||
1835 | #undef CHECK_PROPERTY | ||
1836 | } | ||
1837 | |||
1838 | static const struct drm_encoder_helper_funcs psb_intel_sdvo_helper_funcs = { | ||
1839 | .dpms = psb_intel_sdvo_dpms, | ||
1840 | .mode_fixup = psb_intel_sdvo_mode_fixup, | ||
1841 | .prepare = psb_intel_encoder_prepare, | ||
1842 | .mode_set = psb_intel_sdvo_mode_set, | ||
1843 | .commit = psb_intel_encoder_commit, | ||
1844 | }; | ||
1845 | |||
1846 | static const struct drm_connector_funcs psb_intel_sdvo_connector_funcs = { | ||
1847 | .dpms = drm_helper_connector_dpms, | ||
1848 | .detect = psb_intel_sdvo_detect, | ||
1849 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
1850 | .set_property = psb_intel_sdvo_set_property, | ||
1851 | .destroy = psb_intel_sdvo_destroy, | ||
1852 | }; | ||
1853 | |||
1854 | static const struct drm_connector_helper_funcs psb_intel_sdvo_connector_helper_funcs = { | ||
1855 | .get_modes = psb_intel_sdvo_get_modes, | ||
1856 | .mode_valid = psb_intel_sdvo_mode_valid, | ||
1857 | .best_encoder = psb_intel_best_encoder, | ||
1858 | }; | ||
1859 | |||
1860 | static void psb_intel_sdvo_enc_destroy(struct drm_encoder *encoder) | ||
1861 | { | ||
1862 | struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(encoder); | ||
1863 | |||
1864 | if (psb_intel_sdvo->sdvo_lvds_fixed_mode != NULL) | ||
1865 | drm_mode_destroy(encoder->dev, | ||
1866 | psb_intel_sdvo->sdvo_lvds_fixed_mode); | ||
1867 | |||
1868 | i2c_del_adapter(&psb_intel_sdvo->ddc); | ||
1869 | psb_intel_encoder_destroy(encoder); | ||
1870 | } | ||
1871 | |||
1872 | static const struct drm_encoder_funcs psb_intel_sdvo_enc_funcs = { | ||
1873 | .destroy = psb_intel_sdvo_enc_destroy, | ||
1874 | }; | ||
1875 | |||
1876 | static void | ||
1877 | psb_intel_sdvo_guess_ddc_bus(struct psb_intel_sdvo *sdvo) | ||
1878 | { | ||
1879 | /* FIXME: At the moment, ddc_bus = 2 is the only thing that works. | ||
1880 | * We need to figure out if this is true for all available poulsbo | ||
1881 | * hardware, or if we need to fiddle with the guessing code above. | ||
1882 | * The problem might go away if we can parse sdvo mappings from bios */ | ||
1883 | sdvo->ddc_bus = 2; | ||
1884 | |||
1885 | #if 0 | ||
1886 | uint16_t mask = 0; | ||
1887 | unsigned int num_bits; | ||
1888 | |||
1889 | /* Make a mask of outputs less than or equal to our own priority in the | ||
1890 | * list. | ||
1891 | */ | ||
1892 | switch (sdvo->controlled_output) { | ||
1893 | case SDVO_OUTPUT_LVDS1: | ||
1894 | mask |= SDVO_OUTPUT_LVDS1; | ||
1895 | case SDVO_OUTPUT_LVDS0: | ||
1896 | mask |= SDVO_OUTPUT_LVDS0; | ||
1897 | case SDVO_OUTPUT_TMDS1: | ||
1898 | mask |= SDVO_OUTPUT_TMDS1; | ||
1899 | case SDVO_OUTPUT_TMDS0: | ||
1900 | mask |= SDVO_OUTPUT_TMDS0; | ||
1901 | case SDVO_OUTPUT_RGB1: | ||
1902 | mask |= SDVO_OUTPUT_RGB1; | ||
1903 | case SDVO_OUTPUT_RGB0: | ||
1904 | mask |= SDVO_OUTPUT_RGB0; | ||
1905 | break; | ||
1906 | } | ||
1907 | |||
1908 | /* Count bits to find what number we are in the priority list. */ | ||
1909 | mask &= sdvo->caps.output_flags; | ||
1910 | num_bits = hweight16(mask); | ||
1911 | /* If more than 3 outputs, default to DDC bus 3 for now. */ | ||
1912 | if (num_bits > 3) | ||
1913 | num_bits = 3; | ||
1914 | |||
1915 | /* Corresponds to SDVO_CONTROL_BUS_DDCx */ | ||
1916 | sdvo->ddc_bus = 1 << num_bits; | ||
1917 | #endif | ||
1918 | } | ||
1919 | |||
1920 | /** | ||
1921 | * Choose the appropriate DDC bus for control bus switch command for this | ||
1922 | * SDVO output based on the controlled output. | ||
1923 | * | ||
1924 | * DDC bus number assignment is in a priority order of RGB outputs, then TMDS | ||
1925 | * outputs, then LVDS outputs. | ||
1926 | */ | ||
1927 | static void | ||
1928 | psb_intel_sdvo_select_ddc_bus(struct drm_psb_private *dev_priv, | ||
1929 | struct psb_intel_sdvo *sdvo, u32 reg) | ||
1930 | { | ||
1931 | struct sdvo_device_mapping *mapping; | ||
1932 | |||
1933 | if (IS_SDVOB(reg)) | ||
1934 | mapping = &(dev_priv->sdvo_mappings[0]); | ||
1935 | else | ||
1936 | mapping = &(dev_priv->sdvo_mappings[1]); | ||
1937 | |||
1938 | if (mapping->initialized) | ||
1939 | sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4); | ||
1940 | else | ||
1941 | psb_intel_sdvo_guess_ddc_bus(sdvo); | ||
1942 | } | ||
1943 | |||
1944 | static void | ||
1945 | psb_intel_sdvo_select_i2c_bus(struct drm_psb_private *dev_priv, | ||
1946 | struct psb_intel_sdvo *sdvo, u32 reg) | ||
1947 | { | ||
1948 | struct sdvo_device_mapping *mapping; | ||
1949 | u8 pin, speed; | ||
1950 | |||
1951 | if (IS_SDVOB(reg)) | ||
1952 | mapping = &dev_priv->sdvo_mappings[0]; | ||
1953 | else | ||
1954 | mapping = &dev_priv->sdvo_mappings[1]; | ||
1955 | |||
1956 | pin = GMBUS_PORT_DPB; | ||
1957 | speed = GMBUS_RATE_1MHZ >> 8; | ||
1958 | if (mapping->initialized) { | ||
1959 | pin = mapping->i2c_pin; | ||
1960 | speed = mapping->i2c_speed; | ||
1961 | } | ||
1962 | |||
1963 | if (pin < GMBUS_NUM_PORTS) { | ||
1964 | sdvo->i2c = &dev_priv->gmbus[pin].adapter; | ||
1965 | gma_intel_gmbus_set_speed(sdvo->i2c, speed); | ||
1966 | gma_intel_gmbus_force_bit(sdvo->i2c, true); | ||
1967 | } else | ||
1968 | sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter; | ||
1969 | } | ||
1970 | |||
1971 | static bool | ||
1972 | psb_intel_sdvo_is_hdmi_connector(struct psb_intel_sdvo *psb_intel_sdvo, int device) | ||
1973 | { | ||
1974 | return psb_intel_sdvo_check_supp_encode(psb_intel_sdvo); | ||
1975 | } | ||
1976 | |||
1977 | static u8 | ||
1978 | psb_intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) | ||
1979 | { | ||
1980 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
1981 | struct sdvo_device_mapping *my_mapping, *other_mapping; | ||
1982 | |||
1983 | if (IS_SDVOB(sdvo_reg)) { | ||
1984 | my_mapping = &dev_priv->sdvo_mappings[0]; | ||
1985 | other_mapping = &dev_priv->sdvo_mappings[1]; | ||
1986 | } else { | ||
1987 | my_mapping = &dev_priv->sdvo_mappings[1]; | ||
1988 | other_mapping = &dev_priv->sdvo_mappings[0]; | ||
1989 | } | ||
1990 | |||
1991 | /* If the BIOS described our SDVO device, take advantage of it. */ | ||
1992 | if (my_mapping->slave_addr) | ||
1993 | return my_mapping->slave_addr; | ||
1994 | |||
1995 | /* If the BIOS only described a different SDVO device, use the | ||
1996 | * address that it isn't using. | ||
1997 | */ | ||
1998 | if (other_mapping->slave_addr) { | ||
1999 | if (other_mapping->slave_addr == 0x70) | ||
2000 | return 0x72; | ||
2001 | else | ||
2002 | return 0x70; | ||
2003 | } | ||
2004 | |||
2005 | /* No SDVO device info is found for another DVO port, | ||
2006 | * so use mapping assumption we had before BIOS parsing. | ||
2007 | */ | ||
2008 | if (IS_SDVOB(sdvo_reg)) | ||
2009 | return 0x70; | ||
2010 | else | ||
2011 | return 0x72; | ||
2012 | } | ||
2013 | |||
2014 | static void | ||
2015 | psb_intel_sdvo_connector_init(struct psb_intel_sdvo_connector *connector, | ||
2016 | struct psb_intel_sdvo *encoder) | ||
2017 | { | ||
2018 | drm_connector_init(encoder->base.base.dev, | ||
2019 | &connector->base.base, | ||
2020 | &psb_intel_sdvo_connector_funcs, | ||
2021 | connector->base.base.connector_type); | ||
2022 | |||
2023 | drm_connector_helper_add(&connector->base.base, | ||
2024 | &psb_intel_sdvo_connector_helper_funcs); | ||
2025 | |||
2026 | connector->base.base.interlace_allowed = 0; | ||
2027 | connector->base.base.doublescan_allowed = 0; | ||
2028 | connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; | ||
2029 | |||
2030 | psb_intel_connector_attach_encoder(&connector->base, &encoder->base); | ||
2031 | drm_sysfs_connector_add(&connector->base.base); | ||
2032 | } | ||
2033 | |||
2034 | static void | ||
2035 | psb_intel_sdvo_add_hdmi_properties(struct psb_intel_sdvo_connector *connector) | ||
2036 | { | ||
2037 | /* FIXME: We don't support HDMI at the moment | ||
2038 | struct drm_device *dev = connector->base.base.dev; | ||
2039 | |||
2040 | intel_attach_force_audio_property(&connector->base.base); | ||
2041 | if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) | ||
2042 | intel_attach_broadcast_rgb_property(&connector->base.base); | ||
2043 | */ | ||
2044 | } | ||
2045 | |||
2046 | static bool | ||
2047 | psb_intel_sdvo_dvi_init(struct psb_intel_sdvo *psb_intel_sdvo, int device) | ||
2048 | { | ||
2049 | struct drm_encoder *encoder = &psb_intel_sdvo->base.base; | ||
2050 | struct drm_connector *connector; | ||
2051 | struct psb_intel_connector *intel_connector; | ||
2052 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector; | ||
2053 | |||
2054 | psb_intel_sdvo_connector = kzalloc(sizeof(struct psb_intel_sdvo_connector), GFP_KERNEL); | ||
2055 | if (!psb_intel_sdvo_connector) | ||
2056 | return false; | ||
2057 | |||
2058 | if (device == 0) { | ||
2059 | psb_intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0; | ||
2060 | psb_intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; | ||
2061 | } else if (device == 1) { | ||
2062 | psb_intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1; | ||
2063 | psb_intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; | ||
2064 | } | ||
2065 | |||
2066 | intel_connector = &psb_intel_sdvo_connector->base; | ||
2067 | connector = &intel_connector->base; | ||
2068 | // connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; | ||
2069 | encoder->encoder_type = DRM_MODE_ENCODER_TMDS; | ||
2070 | connector->connector_type = DRM_MODE_CONNECTOR_DVID; | ||
2071 | |||
2072 | if (psb_intel_sdvo_is_hdmi_connector(psb_intel_sdvo, device)) { | ||
2073 | connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; | ||
2074 | psb_intel_sdvo->is_hdmi = true; | ||
2075 | } | ||
2076 | psb_intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | | ||
2077 | (1 << INTEL_ANALOG_CLONE_BIT)); | ||
2078 | |||
2079 | psb_intel_sdvo_connector_init(psb_intel_sdvo_connector, psb_intel_sdvo); | ||
2080 | if (psb_intel_sdvo->is_hdmi) | ||
2081 | psb_intel_sdvo_add_hdmi_properties(psb_intel_sdvo_connector); | ||
2082 | |||
2083 | return true; | ||
2084 | } | ||
2085 | |||
2086 | static bool | ||
2087 | psb_intel_sdvo_tv_init(struct psb_intel_sdvo *psb_intel_sdvo, int type) | ||
2088 | { | ||
2089 | struct drm_encoder *encoder = &psb_intel_sdvo->base.base; | ||
2090 | struct drm_connector *connector; | ||
2091 | struct psb_intel_connector *intel_connector; | ||
2092 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector; | ||
2093 | |||
2094 | psb_intel_sdvo_connector = kzalloc(sizeof(struct psb_intel_sdvo_connector), GFP_KERNEL); | ||
2095 | if (!psb_intel_sdvo_connector) | ||
2096 | return false; | ||
2097 | |||
2098 | intel_connector = &psb_intel_sdvo_connector->base; | ||
2099 | connector = &intel_connector->base; | ||
2100 | encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; | ||
2101 | connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; | ||
2102 | |||
2103 | psb_intel_sdvo->controlled_output |= type; | ||
2104 | psb_intel_sdvo_connector->output_flag = type; | ||
2105 | |||
2106 | psb_intel_sdvo->is_tv = true; | ||
2107 | psb_intel_sdvo->base.needs_tv_clock = true; | ||
2108 | psb_intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; | ||
2109 | |||
2110 | psb_intel_sdvo_connector_init(psb_intel_sdvo_connector, psb_intel_sdvo); | ||
2111 | |||
2112 | if (!psb_intel_sdvo_tv_create_property(psb_intel_sdvo, psb_intel_sdvo_connector, type)) | ||
2113 | goto err; | ||
2114 | |||
2115 | if (!psb_intel_sdvo_create_enhance_property(psb_intel_sdvo, psb_intel_sdvo_connector)) | ||
2116 | goto err; | ||
2117 | |||
2118 | return true; | ||
2119 | |||
2120 | err: | ||
2121 | psb_intel_sdvo_destroy(connector); | ||
2122 | return false; | ||
2123 | } | ||
2124 | |||
2125 | static bool | ||
2126 | psb_intel_sdvo_analog_init(struct psb_intel_sdvo *psb_intel_sdvo, int device) | ||
2127 | { | ||
2128 | struct drm_encoder *encoder = &psb_intel_sdvo->base.base; | ||
2129 | struct drm_connector *connector; | ||
2130 | struct psb_intel_connector *intel_connector; | ||
2131 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector; | ||
2132 | |||
2133 | psb_intel_sdvo_connector = kzalloc(sizeof(struct psb_intel_sdvo_connector), GFP_KERNEL); | ||
2134 | if (!psb_intel_sdvo_connector) | ||
2135 | return false; | ||
2136 | |||
2137 | intel_connector = &psb_intel_sdvo_connector->base; | ||
2138 | connector = &intel_connector->base; | ||
2139 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; | ||
2140 | encoder->encoder_type = DRM_MODE_ENCODER_DAC; | ||
2141 | connector->connector_type = DRM_MODE_CONNECTOR_VGA; | ||
2142 | |||
2143 | if (device == 0) { | ||
2144 | psb_intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; | ||
2145 | psb_intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; | ||
2146 | } else if (device == 1) { | ||
2147 | psb_intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; | ||
2148 | psb_intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; | ||
2149 | } | ||
2150 | |||
2151 | psb_intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | | ||
2152 | (1 << INTEL_ANALOG_CLONE_BIT)); | ||
2153 | |||
2154 | psb_intel_sdvo_connector_init(psb_intel_sdvo_connector, | ||
2155 | psb_intel_sdvo); | ||
2156 | return true; | ||
2157 | } | ||
2158 | |||
2159 | static bool | ||
2160 | psb_intel_sdvo_lvds_init(struct psb_intel_sdvo *psb_intel_sdvo, int device) | ||
2161 | { | ||
2162 | struct drm_encoder *encoder = &psb_intel_sdvo->base.base; | ||
2163 | struct drm_connector *connector; | ||
2164 | struct psb_intel_connector *intel_connector; | ||
2165 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector; | ||
2166 | |||
2167 | psb_intel_sdvo_connector = kzalloc(sizeof(struct psb_intel_sdvo_connector), GFP_KERNEL); | ||
2168 | if (!psb_intel_sdvo_connector) | ||
2169 | return false; | ||
2170 | |||
2171 | intel_connector = &psb_intel_sdvo_connector->base; | ||
2172 | connector = &intel_connector->base; | ||
2173 | encoder->encoder_type = DRM_MODE_ENCODER_LVDS; | ||
2174 | connector->connector_type = DRM_MODE_CONNECTOR_LVDS; | ||
2175 | |||
2176 | if (device == 0) { | ||
2177 | psb_intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; | ||
2178 | psb_intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; | ||
2179 | } else if (device == 1) { | ||
2180 | psb_intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; | ||
2181 | psb_intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; | ||
2182 | } | ||
2183 | |||
2184 | psb_intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | | ||
2185 | (1 << INTEL_SDVO_LVDS_CLONE_BIT)); | ||
2186 | |||
2187 | psb_intel_sdvo_connector_init(psb_intel_sdvo_connector, psb_intel_sdvo); | ||
2188 | if (!psb_intel_sdvo_create_enhance_property(psb_intel_sdvo, psb_intel_sdvo_connector)) | ||
2189 | goto err; | ||
2190 | |||
2191 | return true; | ||
2192 | |||
2193 | err: | ||
2194 | psb_intel_sdvo_destroy(connector); | ||
2195 | return false; | ||
2196 | } | ||
2197 | |||
2198 | static bool | ||
2199 | psb_intel_sdvo_output_setup(struct psb_intel_sdvo *psb_intel_sdvo, uint16_t flags) | ||
2200 | { | ||
2201 | psb_intel_sdvo->is_tv = false; | ||
2202 | psb_intel_sdvo->base.needs_tv_clock = false; | ||
2203 | psb_intel_sdvo->is_lvds = false; | ||
2204 | |||
2205 | /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ | ||
2206 | |||
2207 | if (flags & SDVO_OUTPUT_TMDS0) | ||
2208 | if (!psb_intel_sdvo_dvi_init(psb_intel_sdvo, 0)) | ||
2209 | return false; | ||
2210 | |||
2211 | if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK) | ||
2212 | if (!psb_intel_sdvo_dvi_init(psb_intel_sdvo, 1)) | ||
2213 | return false; | ||
2214 | |||
2215 | /* TV has no XXX1 function block */ | ||
2216 | if (flags & SDVO_OUTPUT_SVID0) | ||
2217 | if (!psb_intel_sdvo_tv_init(psb_intel_sdvo, SDVO_OUTPUT_SVID0)) | ||
2218 | return false; | ||
2219 | |||
2220 | if (flags & SDVO_OUTPUT_CVBS0) | ||
2221 | if (!psb_intel_sdvo_tv_init(psb_intel_sdvo, SDVO_OUTPUT_CVBS0)) | ||
2222 | return false; | ||
2223 | |||
2224 | if (flags & SDVO_OUTPUT_RGB0) | ||
2225 | if (!psb_intel_sdvo_analog_init(psb_intel_sdvo, 0)) | ||
2226 | return false; | ||
2227 | |||
2228 | if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK) | ||
2229 | if (!psb_intel_sdvo_analog_init(psb_intel_sdvo, 1)) | ||
2230 | return false; | ||
2231 | |||
2232 | if (flags & SDVO_OUTPUT_LVDS0) | ||
2233 | if (!psb_intel_sdvo_lvds_init(psb_intel_sdvo, 0)) | ||
2234 | return false; | ||
2235 | |||
2236 | if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK) | ||
2237 | if (!psb_intel_sdvo_lvds_init(psb_intel_sdvo, 1)) | ||
2238 | return false; | ||
2239 | |||
2240 | if ((flags & SDVO_OUTPUT_MASK) == 0) { | ||
2241 | unsigned char bytes[2]; | ||
2242 | |||
2243 | psb_intel_sdvo->controlled_output = 0; | ||
2244 | memcpy(bytes, &psb_intel_sdvo->caps.output_flags, 2); | ||
2245 | DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", | ||
2246 | SDVO_NAME(psb_intel_sdvo), | ||
2247 | bytes[0], bytes[1]); | ||
2248 | return false; | ||
2249 | } | ||
2250 | psb_intel_sdvo->base.crtc_mask = (1 << 0) | (1 << 1); | ||
2251 | |||
2252 | return true; | ||
2253 | } | ||
2254 | |||
2255 | static bool psb_intel_sdvo_tv_create_property(struct psb_intel_sdvo *psb_intel_sdvo, | ||
2256 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector, | ||
2257 | int type) | ||
2258 | { | ||
2259 | struct drm_device *dev = psb_intel_sdvo->base.base.dev; | ||
2260 | struct psb_intel_sdvo_tv_format format; | ||
2261 | uint32_t format_map, i; | ||
2262 | |||
2263 | if (!psb_intel_sdvo_set_target_output(psb_intel_sdvo, type)) | ||
2264 | return false; | ||
2265 | |||
2266 | BUILD_BUG_ON(sizeof(format) != 6); | ||
2267 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
2268 | SDVO_CMD_GET_SUPPORTED_TV_FORMATS, | ||
2269 | &format, sizeof(format))) | ||
2270 | return false; | ||
2271 | |||
2272 | memcpy(&format_map, &format, min(sizeof(format_map), sizeof(format))); | ||
2273 | |||
2274 | if (format_map == 0) | ||
2275 | return false; | ||
2276 | |||
2277 | psb_intel_sdvo_connector->format_supported_num = 0; | ||
2278 | for (i = 0 ; i < TV_FORMAT_NUM; i++) | ||
2279 | if (format_map & (1 << i)) | ||
2280 | psb_intel_sdvo_connector->tv_format_supported[psb_intel_sdvo_connector->format_supported_num++] = i; | ||
2281 | |||
2282 | |||
2283 | psb_intel_sdvo_connector->tv_format = | ||
2284 | drm_property_create(dev, DRM_MODE_PROP_ENUM, | ||
2285 | "mode", psb_intel_sdvo_connector->format_supported_num); | ||
2286 | if (!psb_intel_sdvo_connector->tv_format) | ||
2287 | return false; | ||
2288 | |||
2289 | for (i = 0; i < psb_intel_sdvo_connector->format_supported_num; i++) | ||
2290 | drm_property_add_enum( | ||
2291 | psb_intel_sdvo_connector->tv_format, i, | ||
2292 | i, tv_format_names[psb_intel_sdvo_connector->tv_format_supported[i]]); | ||
2293 | |||
2294 | psb_intel_sdvo->tv_format_index = psb_intel_sdvo_connector->tv_format_supported[0]; | ||
2295 | drm_connector_attach_property(&psb_intel_sdvo_connector->base.base, | ||
2296 | psb_intel_sdvo_connector->tv_format, 0); | ||
2297 | return true; | ||
2298 | |||
2299 | } | ||
2300 | |||
2301 | #define ENHANCEMENT(name, NAME) do { \ | ||
2302 | if (enhancements.name) { \ | ||
2303 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \ | ||
2304 | !psb_intel_sdvo_get_value(psb_intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \ | ||
2305 | return false; \ | ||
2306 | psb_intel_sdvo_connector->max_##name = data_value[0]; \ | ||
2307 | psb_intel_sdvo_connector->cur_##name = response; \ | ||
2308 | psb_intel_sdvo_connector->name = \ | ||
2309 | drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \ | ||
2310 | if (!psb_intel_sdvo_connector->name) return false; \ | ||
2311 | psb_intel_sdvo_connector->name->values[0] = 0; \ | ||
2312 | psb_intel_sdvo_connector->name->values[1] = data_value[0]; \ | ||
2313 | drm_connector_attach_property(connector, \ | ||
2314 | psb_intel_sdvo_connector->name, \ | ||
2315 | psb_intel_sdvo_connector->cur_##name); \ | ||
2316 | DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \ | ||
2317 | data_value[0], data_value[1], response); \ | ||
2318 | } \ | ||
2319 | } while(0) | ||
2320 | |||
2321 | static bool | ||
2322 | psb_intel_sdvo_create_enhance_property_tv(struct psb_intel_sdvo *psb_intel_sdvo, | ||
2323 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector, | ||
2324 | struct psb_intel_sdvo_enhancements_reply enhancements) | ||
2325 | { | ||
2326 | struct drm_device *dev = psb_intel_sdvo->base.base.dev; | ||
2327 | struct drm_connector *connector = &psb_intel_sdvo_connector->base.base; | ||
2328 | uint16_t response, data_value[2]; | ||
2329 | |||
2330 | /* when horizontal overscan is supported, Add the left/right property */ | ||
2331 | if (enhancements.overscan_h) { | ||
2332 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
2333 | SDVO_CMD_GET_MAX_OVERSCAN_H, | ||
2334 | &data_value, 4)) | ||
2335 | return false; | ||
2336 | |||
2337 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
2338 | SDVO_CMD_GET_OVERSCAN_H, | ||
2339 | &response, 2)) | ||
2340 | return false; | ||
2341 | |||
2342 | psb_intel_sdvo_connector->max_hscan = data_value[0]; | ||
2343 | psb_intel_sdvo_connector->left_margin = data_value[0] - response; | ||
2344 | psb_intel_sdvo_connector->right_margin = psb_intel_sdvo_connector->left_margin; | ||
2345 | psb_intel_sdvo_connector->left = | ||
2346 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
2347 | "left_margin", 2); | ||
2348 | if (!psb_intel_sdvo_connector->left) | ||
2349 | return false; | ||
2350 | |||
2351 | psb_intel_sdvo_connector->left->values[0] = 0; | ||
2352 | psb_intel_sdvo_connector->left->values[1] = data_value[0]; | ||
2353 | drm_connector_attach_property(connector, | ||
2354 | psb_intel_sdvo_connector->left, | ||
2355 | psb_intel_sdvo_connector->left_margin); | ||
2356 | |||
2357 | psb_intel_sdvo_connector->right = | ||
2358 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
2359 | "right_margin", 2); | ||
2360 | if (!psb_intel_sdvo_connector->right) | ||
2361 | return false; | ||
2362 | |||
2363 | psb_intel_sdvo_connector->right->values[0] = 0; | ||
2364 | psb_intel_sdvo_connector->right->values[1] = data_value[0]; | ||
2365 | drm_connector_attach_property(connector, | ||
2366 | psb_intel_sdvo_connector->right, | ||
2367 | psb_intel_sdvo_connector->right_margin); | ||
2368 | DRM_DEBUG_KMS("h_overscan: max %d, " | ||
2369 | "default %d, current %d\n", | ||
2370 | data_value[0], data_value[1], response); | ||
2371 | } | ||
2372 | |||
2373 | if (enhancements.overscan_v) { | ||
2374 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
2375 | SDVO_CMD_GET_MAX_OVERSCAN_V, | ||
2376 | &data_value, 4)) | ||
2377 | return false; | ||
2378 | |||
2379 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
2380 | SDVO_CMD_GET_OVERSCAN_V, | ||
2381 | &response, 2)) | ||
2382 | return false; | ||
2383 | |||
2384 | psb_intel_sdvo_connector->max_vscan = data_value[0]; | ||
2385 | psb_intel_sdvo_connector->top_margin = data_value[0] - response; | ||
2386 | psb_intel_sdvo_connector->bottom_margin = psb_intel_sdvo_connector->top_margin; | ||
2387 | psb_intel_sdvo_connector->top = | ||
2388 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
2389 | "top_margin", 2); | ||
2390 | if (!psb_intel_sdvo_connector->top) | ||
2391 | return false; | ||
2392 | |||
2393 | psb_intel_sdvo_connector->top->values[0] = 0; | ||
2394 | psb_intel_sdvo_connector->top->values[1] = data_value[0]; | ||
2395 | drm_connector_attach_property(connector, | ||
2396 | psb_intel_sdvo_connector->top, | ||
2397 | psb_intel_sdvo_connector->top_margin); | ||
2398 | |||
2399 | psb_intel_sdvo_connector->bottom = | ||
2400 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
2401 | "bottom_margin", 2); | ||
2402 | if (!psb_intel_sdvo_connector->bottom) | ||
2403 | return false; | ||
2404 | |||
2405 | psb_intel_sdvo_connector->bottom->values[0] = 0; | ||
2406 | psb_intel_sdvo_connector->bottom->values[1] = data_value[0]; | ||
2407 | drm_connector_attach_property(connector, | ||
2408 | psb_intel_sdvo_connector->bottom, | ||
2409 | psb_intel_sdvo_connector->bottom_margin); | ||
2410 | DRM_DEBUG_KMS("v_overscan: max %d, " | ||
2411 | "default %d, current %d\n", | ||
2412 | data_value[0], data_value[1], response); | ||
2413 | } | ||
2414 | |||
2415 | ENHANCEMENT(hpos, HPOS); | ||
2416 | ENHANCEMENT(vpos, VPOS); | ||
2417 | ENHANCEMENT(saturation, SATURATION); | ||
2418 | ENHANCEMENT(contrast, CONTRAST); | ||
2419 | ENHANCEMENT(hue, HUE); | ||
2420 | ENHANCEMENT(sharpness, SHARPNESS); | ||
2421 | ENHANCEMENT(brightness, BRIGHTNESS); | ||
2422 | ENHANCEMENT(flicker_filter, FLICKER_FILTER); | ||
2423 | ENHANCEMENT(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE); | ||
2424 | ENHANCEMENT(flicker_filter_2d, FLICKER_FILTER_2D); | ||
2425 | ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER); | ||
2426 | ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER); | ||
2427 | |||
2428 | if (enhancements.dot_crawl) { | ||
2429 | if (!psb_intel_sdvo_get_value(psb_intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2)) | ||
2430 | return false; | ||
2431 | |||
2432 | psb_intel_sdvo_connector->max_dot_crawl = 1; | ||
2433 | psb_intel_sdvo_connector->cur_dot_crawl = response & 0x1; | ||
2434 | psb_intel_sdvo_connector->dot_crawl = | ||
2435 | drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2); | ||
2436 | if (!psb_intel_sdvo_connector->dot_crawl) | ||
2437 | return false; | ||
2438 | |||
2439 | psb_intel_sdvo_connector->dot_crawl->values[0] = 0; | ||
2440 | psb_intel_sdvo_connector->dot_crawl->values[1] = 1; | ||
2441 | drm_connector_attach_property(connector, | ||
2442 | psb_intel_sdvo_connector->dot_crawl, | ||
2443 | psb_intel_sdvo_connector->cur_dot_crawl); | ||
2444 | DRM_DEBUG_KMS("dot crawl: current %d\n", response); | ||
2445 | } | ||
2446 | |||
2447 | return true; | ||
2448 | } | ||
2449 | |||
2450 | static bool | ||
2451 | psb_intel_sdvo_create_enhance_property_lvds(struct psb_intel_sdvo *psb_intel_sdvo, | ||
2452 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector, | ||
2453 | struct psb_intel_sdvo_enhancements_reply enhancements) | ||
2454 | { | ||
2455 | struct drm_device *dev = psb_intel_sdvo->base.base.dev; | ||
2456 | struct drm_connector *connector = &psb_intel_sdvo_connector->base.base; | ||
2457 | uint16_t response, data_value[2]; | ||
2458 | |||
2459 | ENHANCEMENT(brightness, BRIGHTNESS); | ||
2460 | |||
2461 | return true; | ||
2462 | } | ||
2463 | #undef ENHANCEMENT | ||
2464 | |||
2465 | static bool psb_intel_sdvo_create_enhance_property(struct psb_intel_sdvo *psb_intel_sdvo, | ||
2466 | struct psb_intel_sdvo_connector *psb_intel_sdvo_connector) | ||
2467 | { | ||
2468 | union { | ||
2469 | struct psb_intel_sdvo_enhancements_reply reply; | ||
2470 | uint16_t response; | ||
2471 | } enhancements; | ||
2472 | |||
2473 | BUILD_BUG_ON(sizeof(enhancements) != 2); | ||
2474 | |||
2475 | enhancements.response = 0; | ||
2476 | psb_intel_sdvo_get_value(psb_intel_sdvo, | ||
2477 | SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, | ||
2478 | &enhancements, sizeof(enhancements)); | ||
2479 | if (enhancements.response == 0) { | ||
2480 | DRM_DEBUG_KMS("No enhancement is supported\n"); | ||
2481 | return true; | ||
2482 | } | ||
2483 | |||
2484 | if (IS_TV(psb_intel_sdvo_connector)) | ||
2485 | return psb_intel_sdvo_create_enhance_property_tv(psb_intel_sdvo, psb_intel_sdvo_connector, enhancements.reply); | ||
2486 | else if(IS_LVDS(psb_intel_sdvo_connector)) | ||
2487 | return psb_intel_sdvo_create_enhance_property_lvds(psb_intel_sdvo, psb_intel_sdvo_connector, enhancements.reply); | ||
2488 | else | ||
2489 | return true; | ||
2490 | } | ||
2491 | |||
2492 | static int psb_intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, | ||
2493 | struct i2c_msg *msgs, | ||
2494 | int num) | ||
2495 | { | ||
2496 | struct psb_intel_sdvo *sdvo = adapter->algo_data; | ||
2497 | |||
2498 | if (!psb_intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus)) | ||
2499 | return -EIO; | ||
2500 | |||
2501 | return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num); | ||
2502 | } | ||
2503 | |||
2504 | static u32 psb_intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter) | ||
2505 | { | ||
2506 | struct psb_intel_sdvo *sdvo = adapter->algo_data; | ||
2507 | return sdvo->i2c->algo->functionality(sdvo->i2c); | ||
2508 | } | ||
2509 | |||
2510 | static const struct i2c_algorithm psb_intel_sdvo_ddc_proxy = { | ||
2511 | .master_xfer = psb_intel_sdvo_ddc_proxy_xfer, | ||
2512 | .functionality = psb_intel_sdvo_ddc_proxy_func | ||
2513 | }; | ||
2514 | |||
2515 | static bool | ||
2516 | psb_intel_sdvo_init_ddc_proxy(struct psb_intel_sdvo *sdvo, | ||
2517 | struct drm_device *dev) | ||
2518 | { | ||
2519 | sdvo->ddc.owner = THIS_MODULE; | ||
2520 | sdvo->ddc.class = I2C_CLASS_DDC; | ||
2521 | snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); | ||
2522 | sdvo->ddc.dev.parent = &dev->pdev->dev; | ||
2523 | sdvo->ddc.algo_data = sdvo; | ||
2524 | sdvo->ddc.algo = &psb_intel_sdvo_ddc_proxy; | ||
2525 | |||
2526 | return i2c_add_adapter(&sdvo->ddc) == 0; | ||
2527 | } | ||
2528 | |||
2529 | bool psb_intel_sdvo_init(struct drm_device *dev, int sdvo_reg) | ||
2530 | { | ||
2531 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
2532 | struct psb_intel_encoder *psb_intel_encoder; | ||
2533 | struct psb_intel_sdvo *psb_intel_sdvo; | ||
2534 | int i; | ||
2535 | |||
2536 | psb_intel_sdvo = kzalloc(sizeof(struct psb_intel_sdvo), GFP_KERNEL); | ||
2537 | if (!psb_intel_sdvo) | ||
2538 | return false; | ||
2539 | |||
2540 | psb_intel_sdvo->sdvo_reg = sdvo_reg; | ||
2541 | psb_intel_sdvo->slave_addr = psb_intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1; | ||
2542 | psb_intel_sdvo_select_i2c_bus(dev_priv, psb_intel_sdvo, sdvo_reg); | ||
2543 | if (!psb_intel_sdvo_init_ddc_proxy(psb_intel_sdvo, dev)) { | ||
2544 | kfree(psb_intel_sdvo); | ||
2545 | return false; | ||
2546 | } | ||
2547 | |||
2548 | /* encoder type will be decided later */ | ||
2549 | psb_intel_encoder = &psb_intel_sdvo->base; | ||
2550 | psb_intel_encoder->type = INTEL_OUTPUT_SDVO; | ||
2551 | drm_encoder_init(dev, &psb_intel_encoder->base, &psb_intel_sdvo_enc_funcs, 0); | ||
2552 | |||
2553 | /* Read the regs to test if we can talk to the device */ | ||
2554 | for (i = 0; i < 0x40; i++) { | ||
2555 | u8 byte; | ||
2556 | |||
2557 | if (!psb_intel_sdvo_read_byte(psb_intel_sdvo, i, &byte)) { | ||
2558 | DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n", | ||
2559 | IS_SDVOB(sdvo_reg) ? 'B' : 'C'); | ||
2560 | goto err; | ||
2561 | } | ||
2562 | } | ||
2563 | |||
2564 | if (IS_SDVOB(sdvo_reg)) | ||
2565 | dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; | ||
2566 | else | ||
2567 | dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; | ||
2568 | |||
2569 | drm_encoder_helper_add(&psb_intel_encoder->base, &psb_intel_sdvo_helper_funcs); | ||
2570 | |||
2571 | /* In default case sdvo lvds is false */ | ||
2572 | if (!psb_intel_sdvo_get_capabilities(psb_intel_sdvo, &psb_intel_sdvo->caps)) | ||
2573 | goto err; | ||
2574 | |||
2575 | if (psb_intel_sdvo_output_setup(psb_intel_sdvo, | ||
2576 | psb_intel_sdvo->caps.output_flags) != true) { | ||
2577 | DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", | ||
2578 | IS_SDVOB(sdvo_reg) ? 'B' : 'C'); | ||
2579 | goto err; | ||
2580 | } | ||
2581 | |||
2582 | psb_intel_sdvo_select_ddc_bus(dev_priv, psb_intel_sdvo, sdvo_reg); | ||
2583 | |||
2584 | /* Set the input timing to the screen. Assume always input 0. */ | ||
2585 | if (!psb_intel_sdvo_set_target_input(psb_intel_sdvo)) | ||
2586 | goto err; | ||
2587 | |||
2588 | if (!psb_intel_sdvo_get_input_pixel_clock_range(psb_intel_sdvo, | ||
2589 | &psb_intel_sdvo->pixel_clock_min, | ||
2590 | &psb_intel_sdvo->pixel_clock_max)) | ||
2591 | goto err; | ||
2592 | |||
2593 | DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " | ||
2594 | "clock range %dMHz - %dMHz, " | ||
2595 | "input 1: %c, input 2: %c, " | ||
2596 | "output 1: %c, output 2: %c\n", | ||
2597 | SDVO_NAME(psb_intel_sdvo), | ||
2598 | psb_intel_sdvo->caps.vendor_id, psb_intel_sdvo->caps.device_id, | ||
2599 | psb_intel_sdvo->caps.device_rev_id, | ||
2600 | psb_intel_sdvo->pixel_clock_min / 1000, | ||
2601 | psb_intel_sdvo->pixel_clock_max / 1000, | ||
2602 | (psb_intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', | ||
2603 | (psb_intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', | ||
2604 | /* check currently supported outputs */ | ||
2605 | psb_intel_sdvo->caps.output_flags & | ||
2606 | (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', | ||
2607 | psb_intel_sdvo->caps.output_flags & | ||
2608 | (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); | ||
2609 | return true; | ||
2610 | |||
2611 | err: | ||
2612 | drm_encoder_cleanup(&psb_intel_encoder->base); | ||
2613 | i2c_del_adapter(&psb_intel_sdvo->ddc); | ||
2614 | kfree(psb_intel_sdvo); | ||
2615 | |||
2616 | return false; | ||
2617 | } | ||
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo_regs.h b/drivers/gpu/drm/gma500/psb_intel_sdvo_regs.h new file mode 100644 index 00000000000..600e79744d6 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo_regs.h | |||
@@ -0,0 +1,723 @@ | |||
1 | /* | ||
2 | * Copyright ? 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | */ | ||
26 | |||
27 | /** | ||
28 | * @file SDVO command definitions and structures. | ||
29 | */ | ||
30 | |||
31 | #define SDVO_OUTPUT_FIRST (0) | ||
32 | #define SDVO_OUTPUT_TMDS0 (1 << 0) | ||
33 | #define SDVO_OUTPUT_RGB0 (1 << 1) | ||
34 | #define SDVO_OUTPUT_CVBS0 (1 << 2) | ||
35 | #define SDVO_OUTPUT_SVID0 (1 << 3) | ||
36 | #define SDVO_OUTPUT_YPRPB0 (1 << 4) | ||
37 | #define SDVO_OUTPUT_SCART0 (1 << 5) | ||
38 | #define SDVO_OUTPUT_LVDS0 (1 << 6) | ||
39 | #define SDVO_OUTPUT_TMDS1 (1 << 8) | ||
40 | #define SDVO_OUTPUT_RGB1 (1 << 9) | ||
41 | #define SDVO_OUTPUT_CVBS1 (1 << 10) | ||
42 | #define SDVO_OUTPUT_SVID1 (1 << 11) | ||
43 | #define SDVO_OUTPUT_YPRPB1 (1 << 12) | ||
44 | #define SDVO_OUTPUT_SCART1 (1 << 13) | ||
45 | #define SDVO_OUTPUT_LVDS1 (1 << 14) | ||
46 | #define SDVO_OUTPUT_LAST (14) | ||
47 | |||
48 | struct psb_intel_sdvo_caps { | ||
49 | u8 vendor_id; | ||
50 | u8 device_id; | ||
51 | u8 device_rev_id; | ||
52 | u8 sdvo_version_major; | ||
53 | u8 sdvo_version_minor; | ||
54 | unsigned int sdvo_inputs_mask:2; | ||
55 | unsigned int smooth_scaling:1; | ||
56 | unsigned int sharp_scaling:1; | ||
57 | unsigned int up_scaling:1; | ||
58 | unsigned int down_scaling:1; | ||
59 | unsigned int stall_support:1; | ||
60 | unsigned int pad:1; | ||
61 | u16 output_flags; | ||
62 | } __attribute__((packed)); | ||
63 | |||
64 | /** This matches the EDID DTD structure, more or less */ | ||
65 | struct psb_intel_sdvo_dtd { | ||
66 | struct { | ||
67 | u16 clock; /**< pixel clock, in 10kHz units */ | ||
68 | u8 h_active; /**< lower 8 bits (pixels) */ | ||
69 | u8 h_blank; /**< lower 8 bits (pixels) */ | ||
70 | u8 h_high; /**< upper 4 bits each h_active, h_blank */ | ||
71 | u8 v_active; /**< lower 8 bits (lines) */ | ||
72 | u8 v_blank; /**< lower 8 bits (lines) */ | ||
73 | u8 v_high; /**< upper 4 bits each v_active, v_blank */ | ||
74 | } part1; | ||
75 | |||
76 | struct { | ||
77 | u8 h_sync_off; /**< lower 8 bits, from hblank start */ | ||
78 | u8 h_sync_width; /**< lower 8 bits (pixels) */ | ||
79 | /** lower 4 bits each vsync offset, vsync width */ | ||
80 | u8 v_sync_off_width; | ||
81 | /** | ||
82 | * 2 high bits of hsync offset, 2 high bits of hsync width, | ||
83 | * bits 4-5 of vsync offset, and 2 high bits of vsync width. | ||
84 | */ | ||
85 | u8 sync_off_width_high; | ||
86 | u8 dtd_flags; | ||
87 | u8 sdvo_flags; | ||
88 | /** bits 6-7 of vsync offset at bits 6-7 */ | ||
89 | u8 v_sync_off_high; | ||
90 | u8 reserved; | ||
91 | } part2; | ||
92 | } __attribute__((packed)); | ||
93 | |||
94 | struct psb_intel_sdvo_pixel_clock_range { | ||
95 | u16 min; /**< pixel clock, in 10kHz units */ | ||
96 | u16 max; /**< pixel clock, in 10kHz units */ | ||
97 | } __attribute__((packed)); | ||
98 | |||
99 | struct psb_intel_sdvo_preferred_input_timing_args { | ||
100 | u16 clock; | ||
101 | u16 width; | ||
102 | u16 height; | ||
103 | u8 interlace:1; | ||
104 | u8 scaled:1; | ||
105 | u8 pad:6; | ||
106 | } __attribute__((packed)); | ||
107 | |||
108 | /* I2C registers for SDVO */ | ||
109 | #define SDVO_I2C_ARG_0 0x07 | ||
110 | #define SDVO_I2C_ARG_1 0x06 | ||
111 | #define SDVO_I2C_ARG_2 0x05 | ||
112 | #define SDVO_I2C_ARG_3 0x04 | ||
113 | #define SDVO_I2C_ARG_4 0x03 | ||
114 | #define SDVO_I2C_ARG_5 0x02 | ||
115 | #define SDVO_I2C_ARG_6 0x01 | ||
116 | #define SDVO_I2C_ARG_7 0x00 | ||
117 | #define SDVO_I2C_OPCODE 0x08 | ||
118 | #define SDVO_I2C_CMD_STATUS 0x09 | ||
119 | #define SDVO_I2C_RETURN_0 0x0a | ||
120 | #define SDVO_I2C_RETURN_1 0x0b | ||
121 | #define SDVO_I2C_RETURN_2 0x0c | ||
122 | #define SDVO_I2C_RETURN_3 0x0d | ||
123 | #define SDVO_I2C_RETURN_4 0x0e | ||
124 | #define SDVO_I2C_RETURN_5 0x0f | ||
125 | #define SDVO_I2C_RETURN_6 0x10 | ||
126 | #define SDVO_I2C_RETURN_7 0x11 | ||
127 | #define SDVO_I2C_VENDOR_BEGIN 0x20 | ||
128 | |||
129 | /* Status results */ | ||
130 | #define SDVO_CMD_STATUS_POWER_ON 0x0 | ||
131 | #define SDVO_CMD_STATUS_SUCCESS 0x1 | ||
132 | #define SDVO_CMD_STATUS_NOTSUPP 0x2 | ||
133 | #define SDVO_CMD_STATUS_INVALID_ARG 0x3 | ||
134 | #define SDVO_CMD_STATUS_PENDING 0x4 | ||
135 | #define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED 0x5 | ||
136 | #define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6 | ||
137 | |||
138 | /* SDVO commands, argument/result registers */ | ||
139 | |||
140 | #define SDVO_CMD_RESET 0x01 | ||
141 | |||
142 | /** Returns a struct intel_sdvo_caps */ | ||
143 | #define SDVO_CMD_GET_DEVICE_CAPS 0x02 | ||
144 | |||
145 | #define SDVO_CMD_GET_FIRMWARE_REV 0x86 | ||
146 | # define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0 | ||
147 | # define SDVO_DEVICE_FIRMWARE_MAJOR SDVO_I2C_RETURN_1 | ||
148 | # define SDVO_DEVICE_FIRMWARE_PATCH SDVO_I2C_RETURN_2 | ||
149 | |||
150 | /** | ||
151 | * Reports which inputs are trained (managed to sync). | ||
152 | * | ||
153 | * Devices must have trained within 2 vsyncs of a mode change. | ||
154 | */ | ||
155 | #define SDVO_CMD_GET_TRAINED_INPUTS 0x03 | ||
156 | struct psb_intel_sdvo_get_trained_inputs_response { | ||
157 | unsigned int input0_trained:1; | ||
158 | unsigned int input1_trained:1; | ||
159 | unsigned int pad:6; | ||
160 | } __attribute__((packed)); | ||
161 | |||
162 | /** Returns a struct intel_sdvo_output_flags of active outputs. */ | ||
163 | #define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 | ||
164 | |||
165 | /** | ||
166 | * Sets the current set of active outputs. | ||
167 | * | ||
168 | * Takes a struct intel_sdvo_output_flags. Must be preceded by a SET_IN_OUT_MAP | ||
169 | * on multi-output devices. | ||
170 | */ | ||
171 | #define SDVO_CMD_SET_ACTIVE_OUTPUTS 0x05 | ||
172 | |||
173 | /** | ||
174 | * Returns the current mapping of SDVO inputs to outputs on the device. | ||
175 | * | ||
176 | * Returns two struct intel_sdvo_output_flags structures. | ||
177 | */ | ||
178 | #define SDVO_CMD_GET_IN_OUT_MAP 0x06 | ||
179 | struct psb_intel_sdvo_in_out_map { | ||
180 | u16 in0, in1; | ||
181 | }; | ||
182 | |||
183 | /** | ||
184 | * Sets the current mapping of SDVO inputs to outputs on the device. | ||
185 | * | ||
186 | * Takes two struct i380_sdvo_output_flags structures. | ||
187 | */ | ||
188 | #define SDVO_CMD_SET_IN_OUT_MAP 0x07 | ||
189 | |||
190 | /** | ||
191 | * Returns a struct intel_sdvo_output_flags of attached displays. | ||
192 | */ | ||
193 | #define SDVO_CMD_GET_ATTACHED_DISPLAYS 0x0b | ||
194 | |||
195 | /** | ||
196 | * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging. | ||
197 | */ | ||
198 | #define SDVO_CMD_GET_HOT_PLUG_SUPPORT 0x0c | ||
199 | |||
200 | /** | ||
201 | * Takes a struct intel_sdvo_output_flags. | ||
202 | */ | ||
203 | #define SDVO_CMD_SET_ACTIVE_HOT_PLUG 0x0d | ||
204 | |||
205 | /** | ||
206 | * Returns a struct intel_sdvo_output_flags of displays with hot plug | ||
207 | * interrupts enabled. | ||
208 | */ | ||
209 | #define SDVO_CMD_GET_ACTIVE_HOT_PLUG 0x0e | ||
210 | |||
211 | #define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE 0x0f | ||
212 | struct intel_sdvo_get_interrupt_event_source_response { | ||
213 | u16 interrupt_status; | ||
214 | unsigned int ambient_light_interrupt:1; | ||
215 | unsigned int hdmi_audio_encrypt_change:1; | ||
216 | unsigned int pad:6; | ||
217 | } __attribute__((packed)); | ||
218 | |||
219 | /** | ||
220 | * Selects which input is affected by future input commands. | ||
221 | * | ||
222 | * Commands affected include SET_INPUT_TIMINGS_PART[12], | ||
223 | * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12], | ||
224 | * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS. | ||
225 | */ | ||
226 | #define SDVO_CMD_SET_TARGET_INPUT 0x10 | ||
227 | struct psb_intel_sdvo_set_target_input_args { | ||
228 | unsigned int target_1:1; | ||
229 | unsigned int pad:7; | ||
230 | } __attribute__((packed)); | ||
231 | |||
232 | /** | ||
233 | * Takes a struct intel_sdvo_output_flags of which outputs are targeted by | ||
234 | * future output commands. | ||
235 | * | ||
236 | * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], | ||
237 | * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE. | ||
238 | */ | ||
239 | #define SDVO_CMD_SET_TARGET_OUTPUT 0x11 | ||
240 | |||
241 | #define SDVO_CMD_GET_INPUT_TIMINGS_PART1 0x12 | ||
242 | #define SDVO_CMD_GET_INPUT_TIMINGS_PART2 0x13 | ||
243 | #define SDVO_CMD_SET_INPUT_TIMINGS_PART1 0x14 | ||
244 | #define SDVO_CMD_SET_INPUT_TIMINGS_PART2 0x15 | ||
245 | #define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1 0x16 | ||
246 | #define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2 0x17 | ||
247 | #define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1 0x18 | ||
248 | #define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2 0x19 | ||
249 | /* Part 1 */ | ||
250 | # define SDVO_DTD_CLOCK_LOW SDVO_I2C_ARG_0 | ||
251 | # define SDVO_DTD_CLOCK_HIGH SDVO_I2C_ARG_1 | ||
252 | # define SDVO_DTD_H_ACTIVE SDVO_I2C_ARG_2 | ||
253 | # define SDVO_DTD_H_BLANK SDVO_I2C_ARG_3 | ||
254 | # define SDVO_DTD_H_HIGH SDVO_I2C_ARG_4 | ||
255 | # define SDVO_DTD_V_ACTIVE SDVO_I2C_ARG_5 | ||
256 | # define SDVO_DTD_V_BLANK SDVO_I2C_ARG_6 | ||
257 | # define SDVO_DTD_V_HIGH SDVO_I2C_ARG_7 | ||
258 | /* Part 2 */ | ||
259 | # define SDVO_DTD_HSYNC_OFF SDVO_I2C_ARG_0 | ||
260 | # define SDVO_DTD_HSYNC_WIDTH SDVO_I2C_ARG_1 | ||
261 | # define SDVO_DTD_VSYNC_OFF_WIDTH SDVO_I2C_ARG_2 | ||
262 | # define SDVO_DTD_SYNC_OFF_WIDTH_HIGH SDVO_I2C_ARG_3 | ||
263 | # define SDVO_DTD_DTD_FLAGS SDVO_I2C_ARG_4 | ||
264 | # define SDVO_DTD_DTD_FLAG_INTERLACED (1 << 7) | ||
265 | # define SDVO_DTD_DTD_FLAG_STEREO_MASK (3 << 5) | ||
266 | # define SDVO_DTD_DTD_FLAG_INPUT_MASK (3 << 3) | ||
267 | # define SDVO_DTD_DTD_FLAG_SYNC_MASK (3 << 1) | ||
268 | # define SDVO_DTD_SDVO_FLAS SDVO_I2C_ARG_5 | ||
269 | # define SDVO_DTD_SDVO_FLAG_STALL (1 << 7) | ||
270 | # define SDVO_DTD_SDVO_FLAG_CENTERED (0 << 6) | ||
271 | # define SDVO_DTD_SDVO_FLAG_UPPER_LEFT (1 << 6) | ||
272 | # define SDVO_DTD_SDVO_FLAG_SCALING_MASK (3 << 4) | ||
273 | # define SDVO_DTD_SDVO_FLAG_SCALING_NONE (0 << 4) | ||
274 | # define SDVO_DTD_SDVO_FLAG_SCALING_SHARP (1 << 4) | ||
275 | # define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH (2 << 4) | ||
276 | # define SDVO_DTD_VSYNC_OFF_HIGH SDVO_I2C_ARG_6 | ||
277 | |||
278 | /** | ||
279 | * Generates a DTD based on the given width, height, and flags. | ||
280 | * | ||
281 | * This will be supported by any device supporting scaling or interlaced | ||
282 | * modes. | ||
283 | */ | ||
284 | #define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING 0x1a | ||
285 | # define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW SDVO_I2C_ARG_0 | ||
286 | # define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH SDVO_I2C_ARG_1 | ||
287 | # define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW SDVO_I2C_ARG_2 | ||
288 | # define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH SDVO_I2C_ARG_3 | ||
289 | # define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW SDVO_I2C_ARG_4 | ||
290 | # define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH SDVO_I2C_ARG_5 | ||
291 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS SDVO_I2C_ARG_6 | ||
292 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED (1 << 0) | ||
293 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED (1 << 1) | ||
294 | |||
295 | #define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1 0x1b | ||
296 | #define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2 0x1c | ||
297 | |||
298 | /** Returns a struct intel_sdvo_pixel_clock_range */ | ||
299 | #define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE 0x1d | ||
300 | /** Returns a struct intel_sdvo_pixel_clock_range */ | ||
301 | #define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e | ||
302 | |||
303 | /** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */ | ||
304 | #define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f | ||
305 | |||
306 | /** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ | ||
307 | #define SDVO_CMD_GET_CLOCK_RATE_MULT 0x20 | ||
308 | /** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ | ||
309 | #define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21 | ||
310 | # define SDVO_CLOCK_RATE_MULT_1X (1 << 0) | ||
311 | # define SDVO_CLOCK_RATE_MULT_2X (1 << 1) | ||
312 | # define SDVO_CLOCK_RATE_MULT_4X (1 << 3) | ||
313 | |||
314 | #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 | ||
315 | /** 6 bytes of bit flags for TV formats shared by all TV format functions */ | ||
316 | struct psb_intel_sdvo_tv_format { | ||
317 | unsigned int ntsc_m:1; | ||
318 | unsigned int ntsc_j:1; | ||
319 | unsigned int ntsc_443:1; | ||
320 | unsigned int pal_b:1; | ||
321 | unsigned int pal_d:1; | ||
322 | unsigned int pal_g:1; | ||
323 | unsigned int pal_h:1; | ||
324 | unsigned int pal_i:1; | ||
325 | |||
326 | unsigned int pal_m:1; | ||
327 | unsigned int pal_n:1; | ||
328 | unsigned int pal_nc:1; | ||
329 | unsigned int pal_60:1; | ||
330 | unsigned int secam_b:1; | ||
331 | unsigned int secam_d:1; | ||
332 | unsigned int secam_g:1; | ||
333 | unsigned int secam_k:1; | ||
334 | |||
335 | unsigned int secam_k1:1; | ||
336 | unsigned int secam_l:1; | ||
337 | unsigned int secam_60:1; | ||
338 | unsigned int hdtv_std_smpte_240m_1080i_59:1; | ||
339 | unsigned int hdtv_std_smpte_240m_1080i_60:1; | ||
340 | unsigned int hdtv_std_smpte_260m_1080i_59:1; | ||
341 | unsigned int hdtv_std_smpte_260m_1080i_60:1; | ||
342 | unsigned int hdtv_std_smpte_274m_1080i_50:1; | ||
343 | |||
344 | unsigned int hdtv_std_smpte_274m_1080i_59:1; | ||
345 | unsigned int hdtv_std_smpte_274m_1080i_60:1; | ||
346 | unsigned int hdtv_std_smpte_274m_1080p_23:1; | ||
347 | unsigned int hdtv_std_smpte_274m_1080p_24:1; | ||
348 | unsigned int hdtv_std_smpte_274m_1080p_25:1; | ||
349 | unsigned int hdtv_std_smpte_274m_1080p_29:1; | ||
350 | unsigned int hdtv_std_smpte_274m_1080p_30:1; | ||
351 | unsigned int hdtv_std_smpte_274m_1080p_50:1; | ||
352 | |||
353 | unsigned int hdtv_std_smpte_274m_1080p_59:1; | ||
354 | unsigned int hdtv_std_smpte_274m_1080p_60:1; | ||
355 | unsigned int hdtv_std_smpte_295m_1080i_50:1; | ||
356 | unsigned int hdtv_std_smpte_295m_1080p_50:1; | ||
357 | unsigned int hdtv_std_smpte_296m_720p_59:1; | ||
358 | unsigned int hdtv_std_smpte_296m_720p_60:1; | ||
359 | unsigned int hdtv_std_smpte_296m_720p_50:1; | ||
360 | unsigned int hdtv_std_smpte_293m_480p_59:1; | ||
361 | |||
362 | unsigned int hdtv_std_smpte_170m_480i_59:1; | ||
363 | unsigned int hdtv_std_iturbt601_576i_50:1; | ||
364 | unsigned int hdtv_std_iturbt601_576p_50:1; | ||
365 | unsigned int hdtv_std_eia_7702a_480i_60:1; | ||
366 | unsigned int hdtv_std_eia_7702a_480p_60:1; | ||
367 | unsigned int pad:3; | ||
368 | } __attribute__((packed)); | ||
369 | |||
370 | #define SDVO_CMD_GET_TV_FORMAT 0x28 | ||
371 | |||
372 | #define SDVO_CMD_SET_TV_FORMAT 0x29 | ||
373 | |||
374 | /** Returns the resolutiosn that can be used with the given TV format */ | ||
375 | #define SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT 0x83 | ||
376 | struct psb_intel_sdvo_sdtv_resolution_request { | ||
377 | unsigned int ntsc_m:1; | ||
378 | unsigned int ntsc_j:1; | ||
379 | unsigned int ntsc_443:1; | ||
380 | unsigned int pal_b:1; | ||
381 | unsigned int pal_d:1; | ||
382 | unsigned int pal_g:1; | ||
383 | unsigned int pal_h:1; | ||
384 | unsigned int pal_i:1; | ||
385 | |||
386 | unsigned int pal_m:1; | ||
387 | unsigned int pal_n:1; | ||
388 | unsigned int pal_nc:1; | ||
389 | unsigned int pal_60:1; | ||
390 | unsigned int secam_b:1; | ||
391 | unsigned int secam_d:1; | ||
392 | unsigned int secam_g:1; | ||
393 | unsigned int secam_k:1; | ||
394 | |||
395 | unsigned int secam_k1:1; | ||
396 | unsigned int secam_l:1; | ||
397 | unsigned int secam_60:1; | ||
398 | unsigned int pad:5; | ||
399 | } __attribute__((packed)); | ||
400 | |||
401 | struct psb_intel_sdvo_sdtv_resolution_reply { | ||
402 | unsigned int res_320x200:1; | ||
403 | unsigned int res_320x240:1; | ||
404 | unsigned int res_400x300:1; | ||
405 | unsigned int res_640x350:1; | ||
406 | unsigned int res_640x400:1; | ||
407 | unsigned int res_640x480:1; | ||
408 | unsigned int res_704x480:1; | ||
409 | unsigned int res_704x576:1; | ||
410 | |||
411 | unsigned int res_720x350:1; | ||
412 | unsigned int res_720x400:1; | ||
413 | unsigned int res_720x480:1; | ||
414 | unsigned int res_720x540:1; | ||
415 | unsigned int res_720x576:1; | ||
416 | unsigned int res_768x576:1; | ||
417 | unsigned int res_800x600:1; | ||
418 | unsigned int res_832x624:1; | ||
419 | |||
420 | unsigned int res_920x766:1; | ||
421 | unsigned int res_1024x768:1; | ||
422 | unsigned int res_1280x1024:1; | ||
423 | unsigned int pad:5; | ||
424 | } __attribute__((packed)); | ||
425 | |||
426 | /* Get supported resolution with squire pixel aspect ratio that can be | ||
427 | scaled for the requested HDTV format */ | ||
428 | #define SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT 0x85 | ||
429 | |||
430 | struct psb_intel_sdvo_hdtv_resolution_request { | ||
431 | unsigned int hdtv_std_smpte_240m_1080i_59:1; | ||
432 | unsigned int hdtv_std_smpte_240m_1080i_60:1; | ||
433 | unsigned int hdtv_std_smpte_260m_1080i_59:1; | ||
434 | unsigned int hdtv_std_smpte_260m_1080i_60:1; | ||
435 | unsigned int hdtv_std_smpte_274m_1080i_50:1; | ||
436 | unsigned int hdtv_std_smpte_274m_1080i_59:1; | ||
437 | unsigned int hdtv_std_smpte_274m_1080i_60:1; | ||
438 | unsigned int hdtv_std_smpte_274m_1080p_23:1; | ||
439 | |||
440 | unsigned int hdtv_std_smpte_274m_1080p_24:1; | ||
441 | unsigned int hdtv_std_smpte_274m_1080p_25:1; | ||
442 | unsigned int hdtv_std_smpte_274m_1080p_29:1; | ||
443 | unsigned int hdtv_std_smpte_274m_1080p_30:1; | ||
444 | unsigned int hdtv_std_smpte_274m_1080p_50:1; | ||
445 | unsigned int hdtv_std_smpte_274m_1080p_59:1; | ||
446 | unsigned int hdtv_std_smpte_274m_1080p_60:1; | ||
447 | unsigned int hdtv_std_smpte_295m_1080i_50:1; | ||
448 | |||
449 | unsigned int hdtv_std_smpte_295m_1080p_50:1; | ||
450 | unsigned int hdtv_std_smpte_296m_720p_59:1; | ||
451 | unsigned int hdtv_std_smpte_296m_720p_60:1; | ||
452 | unsigned int hdtv_std_smpte_296m_720p_50:1; | ||
453 | unsigned int hdtv_std_smpte_293m_480p_59:1; | ||
454 | unsigned int hdtv_std_smpte_170m_480i_59:1; | ||
455 | unsigned int hdtv_std_iturbt601_576i_50:1; | ||
456 | unsigned int hdtv_std_iturbt601_576p_50:1; | ||
457 | |||
458 | unsigned int hdtv_std_eia_7702a_480i_60:1; | ||
459 | unsigned int hdtv_std_eia_7702a_480p_60:1; | ||
460 | unsigned int pad:6; | ||
461 | } __attribute__((packed)); | ||
462 | |||
463 | struct psb_intel_sdvo_hdtv_resolution_reply { | ||
464 | unsigned int res_640x480:1; | ||
465 | unsigned int res_800x600:1; | ||
466 | unsigned int res_1024x768:1; | ||
467 | unsigned int res_1280x960:1; | ||
468 | unsigned int res_1400x1050:1; | ||
469 | unsigned int res_1600x1200:1; | ||
470 | unsigned int res_1920x1440:1; | ||
471 | unsigned int res_2048x1536:1; | ||
472 | |||
473 | unsigned int res_2560x1920:1; | ||
474 | unsigned int res_3200x2400:1; | ||
475 | unsigned int res_3840x2880:1; | ||
476 | unsigned int pad1:5; | ||
477 | |||
478 | unsigned int res_848x480:1; | ||
479 | unsigned int res_1064x600:1; | ||
480 | unsigned int res_1280x720:1; | ||
481 | unsigned int res_1360x768:1; | ||
482 | unsigned int res_1704x960:1; | ||
483 | unsigned int res_1864x1050:1; | ||
484 | unsigned int res_1920x1080:1; | ||
485 | unsigned int res_2128x1200:1; | ||
486 | |||
487 | unsigned int res_2560x1400:1; | ||
488 | unsigned int res_2728x1536:1; | ||
489 | unsigned int res_3408x1920:1; | ||
490 | unsigned int res_4264x2400:1; | ||
491 | unsigned int res_5120x2880:1; | ||
492 | unsigned int pad2:3; | ||
493 | |||
494 | unsigned int res_768x480:1; | ||
495 | unsigned int res_960x600:1; | ||
496 | unsigned int res_1152x720:1; | ||
497 | unsigned int res_1124x768:1; | ||
498 | unsigned int res_1536x960:1; | ||
499 | unsigned int res_1680x1050:1; | ||
500 | unsigned int res_1728x1080:1; | ||
501 | unsigned int res_1920x1200:1; | ||
502 | |||
503 | unsigned int res_2304x1440:1; | ||
504 | unsigned int res_2456x1536:1; | ||
505 | unsigned int res_3072x1920:1; | ||
506 | unsigned int res_3840x2400:1; | ||
507 | unsigned int res_4608x2880:1; | ||
508 | unsigned int pad3:3; | ||
509 | |||
510 | unsigned int res_1280x1024:1; | ||
511 | unsigned int pad4:7; | ||
512 | |||
513 | unsigned int res_1280x768:1; | ||
514 | unsigned int pad5:7; | ||
515 | } __attribute__((packed)); | ||
516 | |||
517 | /* Get supported power state returns info for encoder and monitor, rely on | ||
518 | last SetTargetInput and SetTargetOutput calls */ | ||
519 | #define SDVO_CMD_GET_SUPPORTED_POWER_STATES 0x2a | ||
520 | /* Get power state returns info for encoder and monitor, rely on last | ||
521 | SetTargetInput and SetTargetOutput calls */ | ||
522 | #define SDVO_CMD_GET_POWER_STATE 0x2b | ||
523 | #define SDVO_CMD_GET_ENCODER_POWER_STATE 0x2b | ||
524 | #define SDVO_CMD_SET_ENCODER_POWER_STATE 0x2c | ||
525 | # define SDVO_ENCODER_STATE_ON (1 << 0) | ||
526 | # define SDVO_ENCODER_STATE_STANDBY (1 << 1) | ||
527 | # define SDVO_ENCODER_STATE_SUSPEND (1 << 2) | ||
528 | # define SDVO_ENCODER_STATE_OFF (1 << 3) | ||
529 | # define SDVO_MONITOR_STATE_ON (1 << 4) | ||
530 | # define SDVO_MONITOR_STATE_STANDBY (1 << 5) | ||
531 | # define SDVO_MONITOR_STATE_SUSPEND (1 << 6) | ||
532 | # define SDVO_MONITOR_STATE_OFF (1 << 7) | ||
533 | |||
534 | #define SDVO_CMD_GET_MAX_PANEL_POWER_SEQUENCING 0x2d | ||
535 | #define SDVO_CMD_GET_PANEL_POWER_SEQUENCING 0x2e | ||
536 | #define SDVO_CMD_SET_PANEL_POWER_SEQUENCING 0x2f | ||
537 | /** | ||
538 | * The panel power sequencing parameters are in units of milliseconds. | ||
539 | * The high fields are bits 8:9 of the 10-bit values. | ||
540 | */ | ||
541 | struct psb_sdvo_panel_power_sequencing { | ||
542 | u8 t0; | ||
543 | u8 t1; | ||
544 | u8 t2; | ||
545 | u8 t3; | ||
546 | u8 t4; | ||
547 | |||
548 | unsigned int t0_high:2; | ||
549 | unsigned int t1_high:2; | ||
550 | unsigned int t2_high:2; | ||
551 | unsigned int t3_high:2; | ||
552 | |||
553 | unsigned int t4_high:2; | ||
554 | unsigned int pad:6; | ||
555 | } __attribute__((packed)); | ||
556 | |||
557 | #define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL 0x30 | ||
558 | struct sdvo_max_backlight_reply { | ||
559 | u8 max_value; | ||
560 | u8 default_value; | ||
561 | } __attribute__((packed)); | ||
562 | |||
563 | #define SDVO_CMD_GET_BACKLIGHT_LEVEL 0x31 | ||
564 | #define SDVO_CMD_SET_BACKLIGHT_LEVEL 0x32 | ||
565 | |||
566 | #define SDVO_CMD_GET_AMBIENT_LIGHT 0x33 | ||
567 | struct sdvo_get_ambient_light_reply { | ||
568 | u16 trip_low; | ||
569 | u16 trip_high; | ||
570 | u16 value; | ||
571 | } __attribute__((packed)); | ||
572 | #define SDVO_CMD_SET_AMBIENT_LIGHT 0x34 | ||
573 | struct sdvo_set_ambient_light_reply { | ||
574 | u16 trip_low; | ||
575 | u16 trip_high; | ||
576 | unsigned int enable:1; | ||
577 | unsigned int pad:7; | ||
578 | } __attribute__((packed)); | ||
579 | |||
580 | /* Set display power state */ | ||
581 | #define SDVO_CMD_SET_DISPLAY_POWER_STATE 0x7d | ||
582 | # define SDVO_DISPLAY_STATE_ON (1 << 0) | ||
583 | # define SDVO_DISPLAY_STATE_STANDBY (1 << 1) | ||
584 | # define SDVO_DISPLAY_STATE_SUSPEND (1 << 2) | ||
585 | # define SDVO_DISPLAY_STATE_OFF (1 << 3) | ||
586 | |||
587 | #define SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS 0x84 | ||
588 | struct psb_intel_sdvo_enhancements_reply { | ||
589 | unsigned int flicker_filter:1; | ||
590 | unsigned int flicker_filter_adaptive:1; | ||
591 | unsigned int flicker_filter_2d:1; | ||
592 | unsigned int saturation:1; | ||
593 | unsigned int hue:1; | ||
594 | unsigned int brightness:1; | ||
595 | unsigned int contrast:1; | ||
596 | unsigned int overscan_h:1; | ||
597 | |||
598 | unsigned int overscan_v:1; | ||
599 | unsigned int hpos:1; | ||
600 | unsigned int vpos:1; | ||
601 | unsigned int sharpness:1; | ||
602 | unsigned int dot_crawl:1; | ||
603 | unsigned int dither:1; | ||
604 | unsigned int tv_chroma_filter:1; | ||
605 | unsigned int tv_luma_filter:1; | ||
606 | } __attribute__((packed)); | ||
607 | |||
608 | /* Picture enhancement limits below are dependent on the current TV format, | ||
609 | * and thus need to be queried and set after it. | ||
610 | */ | ||
611 | #define SDVO_CMD_GET_MAX_FLICKER_FILTER 0x4d | ||
612 | #define SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE 0x7b | ||
613 | #define SDVO_CMD_GET_MAX_FLICKER_FILTER_2D 0x52 | ||
614 | #define SDVO_CMD_GET_MAX_SATURATION 0x55 | ||
615 | #define SDVO_CMD_GET_MAX_HUE 0x58 | ||
616 | #define SDVO_CMD_GET_MAX_BRIGHTNESS 0x5b | ||
617 | #define SDVO_CMD_GET_MAX_CONTRAST 0x5e | ||
618 | #define SDVO_CMD_GET_MAX_OVERSCAN_H 0x61 | ||
619 | #define SDVO_CMD_GET_MAX_OVERSCAN_V 0x64 | ||
620 | #define SDVO_CMD_GET_MAX_HPOS 0x67 | ||
621 | #define SDVO_CMD_GET_MAX_VPOS 0x6a | ||
622 | #define SDVO_CMD_GET_MAX_SHARPNESS 0x6d | ||
623 | #define SDVO_CMD_GET_MAX_TV_CHROMA_FILTER 0x74 | ||
624 | #define SDVO_CMD_GET_MAX_TV_LUMA_FILTER 0x77 | ||
625 | struct psb_intel_sdvo_enhancement_limits_reply { | ||
626 | u16 max_value; | ||
627 | u16 default_value; | ||
628 | } __attribute__((packed)); | ||
629 | |||
630 | #define SDVO_CMD_GET_LVDS_PANEL_INFORMATION 0x7f | ||
631 | #define SDVO_CMD_SET_LVDS_PANEL_INFORMATION 0x80 | ||
632 | # define SDVO_LVDS_COLOR_DEPTH_18 (0 << 0) | ||
633 | # define SDVO_LVDS_COLOR_DEPTH_24 (1 << 0) | ||
634 | # define SDVO_LVDS_CONNECTOR_SPWG (0 << 2) | ||
635 | # define SDVO_LVDS_CONNECTOR_OPENLDI (1 << 2) | ||
636 | # define SDVO_LVDS_SINGLE_CHANNEL (0 << 4) | ||
637 | # define SDVO_LVDS_DUAL_CHANNEL (1 << 4) | ||
638 | |||
639 | #define SDVO_CMD_GET_FLICKER_FILTER 0x4e | ||
640 | #define SDVO_CMD_SET_FLICKER_FILTER 0x4f | ||
641 | #define SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE 0x50 | ||
642 | #define SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE 0x51 | ||
643 | #define SDVO_CMD_GET_FLICKER_FILTER_2D 0x53 | ||
644 | #define SDVO_CMD_SET_FLICKER_FILTER_2D 0x54 | ||
645 | #define SDVO_CMD_GET_SATURATION 0x56 | ||
646 | #define SDVO_CMD_SET_SATURATION 0x57 | ||
647 | #define SDVO_CMD_GET_HUE 0x59 | ||
648 | #define SDVO_CMD_SET_HUE 0x5a | ||
649 | #define SDVO_CMD_GET_BRIGHTNESS 0x5c | ||
650 | #define SDVO_CMD_SET_BRIGHTNESS 0x5d | ||
651 | #define SDVO_CMD_GET_CONTRAST 0x5f | ||
652 | #define SDVO_CMD_SET_CONTRAST 0x60 | ||
653 | #define SDVO_CMD_GET_OVERSCAN_H 0x62 | ||
654 | #define SDVO_CMD_SET_OVERSCAN_H 0x63 | ||
655 | #define SDVO_CMD_GET_OVERSCAN_V 0x65 | ||
656 | #define SDVO_CMD_SET_OVERSCAN_V 0x66 | ||
657 | #define SDVO_CMD_GET_HPOS 0x68 | ||
658 | #define SDVO_CMD_SET_HPOS 0x69 | ||
659 | #define SDVO_CMD_GET_VPOS 0x6b | ||
660 | #define SDVO_CMD_SET_VPOS 0x6c | ||
661 | #define SDVO_CMD_GET_SHARPNESS 0x6e | ||
662 | #define SDVO_CMD_SET_SHARPNESS 0x6f | ||
663 | #define SDVO_CMD_GET_TV_CHROMA_FILTER 0x75 | ||
664 | #define SDVO_CMD_SET_TV_CHROMA_FILTER 0x76 | ||
665 | #define SDVO_CMD_GET_TV_LUMA_FILTER 0x78 | ||
666 | #define SDVO_CMD_SET_TV_LUMA_FILTER 0x79 | ||
667 | struct psb_intel_sdvo_enhancements_arg { | ||
668 | u16 value; | ||
669 | }__attribute__((packed)); | ||
670 | |||
671 | #define SDVO_CMD_GET_DOT_CRAWL 0x70 | ||
672 | #define SDVO_CMD_SET_DOT_CRAWL 0x71 | ||
673 | # define SDVO_DOT_CRAWL_ON (1 << 0) | ||
674 | # define SDVO_DOT_CRAWL_DEFAULT_ON (1 << 1) | ||
675 | |||
676 | #define SDVO_CMD_GET_DITHER 0x72 | ||
677 | #define SDVO_CMD_SET_DITHER 0x73 | ||
678 | # define SDVO_DITHER_ON (1 << 0) | ||
679 | # define SDVO_DITHER_DEFAULT_ON (1 << 1) | ||
680 | |||
681 | #define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a | ||
682 | # define SDVO_CONTROL_BUS_PROM (1 << 0) | ||
683 | # define SDVO_CONTROL_BUS_DDC1 (1 << 1) | ||
684 | # define SDVO_CONTROL_BUS_DDC2 (1 << 2) | ||
685 | # define SDVO_CONTROL_BUS_DDC3 (1 << 3) | ||
686 | |||
687 | /* HDMI op codes */ | ||
688 | #define SDVO_CMD_GET_SUPP_ENCODE 0x9d | ||
689 | #define SDVO_CMD_GET_ENCODE 0x9e | ||
690 | #define SDVO_CMD_SET_ENCODE 0x9f | ||
691 | #define SDVO_ENCODE_DVI 0x0 | ||
692 | #define SDVO_ENCODE_HDMI 0x1 | ||
693 | #define SDVO_CMD_SET_PIXEL_REPLI 0x8b | ||
694 | #define SDVO_CMD_GET_PIXEL_REPLI 0x8c | ||
695 | #define SDVO_CMD_GET_COLORIMETRY_CAP 0x8d | ||
696 | #define SDVO_CMD_SET_COLORIMETRY 0x8e | ||
697 | #define SDVO_COLORIMETRY_RGB256 0x0 | ||
698 | #define SDVO_COLORIMETRY_RGB220 0x1 | ||
699 | #define SDVO_COLORIMETRY_YCrCb422 0x3 | ||
700 | #define SDVO_COLORIMETRY_YCrCb444 0x4 | ||
701 | #define SDVO_CMD_GET_COLORIMETRY 0x8f | ||
702 | #define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90 | ||
703 | #define SDVO_CMD_SET_AUDIO_STAT 0x91 | ||
704 | #define SDVO_CMD_GET_AUDIO_STAT 0x92 | ||
705 | #define SDVO_CMD_SET_HBUF_INDEX 0x93 | ||
706 | #define SDVO_CMD_GET_HBUF_INDEX 0x94 | ||
707 | #define SDVO_CMD_GET_HBUF_INFO 0x95 | ||
708 | #define SDVO_CMD_SET_HBUF_AV_SPLIT 0x96 | ||
709 | #define SDVO_CMD_GET_HBUF_AV_SPLIT 0x97 | ||
710 | #define SDVO_CMD_SET_HBUF_DATA 0x98 | ||
711 | #define SDVO_CMD_GET_HBUF_DATA 0x99 | ||
712 | #define SDVO_CMD_SET_HBUF_TXRATE 0x9a | ||
713 | #define SDVO_CMD_GET_HBUF_TXRATE 0x9b | ||
714 | #define SDVO_HBUF_TX_DISABLED (0 << 6) | ||
715 | #define SDVO_HBUF_TX_ONCE (2 << 6) | ||
716 | #define SDVO_HBUF_TX_VSYNC (3 << 6) | ||
717 | #define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c | ||
718 | #define SDVO_NEED_TO_STALL (1 << 7) | ||
719 | |||
720 | struct psb_intel_sdvo_encode { | ||
721 | u8 dvi_rev; | ||
722 | u8 hdmi_rev; | ||
723 | } __attribute__ ((packed)); | ||
diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c new file mode 100644 index 00000000000..7be802baceb --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_irq.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007, 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 | * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to | ||
19 | * develop this driver. | ||
20 | * | ||
21 | **************************************************************************/ | ||
22 | /* | ||
23 | */ | ||
24 | |||
25 | #include <drm/drmP.h> | ||
26 | #include "psb_drv.h" | ||
27 | #include "psb_reg.h" | ||
28 | #include "psb_intel_reg.h" | ||
29 | #include "power.h" | ||
30 | |||
31 | /* | ||
32 | * inline functions | ||
33 | */ | ||
34 | |||
35 | static inline u32 | ||
36 | psb_pipestat(int pipe) | ||
37 | { | ||
38 | if (pipe == 0) | ||
39 | return PIPEASTAT; | ||
40 | if (pipe == 1) | ||
41 | return PIPEBSTAT; | ||
42 | if (pipe == 2) | ||
43 | return PIPECSTAT; | ||
44 | BUG(); | ||
45 | } | ||
46 | |||
47 | static inline u32 | ||
48 | mid_pipe_event(int pipe) | ||
49 | { | ||
50 | if (pipe == 0) | ||
51 | return _PSB_PIPEA_EVENT_FLAG; | ||
52 | if (pipe == 1) | ||
53 | return _MDFLD_PIPEB_EVENT_FLAG; | ||
54 | if (pipe == 2) | ||
55 | return _MDFLD_PIPEC_EVENT_FLAG; | ||
56 | BUG(); | ||
57 | } | ||
58 | |||
59 | static inline u32 | ||
60 | mid_pipe_vsync(int pipe) | ||
61 | { | ||
62 | if (pipe == 0) | ||
63 | return _PSB_VSYNC_PIPEA_FLAG; | ||
64 | if (pipe == 1) | ||
65 | return _PSB_VSYNC_PIPEB_FLAG; | ||
66 | if (pipe == 2) | ||
67 | return _MDFLD_PIPEC_VBLANK_FLAG; | ||
68 | BUG(); | ||
69 | } | ||
70 | |||
71 | static inline u32 | ||
72 | mid_pipeconf(int pipe) | ||
73 | { | ||
74 | if (pipe == 0) | ||
75 | return PIPEACONF; | ||
76 | if (pipe == 1) | ||
77 | return PIPEBCONF; | ||
78 | if (pipe == 2) | ||
79 | return PIPECCONF; | ||
80 | BUG(); | ||
81 | } | ||
82 | |||
83 | void | ||
84 | psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask) | ||
85 | { | ||
86 | if ((dev_priv->pipestat[pipe] & mask) != mask) { | ||
87 | u32 reg = psb_pipestat(pipe); | ||
88 | dev_priv->pipestat[pipe] |= mask; | ||
89 | /* Enable the interrupt, clear any pending status */ | ||
90 | if (gma_power_begin(dev_priv->dev, false)) { | ||
91 | u32 writeVal = PSB_RVDC32(reg); | ||
92 | writeVal |= (mask | (mask >> 16)); | ||
93 | PSB_WVDC32(writeVal, reg); | ||
94 | (void) PSB_RVDC32(reg); | ||
95 | gma_power_end(dev_priv->dev); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | void | ||
101 | psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask) | ||
102 | { | ||
103 | if ((dev_priv->pipestat[pipe] & mask) != 0) { | ||
104 | u32 reg = psb_pipestat(pipe); | ||
105 | dev_priv->pipestat[pipe] &= ~mask; | ||
106 | if (gma_power_begin(dev_priv->dev, false)) { | ||
107 | u32 writeVal = PSB_RVDC32(reg); | ||
108 | writeVal &= ~mask; | ||
109 | PSB_WVDC32(writeVal, reg); | ||
110 | (void) PSB_RVDC32(reg); | ||
111 | gma_power_end(dev_priv->dev); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe) | ||
117 | { | ||
118 | if (gma_power_begin(dev_priv->dev, false)) { | ||
119 | u32 pipe_event = mid_pipe_event(pipe); | ||
120 | dev_priv->vdc_irq_mask |= pipe_event; | ||
121 | PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); | ||
122 | PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); | ||
123 | gma_power_end(dev_priv->dev); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | void mid_disable_pipe_event(struct drm_psb_private *dev_priv, int pipe) | ||
128 | { | ||
129 | if (dev_priv->pipestat[pipe] == 0) { | ||
130 | if (gma_power_begin(dev_priv->dev, false)) { | ||
131 | u32 pipe_event = mid_pipe_event(pipe); | ||
132 | dev_priv->vdc_irq_mask &= ~pipe_event; | ||
133 | PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); | ||
134 | PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); | ||
135 | gma_power_end(dev_priv->dev); | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * Display controller interrupt handler for pipe event. | ||
142 | * | ||
143 | */ | ||
144 | static void mid_pipe_event_handler(struct drm_device *dev, int pipe) | ||
145 | { | ||
146 | struct drm_psb_private *dev_priv = | ||
147 | (struct drm_psb_private *) dev->dev_private; | ||
148 | |||
149 | uint32_t pipe_stat_val = 0; | ||
150 | uint32_t pipe_stat_reg = psb_pipestat(pipe); | ||
151 | uint32_t pipe_enable = dev_priv->pipestat[pipe]; | ||
152 | uint32_t pipe_status = dev_priv->pipestat[pipe] >> 16; | ||
153 | uint32_t pipe_clear; | ||
154 | uint32_t i = 0; | ||
155 | |||
156 | spin_lock(&dev_priv->irqmask_lock); | ||
157 | |||
158 | pipe_stat_val = PSB_RVDC32(pipe_stat_reg); | ||
159 | pipe_stat_val &= pipe_enable | pipe_status; | ||
160 | pipe_stat_val &= pipe_stat_val >> 16; | ||
161 | |||
162 | spin_unlock(&dev_priv->irqmask_lock); | ||
163 | |||
164 | /* Clear the 2nd level interrupt status bits | ||
165 | * Sometimes the bits are very sticky so we repeat until they unstick */ | ||
166 | for (i = 0; i < 0xffff; i++) { | ||
167 | PSB_WVDC32(PSB_RVDC32(pipe_stat_reg), pipe_stat_reg); | ||
168 | pipe_clear = PSB_RVDC32(pipe_stat_reg) & pipe_status; | ||
169 | |||
170 | if (pipe_clear == 0) | ||
171 | break; | ||
172 | } | ||
173 | |||
174 | if (pipe_clear) | ||
175 | dev_err(dev->dev, | ||
176 | "%s, can't clear status bits for pipe %d, its value = 0x%x.\n", | ||
177 | __func__, pipe, PSB_RVDC32(pipe_stat_reg)); | ||
178 | |||
179 | if (pipe_stat_val & PIPE_VBLANK_STATUS) | ||
180 | drm_handle_vblank(dev, pipe); | ||
181 | |||
182 | if (pipe_stat_val & PIPE_TE_STATUS) | ||
183 | drm_handle_vblank(dev, pipe); | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Display controller interrupt handler. | ||
188 | */ | ||
189 | static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat) | ||
190 | { | ||
191 | if (vdc_stat & _PSB_VSYNC_PIPEA_FLAG) | ||
192 | mid_pipe_event_handler(dev, 0); | ||
193 | |||
194 | if (vdc_stat & _PSB_VSYNC_PIPEB_FLAG) | ||
195 | mid_pipe_event_handler(dev, 1); | ||
196 | } | ||
197 | |||
198 | irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) | ||
199 | { | ||
200 | struct drm_device *dev = (struct drm_device *) arg; | ||
201 | struct drm_psb_private *dev_priv = | ||
202 | (struct drm_psb_private *) dev->dev_private; | ||
203 | |||
204 | uint32_t vdc_stat, dsp_int = 0, sgx_int = 0; | ||
205 | int handled = 0; | ||
206 | |||
207 | spin_lock(&dev_priv->irqmask_lock); | ||
208 | |||
209 | vdc_stat = PSB_RVDC32(PSB_INT_IDENTITY_R); | ||
210 | |||
211 | if (vdc_stat & _PSB_PIPE_EVENT_FLAG) | ||
212 | dsp_int = 1; | ||
213 | |||
214 | /* FIXME: Handle Medfield | ||
215 | if (vdc_stat & _MDFLD_DISP_ALL_IRQ_FLAG) | ||
216 | dsp_int = 1; | ||
217 | */ | ||
218 | |||
219 | if (vdc_stat & _PSB_IRQ_SGX_FLAG) | ||
220 | sgx_int = 1; | ||
221 | |||
222 | vdc_stat &= dev_priv->vdc_irq_mask; | ||
223 | spin_unlock(&dev_priv->irqmask_lock); | ||
224 | |||
225 | if (dsp_int && gma_power_is_on(dev)) { | ||
226 | psb_vdc_interrupt(dev, vdc_stat); | ||
227 | handled = 1; | ||
228 | } | ||
229 | |||
230 | if (sgx_int) { | ||
231 | /* Not expected - we have it masked, shut it up */ | ||
232 | u32 s, s2; | ||
233 | s = PSB_RSGX32(PSB_CR_EVENT_STATUS); | ||
234 | s2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2); | ||
235 | PSB_WSGX32(s, PSB_CR_EVENT_HOST_CLEAR); | ||
236 | PSB_WSGX32(s2, PSB_CR_EVENT_HOST_CLEAR2); | ||
237 | /* if s & _PSB_CE_TWOD_COMPLETE we have 2D done but | ||
238 | we may as well poll even if we add that ! */ | ||
239 | handled = 1; | ||
240 | } | ||
241 | |||
242 | PSB_WVDC32(vdc_stat, PSB_INT_IDENTITY_R); | ||
243 | (void) PSB_RVDC32(PSB_INT_IDENTITY_R); | ||
244 | DRM_READMEMORYBARRIER(); | ||
245 | |||
246 | if (!handled) | ||
247 | return IRQ_NONE; | ||
248 | |||
249 | return IRQ_HANDLED; | ||
250 | } | ||
251 | |||
252 | void psb_irq_preinstall(struct drm_device *dev) | ||
253 | { | ||
254 | struct drm_psb_private *dev_priv = | ||
255 | (struct drm_psb_private *) dev->dev_private; | ||
256 | unsigned long irqflags; | ||
257 | |||
258 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
259 | |||
260 | if (gma_power_is_on(dev)) | ||
261 | PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); | ||
262 | if (dev->vblank_enabled[0]) | ||
263 | dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG; | ||
264 | if (dev->vblank_enabled[1]) | ||
265 | dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEB_FLAG; | ||
266 | |||
267 | /* FIXME: Handle Medfield irq mask | ||
268 | if (dev->vblank_enabled[1]) | ||
269 | dev_priv->vdc_irq_mask |= _MDFLD_PIPEB_EVENT_FLAG; | ||
270 | if (dev->vblank_enabled[2]) | ||
271 | dev_priv->vdc_irq_mask |= _MDFLD_PIPEC_EVENT_FLAG; | ||
272 | */ | ||
273 | |||
274 | /* This register is safe even if display island is off */ | ||
275 | PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); | ||
276 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
277 | } | ||
278 | |||
279 | int psb_irq_postinstall(struct drm_device *dev) | ||
280 | { | ||
281 | struct drm_psb_private *dev_priv = | ||
282 | (struct drm_psb_private *) dev->dev_private; | ||
283 | unsigned long irqflags; | ||
284 | |||
285 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
286 | |||
287 | /* This register is safe even if display island is off */ | ||
288 | PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); | ||
289 | PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); | ||
290 | |||
291 | if (dev->vblank_enabled[0]) | ||
292 | psb_enable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
293 | else | ||
294 | psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
295 | |||
296 | if (dev->vblank_enabled[1]) | ||
297 | psb_enable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
298 | else | ||
299 | psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
300 | |||
301 | if (dev->vblank_enabled[2]) | ||
302 | psb_enable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
303 | else | ||
304 | psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
305 | |||
306 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | void psb_irq_uninstall(struct drm_device *dev) | ||
311 | { | ||
312 | struct drm_psb_private *dev_priv = | ||
313 | (struct drm_psb_private *) dev->dev_private; | ||
314 | unsigned long irqflags; | ||
315 | |||
316 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
317 | |||
318 | PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); | ||
319 | |||
320 | if (dev->vblank_enabled[0]) | ||
321 | psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
322 | |||
323 | if (dev->vblank_enabled[1]) | ||
324 | psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
325 | |||
326 | if (dev->vblank_enabled[2]) | ||
327 | psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
328 | |||
329 | dev_priv->vdc_irq_mask &= _PSB_IRQ_SGX_FLAG | | ||
330 | _PSB_IRQ_MSVDX_FLAG | | ||
331 | _LNC_IRQ_TOPAZ_FLAG; | ||
332 | |||
333 | /* These two registers are safe even if display island is off */ | ||
334 | PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); | ||
335 | PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); | ||
336 | |||
337 | wmb(); | ||
338 | |||
339 | /* This register is safe even if display island is off */ | ||
340 | PSB_WVDC32(PSB_RVDC32(PSB_INT_IDENTITY_R), PSB_INT_IDENTITY_R); | ||
341 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
342 | } | ||
343 | |||
344 | void psb_irq_turn_on_dpst(struct drm_device *dev) | ||
345 | { | ||
346 | struct drm_psb_private *dev_priv = | ||
347 | (struct drm_psb_private *) dev->dev_private; | ||
348 | u32 hist_reg; | ||
349 | u32 pwm_reg; | ||
350 | |||
351 | if (gma_power_begin(dev, false)) { | ||
352 | PSB_WVDC32(1 << 31, HISTOGRAM_LOGIC_CONTROL); | ||
353 | hist_reg = PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL); | ||
354 | PSB_WVDC32(1 << 31, HISTOGRAM_INT_CONTROL); | ||
355 | hist_reg = PSB_RVDC32(HISTOGRAM_INT_CONTROL); | ||
356 | |||
357 | PSB_WVDC32(0x80010100, PWM_CONTROL_LOGIC); | ||
358 | pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); | ||
359 | PSB_WVDC32(pwm_reg | PWM_PHASEIN_ENABLE | ||
360 | | PWM_PHASEIN_INT_ENABLE, | ||
361 | PWM_CONTROL_LOGIC); | ||
362 | pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); | ||
363 | |||
364 | psb_enable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE); | ||
365 | |||
366 | hist_reg = PSB_RVDC32(HISTOGRAM_INT_CONTROL); | ||
367 | PSB_WVDC32(hist_reg | HISTOGRAM_INT_CTRL_CLEAR, | ||
368 | HISTOGRAM_INT_CONTROL); | ||
369 | pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); | ||
370 | PSB_WVDC32(pwm_reg | 0x80010100 | PWM_PHASEIN_ENABLE, | ||
371 | PWM_CONTROL_LOGIC); | ||
372 | |||
373 | gma_power_end(dev); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | int psb_irq_enable_dpst(struct drm_device *dev) | ||
378 | { | ||
379 | struct drm_psb_private *dev_priv = | ||
380 | (struct drm_psb_private *) dev->dev_private; | ||
381 | unsigned long irqflags; | ||
382 | |||
383 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
384 | |||
385 | /* enable DPST */ | ||
386 | mid_enable_pipe_event(dev_priv, 0); | ||
387 | psb_irq_turn_on_dpst(dev); | ||
388 | |||
389 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | void psb_irq_turn_off_dpst(struct drm_device *dev) | ||
394 | { | ||
395 | struct drm_psb_private *dev_priv = | ||
396 | (struct drm_psb_private *) dev->dev_private; | ||
397 | u32 hist_reg; | ||
398 | u32 pwm_reg; | ||
399 | |||
400 | if (gma_power_begin(dev, false)) { | ||
401 | PSB_WVDC32(0x00000000, HISTOGRAM_INT_CONTROL); | ||
402 | hist_reg = PSB_RVDC32(HISTOGRAM_INT_CONTROL); | ||
403 | |||
404 | psb_disable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE); | ||
405 | |||
406 | pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); | ||
407 | PSB_WVDC32(pwm_reg & !(PWM_PHASEIN_INT_ENABLE), | ||
408 | PWM_CONTROL_LOGIC); | ||
409 | pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); | ||
410 | |||
411 | gma_power_end(dev); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | int psb_irq_disable_dpst(struct drm_device *dev) | ||
416 | { | ||
417 | struct drm_psb_private *dev_priv = | ||
418 | (struct drm_psb_private *) dev->dev_private; | ||
419 | unsigned long irqflags; | ||
420 | |||
421 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
422 | |||
423 | mid_disable_pipe_event(dev_priv, 0); | ||
424 | psb_irq_turn_off_dpst(dev); | ||
425 | |||
426 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | #ifdef PSB_FIXME | ||
432 | static int psb_vblank_do_wait(struct drm_device *dev, | ||
433 | unsigned int *sequence, atomic_t *counter) | ||
434 | { | ||
435 | unsigned int cur_vblank; | ||
436 | int ret = 0; | ||
437 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
438 | (((cur_vblank = atomic_read(counter)) | ||
439 | - *sequence) <= (1 << 23))); | ||
440 | *sequence = cur_vblank; | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | #endif | ||
445 | |||
446 | /* | ||
447 | * It is used to enable VBLANK interrupt | ||
448 | */ | ||
449 | int psb_enable_vblank(struct drm_device *dev, int pipe) | ||
450 | { | ||
451 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
452 | unsigned long irqflags; | ||
453 | uint32_t reg_val = 0; | ||
454 | uint32_t pipeconf_reg = mid_pipeconf(pipe); | ||
455 | |||
456 | if (gma_power_begin(dev, false)) { | ||
457 | reg_val = REG_READ(pipeconf_reg); | ||
458 | gma_power_end(dev); | ||
459 | } | ||
460 | |||
461 | if (!(reg_val & PIPEACONF_ENABLE)) | ||
462 | return -EINVAL; | ||
463 | |||
464 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
465 | |||
466 | if (pipe == 0) | ||
467 | dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG; | ||
468 | else if (pipe == 1) | ||
469 | dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEB_FLAG; | ||
470 | |||
471 | PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); | ||
472 | PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); | ||
473 | psb_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
474 | |||
475 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * It is used to disable VBLANK interrupt | ||
482 | */ | ||
483 | void psb_disable_vblank(struct drm_device *dev, int pipe) | ||
484 | { | ||
485 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
486 | unsigned long irqflags; | ||
487 | |||
488 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
489 | |||
490 | if (pipe == 0) | ||
491 | dev_priv->vdc_irq_mask &= ~_PSB_VSYNC_PIPEA_FLAG; | ||
492 | else if (pipe == 1) | ||
493 | dev_priv->vdc_irq_mask &= ~_PSB_VSYNC_PIPEB_FLAG; | ||
494 | |||
495 | PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); | ||
496 | PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); | ||
497 | psb_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); | ||
498 | |||
499 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
500 | } | ||
501 | |||
502 | /* Called from drm generic code, passed a 'crtc', which | ||
503 | * we use as a pipe index | ||
504 | */ | ||
505 | u32 psb_get_vblank_counter(struct drm_device *dev, int pipe) | ||
506 | { | ||
507 | uint32_t high_frame = PIPEAFRAMEHIGH; | ||
508 | uint32_t low_frame = PIPEAFRAMEPIXEL; | ||
509 | uint32_t pipeconf_reg = PIPEACONF; | ||
510 | uint32_t reg_val = 0; | ||
511 | uint32_t high1 = 0, high2 = 0, low = 0, count = 0; | ||
512 | |||
513 | switch (pipe) { | ||
514 | case 0: | ||
515 | break; | ||
516 | case 1: | ||
517 | high_frame = PIPEBFRAMEHIGH; | ||
518 | low_frame = PIPEBFRAMEPIXEL; | ||
519 | pipeconf_reg = PIPEBCONF; | ||
520 | break; | ||
521 | case 2: | ||
522 | high_frame = PIPECFRAMEHIGH; | ||
523 | low_frame = PIPECFRAMEPIXEL; | ||
524 | pipeconf_reg = PIPECCONF; | ||
525 | break; | ||
526 | default: | ||
527 | dev_err(dev->dev, "%s, invalid pipe.\n", __func__); | ||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | if (!gma_power_begin(dev, false)) | ||
532 | return 0; | ||
533 | |||
534 | reg_val = REG_READ(pipeconf_reg); | ||
535 | |||
536 | if (!(reg_val & PIPEACONF_ENABLE)) { | ||
537 | dev_err(dev->dev, "trying to get vblank count for disabled pipe %d\n", | ||
538 | pipe); | ||
539 | goto psb_get_vblank_counter_exit; | ||
540 | } | ||
541 | |||
542 | /* | ||
543 | * High & low register fields aren't synchronized, so make sure | ||
544 | * we get a low value that's stable across two reads of the high | ||
545 | * register. | ||
546 | */ | ||
547 | do { | ||
548 | high1 = ((REG_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
549 | PIPE_FRAME_HIGH_SHIFT); | ||
550 | low = ((REG_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> | ||
551 | PIPE_FRAME_LOW_SHIFT); | ||
552 | high2 = ((REG_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
553 | PIPE_FRAME_HIGH_SHIFT); | ||
554 | } while (high1 != high2); | ||
555 | |||
556 | count = (high1 << 8) | low; | ||
557 | |||
558 | psb_get_vblank_counter_exit: | ||
559 | |||
560 | gma_power_end(dev); | ||
561 | |||
562 | return count; | ||
563 | } | ||
564 | |||
diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h new file mode 100644 index 00000000000..216fda38b57 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_irq.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2009-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 | * Authors: | ||
19 | * Benjamin Defnet <benjamin.r.defnet@intel.com> | ||
20 | * Rajesh Poornachandran <rajesh.poornachandran@intel.com> | ||
21 | * | ||
22 | **************************************************************************/ | ||
23 | |||
24 | #ifndef _SYSIRQ_H_ | ||
25 | #define _SYSIRQ_H_ | ||
26 | |||
27 | #include <drm/drmP.h> | ||
28 | |||
29 | bool sysirq_init(struct drm_device *dev); | ||
30 | void sysirq_uninit(struct drm_device *dev); | ||
31 | |||
32 | void psb_irq_preinstall(struct drm_device *dev); | ||
33 | int psb_irq_postinstall(struct drm_device *dev); | ||
34 | void psb_irq_uninstall(struct drm_device *dev); | ||
35 | irqreturn_t psb_irq_handler(DRM_IRQ_ARGS); | ||
36 | |||
37 | int psb_irq_enable_dpst(struct drm_device *dev); | ||
38 | int psb_irq_disable_dpst(struct drm_device *dev); | ||
39 | void psb_irq_turn_on_dpst(struct drm_device *dev); | ||
40 | void psb_irq_turn_off_dpst(struct drm_device *dev); | ||
41 | int psb_enable_vblank(struct drm_device *dev, int pipe); | ||
42 | void psb_disable_vblank(struct drm_device *dev, int pipe); | ||
43 | u32 psb_get_vblank_counter(struct drm_device *dev, int pipe); | ||
44 | |||
45 | #endif /* _SYSIRQ_H_ */ | ||
diff --git a/drivers/gpu/drm/gma500/psb_lid.c b/drivers/gpu/drm/gma500/psb_lid.c new file mode 100644 index 00000000000..b867aabe6bf --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_lid.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007, Intel Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> | ||
18 | **************************************************************************/ | ||
19 | |||
20 | #include <drm/drmP.h> | ||
21 | #include "psb_drv.h" | ||
22 | #include "psb_reg.h" | ||
23 | #include "psb_intel_reg.h" | ||
24 | #include <linux/spinlock.h> | ||
25 | |||
26 | static void psb_lid_timer_func(unsigned long data) | ||
27 | { | ||
28 | struct drm_psb_private * dev_priv = (struct drm_psb_private *)data; | ||
29 | struct drm_device *dev = (struct drm_device *)dev_priv->dev; | ||
30 | struct timer_list *lid_timer = &dev_priv->lid_timer; | ||
31 | unsigned long irq_flags; | ||
32 | u32 *lid_state = dev_priv->lid_state; | ||
33 | u32 pp_status; | ||
34 | |||
35 | if (readl(lid_state) == dev_priv->lid_last_state) | ||
36 | goto lid_timer_schedule; | ||
37 | |||
38 | if ((readl(lid_state)) & 0x01) { | ||
39 | /*lid state is open*/ | ||
40 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | POWER_TARGET_ON); | ||
41 | do { | ||
42 | pp_status = REG_READ(PP_STATUS); | ||
43 | } while ((pp_status & PP_ON) == 0); | ||
44 | |||
45 | /*FIXME: should be backlight level before*/ | ||
46 | psb_intel_lvds_set_brightness(dev, 100); | ||
47 | } else { | ||
48 | psb_intel_lvds_set_brightness(dev, 0); | ||
49 | |||
50 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & ~POWER_TARGET_ON); | ||
51 | do { | ||
52 | pp_status = REG_READ(PP_STATUS); | ||
53 | } while ((pp_status & PP_ON) == 0); | ||
54 | } | ||
55 | dev_priv->lid_last_state = readl(lid_state); | ||
56 | |||
57 | lid_timer_schedule: | ||
58 | spin_lock_irqsave(&dev_priv->lid_lock, irq_flags); | ||
59 | if (!timer_pending(lid_timer)) { | ||
60 | lid_timer->expires = jiffies + PSB_LID_DELAY; | ||
61 | add_timer(lid_timer); | ||
62 | } | ||
63 | spin_unlock_irqrestore(&dev_priv->lid_lock, irq_flags); | ||
64 | } | ||
65 | |||
66 | void psb_lid_timer_init(struct drm_psb_private *dev_priv) | ||
67 | { | ||
68 | struct timer_list *lid_timer = &dev_priv->lid_timer; | ||
69 | unsigned long irq_flags; | ||
70 | |||
71 | spin_lock_init(&dev_priv->lid_lock); | ||
72 | spin_lock_irqsave(&dev_priv->lid_lock, irq_flags); | ||
73 | |||
74 | init_timer(lid_timer); | ||
75 | |||
76 | lid_timer->data = (unsigned long)dev_priv; | ||
77 | lid_timer->function = psb_lid_timer_func; | ||
78 | lid_timer->expires = jiffies + PSB_LID_DELAY; | ||
79 | |||
80 | add_timer(lid_timer); | ||
81 | spin_unlock_irqrestore(&dev_priv->lid_lock, irq_flags); | ||
82 | } | ||
83 | |||
84 | void psb_lid_timer_takedown(struct drm_psb_private *dev_priv) | ||
85 | { | ||
86 | del_timer_sync(&dev_priv->lid_timer); | ||
87 | } | ||
88 | |||
diff --git a/drivers/gpu/drm/gma500/psb_reg.h b/drivers/gpu/drm/gma500/psb_reg.h new file mode 100644 index 00000000000..b81c7c1e9c2 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_reg.h | |||
@@ -0,0 +1,582 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright (c) (2005-2007) Imagination Technologies Limited. | ||
4 | * Copyright (c) 2007, Intel Corporation. | ||
5 | * All Rights Reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.. | ||
19 | * | ||
20 | **************************************************************************/ | ||
21 | |||
22 | #ifndef _PSB_REG_H_ | ||
23 | #define _PSB_REG_H_ | ||
24 | |||
25 | #define PSB_CR_CLKGATECTL 0x0000 | ||
26 | #define _PSB_C_CLKGATECTL_AUTO_MAN_REG (1 << 24) | ||
27 | #define _PSB_C_CLKGATECTL_USE_CLKG_SHIFT (20) | ||
28 | #define _PSB_C_CLKGATECTL_USE_CLKG_MASK (0x3 << 20) | ||
29 | #define _PSB_C_CLKGATECTL_DPM_CLKG_SHIFT (16) | ||
30 | #define _PSB_C_CLKGATECTL_DPM_CLKG_MASK (0x3 << 16) | ||
31 | #define _PSB_C_CLKGATECTL_TA_CLKG_SHIFT (12) | ||
32 | #define _PSB_C_CLKGATECTL_TA_CLKG_MASK (0x3 << 12) | ||
33 | #define _PSB_C_CLKGATECTL_TSP_CLKG_SHIFT (8) | ||
34 | #define _PSB_C_CLKGATECTL_TSP_CLKG_MASK (0x3 << 8) | ||
35 | #define _PSB_C_CLKGATECTL_ISP_CLKG_SHIFT (4) | ||
36 | #define _PSB_C_CLKGATECTL_ISP_CLKG_MASK (0x3 << 4) | ||
37 | #define _PSB_C_CLKGATECTL_2D_CLKG_SHIFT (0) | ||
38 | #define _PSB_C_CLKGATECTL_2D_CLKG_MASK (0x3 << 0) | ||
39 | #define _PSB_C_CLKGATECTL_CLKG_ENABLED (0) | ||
40 | #define _PSB_C_CLKGATECTL_CLKG_DISABLED (1) | ||
41 | #define _PSB_C_CLKGATECTL_CLKG_AUTO (2) | ||
42 | |||
43 | #define PSB_CR_CORE_ID 0x0010 | ||
44 | #define _PSB_CC_ID_ID_SHIFT (16) | ||
45 | #define _PSB_CC_ID_ID_MASK (0xFFFF << 16) | ||
46 | #define _PSB_CC_ID_CONFIG_SHIFT (0) | ||
47 | #define _PSB_CC_ID_CONFIG_MASK (0xFFFF << 0) | ||
48 | |||
49 | #define PSB_CR_CORE_REVISION 0x0014 | ||
50 | #define _PSB_CC_REVISION_DESIGNER_SHIFT (24) | ||
51 | #define _PSB_CC_REVISION_DESIGNER_MASK (0xFF << 24) | ||
52 | #define _PSB_CC_REVISION_MAJOR_SHIFT (16) | ||
53 | #define _PSB_CC_REVISION_MAJOR_MASK (0xFF << 16) | ||
54 | #define _PSB_CC_REVISION_MINOR_SHIFT (8) | ||
55 | #define _PSB_CC_REVISION_MINOR_MASK (0xFF << 8) | ||
56 | #define _PSB_CC_REVISION_MAINTENANCE_SHIFT (0) | ||
57 | #define _PSB_CC_REVISION_MAINTENANCE_MASK (0xFF << 0) | ||
58 | |||
59 | #define PSB_CR_DESIGNER_REV_FIELD1 0x0018 | ||
60 | |||
61 | #define PSB_CR_SOFT_RESET 0x0080 | ||
62 | #define _PSB_CS_RESET_TSP_RESET (1 << 6) | ||
63 | #define _PSB_CS_RESET_ISP_RESET (1 << 5) | ||
64 | #define _PSB_CS_RESET_USE_RESET (1 << 4) | ||
65 | #define _PSB_CS_RESET_TA_RESET (1 << 3) | ||
66 | #define _PSB_CS_RESET_DPM_RESET (1 << 2) | ||
67 | #define _PSB_CS_RESET_TWOD_RESET (1 << 1) | ||
68 | #define _PSB_CS_RESET_BIF_RESET (1 << 0) | ||
69 | |||
70 | #define PSB_CR_DESIGNER_REV_FIELD2 0x001C | ||
71 | |||
72 | #define PSB_CR_EVENT_HOST_ENABLE2 0x0110 | ||
73 | |||
74 | #define PSB_CR_EVENT_STATUS2 0x0118 | ||
75 | |||
76 | #define PSB_CR_EVENT_HOST_CLEAR2 0x0114 | ||
77 | #define _PSB_CE2_BIF_REQUESTER_FAULT (1 << 4) | ||
78 | |||
79 | #define PSB_CR_EVENT_STATUS 0x012C | ||
80 | |||
81 | #define PSB_CR_EVENT_HOST_ENABLE 0x0130 | ||
82 | |||
83 | #define PSB_CR_EVENT_HOST_CLEAR 0x0134 | ||
84 | #define _PSB_CE_MASTER_INTERRUPT (1 << 31) | ||
85 | #define _PSB_CE_TA_DPM_FAULT (1 << 28) | ||
86 | #define _PSB_CE_TWOD_COMPLETE (1 << 27) | ||
87 | #define _PSB_CE_DPM_OUT_OF_MEMORY_ZLS (1 << 25) | ||
88 | #define _PSB_CE_DPM_TA_MEM_FREE (1 << 24) | ||
89 | #define _PSB_CE_PIXELBE_END_RENDER (1 << 18) | ||
90 | #define _PSB_CE_SW_EVENT (1 << 14) | ||
91 | #define _PSB_CE_TA_FINISHED (1 << 13) | ||
92 | #define _PSB_CE_TA_TERMINATE (1 << 12) | ||
93 | #define _PSB_CE_DPM_REACHED_MEM_THRESH (1 << 3) | ||
94 | #define _PSB_CE_DPM_OUT_OF_MEMORY_GBL (1 << 2) | ||
95 | #define _PSB_CE_DPM_OUT_OF_MEMORY_MT (1 << 1) | ||
96 | #define _PSB_CE_DPM_3D_MEM_FREE (1 << 0) | ||
97 | |||
98 | |||
99 | #define PSB_USE_OFFSET_MASK 0x0007FFFF | ||
100 | #define PSB_USE_OFFSET_SIZE (PSB_USE_OFFSET_MASK + 1) | ||
101 | #define PSB_CR_USE_CODE_BASE0 0x0A0C | ||
102 | #define PSB_CR_USE_CODE_BASE1 0x0A10 | ||
103 | #define PSB_CR_USE_CODE_BASE2 0x0A14 | ||
104 | #define PSB_CR_USE_CODE_BASE3 0x0A18 | ||
105 | #define PSB_CR_USE_CODE_BASE4 0x0A1C | ||
106 | #define PSB_CR_USE_CODE_BASE5 0x0A20 | ||
107 | #define PSB_CR_USE_CODE_BASE6 0x0A24 | ||
108 | #define PSB_CR_USE_CODE_BASE7 0x0A28 | ||
109 | #define PSB_CR_USE_CODE_BASE8 0x0A2C | ||
110 | #define PSB_CR_USE_CODE_BASE9 0x0A30 | ||
111 | #define PSB_CR_USE_CODE_BASE10 0x0A34 | ||
112 | #define PSB_CR_USE_CODE_BASE11 0x0A38 | ||
113 | #define PSB_CR_USE_CODE_BASE12 0x0A3C | ||
114 | #define PSB_CR_USE_CODE_BASE13 0x0A40 | ||
115 | #define PSB_CR_USE_CODE_BASE14 0x0A44 | ||
116 | #define PSB_CR_USE_CODE_BASE15 0x0A48 | ||
117 | #define PSB_CR_USE_CODE_BASE(_i) (0x0A0C + ((_i) << 2)) | ||
118 | #define _PSB_CUC_BASE_DM_SHIFT (25) | ||
119 | #define _PSB_CUC_BASE_DM_MASK (0x3 << 25) | ||
120 | #define _PSB_CUC_BASE_ADDR_SHIFT (0) /* 1024-bit aligned address? */ | ||
121 | #define _PSB_CUC_BASE_ADDR_ALIGNSHIFT (7) | ||
122 | #define _PSB_CUC_BASE_ADDR_MASK (0x1FFFFFF << 0) | ||
123 | #define _PSB_CUC_DM_VERTEX (0) | ||
124 | #define _PSB_CUC_DM_PIXEL (1) | ||
125 | #define _PSB_CUC_DM_RESERVED (2) | ||
126 | #define _PSB_CUC_DM_EDM (3) | ||
127 | |||
128 | #define PSB_CR_PDS_EXEC_BASE 0x0AB8 | ||
129 | #define _PSB_CR_PDS_EXEC_BASE_ADDR_SHIFT (20) /* 1MB aligned address */ | ||
130 | #define _PSB_CR_PDS_EXEC_BASE_ADDR_ALIGNSHIFT (20) | ||
131 | |||
132 | #define PSB_CR_EVENT_KICKER 0x0AC4 | ||
133 | #define _PSB_CE_KICKER_ADDRESS_SHIFT (4) /* 128-bit aligned address */ | ||
134 | |||
135 | #define PSB_CR_EVENT_KICK 0x0AC8 | ||
136 | #define _PSB_CE_KICK_NOW (1 << 0) | ||
137 | |||
138 | #define PSB_CR_BIF_DIR_LIST_BASE1 0x0C38 | ||
139 | |||
140 | #define PSB_CR_BIF_CTRL 0x0C00 | ||
141 | #define _PSB_CB_CTRL_CLEAR_FAULT (1 << 4) | ||
142 | #define _PSB_CB_CTRL_INVALDC (1 << 3) | ||
143 | #define _PSB_CB_CTRL_FLUSH (1 << 2) | ||
144 | |||
145 | #define PSB_CR_BIF_INT_STAT 0x0C04 | ||
146 | |||
147 | #define PSB_CR_BIF_FAULT 0x0C08 | ||
148 | #define _PSB_CBI_STAT_PF_N_RW (1 << 14) | ||
149 | #define _PSB_CBI_STAT_FAULT_SHIFT (0) | ||
150 | #define _PSB_CBI_STAT_FAULT_MASK (0x3FFF << 0) | ||
151 | #define _PSB_CBI_STAT_FAULT_CACHE (1 << 1) | ||
152 | #define _PSB_CBI_STAT_FAULT_TA (1 << 2) | ||
153 | #define _PSB_CBI_STAT_FAULT_VDM (1 << 3) | ||
154 | #define _PSB_CBI_STAT_FAULT_2D (1 << 4) | ||
155 | #define _PSB_CBI_STAT_FAULT_PBE (1 << 5) | ||
156 | #define _PSB_CBI_STAT_FAULT_TSP (1 << 6) | ||
157 | #define _PSB_CBI_STAT_FAULT_ISP (1 << 7) | ||
158 | #define _PSB_CBI_STAT_FAULT_USSEPDS (1 << 8) | ||
159 | #define _PSB_CBI_STAT_FAULT_HOST (1 << 9) | ||
160 | |||
161 | #define PSB_CR_BIF_BANK0 0x0C78 | ||
162 | #define PSB_CR_BIF_BANK1 0x0C7C | ||
163 | #define PSB_CR_BIF_DIR_LIST_BASE0 0x0C84 | ||
164 | #define PSB_CR_BIF_TWOD_REQ_BASE 0x0C88 | ||
165 | #define PSB_CR_BIF_3D_REQ_BASE 0x0CAC | ||
166 | |||
167 | #define PSB_CR_2D_SOCIF 0x0E18 | ||
168 | #define _PSB_C2_SOCIF_FREESPACE_SHIFT (0) | ||
169 | #define _PSB_C2_SOCIF_FREESPACE_MASK (0xFF << 0) | ||
170 | #define _PSB_C2_SOCIF_EMPTY (0x80 << 0) | ||
171 | |||
172 | #define PSB_CR_2D_BLIT_STATUS 0x0E04 | ||
173 | #define _PSB_C2B_STATUS_BUSY (1 << 24) | ||
174 | #define _PSB_C2B_STATUS_COMPLETE_SHIFT (0) | ||
175 | #define _PSB_C2B_STATUS_COMPLETE_MASK (0xFFFFFF << 0) | ||
176 | |||
177 | /* | ||
178 | * 2D defs. | ||
179 | */ | ||
180 | |||
181 | /* | ||
182 | * 2D Slave Port Data : Block Header's Object Type | ||
183 | */ | ||
184 | |||
185 | #define PSB_2D_CLIP_BH (0x00000000) | ||
186 | #define PSB_2D_PAT_BH (0x10000000) | ||
187 | #define PSB_2D_CTRL_BH (0x20000000) | ||
188 | #define PSB_2D_SRC_OFF_BH (0x30000000) | ||
189 | #define PSB_2D_MASK_OFF_BH (0x40000000) | ||
190 | #define PSB_2D_RESERVED1_BH (0x50000000) | ||
191 | #define PSB_2D_RESERVED2_BH (0x60000000) | ||
192 | #define PSB_2D_FENCE_BH (0x70000000) | ||
193 | #define PSB_2D_BLIT_BH (0x80000000) | ||
194 | #define PSB_2D_SRC_SURF_BH (0x90000000) | ||
195 | #define PSB_2D_DST_SURF_BH (0xA0000000) | ||
196 | #define PSB_2D_PAT_SURF_BH (0xB0000000) | ||
197 | #define PSB_2D_SRC_PAL_BH (0xC0000000) | ||
198 | #define PSB_2D_PAT_PAL_BH (0xD0000000) | ||
199 | #define PSB_2D_MASK_SURF_BH (0xE0000000) | ||
200 | #define PSB_2D_FLUSH_BH (0xF0000000) | ||
201 | |||
202 | /* | ||
203 | * Clip Definition block (PSB_2D_CLIP_BH) | ||
204 | */ | ||
205 | #define PSB_2D_CLIPCOUNT_MAX (1) | ||
206 | #define PSB_2D_CLIPCOUNT_MASK (0x00000000) | ||
207 | #define PSB_2D_CLIPCOUNT_CLRMASK (0xFFFFFFFF) | ||
208 | #define PSB_2D_CLIPCOUNT_SHIFT (0) | ||
209 | /* clip rectangle min & max */ | ||
210 | #define PSB_2D_CLIP_XMAX_MASK (0x00FFF000) | ||
211 | #define PSB_2D_CLIP_XMAX_CLRMASK (0xFF000FFF) | ||
212 | #define PSB_2D_CLIP_XMAX_SHIFT (12) | ||
213 | #define PSB_2D_CLIP_XMIN_MASK (0x00000FFF) | ||
214 | #define PSB_2D_CLIP_XMIN_CLRMASK (0x00FFF000) | ||
215 | #define PSB_2D_CLIP_XMIN_SHIFT (0) | ||
216 | /* clip rectangle offset */ | ||
217 | #define PSB_2D_CLIP_YMAX_MASK (0x00FFF000) | ||
218 | #define PSB_2D_CLIP_YMAX_CLRMASK (0xFF000FFF) | ||
219 | #define PSB_2D_CLIP_YMAX_SHIFT (12) | ||
220 | #define PSB_2D_CLIP_YMIN_MASK (0x00000FFF) | ||
221 | #define PSB_2D_CLIP_YMIN_CLRMASK (0x00FFF000) | ||
222 | #define PSB_2D_CLIP_YMIN_SHIFT (0) | ||
223 | |||
224 | /* | ||
225 | * Pattern Control (PSB_2D_PAT_BH) | ||
226 | */ | ||
227 | #define PSB_2D_PAT_HEIGHT_MASK (0x0000001F) | ||
228 | #define PSB_2D_PAT_HEIGHT_SHIFT (0) | ||
229 | #define PSB_2D_PAT_WIDTH_MASK (0x000003E0) | ||
230 | #define PSB_2D_PAT_WIDTH_SHIFT (5) | ||
231 | #define PSB_2D_PAT_YSTART_MASK (0x00007C00) | ||
232 | #define PSB_2D_PAT_YSTART_SHIFT (10) | ||
233 | #define PSB_2D_PAT_XSTART_MASK (0x000F8000) | ||
234 | #define PSB_2D_PAT_XSTART_SHIFT (15) | ||
235 | |||
236 | /* | ||
237 | * 2D Control block (PSB_2D_CTRL_BH) | ||
238 | */ | ||
239 | /* Present Flags */ | ||
240 | #define PSB_2D_SRCCK_CTRL (0x00000001) | ||
241 | #define PSB_2D_DSTCK_CTRL (0x00000002) | ||
242 | #define PSB_2D_ALPHA_CTRL (0x00000004) | ||
243 | /* Colour Key Colour (SRC/DST)*/ | ||
244 | #define PSB_2D_CK_COL_MASK (0xFFFFFFFF) | ||
245 | #define PSB_2D_CK_COL_CLRMASK (0x00000000) | ||
246 | #define PSB_2D_CK_COL_SHIFT (0) | ||
247 | /* Colour Key Mask (SRC/DST)*/ | ||
248 | #define PSB_2D_CK_MASK_MASK (0xFFFFFFFF) | ||
249 | #define PSB_2D_CK_MASK_CLRMASK (0x00000000) | ||
250 | #define PSB_2D_CK_MASK_SHIFT (0) | ||
251 | /* Alpha Control (Alpha/RGB)*/ | ||
252 | #define PSB_2D_GBLALPHA_MASK (0x000FF000) | ||
253 | #define PSB_2D_GBLALPHA_CLRMASK (0xFFF00FFF) | ||
254 | #define PSB_2D_GBLALPHA_SHIFT (12) | ||
255 | #define PSB_2D_SRCALPHA_OP_MASK (0x00700000) | ||
256 | #define PSB_2D_SRCALPHA_OP_CLRMASK (0xFF8FFFFF) | ||
257 | #define PSB_2D_SRCALPHA_OP_SHIFT (20) | ||
258 | #define PSB_2D_SRCALPHA_OP_ONE (0x00000000) | ||
259 | #define PSB_2D_SRCALPHA_OP_SRC (0x00100000) | ||
260 | #define PSB_2D_SRCALPHA_OP_DST (0x00200000) | ||
261 | #define PSB_2D_SRCALPHA_OP_SG (0x00300000) | ||
262 | #define PSB_2D_SRCALPHA_OP_DG (0x00400000) | ||
263 | #define PSB_2D_SRCALPHA_OP_GBL (0x00500000) | ||
264 | #define PSB_2D_SRCALPHA_OP_ZERO (0x00600000) | ||
265 | #define PSB_2D_SRCALPHA_INVERT (0x00800000) | ||
266 | #define PSB_2D_SRCALPHA_INVERT_CLR (0xFF7FFFFF) | ||
267 | #define PSB_2D_DSTALPHA_OP_MASK (0x07000000) | ||
268 | #define PSB_2D_DSTALPHA_OP_CLRMASK (0xF8FFFFFF) | ||
269 | #define PSB_2D_DSTALPHA_OP_SHIFT (24) | ||
270 | #define PSB_2D_DSTALPHA_OP_ONE (0x00000000) | ||
271 | #define PSB_2D_DSTALPHA_OP_SRC (0x01000000) | ||
272 | #define PSB_2D_DSTALPHA_OP_DST (0x02000000) | ||
273 | #define PSB_2D_DSTALPHA_OP_SG (0x03000000) | ||
274 | #define PSB_2D_DSTALPHA_OP_DG (0x04000000) | ||
275 | #define PSB_2D_DSTALPHA_OP_GBL (0x05000000) | ||
276 | #define PSB_2D_DSTALPHA_OP_ZERO (0x06000000) | ||
277 | #define PSB_2D_DSTALPHA_INVERT (0x08000000) | ||
278 | #define PSB_2D_DSTALPHA_INVERT_CLR (0xF7FFFFFF) | ||
279 | |||
280 | #define PSB_2D_PRE_MULTIPLICATION_ENABLE (0x10000000) | ||
281 | #define PSB_2D_PRE_MULTIPLICATION_CLRMASK (0xEFFFFFFF) | ||
282 | #define PSB_2D_ZERO_SOURCE_ALPHA_ENABLE (0x20000000) | ||
283 | #define PSB_2D_ZERO_SOURCE_ALPHA_CLRMASK (0xDFFFFFFF) | ||
284 | |||
285 | /* | ||
286 | *Source Offset (PSB_2D_SRC_OFF_BH) | ||
287 | */ | ||
288 | #define PSB_2D_SRCOFF_XSTART_MASK ((0x00000FFF) << 12) | ||
289 | #define PSB_2D_SRCOFF_XSTART_SHIFT (12) | ||
290 | #define PSB_2D_SRCOFF_YSTART_MASK (0x00000FFF) | ||
291 | #define PSB_2D_SRCOFF_YSTART_SHIFT (0) | ||
292 | |||
293 | /* | ||
294 | * Mask Offset (PSB_2D_MASK_OFF_BH) | ||
295 | */ | ||
296 | #define PSB_2D_MASKOFF_XSTART_MASK ((0x00000FFF) << 12) | ||
297 | #define PSB_2D_MASKOFF_XSTART_SHIFT (12) | ||
298 | #define PSB_2D_MASKOFF_YSTART_MASK (0x00000FFF) | ||
299 | #define PSB_2D_MASKOFF_YSTART_SHIFT (0) | ||
300 | |||
301 | /* | ||
302 | * 2D Fence (see PSB_2D_FENCE_BH): bits 0:27 are ignored | ||
303 | */ | ||
304 | |||
305 | /* | ||
306 | *Blit Rectangle (PSB_2D_BLIT_BH) | ||
307 | */ | ||
308 | |||
309 | #define PSB_2D_ROT_MASK (3 << 25) | ||
310 | #define PSB_2D_ROT_CLRMASK (~PSB_2D_ROT_MASK) | ||
311 | #define PSB_2D_ROT_NONE (0 << 25) | ||
312 | #define PSB_2D_ROT_90DEGS (1 << 25) | ||
313 | #define PSB_2D_ROT_180DEGS (2 << 25) | ||
314 | #define PSB_2D_ROT_270DEGS (3 << 25) | ||
315 | |||
316 | #define PSB_2D_COPYORDER_MASK (3 << 23) | ||
317 | #define PSB_2D_COPYORDER_CLRMASK (~PSB_2D_COPYORDER_MASK) | ||
318 | #define PSB_2D_COPYORDER_TL2BR (0 << 23) | ||
319 | #define PSB_2D_COPYORDER_BR2TL (1 << 23) | ||
320 | #define PSB_2D_COPYORDER_TR2BL (2 << 23) | ||
321 | #define PSB_2D_COPYORDER_BL2TR (3 << 23) | ||
322 | |||
323 | #define PSB_2D_DSTCK_CLRMASK (0xFF9FFFFF) | ||
324 | #define PSB_2D_DSTCK_DISABLE (0x00000000) | ||
325 | #define PSB_2D_DSTCK_PASS (0x00200000) | ||
326 | #define PSB_2D_DSTCK_REJECT (0x00400000) | ||
327 | |||
328 | #define PSB_2D_SRCCK_CLRMASK (0xFFE7FFFF) | ||
329 | #define PSB_2D_SRCCK_DISABLE (0x00000000) | ||
330 | #define PSB_2D_SRCCK_PASS (0x00080000) | ||
331 | #define PSB_2D_SRCCK_REJECT (0x00100000) | ||
332 | |||
333 | #define PSB_2D_CLIP_ENABLE (0x00040000) | ||
334 | |||
335 | #define PSB_2D_ALPHA_ENABLE (0x00020000) | ||
336 | |||
337 | #define PSB_2D_PAT_CLRMASK (0xFFFEFFFF) | ||
338 | #define PSB_2D_PAT_MASK (0x00010000) | ||
339 | #define PSB_2D_USE_PAT (0x00010000) | ||
340 | #define PSB_2D_USE_FILL (0x00000000) | ||
341 | /* | ||
342 | * Tungsten Graphics note on rop codes: If rop A and rop B are | ||
343 | * identical, the mask surface will not be read and need not be | ||
344 | * set up. | ||
345 | */ | ||
346 | |||
347 | #define PSB_2D_ROP3B_MASK (0x0000FF00) | ||
348 | #define PSB_2D_ROP3B_CLRMASK (0xFFFF00FF) | ||
349 | #define PSB_2D_ROP3B_SHIFT (8) | ||
350 | /* rop code A */ | ||
351 | #define PSB_2D_ROP3A_MASK (0x000000FF) | ||
352 | #define PSB_2D_ROP3A_CLRMASK (0xFFFFFF00) | ||
353 | #define PSB_2D_ROP3A_SHIFT (0) | ||
354 | |||
355 | #define PSB_2D_ROP4_MASK (0x0000FFFF) | ||
356 | /* | ||
357 | * DWORD0: (Only pass if Pattern control == Use Fill Colour) | ||
358 | * Fill Colour RGBA8888 | ||
359 | */ | ||
360 | #define PSB_2D_FILLCOLOUR_MASK (0xFFFFFFFF) | ||
361 | #define PSB_2D_FILLCOLOUR_SHIFT (0) | ||
362 | /* | ||
363 | * DWORD1: (Always Present) | ||
364 | * X Start (Dest) | ||
365 | * Y Start (Dest) | ||
366 | */ | ||
367 | #define PSB_2D_DST_XSTART_MASK (0x00FFF000) | ||
368 | #define PSB_2D_DST_XSTART_CLRMASK (0xFF000FFF) | ||
369 | #define PSB_2D_DST_XSTART_SHIFT (12) | ||
370 | #define PSB_2D_DST_YSTART_MASK (0x00000FFF) | ||
371 | #define PSB_2D_DST_YSTART_CLRMASK (0xFFFFF000) | ||
372 | #define PSB_2D_DST_YSTART_SHIFT (0) | ||
373 | /* | ||
374 | * DWORD2: (Always Present) | ||
375 | * X Size (Dest) | ||
376 | * Y Size (Dest) | ||
377 | */ | ||
378 | #define PSB_2D_DST_XSIZE_MASK (0x00FFF000) | ||
379 | #define PSB_2D_DST_XSIZE_CLRMASK (0xFF000FFF) | ||
380 | #define PSB_2D_DST_XSIZE_SHIFT (12) | ||
381 | #define PSB_2D_DST_YSIZE_MASK (0x00000FFF) | ||
382 | #define PSB_2D_DST_YSIZE_CLRMASK (0xFFFFF000) | ||
383 | #define PSB_2D_DST_YSIZE_SHIFT (0) | ||
384 | |||
385 | /* | ||
386 | * Source Surface (PSB_2D_SRC_SURF_BH) | ||
387 | */ | ||
388 | /* | ||
389 | * WORD 0 | ||
390 | */ | ||
391 | |||
392 | #define PSB_2D_SRC_FORMAT_MASK (0x00078000) | ||
393 | #define PSB_2D_SRC_1_PAL (0x00000000) | ||
394 | #define PSB_2D_SRC_2_PAL (0x00008000) | ||
395 | #define PSB_2D_SRC_4_PAL (0x00010000) | ||
396 | #define PSB_2D_SRC_8_PAL (0x00018000) | ||
397 | #define PSB_2D_SRC_8_ALPHA (0x00020000) | ||
398 | #define PSB_2D_SRC_4_ALPHA (0x00028000) | ||
399 | #define PSB_2D_SRC_332RGB (0x00030000) | ||
400 | #define PSB_2D_SRC_4444ARGB (0x00038000) | ||
401 | #define PSB_2D_SRC_555RGB (0x00040000) | ||
402 | #define PSB_2D_SRC_1555ARGB (0x00048000) | ||
403 | #define PSB_2D_SRC_565RGB (0x00050000) | ||
404 | #define PSB_2D_SRC_0888ARGB (0x00058000) | ||
405 | #define PSB_2D_SRC_8888ARGB (0x00060000) | ||
406 | #define PSB_2D_SRC_8888UYVY (0x00068000) | ||
407 | #define PSB_2D_SRC_RESERVED (0x00070000) | ||
408 | #define PSB_2D_SRC_1555ARGB_LOOKUP (0x00078000) | ||
409 | |||
410 | |||
411 | #define PSB_2D_SRC_STRIDE_MASK (0x00007FFF) | ||
412 | #define PSB_2D_SRC_STRIDE_CLRMASK (0xFFFF8000) | ||
413 | #define PSB_2D_SRC_STRIDE_SHIFT (0) | ||
414 | /* | ||
415 | * WORD 1 - Base Address | ||
416 | */ | ||
417 | #define PSB_2D_SRC_ADDR_MASK (0x0FFFFFFC) | ||
418 | #define PSB_2D_SRC_ADDR_CLRMASK (0x00000003) | ||
419 | #define PSB_2D_SRC_ADDR_SHIFT (2) | ||
420 | #define PSB_2D_SRC_ADDR_ALIGNSHIFT (2) | ||
421 | |||
422 | /* | ||
423 | * Pattern Surface (PSB_2D_PAT_SURF_BH) | ||
424 | */ | ||
425 | /* | ||
426 | * WORD 0 | ||
427 | */ | ||
428 | |||
429 | #define PSB_2D_PAT_FORMAT_MASK (0x00078000) | ||
430 | #define PSB_2D_PAT_1_PAL (0x00000000) | ||
431 | #define PSB_2D_PAT_2_PAL (0x00008000) | ||
432 | #define PSB_2D_PAT_4_PAL (0x00010000) | ||
433 | #define PSB_2D_PAT_8_PAL (0x00018000) | ||
434 | #define PSB_2D_PAT_8_ALPHA (0x00020000) | ||
435 | #define PSB_2D_PAT_4_ALPHA (0x00028000) | ||
436 | #define PSB_2D_PAT_332RGB (0x00030000) | ||
437 | #define PSB_2D_PAT_4444ARGB (0x00038000) | ||
438 | #define PSB_2D_PAT_555RGB (0x00040000) | ||
439 | #define PSB_2D_PAT_1555ARGB (0x00048000) | ||
440 | #define PSB_2D_PAT_565RGB (0x00050000) | ||
441 | #define PSB_2D_PAT_0888ARGB (0x00058000) | ||
442 | #define PSB_2D_PAT_8888ARGB (0x00060000) | ||
443 | |||
444 | #define PSB_2D_PAT_STRIDE_MASK (0x00007FFF) | ||
445 | #define PSB_2D_PAT_STRIDE_CLRMASK (0xFFFF8000) | ||
446 | #define PSB_2D_PAT_STRIDE_SHIFT (0) | ||
447 | /* | ||
448 | * WORD 1 - Base Address | ||
449 | */ | ||
450 | #define PSB_2D_PAT_ADDR_MASK (0x0FFFFFFC) | ||
451 | #define PSB_2D_PAT_ADDR_CLRMASK (0x00000003) | ||
452 | #define PSB_2D_PAT_ADDR_SHIFT (2) | ||
453 | #define PSB_2D_PAT_ADDR_ALIGNSHIFT (2) | ||
454 | |||
455 | /* | ||
456 | * Destination Surface (PSB_2D_DST_SURF_BH) | ||
457 | */ | ||
458 | /* | ||
459 | * WORD 0 | ||
460 | */ | ||
461 | |||
462 | #define PSB_2D_DST_FORMAT_MASK (0x00078000) | ||
463 | #define PSB_2D_DST_332RGB (0x00030000) | ||
464 | #define PSB_2D_DST_4444ARGB (0x00038000) | ||
465 | #define PSB_2D_DST_555RGB (0x00040000) | ||
466 | #define PSB_2D_DST_1555ARGB (0x00048000) | ||
467 | #define PSB_2D_DST_565RGB (0x00050000) | ||
468 | #define PSB_2D_DST_0888ARGB (0x00058000) | ||
469 | #define PSB_2D_DST_8888ARGB (0x00060000) | ||
470 | #define PSB_2D_DST_8888AYUV (0x00070000) | ||
471 | |||
472 | #define PSB_2D_DST_STRIDE_MASK (0x00007FFF) | ||
473 | #define PSB_2D_DST_STRIDE_CLRMASK (0xFFFF8000) | ||
474 | #define PSB_2D_DST_STRIDE_SHIFT (0) | ||
475 | /* | ||
476 | * WORD 1 - Base Address | ||
477 | */ | ||
478 | #define PSB_2D_DST_ADDR_MASK (0x0FFFFFFC) | ||
479 | #define PSB_2D_DST_ADDR_CLRMASK (0x00000003) | ||
480 | #define PSB_2D_DST_ADDR_SHIFT (2) | ||
481 | #define PSB_2D_DST_ADDR_ALIGNSHIFT (2) | ||
482 | |||
483 | /* | ||
484 | * Mask Surface (PSB_2D_MASK_SURF_BH) | ||
485 | */ | ||
486 | /* | ||
487 | * WORD 0 | ||
488 | */ | ||
489 | #define PSB_2D_MASK_STRIDE_MASK (0x00007FFF) | ||
490 | #define PSB_2D_MASK_STRIDE_CLRMASK (0xFFFF8000) | ||
491 | #define PSB_2D_MASK_STRIDE_SHIFT (0) | ||
492 | /* | ||
493 | * WORD 1 - Base Address | ||
494 | */ | ||
495 | #define PSB_2D_MASK_ADDR_MASK (0x0FFFFFFC) | ||
496 | #define PSB_2D_MASK_ADDR_CLRMASK (0x00000003) | ||
497 | #define PSB_2D_MASK_ADDR_SHIFT (2) | ||
498 | #define PSB_2D_MASK_ADDR_ALIGNSHIFT (2) | ||
499 | |||
500 | /* | ||
501 | * Source Palette (PSB_2D_SRC_PAL_BH) | ||
502 | */ | ||
503 | |||
504 | #define PSB_2D_SRCPAL_ADDR_SHIFT (0) | ||
505 | #define PSB_2D_SRCPAL_ADDR_CLRMASK (0xF0000007) | ||
506 | #define PSB_2D_SRCPAL_ADDR_MASK (0x0FFFFFF8) | ||
507 | #define PSB_2D_SRCPAL_BYTEALIGN (1024) | ||
508 | |||
509 | /* | ||
510 | * Pattern Palette (PSB_2D_PAT_PAL_BH) | ||
511 | */ | ||
512 | |||
513 | #define PSB_2D_PATPAL_ADDR_SHIFT (0) | ||
514 | #define PSB_2D_PATPAL_ADDR_CLRMASK (0xF0000007) | ||
515 | #define PSB_2D_PATPAL_ADDR_MASK (0x0FFFFFF8) | ||
516 | #define PSB_2D_PATPAL_BYTEALIGN (1024) | ||
517 | |||
518 | /* | ||
519 | * Rop3 Codes (2 LS bytes) | ||
520 | */ | ||
521 | |||
522 | #define PSB_2D_ROP3_SRCCOPY (0xCCCC) | ||
523 | #define PSB_2D_ROP3_PATCOPY (0xF0F0) | ||
524 | #define PSB_2D_ROP3_WHITENESS (0xFFFF) | ||
525 | #define PSB_2D_ROP3_BLACKNESS (0x0000) | ||
526 | #define PSB_2D_ROP3_SRC (0xCC) | ||
527 | #define PSB_2D_ROP3_PAT (0xF0) | ||
528 | #define PSB_2D_ROP3_DST (0xAA) | ||
529 | |||
530 | /* | ||
531 | * Sizes. | ||
532 | */ | ||
533 | |||
534 | #define PSB_SCENE_HW_COOKIE_SIZE 16 | ||
535 | #define PSB_TA_MEM_HW_COOKIE_SIZE 16 | ||
536 | |||
537 | /* | ||
538 | * Scene stuff. | ||
539 | */ | ||
540 | |||
541 | #define PSB_NUM_HW_SCENES 2 | ||
542 | |||
543 | /* | ||
544 | * Scheduler completion actions. | ||
545 | */ | ||
546 | |||
547 | #define PSB_RASTER_BLOCK 0 | ||
548 | #define PSB_RASTER 1 | ||
549 | #define PSB_RETURN 2 | ||
550 | #define PSB_TA 3 | ||
551 | |||
552 | /* Power management */ | ||
553 | #define PSB_PUNIT_PORT 0x04 | ||
554 | #define PSB_OSPMBA 0x78 | ||
555 | #define PSB_APMBA 0x7a | ||
556 | #define PSB_APM_CMD 0x0 | ||
557 | #define PSB_APM_STS 0x04 | ||
558 | #define PSB_PWRGT_VID_ENC_MASK 0x30 | ||
559 | #define PSB_PWRGT_VID_DEC_MASK 0xc | ||
560 | #define PSB_PWRGT_GL3_MASK 0xc0 | ||
561 | |||
562 | #define PSB_PM_SSC 0x20 | ||
563 | #define PSB_PM_SSS 0x30 | ||
564 | #define PSB_PWRGT_DISPLAY_MASK 0xc /*on a different BA than video/gfx*/ | ||
565 | #define MDFLD_PWRGT_DISPLAY_A_CNTR 0x0000000c | ||
566 | #define MDFLD_PWRGT_DISPLAY_B_CNTR 0x0000c000 | ||
567 | #define MDFLD_PWRGT_DISPLAY_C_CNTR 0x00030000 | ||
568 | #define MDFLD_PWRGT_DISP_MIPI_CNTR 0x000c0000 | ||
569 | #define MDFLD_PWRGT_DISPLAY_CNTR (MDFLD_PWRGT_DISPLAY_A_CNTR | MDFLD_PWRGT_DISPLAY_B_CNTR | MDFLD_PWRGT_DISPLAY_C_CNTR | MDFLD_PWRGT_DISP_MIPI_CNTR) /* 0x000fc00c */ | ||
570 | /* Display SSS register bits are different in A0 vs. B0 */ | ||
571 | #define PSB_PWRGT_GFX_MASK 0x3 | ||
572 | #define MDFLD_PWRGT_DISPLAY_A_STS 0x000000c0 | ||
573 | #define MDFLD_PWRGT_DISPLAY_B_STS 0x00000300 | ||
574 | #define MDFLD_PWRGT_DISPLAY_C_STS 0x00000c00 | ||
575 | #define PSB_PWRGT_GFX_MASK_B0 0xc3 | ||
576 | #define MDFLD_PWRGT_DISPLAY_A_STS_B0 0x0000000c | ||
577 | #define MDFLD_PWRGT_DISPLAY_B_STS_B0 0x0000c000 | ||
578 | #define MDFLD_PWRGT_DISPLAY_C_STS_B0 0x00030000 | ||
579 | #define MDFLD_PWRGT_DISP_MIPI_STS 0x000c0000 | ||
580 | #define MDFLD_PWRGT_DISPLAY_STS_A0 (MDFLD_PWRGT_DISPLAY_A_STS | MDFLD_PWRGT_DISPLAY_B_STS | MDFLD_PWRGT_DISPLAY_C_STS | MDFLD_PWRGT_DISP_MIPI_STS) /* 0x000fc00c */ | ||
581 | #define MDFLD_PWRGT_DISPLAY_STS_B0 (MDFLD_PWRGT_DISPLAY_A_STS_B0 | MDFLD_PWRGT_DISPLAY_B_STS_B0 | MDFLD_PWRGT_DISPLAY_C_STS_B0 | MDFLD_PWRGT_DISP_MIPI_STS) /* 0x000fc00c */ | ||
582 | #endif | ||