Commit | Line | Data |
---|---|---|
0867b421 AC |
1 | /************************************************************************** |
2 | * Copyright (c) 2007, 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 "psb_drm.h" | |
25 | #include "psb_drv.h" | |
26 | #include "psb_fb.h" | |
27 | #include "psb_reg.h" | |
28 | #include "psb_intel_reg.h" | |
29 | #include "psb_intel_bios.h" | |
30 | #include <drm/drm_pciids.h> | |
31 | #include "psb_powermgmt.h" | |
32 | #include <linux/cpu.h> | |
33 | #include <linux/notifier.h> | |
34 | #include <linux/spinlock.h> | |
35 | #include <linux/pm_runtime.h> | |
36 | ||
37 | int drm_psb_debug; | |
38 | static int drm_psb_trap_pagefaults; | |
39 | ||
40 | int drm_psb_disable_vsync = 1; | |
41 | int drm_psb_no_fb; | |
42 | int drm_psb_force_pipeb; | |
43 | int drm_idle_check_interval = 5; | |
44 | int gfxrtdelay = 2 * 1000; | |
45 | ||
46 | static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | |
47 | ||
48 | MODULE_PARM_DESC(debug, "Enable debug output"); | |
49 | MODULE_PARM_DESC(no_fb, "Disable FBdev"); | |
50 | MODULE_PARM_DESC(trap_pagefaults, "Error and reset on MMU pagefaults"); | |
51 | MODULE_PARM_DESC(disable_vsync, "Disable vsync interrupts"); | |
52 | MODULE_PARM_DESC(force_pipeb, "Forces PIPEB to become primary fb"); | |
53 | MODULE_PARM_DESC(ta_mem_size, "TA memory size in kiB"); | |
54 | MODULE_PARM_DESC(ospm, "switch for ospm support"); | |
55 | MODULE_PARM_DESC(rtpm, "Specifies Runtime PM delay for GFX"); | |
56 | MODULE_PARM_DESC(hdmi_edid, "EDID info for HDMI monitor"); | |
57 | module_param_named(debug, drm_psb_debug, int, 0600); | |
58 | module_param_named(no_fb, drm_psb_no_fb, int, 0600); | |
59 | module_param_named(trap_pagefaults, drm_psb_trap_pagefaults, int, 0600); | |
60 | module_param_named(force_pipeb, drm_psb_force_pipeb, int, 0600); | |
61 | module_param_named(rtpm, gfxrtdelay, int, 0600); | |
62 | ||
63 | ||
64 | static struct pci_device_id pciidlist[] = { | |
65 | { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8108 }, | |
66 | { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8109 }, | |
67 | { 0, 0, 0} | |
68 | }; | |
69 | MODULE_DEVICE_TABLE(pci, pciidlist); | |
70 | ||
71 | /* | |
72 | * Standard IOCTLs. | |
73 | */ | |
74 | ||
75 | #define DRM_IOCTL_PSB_KMS_OFF \ | |
76 | DRM_IO(DRM_PSB_KMS_OFF + DRM_COMMAND_BASE) | |
77 | #define DRM_IOCTL_PSB_KMS_ON \ | |
78 | DRM_IO(DRM_PSB_KMS_ON + DRM_COMMAND_BASE) | |
79 | #define DRM_IOCTL_PSB_VT_LEAVE \ | |
80 | DRM_IO(DRM_PSB_VT_LEAVE + DRM_COMMAND_BASE) | |
81 | #define DRM_IOCTL_PSB_VT_ENTER \ | |
82 | DRM_IO(DRM_PSB_VT_ENTER + DRM_COMMAND_BASE) | |
83 | #define DRM_IOCTL_PSB_SIZES \ | |
84 | DRM_IOR(DRM_PSB_SIZES + DRM_COMMAND_BASE, \ | |
85 | struct drm_psb_sizes_arg) | |
86 | #define DRM_IOCTL_PSB_FUSE_REG \ | |
87 | DRM_IOWR(DRM_PSB_FUSE_REG + DRM_COMMAND_BASE, uint32_t) | |
88 | #define DRM_IOCTL_PSB_DC_STATE \ | |
89 | DRM_IOW(DRM_PSB_DC_STATE + DRM_COMMAND_BASE, \ | |
90 | struct drm_psb_dc_state_arg) | |
91 | #define DRM_IOCTL_PSB_ADB \ | |
92 | DRM_IOWR(DRM_PSB_ADB + DRM_COMMAND_BASE, uint32_t) | |
93 | #define DRM_IOCTL_PSB_MODE_OPERATION \ | |
94 | DRM_IOWR(DRM_PSB_MODE_OPERATION + DRM_COMMAND_BASE, \ | |
95 | struct drm_psb_mode_operation_arg) | |
96 | #define DRM_IOCTL_PSB_STOLEN_MEMORY \ | |
97 | DRM_IOWR(DRM_PSB_STOLEN_MEMORY + DRM_COMMAND_BASE, \ | |
98 | struct drm_psb_stolen_memory_arg) | |
99 | #define DRM_IOCTL_PSB_REGISTER_RW \ | |
100 | DRM_IOWR(DRM_PSB_REGISTER_RW + DRM_COMMAND_BASE, \ | |
101 | struct drm_psb_register_rw_arg) | |
102 | #define DRM_IOCTL_PSB_GTT_MAP \ | |
103 | DRM_IOWR(DRM_PSB_GTT_MAP + DRM_COMMAND_BASE, \ | |
104 | struct psb_gtt_mapping_arg) | |
105 | #define DRM_IOCTL_PSB_GTT_UNMAP \ | |
106 | DRM_IOW(DRM_PSB_GTT_UNMAP + DRM_COMMAND_BASE, \ | |
107 | struct psb_gtt_mapping_arg) | |
108 | #define DRM_IOCTL_PSB_GETPAGEADDRS \ | |
109 | DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_GETPAGEADDRS,\ | |
110 | struct drm_psb_getpageaddrs_arg) | |
111 | #define DRM_IOCTL_PSB_HIST_ENABLE \ | |
112 | DRM_IOWR(DRM_PSB_HIST_ENABLE + DRM_COMMAND_BASE, \ | |
113 | uint32_t) | |
114 | #define DRM_IOCTL_PSB_HIST_STATUS \ | |
115 | DRM_IOWR(DRM_PSB_HIST_STATUS + DRM_COMMAND_BASE, \ | |
116 | struct drm_psb_hist_status_arg) | |
117 | #define DRM_IOCTL_PSB_UPDATE_GUARD \ | |
118 | DRM_IOWR(DRM_PSB_UPDATE_GUARD + DRM_COMMAND_BASE, \ | |
119 | uint32_t) | |
120 | #define DRM_IOCTL_PSB_DPST \ | |
121 | DRM_IOWR(DRM_PSB_DPST + DRM_COMMAND_BASE, \ | |
122 | uint32_t) | |
123 | #define DRM_IOCTL_PSB_GAMMA \ | |
124 | DRM_IOWR(DRM_PSB_GAMMA + DRM_COMMAND_BASE, \ | |
125 | struct drm_psb_dpst_lut_arg) | |
126 | #define DRM_IOCTL_PSB_DPST_BL \ | |
127 | DRM_IOWR(DRM_PSB_DPST_BL + DRM_COMMAND_BASE, \ | |
128 | uint32_t) | |
129 | #define DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID \ | |
130 | DRM_IOWR(DRM_PSB_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \ | |
131 | struct drm_psb_get_pipe_from_crtc_id_arg) | |
132 | ||
133 | /* | |
134 | * TTM execbuf extension. | |
135 | */ | |
136 | #define DRM_PSB_CMDBUF (DRM_PSB_DPU_DSR_OFF + 1) | |
137 | ||
138 | #define DRM_PSB_SCENE_UNREF (DRM_PSB_CMDBUF + 1) | |
139 | #define DRM_IOCTL_PSB_CMDBUF \ | |
140 | DRM_IOW(DRM_PSB_CMDBUF + DRM_COMMAND_BASE, \ | |
141 | struct drm_psb_cmdbuf_arg) | |
142 | #define DRM_IOCTL_PSB_SCENE_UNREF \ | |
143 | DRM_IOW(DRM_PSB_SCENE_UNREF + DRM_COMMAND_BASE, \ | |
144 | struct drm_psb_scene) | |
145 | #define DRM_IOCTL_PSB_KMS_OFF DRM_IO(DRM_PSB_KMS_OFF + DRM_COMMAND_BASE) | |
146 | #define DRM_IOCTL_PSB_KMS_ON DRM_IO(DRM_PSB_KMS_ON + DRM_COMMAND_BASE) | |
147 | /* | |
148 | * TTM placement user extension. | |
149 | */ | |
150 | ||
151 | #define DRM_PSB_PLACEMENT_OFFSET (DRM_PSB_SCENE_UNREF + 1) | |
152 | ||
153 | #define DRM_PSB_TTM_PL_CREATE (TTM_PL_CREATE + DRM_PSB_PLACEMENT_OFFSET) | |
154 | #define DRM_PSB_TTM_PL_REFERENCE (TTM_PL_REFERENCE + DRM_PSB_PLACEMENT_OFFSET) | |
155 | #define DRM_PSB_TTM_PL_UNREF (TTM_PL_UNREF + DRM_PSB_PLACEMENT_OFFSET) | |
156 | #define DRM_PSB_TTM_PL_SYNCCPU (TTM_PL_SYNCCPU + DRM_PSB_PLACEMENT_OFFSET) | |
157 | #define DRM_PSB_TTM_PL_WAITIDLE (TTM_PL_WAITIDLE + DRM_PSB_PLACEMENT_OFFSET) | |
158 | #define DRM_PSB_TTM_PL_SETSTATUS (TTM_PL_SETSTATUS + DRM_PSB_PLACEMENT_OFFSET) | |
159 | #define DRM_PSB_TTM_PL_CREATE_UB (TTM_PL_CREATE_UB + DRM_PSB_PLACEMENT_OFFSET) | |
160 | ||
161 | /* | |
162 | * TTM fence extension. | |
163 | */ | |
164 | ||
165 | #define DRM_PSB_FENCE_OFFSET (DRM_PSB_TTM_PL_CREATE_UB + 1) | |
166 | #define DRM_PSB_TTM_FENCE_SIGNALED (TTM_FENCE_SIGNALED + DRM_PSB_FENCE_OFFSET) | |
167 | #define DRM_PSB_TTM_FENCE_FINISH (TTM_FENCE_FINISH + DRM_PSB_FENCE_OFFSET) | |
168 | #define DRM_PSB_TTM_FENCE_UNREF (TTM_FENCE_UNREF + DRM_PSB_FENCE_OFFSET) | |
169 | ||
170 | #define DRM_PSB_FLIP (DRM_PSB_TTM_FENCE_UNREF + 1) /*20*/ | |
171 | /* PSB video extension */ | |
172 | #define DRM_LNC_VIDEO_GETPARAM (DRM_PSB_FLIP + 1) | |
173 | ||
174 | #define DRM_IOCTL_PSB_TTM_PL_CREATE \ | |
175 | DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_TTM_PL_CREATE,\ | |
176 | union ttm_pl_create_arg) | |
177 | #define DRM_IOCTL_PSB_TTM_PL_REFERENCE \ | |
178 | DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_TTM_PL_REFERENCE,\ | |
179 | union ttm_pl_reference_arg) | |
180 | #define DRM_IOCTL_PSB_TTM_PL_UNREF \ | |
181 | DRM_IOW(DRM_COMMAND_BASE + DRM_PSB_TTM_PL_UNREF,\ | |
182 | struct ttm_pl_reference_req) | |
183 | #define DRM_IOCTL_PSB_TTM_PL_SYNCCPU \ | |
184 | DRM_IOW(DRM_COMMAND_BASE + DRM_PSB_TTM_PL_SYNCCPU,\ | |
185 | struct ttm_pl_synccpu_arg) | |
186 | #define DRM_IOCTL_PSB_TTM_PL_WAITIDLE \ | |
187 | DRM_IOW(DRM_COMMAND_BASE + DRM_PSB_TTM_PL_WAITIDLE,\ | |
188 | struct ttm_pl_waitidle_arg) | |
189 | #define DRM_IOCTL_PSB_TTM_PL_SETSTATUS \ | |
190 | DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_TTM_PL_SETSTATUS,\ | |
191 | union ttm_pl_setstatus_arg) | |
192 | #define DRM_IOCTL_PSB_TTM_PL_CREATE_UB \ | |
193 | DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_TTM_PL_CREATE_UB,\ | |
194 | union ttm_pl_create_ub_arg) | |
195 | #define DRM_IOCTL_PSB_TTM_FENCE_SIGNALED \ | |
196 | DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_TTM_FENCE_SIGNALED, \ | |
197 | union ttm_fence_signaled_arg) | |
198 | #define DRM_IOCTL_PSB_TTM_FENCE_FINISH \ | |
199 | DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_TTM_FENCE_FINISH, \ | |
200 | union ttm_fence_finish_arg) | |
201 | #define DRM_IOCTL_PSB_TTM_FENCE_UNREF \ | |
202 | DRM_IOW(DRM_COMMAND_BASE + DRM_PSB_TTM_FENCE_UNREF, \ | |
203 | struct ttm_fence_unref_arg) | |
204 | #define DRM_IOCTL_PSB_FLIP \ | |
205 | DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_FLIP, \ | |
206 | struct drm_psb_pageflip_arg) | |
207 | #define DRM_IOCTL_LNC_VIDEO_GETPARAM \ | |
208 | DRM_IOWR(DRM_COMMAND_BASE + DRM_LNC_VIDEO_GETPARAM, \ | |
209 | struct drm_lnc_video_getparam_arg) | |
210 | ||
211 | static int psb_vt_leave_ioctl(struct drm_device *dev, void *data, | |
212 | struct drm_file *file_priv); | |
213 | static int psb_vt_enter_ioctl(struct drm_device *dev, void *data, | |
214 | struct drm_file *file_priv); | |
215 | static int psb_sizes_ioctl(struct drm_device *dev, void *data, | |
216 | struct drm_file *file_priv); | |
217 | static int psb_dc_state_ioctl(struct drm_device *dev, void * data, | |
218 | struct drm_file *file_priv); | |
219 | static int psb_adb_ioctl(struct drm_device *dev, void *data, | |
220 | struct drm_file *file_priv); | |
221 | static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, | |
222 | struct drm_file *file_priv); | |
223 | static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, | |
224 | struct drm_file *file_priv); | |
225 | static int psb_register_rw_ioctl(struct drm_device *dev, void *data, | |
226 | struct drm_file *file_priv); | |
227 | static int psb_dpst_ioctl(struct drm_device *dev, void *data, | |
228 | struct drm_file *file_priv); | |
229 | static int psb_gamma_ioctl(struct drm_device *dev, void *data, | |
230 | struct drm_file *file_priv); | |
231 | static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, | |
232 | struct drm_file *file_priv); | |
233 | ||
234 | #define PSB_IOCTL_DEF(ioctl, func, flags) \ | |
235 | [DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func} | |
236 | ||
237 | static struct drm_ioctl_desc psb_ioctls[] = { | |
238 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_KMS_OFF, psbfb_kms_off_ioctl, | |
239 | DRM_ROOT_ONLY), | |
240 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_KMS_ON, | |
241 | psbfb_kms_on_ioctl, | |
242 | DRM_ROOT_ONLY), | |
243 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_VT_LEAVE, psb_vt_leave_ioctl, | |
244 | DRM_ROOT_ONLY), | |
245 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_VT_ENTER, | |
246 | psb_vt_enter_ioctl, | |
247 | DRM_ROOT_ONLY), | |
248 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_SIZES, psb_sizes_ioctl, DRM_AUTH), | |
249 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_DC_STATE, psb_dc_state_ioctl, DRM_AUTH), | |
250 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_ADB, psb_adb_ioctl, DRM_AUTH), | |
251 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_MODE_OPERATION, psb_mode_operation_ioctl, | |
252 | DRM_AUTH), | |
253 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_STOLEN_MEMORY, psb_stolen_memory_ioctl, | |
254 | DRM_AUTH), | |
255 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_REGISTER_RW, psb_register_rw_ioctl, | |
256 | DRM_AUTH), | |
257 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GTT_MAP, | |
258 | psb_gtt_map_meminfo_ioctl, | |
259 | DRM_AUTH), | |
260 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GTT_UNMAP, | |
261 | psb_gtt_unmap_meminfo_ioctl, | |
262 | DRM_AUTH), | |
263 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GETPAGEADDRS, | |
264 | psb_getpageaddrs_ioctl, | |
265 | DRM_AUTH), | |
266 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_DPST, psb_dpst_ioctl, DRM_AUTH), | |
267 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GAMMA, psb_gamma_ioctl, DRM_AUTH), | |
268 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH), | |
269 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID, | |
270 | psb_intel_get_pipe_from_crtc_id, 0), | |
271 | /*to be removed later*/ | |
272 | /*PSB_IOCTL_DEF(DRM_IOCTL_PSB_SCENE_UNREF, drm_psb_scene_unref_ioctl, | |
273 | DRM_AUTH),*/ | |
274 | ||
275 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_CREATE, psb_pl_create_ioctl, | |
276 | DRM_AUTH), | |
277 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_REFERENCE, psb_pl_reference_ioctl, | |
278 | DRM_AUTH), | |
279 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_UNREF, psb_pl_unref_ioctl, | |
280 | DRM_AUTH), | |
281 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_SYNCCPU, psb_pl_synccpu_ioctl, | |
282 | DRM_AUTH), | |
283 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_WAITIDLE, psb_pl_waitidle_ioctl, | |
284 | DRM_AUTH), | |
285 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_SETSTATUS, psb_pl_setstatus_ioctl, | |
286 | DRM_AUTH), | |
287 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_CREATE_UB, psb_pl_ub_create_ioctl, | |
288 | DRM_AUTH), | |
289 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_FENCE_SIGNALED, | |
290 | psb_fence_signaled_ioctl, DRM_AUTH), | |
291 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_FENCE_FINISH, psb_fence_finish_ioctl, | |
292 | DRM_AUTH), | |
293 | PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_FENCE_UNREF, psb_fence_unref_ioctl, | |
294 | DRM_AUTH), | |
295 | }; | |
296 | ||
297 | static void psb_set_uopt(struct drm_psb_uopt *uopt) | |
298 | { | |
299 | return; | |
300 | } | |
301 | ||
302 | static void psb_lastclose(struct drm_device *dev) | |
303 | { | |
304 | struct drm_psb_private *dev_priv = | |
305 | (struct drm_psb_private *) dev->dev_private; | |
306 | ||
307 | return; | |
308 | ||
309 | if (!dev->dev_private) | |
310 | return; | |
311 | ||
312 | mutex_lock(&dev_priv->cmdbuf_mutex); | |
313 | if (dev_priv->context.buffers) { | |
314 | vfree(dev_priv->context.buffers); | |
315 | dev_priv->context.buffers = NULL; | |
316 | } | |
317 | mutex_unlock(&dev_priv->cmdbuf_mutex); | |
318 | } | |
319 | ||
320 | static void psb_do_takedown(struct drm_device *dev) | |
321 | { | |
322 | struct drm_psb_private *dev_priv = | |
323 | (struct drm_psb_private *) dev->dev_private; | |
324 | struct ttm_bo_device *bdev = &dev_priv->bdev; | |
325 | ||
326 | ||
327 | if (dev_priv->have_mem_mmu) { | |
328 | ttm_bo_clean_mm(bdev, DRM_PSB_MEM_MMU); | |
329 | dev_priv->have_mem_mmu = 0; | |
330 | } | |
331 | ||
332 | if (dev_priv->have_tt) { | |
333 | ttm_bo_clean_mm(bdev, TTM_PL_TT); | |
334 | dev_priv->have_tt = 0; | |
335 | } | |
336 | ||
337 | if (dev_priv->have_camera) { | |
338 | ttm_bo_clean_mm(bdev, TTM_PL_CI); | |
339 | dev_priv->have_camera = 0; | |
340 | } | |
341 | if (dev_priv->have_rar) { | |
342 | ttm_bo_clean_mm(bdev, TTM_PL_RAR); | |
343 | dev_priv->have_rar = 0; | |
344 | } | |
345 | ||
346 | } | |
347 | ||
348 | static void psb_get_core_freq(struct drm_device *dev) | |
349 | { | |
350 | uint32_t clock; | |
351 | struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); | |
352 | struct drm_psb_private *dev_priv = dev->dev_private; | |
353 | ||
354 | /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/ | |
355 | /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/ | |
356 | ||
357 | pci_write_config_dword(pci_root, 0xD0, 0xD0050300); | |
358 | pci_read_config_dword(pci_root, 0xD4, &clock); | |
359 | pci_dev_put(pci_root); | |
360 | ||
361 | switch (clock & 0x07) { | |
362 | case 0: | |
363 | dev_priv->core_freq = 100; | |
364 | break; | |
365 | case 1: | |
366 | dev_priv->core_freq = 133; | |
367 | break; | |
368 | case 2: | |
369 | dev_priv->core_freq = 150; | |
370 | break; | |
371 | case 3: | |
372 | dev_priv->core_freq = 178; | |
373 | break; | |
374 | case 4: | |
375 | dev_priv->core_freq = 200; | |
376 | break; | |
377 | case 5: | |
378 | case 6: | |
379 | case 7: | |
380 | dev_priv->core_freq = 266; | |
381 | default: | |
382 | dev_priv->core_freq = 0; | |
383 | } | |
384 | } | |
385 | ||
386 | #define FB_REG06 0xD0810600 | |
387 | #define FB_TOPAZ_DISABLE BIT0 | |
388 | #define FB_MIPI_DISABLE BIT11 | |
389 | #define FB_REG09 0xD0810900 | |
390 | #define FB_SKU_MASK (BIT12|BIT13|BIT14) | |
391 | #define FB_SKU_SHIFT 12 | |
392 | #define FB_SKU_100 0 | |
393 | #define FB_SKU_100L 1 | |
394 | #define FB_SKU_83 2 | |
395 | #if 1 /* FIXME remove it after PO */ | |
396 | #define FB_GFX_CLK_DIVIDE_MASK (BIT20|BIT21|BIT22) | |
397 | #define FB_GFX_CLK_DIVIDE_SHIFT 20 | |
398 | #define FB_VED_CLK_DIVIDE_MASK (BIT23|BIT24) | |
399 | #define FB_VED_CLK_DIVIDE_SHIFT 23 | |
400 | #define FB_VEC_CLK_DIVIDE_MASK (BIT25|BIT26) | |
401 | #define FB_VEC_CLK_DIVIDE_SHIFT 25 | |
402 | #endif /* FIXME remove it after PO */ | |
403 | ||
404 | ||
405 | bool mid_get_pci_revID(struct drm_psb_private *dev_priv) | |
406 | { | |
407 | uint32_t platform_rev_id = 0; | |
408 | struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); | |
409 | ||
410 | /*get the revison ID, B0:D2:F0;0x08 */ | |
411 | pci_read_config_dword(pci_gfx_root, 0x08, &platform_rev_id); | |
412 | dev_priv->platform_rev_id = (uint8_t) platform_rev_id; | |
413 | pci_dev_put(pci_gfx_root); | |
414 | PSB_DEBUG_ENTRY("platform_rev_id is %x\n", | |
415 | dev_priv->platform_rev_id); | |
416 | ||
417 | return true; | |
418 | } | |
419 | ||
420 | static int psb_do_init(struct drm_device *dev) | |
421 | { | |
422 | struct drm_psb_private *dev_priv = | |
423 | (struct drm_psb_private *) dev->dev_private; | |
424 | struct ttm_bo_device *bdev = &dev_priv->bdev; | |
425 | struct psb_gtt *pg = dev_priv->pg; | |
426 | ||
427 | uint32_t stolen_gtt; | |
428 | uint32_t tt_start; | |
429 | uint32_t tt_pages; | |
430 | ||
431 | int ret = -ENOMEM; | |
432 | ||
433 | ||
434 | /* | |
435 | * Initialize sequence numbers for the different command | |
436 | * submission mechanisms. | |
437 | */ | |
438 | ||
439 | dev_priv->sequence[PSB_ENGINE_2D] = 0; | |
440 | dev_priv->sequence[PSB_ENGINE_VIDEO] = 0; | |
441 | dev_priv->sequence[LNC_ENGINE_ENCODE] = 0; | |
442 | ||
443 | if (pg->mmu_gatt_start & 0x0FFFFFFF) { | |
444 | DRM_ERROR("Gatt must be 256M aligned. This is a bug.\n"); | |
445 | ret = -EINVAL; | |
446 | goto out_err; | |
447 | } | |
448 | ||
449 | stolen_gtt = (pg->stolen_size >> PAGE_SHIFT) * 4; | |
450 | stolen_gtt = (stolen_gtt + PAGE_SIZE - 1) >> PAGE_SHIFT; | |
451 | stolen_gtt = | |
452 | (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; | |
453 | ||
454 | dev_priv->gatt_free_offset = pg->mmu_gatt_start + | |
455 | (stolen_gtt << PAGE_SHIFT) * 1024; | |
456 | ||
457 | if (1 || drm_debug) { | |
458 | uint32_t core_id = PSB_RSGX32(PSB_CR_CORE_ID); | |
459 | uint32_t core_rev = PSB_RSGX32(PSB_CR_CORE_REVISION); | |
460 | DRM_INFO("SGX core id = 0x%08x\n", core_id); | |
461 | DRM_INFO("SGX core rev major = 0x%02x, minor = 0x%02x\n", | |
462 | (core_rev & _PSB_CC_REVISION_MAJOR_MASK) >> | |
463 | _PSB_CC_REVISION_MAJOR_SHIFT, | |
464 | (core_rev & _PSB_CC_REVISION_MINOR_MASK) >> | |
465 | _PSB_CC_REVISION_MINOR_SHIFT); | |
466 | DRM_INFO | |
467 | ("SGX core rev maintenance = 0x%02x, designer = 0x%02x\n", | |
468 | (core_rev & _PSB_CC_REVISION_MAINTENANCE_MASK) >> | |
469 | _PSB_CC_REVISION_MAINTENANCE_SHIFT, | |
470 | (core_rev & _PSB_CC_REVISION_DESIGNER_MASK) >> | |
471 | _PSB_CC_REVISION_DESIGNER_SHIFT); | |
472 | } | |
473 | ||
474 | spin_lock_init(&dev_priv->irqmask_lock); | |
475 | ||
476 | tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ? | |
477 | pg->gatt_pages : PSB_TT_PRIV0_PLIMIT; | |
478 | tt_start = dev_priv->gatt_free_offset - pg->mmu_gatt_start; | |
479 | tt_pages -= tt_start >> PAGE_SHIFT; | |
480 | dev_priv->sizes.ta_mem_size = 0; | |
481 | ||
482 | ||
483 | /* TT region managed by TTM. */ | |
484 | if (!ttm_bo_init_mm(bdev, TTM_PL_TT, | |
485 | pg->gatt_pages - | |
486 | (pg->ci_start >> PAGE_SHIFT) - | |
487 | ((dev_priv->ci_region_size + dev_priv->rar_region_size) | |
488 | >> PAGE_SHIFT))) { | |
489 | ||
490 | dev_priv->have_tt = 1; | |
491 | dev_priv->sizes.tt_size = | |
492 | (tt_pages << PAGE_SHIFT) / (1024 * 1024) / 2; | |
493 | } | |
494 | ||
495 | if (!ttm_bo_init_mm(bdev, | |
496 | DRM_PSB_MEM_MMU, | |
497 | PSB_MEM_TT_START >> PAGE_SHIFT)) { | |
498 | dev_priv->have_mem_mmu = 1; | |
499 | dev_priv->sizes.mmu_size = | |
500 | PSB_MEM_TT_START / (1024*1024); | |
501 | } | |
502 | ||
503 | ||
504 | PSB_DEBUG_INIT("Init MSVDX\n"); | |
505 | return 0; | |
506 | out_err: | |
507 | psb_do_takedown(dev); | |
508 | return ret; | |
509 | } | |
510 | ||
511 | static int psb_driver_unload(struct drm_device *dev) | |
512 | { | |
513 | struct drm_psb_private *dev_priv = | |
514 | (struct drm_psb_private *) dev->dev_private; | |
515 | ||
516 | /* Kill vblank etc here */ | |
517 | ||
518 | psb_backlight_exit(); /*writes minimum value to backlight HW reg */ | |
519 | ||
520 | if (drm_psb_no_fb == 0) | |
521 | psb_modeset_cleanup(dev); | |
522 | ||
523 | if (dev_priv) { | |
524 | psb_lid_timer_takedown(dev_priv); | |
525 | ||
526 | psb_do_takedown(dev); | |
527 | ||
528 | ||
529 | if (dev_priv->pf_pd) { | |
530 | psb_mmu_free_pagedir(dev_priv->pf_pd); | |
531 | dev_priv->pf_pd = NULL; | |
532 | } | |
533 | if (dev_priv->mmu) { | |
534 | struct psb_gtt *pg = dev_priv->pg; | |
535 | ||
536 | down_read(&pg->sem); | |
537 | psb_mmu_remove_pfn_sequence( | |
538 | psb_mmu_get_default_pd | |
539 | (dev_priv->mmu), | |
540 | pg->mmu_gatt_start, | |
541 | pg->vram_stolen_size >> PAGE_SHIFT); | |
542 | if (pg->ci_stolen_size != 0) | |
543 | psb_mmu_remove_pfn_sequence( | |
544 | psb_mmu_get_default_pd | |
545 | (dev_priv->mmu), | |
546 | pg->ci_start, | |
547 | pg->ci_stolen_size >> PAGE_SHIFT); | |
548 | if (pg->rar_stolen_size != 0) | |
549 | psb_mmu_remove_pfn_sequence( | |
550 | psb_mmu_get_default_pd | |
551 | (dev_priv->mmu), | |
552 | pg->rar_start, | |
553 | pg->rar_stolen_size >> PAGE_SHIFT); | |
554 | up_read(&pg->sem); | |
555 | psb_mmu_driver_takedown(dev_priv->mmu); | |
556 | dev_priv->mmu = NULL; | |
557 | } | |
558 | psb_gtt_takedown(dev_priv->pg, 1); | |
559 | if (dev_priv->scratch_page) { | |
560 | __free_page(dev_priv->scratch_page); | |
561 | dev_priv->scratch_page = NULL; | |
562 | } | |
563 | if (dev_priv->has_bo_device) { | |
564 | ttm_bo_device_release(&dev_priv->bdev); | |
565 | dev_priv->has_bo_device = 0; | |
566 | } | |
567 | if (dev_priv->has_fence_device) { | |
568 | ttm_fence_device_release(&dev_priv->fdev); | |
569 | dev_priv->has_fence_device = 0; | |
570 | } | |
571 | if (dev_priv->vdc_reg) { | |
572 | iounmap(dev_priv->vdc_reg); | |
573 | dev_priv->vdc_reg = NULL; | |
574 | } | |
575 | if (dev_priv->sgx_reg) { | |
576 | iounmap(dev_priv->sgx_reg); | |
577 | dev_priv->sgx_reg = NULL; | |
578 | } | |
579 | ||
580 | if (dev_priv->tdev) | |
581 | ttm_object_device_release(&dev_priv->tdev); | |
582 | ||
583 | if (dev_priv->has_global) | |
584 | psb_ttm_global_release(dev_priv); | |
585 | ||
586 | kfree(dev_priv); | |
587 | dev->dev_private = NULL; | |
588 | ||
589 | /*destory VBT data*/ | |
590 | psb_intel_destory_bios(dev); | |
591 | } | |
592 | ||
593 | ospm_power_uninit(); | |
594 | ||
595 | return 0; | |
596 | } | |
597 | ||
598 | ||
599 | static int psb_driver_load(struct drm_device *dev, unsigned long chipset) | |
600 | { | |
601 | struct drm_psb_private *dev_priv; | |
602 | struct ttm_bo_device *bdev; | |
603 | unsigned long resource_start; | |
604 | struct psb_gtt *pg; | |
605 | unsigned long irqflags; | |
606 | int ret = -ENOMEM; | |
607 | uint32_t tt_pages; | |
608 | ||
609 | DRM_INFO("psb - %s\n", PSB_PACKAGE_VERSION); | |
610 | ||
611 | DRM_INFO("Run drivers on Poulsbo platform!\n"); | |
612 | ||
613 | dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); | |
614 | if (dev_priv == NULL) | |
615 | return -ENOMEM; | |
616 | INIT_LIST_HEAD(&dev_priv->video_ctx); | |
617 | ||
618 | dev_priv->num_pipe = 2; | |
619 | ||
620 | ||
621 | dev_priv->dev = dev; | |
622 | bdev = &dev_priv->bdev; | |
623 | ||
624 | ret = psb_ttm_global_init(dev_priv); | |
625 | if (unlikely(ret != 0)) | |
626 | goto out_err; | |
627 | dev_priv->has_global = 1; | |
628 | ||
629 | dev_priv->tdev = ttm_object_device_init | |
630 | (dev_priv->mem_global_ref.object, PSB_OBJECT_HASH_ORDER); | |
631 | if (unlikely(dev_priv->tdev == NULL)) | |
632 | goto out_err; | |
633 | ||
634 | mutex_init(&dev_priv->temp_mem); | |
635 | mutex_init(&dev_priv->cmdbuf_mutex); | |
636 | mutex_init(&dev_priv->reset_mutex); | |
637 | INIT_LIST_HEAD(&dev_priv->context.validate_list); | |
638 | INIT_LIST_HEAD(&dev_priv->context.kern_validate_list); | |
639 | ||
640 | /* mutex_init(&dev_priv->dsr_mutex); */ | |
641 | ||
642 | spin_lock_init(&dev_priv->reloc_lock); | |
643 | ||
644 | DRM_INIT_WAITQUEUE(&dev_priv->rel_mapped_queue); | |
645 | ||
646 | dev->dev_private = (void *) dev_priv; | |
647 | dev_priv->chipset = chipset; | |
648 | psb_set_uopt(&dev_priv->uopt); | |
649 | ||
650 | PSB_DEBUG_INIT("Mapping MMIO\n"); | |
651 | resource_start = pci_resource_start(dev->pdev, PSB_MMIO_RESOURCE); | |
652 | ||
653 | dev_priv->vdc_reg = | |
654 | ioremap(resource_start + PSB_VDC_OFFSET, PSB_VDC_SIZE); | |
655 | if (!dev_priv->vdc_reg) | |
656 | goto out_err; | |
657 | ||
658 | dev_priv->sgx_reg = ioremap(resource_start + PSB_SGX_OFFSET, | |
659 | PSB_SGX_SIZE); | |
660 | ||
661 | if (!dev_priv->sgx_reg) | |
662 | goto out_err; | |
663 | ||
664 | psb_get_core_freq(dev); | |
665 | psb_intel_opregion_init(dev); | |
666 | psb_intel_init_bios(dev); | |
667 | ||
668 | PSB_DEBUG_INIT("Init TTM fence and BO driver\n"); | |
669 | ||
670 | /* Init OSPM support */ | |
671 | ospm_power_init(dev); | |
672 | ||
673 | ret = psb_ttm_fence_device_init(&dev_priv->fdev); | |
674 | if (unlikely(ret != 0)) | |
675 | goto out_err; | |
676 | ||
677 | dev_priv->has_fence_device = 1; | |
678 | ret = ttm_bo_device_init(bdev, | |
679 | dev_priv->bo_global_ref.ref.object, | |
680 | &psb_ttm_bo_driver, | |
681 | DRM_PSB_FILE_PAGE_OFFSET, false); | |
682 | if (unlikely(ret != 0)) | |
683 | goto out_err; | |
684 | dev_priv->has_bo_device = 1; | |
685 | ttm_lock_init(&dev_priv->ttm_lock); | |
686 | ||
687 | ret = -ENOMEM; | |
688 | ||
689 | dev_priv->scratch_page = alloc_page(GFP_DMA32 | __GFP_ZERO); | |
690 | if (!dev_priv->scratch_page) | |
691 | goto out_err; | |
692 | ||
693 | set_pages_uc(dev_priv->scratch_page, 1); | |
694 | ||
695 | dev_priv->pg = psb_gtt_alloc(dev); | |
696 | if (!dev_priv->pg) | |
697 | goto out_err; | |
698 | ||
699 | ret = psb_gtt_init(dev_priv->pg, 0); | |
700 | if (ret) | |
701 | goto out_err; | |
702 | ||
703 | ret = psb_gtt_mm_init(dev_priv->pg); | |
704 | if (ret) | |
705 | goto out_err; | |
706 | ||
707 | dev_priv->mmu = psb_mmu_driver_init((void *)0, | |
708 | drm_psb_trap_pagefaults, 0, | |
709 | dev_priv); | |
710 | if (!dev_priv->mmu) | |
711 | goto out_err; | |
712 | ||
713 | pg = dev_priv->pg; | |
714 | ||
715 | tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ? | |
716 | (pg->gatt_pages) : PSB_TT_PRIV0_PLIMIT; | |
717 | ||
718 | /* CI/RAR use the lower half of TT. */ | |
719 | pg->ci_start = (tt_pages / 2) << PAGE_SHIFT; | |
720 | pg->rar_start = pg->ci_start + pg->ci_stolen_size; | |
721 | ||
722 | ||
723 | /* | |
724 | * Make MSVDX/TOPAZ MMU aware of the CI stolen memory area. | |
725 | */ | |
726 | if (dev_priv->pg->ci_stolen_size != 0) { | |
727 | down_read(&pg->sem); | |
728 | ret = psb_mmu_insert_pfn_sequence(psb_mmu_get_default_pd | |
729 | (dev_priv->mmu), | |
730 | dev_priv->ci_region_start >> PAGE_SHIFT, | |
731 | pg->mmu_gatt_start + pg->ci_start, | |
732 | pg->ci_stolen_size >> PAGE_SHIFT, 0); | |
733 | up_read(&pg->sem); | |
734 | if (ret) | |
735 | goto out_err; | |
736 | } | |
737 | ||
738 | /* | |
739 | * Make MSVDX/TOPAZ MMU aware of the rar stolen memory area. | |
740 | */ | |
741 | if (dev_priv->pg->rar_stolen_size != 0) { | |
742 | down_read(&pg->sem); | |
743 | ret = psb_mmu_insert_pfn_sequence( | |
744 | psb_mmu_get_default_pd(dev_priv->mmu), | |
745 | dev_priv->rar_region_start >> PAGE_SHIFT, | |
746 | pg->mmu_gatt_start + pg->rar_start, | |
747 | pg->rar_stolen_size >> PAGE_SHIFT, 0); | |
748 | up_read(&pg->sem); | |
749 | if (ret) | |
750 | goto out_err; | |
751 | } | |
752 | ||
753 | dev_priv->pf_pd = psb_mmu_alloc_pd(dev_priv->mmu, 1, 0); | |
754 | if (!dev_priv->pf_pd) | |
755 | goto out_err; | |
756 | ||
757 | psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0); | |
758 | psb_mmu_set_pd_context(dev_priv->pf_pd, 1); | |
759 | ||
760 | spin_lock_init(&dev_priv->sequence_lock); | |
761 | ||
762 | PSB_DEBUG_INIT("Begin to init MSVDX/Topaz\n"); | |
763 | ||
764 | ret = psb_do_init(dev); | |
765 | if (ret) | |
766 | return ret; | |
767 | ||
768 | /** | |
769 | * Init lid switch timer. | |
770 | * NOTE: must do this after psb_intel_opregion_init | |
771 | * and psb_backlight_init | |
772 | */ | |
773 | if (dev_priv->lid_state) | |
774 | psb_lid_timer_init(dev_priv); | |
775 | ||
776 | ret = drm_vblank_init(dev, dev_priv->num_pipe); | |
777 | if (ret) | |
778 | goto out_err; | |
779 | ||
780 | /* | |
781 | * Install interrupt handlers prior to powering off SGX or else we will | |
782 | * crash. | |
783 | */ | |
784 | dev_priv->vdc_irq_mask = 0; | |
785 | dev_priv->pipestat[0] = 0; | |
786 | dev_priv->pipestat[1] = 0; | |
787 | dev_priv->pipestat[2] = 0; | |
788 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | |
789 | PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); | |
790 | PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R); | |
791 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | |
792 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | |
793 | drm_irq_install(dev); | |
794 | ||
795 | dev->vblank_disable_allowed = 1; | |
796 | ||
797 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | |
798 | ||
799 | dev->driver->get_vblank_counter = psb_get_vblank_counter; | |
800 | ||
801 | if (drm_psb_no_fb == 0) { | |
802 | psb_modeset_init(dev); | |
803 | psb_fbdev_init(dev); | |
804 | drm_kms_helper_poll_init(dev); | |
805 | } | |
806 | ||
807 | ret = psb_backlight_init(dev); | |
808 | if (ret) | |
809 | return ret; | |
810 | #if 0 | |
811 | /*enable runtime pm at last*/ | |
812 | pm_runtime_enable(&dev->pdev->dev); | |
813 | pm_runtime_set_active(&dev->pdev->dev); | |
814 | #endif | |
815 | /*Intel drm driver load is done, continue doing pvr load*/ | |
816 | DRM_DEBUG("Pvr driver load\n"); | |
817 | ||
818 | /* if (PVRCore_Init() < 0) | |
819 | goto out_err; */ | |
820 | /* if (MRSTLFBInit(dev) < 0) | |
821 | goto out_err;*/ | |
822 | return 0; | |
823 | out_err: | |
824 | psb_driver_unload(dev); | |
825 | return ret; | |
826 | } | |
827 | ||
828 | int psb_driver_device_is_agp(struct drm_device *dev) | |
829 | { | |
830 | return 0; | |
831 | } | |
832 | ||
833 | ||
834 | static int psb_vt_leave_ioctl(struct drm_device *dev, void *data, | |
835 | struct drm_file *file_priv) | |
836 | { | |
837 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
838 | struct ttm_bo_device *bdev = &dev_priv->bdev; | |
839 | struct ttm_mem_type_manager *man; | |
840 | int ret; | |
841 | ||
842 | ret = ttm_vt_lock(&dev_priv->ttm_lock, 1, | |
843 | psb_fpriv(file_priv)->tfile); | |
844 | if (unlikely(ret != 0)) | |
845 | return ret; | |
846 | ||
847 | ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_TT); | |
848 | if (unlikely(ret != 0)) | |
849 | goto out_unlock; | |
850 | ||
851 | man = &bdev->man[TTM_PL_TT]; | |
852 | ||
853 | #if 0 /* What to do with this ? */ | |
854 | if (unlikely(!drm_mm_clean(&man->manager))) | |
855 | DRM_INFO("Warning: GATT was not clean after VT switch.\n"); | |
856 | #endif | |
857 | ||
858 | ttm_bo_swapout_all(&dev_priv->bdev); | |
859 | ||
860 | return 0; | |
861 | out_unlock: | |
862 | (void) ttm_vt_unlock(&dev_priv->ttm_lock); | |
863 | return ret; | |
864 | } | |
865 | ||
866 | static int psb_vt_enter_ioctl(struct drm_device *dev, void *data, | |
867 | struct drm_file *file_priv) | |
868 | { | |
869 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
870 | return ttm_vt_unlock(&dev_priv->ttm_lock); | |
871 | } | |
872 | ||
873 | static int psb_sizes_ioctl(struct drm_device *dev, void *data, | |
874 | struct drm_file *file_priv) | |
875 | { | |
876 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
877 | struct drm_psb_sizes_arg *arg = | |
878 | (struct drm_psb_sizes_arg *) data; | |
879 | ||
880 | *arg = dev_priv->sizes; | |
881 | return 0; | |
882 | } | |
883 | ||
884 | static int psb_dc_state_ioctl(struct drm_device *dev, void * data, | |
885 | struct drm_file *file_priv) | |
886 | { | |
887 | uint32_t flags; | |
888 | uint32_t obj_id; | |
889 | struct drm_mode_object *obj; | |
890 | struct drm_connector *connector; | |
891 | struct drm_crtc *crtc; | |
892 | struct drm_psb_dc_state_arg *arg = | |
893 | (struct drm_psb_dc_state_arg *)data; | |
894 | ||
895 | flags = arg->flags; | |
896 | obj_id = arg->obj_id; | |
897 | ||
898 | if (flags & PSB_DC_CRTC_MASK) { | |
899 | obj = drm_mode_object_find(dev, obj_id, | |
900 | DRM_MODE_OBJECT_CRTC); | |
901 | if (!obj) { | |
902 | DRM_DEBUG("Invalid CRTC object.\n"); | |
903 | return -EINVAL; | |
904 | } | |
905 | ||
906 | crtc = obj_to_crtc(obj); | |
907 | ||
908 | mutex_lock(&dev->mode_config.mutex); | |
909 | if (drm_helper_crtc_in_use(crtc)) { | |
910 | if (flags & PSB_DC_CRTC_SAVE) | |
911 | crtc->funcs->save(crtc); | |
912 | else | |
913 | crtc->funcs->restore(crtc); | |
914 | } | |
915 | mutex_unlock(&dev->mode_config.mutex); | |
916 | ||
917 | return 0; | |
918 | } else if (flags & PSB_DC_OUTPUT_MASK) { | |
919 | obj = drm_mode_object_find(dev, obj_id, | |
920 | DRM_MODE_OBJECT_CONNECTOR); | |
921 | if (!obj) { | |
922 | DRM_DEBUG("Invalid connector id.\n"); | |
923 | return -EINVAL; | |
924 | } | |
925 | ||
926 | connector = obj_to_connector(obj); | |
927 | if (flags & PSB_DC_OUTPUT_SAVE) | |
928 | connector->funcs->save(connector); | |
929 | else | |
930 | connector->funcs->restore(connector); | |
931 | ||
932 | return 0; | |
933 | } | |
934 | ||
935 | DRM_DEBUG("Bad flags 0x%x\n", flags); | |
936 | return -EINVAL; | |
937 | } | |
938 | ||
939 | static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, | |
940 | struct drm_file *file_priv) | |
941 | { | |
942 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
943 | uint32_t *arg = data; | |
944 | struct backlight_device bd; | |
945 | dev_priv->blc_adj2 = *arg; | |
946 | ||
947 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | |
948 | bd.props.brightness = psb_get_brightness(&bd); | |
949 | psb_set_brightness(&bd); | |
950 | #endif | |
951 | return 0; | |
952 | } | |
953 | ||
954 | static int psb_adb_ioctl(struct drm_device *dev, void *data, | |
955 | struct drm_file *file_priv) | |
956 | { | |
957 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
958 | uint32_t *arg = data; | |
959 | struct backlight_device bd; | |
960 | dev_priv->blc_adj1 = *arg; | |
961 | ||
962 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | |
963 | bd.props.brightness = psb_get_brightness(&bd); | |
964 | psb_set_brightness(&bd); | |
965 | #endif | |
966 | return 0; | |
967 | } | |
968 | ||
969 | /* return the current mode to the dpst module */ | |
970 | static int psb_dpst_ioctl(struct drm_device *dev, void *data, | |
971 | struct drm_file *file_priv) | |
972 | { | |
973 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
974 | uint32_t *arg = data; | |
975 | uint32_t x; | |
976 | uint32_t y; | |
977 | uint32_t reg; | |
978 | ||
979 | if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, | |
980 | OSPM_UHB_ONLY_IF_ON)) | |
981 | return 0; | |
982 | ||
983 | reg = PSB_RVDC32(PIPEASRC); | |
984 | ||
985 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
986 | ||
987 | /* horizontal is the left 16 bits */ | |
988 | x = reg >> 16; | |
989 | /* vertical is the right 16 bits */ | |
990 | y = reg & 0x0000ffff; | |
991 | ||
992 | /* the values are the image size minus one */ | |
993 | x++; | |
994 | y++; | |
995 | ||
996 | *arg = (x << 16) | y; | |
997 | ||
998 | return 0; | |
999 | } | |
1000 | static int psb_gamma_ioctl(struct drm_device *dev, void *data, | |
1001 | struct drm_file *file_priv) | |
1002 | { | |
1003 | struct drm_psb_dpst_lut_arg *lut_arg = data; | |
1004 | struct drm_mode_object *obj; | |
1005 | struct drm_crtc *crtc; | |
1006 | struct drm_connector *connector; | |
1007 | struct psb_intel_crtc *psb_intel_crtc; | |
1008 | int i = 0; | |
1009 | int32_t obj_id; | |
1010 | ||
1011 | obj_id = lut_arg->output_id; | |
1012 | obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR); | |
1013 | if (!obj) { | |
1014 | DRM_DEBUG("Invalid Connector object.\n"); | |
1015 | return -EINVAL; | |
1016 | } | |
1017 | ||
1018 | connector = obj_to_connector(obj); | |
1019 | crtc = connector->encoder->crtc; | |
1020 | psb_intel_crtc = to_psb_intel_crtc(crtc); | |
1021 | ||
1022 | for (i = 0; i < 256; i++) | |
1023 | psb_intel_crtc->lut_adj[i] = lut_arg->lut[i]; | |
1024 | ||
1025 | psb_intel_crtc_load_lut(crtc); | |
1026 | ||
1027 | return 0; | |
1028 | } | |
1029 | ||
1030 | static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, | |
1031 | struct drm_file *file_priv) | |
1032 | { | |
1033 | uint32_t obj_id; | |
1034 | uint16_t op; | |
1035 | struct drm_mode_modeinfo *umode; | |
1036 | struct drm_display_mode *mode = NULL; | |
1037 | struct drm_psb_mode_operation_arg *arg; | |
1038 | struct drm_mode_object *obj; | |
1039 | struct drm_connector *connector; | |
1040 | struct drm_framebuffer *drm_fb; | |
1041 | struct psb_framebuffer *psb_fb; | |
1042 | struct drm_connector_helper_funcs *connector_funcs; | |
1043 | int ret = 0; | |
1044 | int resp = MODE_OK; | |
1045 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
1046 | ||
1047 | arg = (struct drm_psb_mode_operation_arg *)data; | |
1048 | obj_id = arg->obj_id; | |
1049 | op = arg->operation; | |
1050 | ||
1051 | switch (op) { | |
1052 | case PSB_MODE_OPERATION_SET_DC_BASE: | |
1053 | obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_FB); | |
1054 | if (!obj) { | |
1055 | DRM_ERROR("Invalid FB id %d\n", obj_id); | |
1056 | return -EINVAL; | |
1057 | } | |
1058 | ||
1059 | drm_fb = obj_to_fb(obj); | |
1060 | psb_fb = to_psb_fb(drm_fb); | |
1061 | ||
1062 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, | |
1063 | OSPM_UHB_ONLY_IF_ON)) { | |
1064 | REG_WRITE(DSPASURF, psb_fb->offset); | |
1065 | REG_READ(DSPASURF); | |
1066 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1067 | } else { | |
1068 | dev_priv->saveDSPASURF = psb_fb->offset; | |
1069 | } | |
1070 | ||
1071 | return 0; | |
1072 | case PSB_MODE_OPERATION_MODE_VALID: | |
1073 | umode = &arg->mode; | |
1074 | ||
1075 | mutex_lock(&dev->mode_config.mutex); | |
1076 | ||
1077 | obj = drm_mode_object_find(dev, obj_id, | |
1078 | DRM_MODE_OBJECT_CONNECTOR); | |
1079 | if (!obj) { | |
1080 | ret = -EINVAL; | |
1081 | goto mode_op_out; | |
1082 | } | |
1083 | ||
1084 | connector = obj_to_connector(obj); | |
1085 | ||
1086 | mode = drm_mode_create(dev); | |
1087 | if (!mode) { | |
1088 | ret = -ENOMEM; | |
1089 | goto mode_op_out; | |
1090 | } | |
1091 | ||
1092 | /* drm_crtc_convert_umode(mode, umode); */ | |
1093 | { | |
1094 | mode->clock = umode->clock; | |
1095 | mode->hdisplay = umode->hdisplay; | |
1096 | mode->hsync_start = umode->hsync_start; | |
1097 | mode->hsync_end = umode->hsync_end; | |
1098 | mode->htotal = umode->htotal; | |
1099 | mode->hskew = umode->hskew; | |
1100 | mode->vdisplay = umode->vdisplay; | |
1101 | mode->vsync_start = umode->vsync_start; | |
1102 | mode->vsync_end = umode->vsync_end; | |
1103 | mode->vtotal = umode->vtotal; | |
1104 | mode->vscan = umode->vscan; | |
1105 | mode->vrefresh = umode->vrefresh; | |
1106 | mode->flags = umode->flags; | |
1107 | mode->type = umode->type; | |
1108 | strncpy(mode->name, umode->name, DRM_DISPLAY_MODE_LEN); | |
1109 | mode->name[DRM_DISPLAY_MODE_LEN-1] = 0; | |
1110 | } | |
1111 | ||
1112 | connector_funcs = (struct drm_connector_helper_funcs *) | |
1113 | connector->helper_private; | |
1114 | ||
1115 | if (connector_funcs->mode_valid) { | |
1116 | resp = connector_funcs->mode_valid(connector, mode); | |
1117 | arg->data = (void *)resp; | |
1118 | } | |
1119 | ||
1120 | /*do some clean up work*/ | |
1121 | if (mode) | |
1122 | drm_mode_destroy(dev, mode); | |
1123 | mode_op_out: | |
1124 | mutex_unlock(&dev->mode_config.mutex); | |
1125 | return ret; | |
1126 | ||
1127 | default: | |
1128 | DRM_DEBUG("Unsupported psb mode operation"); | |
1129 | return -EOPNOTSUPP; | |
1130 | } | |
1131 | ||
1132 | return 0; | |
1133 | } | |
1134 | ||
1135 | static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, | |
1136 | struct drm_file *file_priv) | |
1137 | { | |
1138 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
1139 | struct drm_psb_stolen_memory_arg *arg = data; | |
1140 | ||
1141 | arg->base = dev_priv->pg->stolen_base; | |
1142 | arg->size = dev_priv->pg->vram_stolen_size; | |
1143 | ||
1144 | return 0; | |
1145 | } | |
1146 | ||
1147 | static int psb_register_rw_ioctl(struct drm_device *dev, void *data, | |
1148 | struct drm_file *file_priv) | |
1149 | { | |
1150 | struct drm_psb_private *dev_priv = psb_priv(dev); | |
1151 | struct drm_psb_register_rw_arg *arg = data; | |
1152 | UHBUsage usage = | |
1153 | arg->b_force_hw_on ? OSPM_UHB_FORCE_POWER_ON : OSPM_UHB_ONLY_IF_ON; | |
1154 | ||
1155 | if (arg->display_write_mask != 0) { | |
1156 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) { | |
1157 | if (arg->display_write_mask & REGRWBITS_PFIT_CONTROLS) | |
1158 | PSB_WVDC32(arg->display.pfit_controls, | |
1159 | PFIT_CONTROL); | |
1160 | if (arg->display_write_mask & | |
1161 | REGRWBITS_PFIT_AUTOSCALE_RATIOS) | |
1162 | PSB_WVDC32(arg->display.pfit_autoscale_ratios, | |
1163 | PFIT_AUTO_RATIOS); | |
1164 | if (arg->display_write_mask & | |
1165 | REGRWBITS_PFIT_PROGRAMMED_SCALE_RATIOS) | |
1166 | PSB_WVDC32( | |
1167 | arg->display.pfit_programmed_scale_ratios, | |
1168 | PFIT_PGM_RATIOS); | |
1169 | if (arg->display_write_mask & REGRWBITS_PIPEASRC) | |
1170 | PSB_WVDC32(arg->display.pipeasrc, | |
1171 | PIPEASRC); | |
1172 | if (arg->display_write_mask & REGRWBITS_PIPEBSRC) | |
1173 | PSB_WVDC32(arg->display.pipebsrc, | |
1174 | PIPEBSRC); | |
1175 | if (arg->display_write_mask & REGRWBITS_VTOTAL_A) | |
1176 | PSB_WVDC32(arg->display.vtotal_a, | |
1177 | VTOTAL_A); | |
1178 | if (arg->display_write_mask & REGRWBITS_VTOTAL_B) | |
1179 | PSB_WVDC32(arg->display.vtotal_b, | |
1180 | VTOTAL_B); | |
1181 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1182 | } else { | |
1183 | if (arg->display_write_mask & REGRWBITS_PFIT_CONTROLS) | |
1184 | dev_priv->savePFIT_CONTROL = | |
1185 | arg->display.pfit_controls; | |
1186 | if (arg->display_write_mask & | |
1187 | REGRWBITS_PFIT_AUTOSCALE_RATIOS) | |
1188 | dev_priv->savePFIT_AUTO_RATIOS = | |
1189 | arg->display.pfit_autoscale_ratios; | |
1190 | if (arg->display_write_mask & | |
1191 | REGRWBITS_PFIT_PROGRAMMED_SCALE_RATIOS) | |
1192 | dev_priv->savePFIT_PGM_RATIOS = | |
1193 | arg->display.pfit_programmed_scale_ratios; | |
1194 | if (arg->display_write_mask & REGRWBITS_PIPEASRC) | |
1195 | dev_priv->savePIPEASRC = arg->display.pipeasrc; | |
1196 | if (arg->display_write_mask & REGRWBITS_PIPEBSRC) | |
1197 | dev_priv->savePIPEBSRC = arg->display.pipebsrc; | |
1198 | if (arg->display_write_mask & REGRWBITS_VTOTAL_A) | |
1199 | dev_priv->saveVTOTAL_A = arg->display.vtotal_a; | |
1200 | if (arg->display_write_mask & REGRWBITS_VTOTAL_B) | |
1201 | dev_priv->saveVTOTAL_B = arg->display.vtotal_b; | |
1202 | } | |
1203 | } | |
1204 | ||
1205 | if (arg->display_read_mask != 0) { | |
1206 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) { | |
1207 | if (arg->display_read_mask & | |
1208 | REGRWBITS_PFIT_CONTROLS) | |
1209 | arg->display.pfit_controls = | |
1210 | PSB_RVDC32(PFIT_CONTROL); | |
1211 | if (arg->display_read_mask & | |
1212 | REGRWBITS_PFIT_AUTOSCALE_RATIOS) | |
1213 | arg->display.pfit_autoscale_ratios = | |
1214 | PSB_RVDC32(PFIT_AUTO_RATIOS); | |
1215 | if (arg->display_read_mask & | |
1216 | REGRWBITS_PFIT_PROGRAMMED_SCALE_RATIOS) | |
1217 | arg->display.pfit_programmed_scale_ratios = | |
1218 | PSB_RVDC32(PFIT_PGM_RATIOS); | |
1219 | if (arg->display_read_mask & REGRWBITS_PIPEASRC) | |
1220 | arg->display.pipeasrc = PSB_RVDC32(PIPEASRC); | |
1221 | if (arg->display_read_mask & REGRWBITS_PIPEBSRC) | |
1222 | arg->display.pipebsrc = PSB_RVDC32(PIPEBSRC); | |
1223 | if (arg->display_read_mask & REGRWBITS_VTOTAL_A) | |
1224 | arg->display.vtotal_a = PSB_RVDC32(VTOTAL_A); | |
1225 | if (arg->display_read_mask & REGRWBITS_VTOTAL_B) | |
1226 | arg->display.vtotal_b = PSB_RVDC32(VTOTAL_B); | |
1227 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1228 | } else { | |
1229 | if (arg->display_read_mask & | |
1230 | REGRWBITS_PFIT_CONTROLS) | |
1231 | arg->display.pfit_controls = | |
1232 | dev_priv->savePFIT_CONTROL; | |
1233 | if (arg->display_read_mask & | |
1234 | REGRWBITS_PFIT_AUTOSCALE_RATIOS) | |
1235 | arg->display.pfit_autoscale_ratios = | |
1236 | dev_priv->savePFIT_AUTO_RATIOS; | |
1237 | if (arg->display_read_mask & | |
1238 | REGRWBITS_PFIT_PROGRAMMED_SCALE_RATIOS) | |
1239 | arg->display.pfit_programmed_scale_ratios = | |
1240 | dev_priv->savePFIT_PGM_RATIOS; | |
1241 | if (arg->display_read_mask & REGRWBITS_PIPEASRC) | |
1242 | arg->display.pipeasrc = dev_priv->savePIPEASRC; | |
1243 | if (arg->display_read_mask & REGRWBITS_PIPEBSRC) | |
1244 | arg->display.pipebsrc = dev_priv->savePIPEBSRC; | |
1245 | if (arg->display_read_mask & REGRWBITS_VTOTAL_A) | |
1246 | arg->display.vtotal_a = dev_priv->saveVTOTAL_A; | |
1247 | if (arg->display_read_mask & REGRWBITS_VTOTAL_B) | |
1248 | arg->display.vtotal_b = dev_priv->saveVTOTAL_B; | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | if (arg->overlay_write_mask != 0) { | |
1253 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) { | |
1254 | if (arg->overlay_write_mask & OV_REGRWBITS_OGAM_ALL) { | |
1255 | PSB_WVDC32(arg->overlay.OGAMC5, OV_OGAMC5); | |
1256 | PSB_WVDC32(arg->overlay.OGAMC4, OV_OGAMC4); | |
1257 | PSB_WVDC32(arg->overlay.OGAMC3, OV_OGAMC3); | |
1258 | PSB_WVDC32(arg->overlay.OGAMC2, OV_OGAMC2); | |
1259 | PSB_WVDC32(arg->overlay.OGAMC1, OV_OGAMC1); | |
1260 | PSB_WVDC32(arg->overlay.OGAMC0, OV_OGAMC0); | |
1261 | } | |
1262 | if (arg->overlay_write_mask & OVC_REGRWBITS_OGAM_ALL) { | |
1263 | PSB_WVDC32(arg->overlay.OGAMC5, OVC_OGAMC5); | |
1264 | PSB_WVDC32(arg->overlay.OGAMC4, OVC_OGAMC4); | |
1265 | PSB_WVDC32(arg->overlay.OGAMC3, OVC_OGAMC3); | |
1266 | PSB_WVDC32(arg->overlay.OGAMC2, OVC_OGAMC2); | |
1267 | PSB_WVDC32(arg->overlay.OGAMC1, OVC_OGAMC1); | |
1268 | PSB_WVDC32(arg->overlay.OGAMC0, OVC_OGAMC0); | |
1269 | } | |
1270 | ||
1271 | if (arg->overlay_write_mask & OV_REGRWBITS_OVADD) { | |
1272 | PSB_WVDC32(arg->overlay.OVADD, OV_OVADD); | |
1273 | ||
1274 | if (arg->overlay.b_wait_vblank) { | |
1275 | /* Wait for 20ms.*/ | |
1276 | unsigned long vblank_timeout = jiffies | |
1277 | + HZ/50; | |
1278 | uint32_t temp; | |
1279 | while (time_before_eq(jiffies, | |
1280 | vblank_timeout)) { | |
1281 | temp = PSB_RVDC32(OV_DOVASTA); | |
1282 | if ((temp & (0x1 << 31)) != 0) | |
1283 | break; | |
1284 | cpu_relax(); | |
1285 | } | |
1286 | } | |
1287 | } | |
1288 | if (arg->overlay_write_mask & OVC_REGRWBITS_OVADD) { | |
1289 | PSB_WVDC32(arg->overlay.OVADD, OVC_OVADD); | |
1290 | if (arg->overlay.b_wait_vblank) { | |
1291 | /* Wait for 20ms.*/ | |
1292 | unsigned long vblank_timeout = | |
1293 | jiffies + HZ/50; | |
1294 | uint32_t temp; | |
1295 | while (time_before_eq(jiffies, | |
1296 | vblank_timeout)) { | |
1297 | temp = PSB_RVDC32(OVC_DOVCSTA); | |
1298 | if ((temp & (0x1 << 31)) != 0) | |
1299 | break; | |
1300 | cpu_relax(); | |
1301 | } | |
1302 | } | |
1303 | } | |
1304 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1305 | } else { | |
1306 | if (arg->overlay_write_mask & OV_REGRWBITS_OGAM_ALL) { | |
1307 | dev_priv->saveOV_OGAMC5 = arg->overlay.OGAMC5; | |
1308 | dev_priv->saveOV_OGAMC4 = arg->overlay.OGAMC4; | |
1309 | dev_priv->saveOV_OGAMC3 = arg->overlay.OGAMC3; | |
1310 | dev_priv->saveOV_OGAMC2 = arg->overlay.OGAMC2; | |
1311 | dev_priv->saveOV_OGAMC1 = arg->overlay.OGAMC1; | |
1312 | dev_priv->saveOV_OGAMC0 = arg->overlay.OGAMC0; | |
1313 | } | |
1314 | if (arg->overlay_write_mask & OVC_REGRWBITS_OGAM_ALL) { | |
1315 | dev_priv->saveOVC_OGAMC5 = arg->overlay.OGAMC5; | |
1316 | dev_priv->saveOVC_OGAMC4 = arg->overlay.OGAMC4; | |
1317 | dev_priv->saveOVC_OGAMC3 = arg->overlay.OGAMC3; | |
1318 | dev_priv->saveOVC_OGAMC2 = arg->overlay.OGAMC2; | |
1319 | dev_priv->saveOVC_OGAMC1 = arg->overlay.OGAMC1; | |
1320 | dev_priv->saveOVC_OGAMC0 = arg->overlay.OGAMC0; | |
1321 | } | |
1322 | if (arg->overlay_write_mask & OV_REGRWBITS_OVADD) | |
1323 | dev_priv->saveOV_OVADD = arg->overlay.OVADD; | |
1324 | if (arg->overlay_write_mask & OVC_REGRWBITS_OVADD) | |
1325 | dev_priv->saveOVC_OVADD = arg->overlay.OVADD; | |
1326 | } | |
1327 | } | |
1328 | ||
1329 | if (arg->overlay_read_mask != 0) { | |
1330 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) { | |
1331 | if (arg->overlay_read_mask & OV_REGRWBITS_OGAM_ALL) { | |
1332 | arg->overlay.OGAMC5 = PSB_RVDC32(OV_OGAMC5); | |
1333 | arg->overlay.OGAMC4 = PSB_RVDC32(OV_OGAMC4); | |
1334 | arg->overlay.OGAMC3 = PSB_RVDC32(OV_OGAMC3); | |
1335 | arg->overlay.OGAMC2 = PSB_RVDC32(OV_OGAMC2); | |
1336 | arg->overlay.OGAMC1 = PSB_RVDC32(OV_OGAMC1); | |
1337 | arg->overlay.OGAMC0 = PSB_RVDC32(OV_OGAMC0); | |
1338 | } | |
1339 | if (arg->overlay_read_mask & OVC_REGRWBITS_OGAM_ALL) { | |
1340 | arg->overlay.OGAMC5 = PSB_RVDC32(OVC_OGAMC5); | |
1341 | arg->overlay.OGAMC4 = PSB_RVDC32(OVC_OGAMC4); | |
1342 | arg->overlay.OGAMC3 = PSB_RVDC32(OVC_OGAMC3); | |
1343 | arg->overlay.OGAMC2 = PSB_RVDC32(OVC_OGAMC2); | |
1344 | arg->overlay.OGAMC1 = PSB_RVDC32(OVC_OGAMC1); | |
1345 | arg->overlay.OGAMC0 = PSB_RVDC32(OVC_OGAMC0); | |
1346 | } | |
1347 | if (arg->overlay_read_mask & OV_REGRWBITS_OVADD) | |
1348 | arg->overlay.OVADD = PSB_RVDC32(OV_OVADD); | |
1349 | if (arg->overlay_read_mask & OVC_REGRWBITS_OVADD) | |
1350 | arg->overlay.OVADD = PSB_RVDC32(OVC_OVADD); | |
1351 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1352 | } else { | |
1353 | if (arg->overlay_read_mask & OV_REGRWBITS_OGAM_ALL) { | |
1354 | arg->overlay.OGAMC5 = dev_priv->saveOV_OGAMC5; | |
1355 | arg->overlay.OGAMC4 = dev_priv->saveOV_OGAMC4; | |
1356 | arg->overlay.OGAMC3 = dev_priv->saveOV_OGAMC3; | |
1357 | arg->overlay.OGAMC2 = dev_priv->saveOV_OGAMC2; | |
1358 | arg->overlay.OGAMC1 = dev_priv->saveOV_OGAMC1; | |
1359 | arg->overlay.OGAMC0 = dev_priv->saveOV_OGAMC0; | |
1360 | } | |
1361 | if (arg->overlay_read_mask & OVC_REGRWBITS_OGAM_ALL) { | |
1362 | arg->overlay.OGAMC5 = dev_priv->saveOVC_OGAMC5; | |
1363 | arg->overlay.OGAMC4 = dev_priv->saveOVC_OGAMC4; | |
1364 | arg->overlay.OGAMC3 = dev_priv->saveOVC_OGAMC3; | |
1365 | arg->overlay.OGAMC2 = dev_priv->saveOVC_OGAMC2; | |
1366 | arg->overlay.OGAMC1 = dev_priv->saveOVC_OGAMC1; | |
1367 | arg->overlay.OGAMC0 = dev_priv->saveOVC_OGAMC0; | |
1368 | } | |
1369 | if (arg->overlay_read_mask & OV_REGRWBITS_OVADD) | |
1370 | arg->overlay.OVADD = dev_priv->saveOV_OVADD; | |
1371 | if (arg->overlay_read_mask & OVC_REGRWBITS_OVADD) | |
1372 | arg->overlay.OVADD = dev_priv->saveOVC_OVADD; | |
1373 | } | |
1374 | } | |
1375 | ||
1376 | if (arg->sprite_enable_mask != 0) { | |
1377 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) { | |
1378 | PSB_WVDC32(0x1F3E, DSPARB); | |
1379 | PSB_WVDC32(arg->sprite.dspa_control | |
1380 | | PSB_RVDC32(DSPACNTR), DSPACNTR); | |
1381 | PSB_WVDC32(arg->sprite.dspa_key_value, DSPAKEYVAL); | |
1382 | PSB_WVDC32(arg->sprite.dspa_key_mask, DSPAKEYMASK); | |
1383 | PSB_WVDC32(PSB_RVDC32(DSPASURF), DSPASURF); | |
1384 | PSB_RVDC32(DSPASURF); | |
1385 | PSB_WVDC32(arg->sprite.dspc_control, DSPCCNTR); | |
1386 | PSB_WVDC32(arg->sprite.dspc_stride, DSPCSTRIDE); | |
1387 | PSB_WVDC32(arg->sprite.dspc_position, DSPCPOS); | |
1388 | PSB_WVDC32(arg->sprite.dspc_linear_offset, DSPCLINOFF); | |
1389 | PSB_WVDC32(arg->sprite.dspc_size, DSPCSIZE); | |
1390 | PSB_WVDC32(arg->sprite.dspc_surface, DSPCSURF); | |
1391 | PSB_RVDC32(DSPCSURF); | |
1392 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1393 | } | |
1394 | } | |
1395 | ||
1396 | if (arg->sprite_disable_mask != 0) { | |
1397 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) { | |
1398 | PSB_WVDC32(0x3F3E, DSPARB); | |
1399 | PSB_WVDC32(0x0, DSPCCNTR); | |
1400 | PSB_WVDC32(arg->sprite.dspc_surface, DSPCSURF); | |
1401 | PSB_RVDC32(DSPCSURF); | |
1402 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1403 | } | |
1404 | } | |
1405 | ||
1406 | if (arg->subpicture_enable_mask != 0) { | |
1407 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) { | |
1408 | uint32_t temp; | |
1409 | if (arg->subpicture_enable_mask & REGRWBITS_DSPACNTR) { | |
1410 | temp = PSB_RVDC32(DSPACNTR); | |
1411 | temp &= ~DISPPLANE_PIXFORMAT_MASK; | |
1412 | temp &= ~DISPPLANE_BOTTOM; | |
1413 | temp |= DISPPLANE_32BPP; | |
1414 | PSB_WVDC32(temp, DSPACNTR); | |
1415 | ||
1416 | temp = PSB_RVDC32(DSPABASE); | |
1417 | PSB_WVDC32(temp, DSPABASE); | |
1418 | PSB_RVDC32(DSPABASE); | |
1419 | temp = PSB_RVDC32(DSPASURF); | |
1420 | PSB_WVDC32(temp, DSPASURF); | |
1421 | PSB_RVDC32(DSPASURF); | |
1422 | } | |
1423 | if (arg->subpicture_enable_mask & REGRWBITS_DSPBCNTR) { | |
1424 | temp = PSB_RVDC32(DSPBCNTR); | |
1425 | temp &= ~DISPPLANE_PIXFORMAT_MASK; | |
1426 | temp &= ~DISPPLANE_BOTTOM; | |
1427 | temp |= DISPPLANE_32BPP; | |
1428 | PSB_WVDC32(temp, DSPBCNTR); | |
1429 | ||
1430 | temp = PSB_RVDC32(DSPBBASE); | |
1431 | PSB_WVDC32(temp, DSPBBASE); | |
1432 | PSB_RVDC32(DSPBBASE); | |
1433 | temp = PSB_RVDC32(DSPBSURF); | |
1434 | PSB_WVDC32(temp, DSPBSURF); | |
1435 | PSB_RVDC32(DSPBSURF); | |
1436 | } | |
1437 | if (arg->subpicture_enable_mask & REGRWBITS_DSPCCNTR) { | |
1438 | temp = PSB_RVDC32(DSPCCNTR); | |
1439 | temp &= ~DISPPLANE_PIXFORMAT_MASK; | |
1440 | temp &= ~DISPPLANE_BOTTOM; | |
1441 | temp |= DISPPLANE_32BPP; | |
1442 | PSB_WVDC32(temp, DSPCCNTR); | |
1443 | ||
1444 | temp = PSB_RVDC32(DSPCBASE); | |
1445 | PSB_WVDC32(temp, DSPCBASE); | |
1446 | PSB_RVDC32(DSPCBASE); | |
1447 | temp = PSB_RVDC32(DSPCSURF); | |
1448 | PSB_WVDC32(temp, DSPCSURF); | |
1449 | PSB_RVDC32(DSPCSURF); | |
1450 | } | |
1451 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1452 | } | |
1453 | } | |
1454 | ||
1455 | if (arg->subpicture_disable_mask != 0) { | |
1456 | if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, usage)) { | |
1457 | uint32_t temp; | |
1458 | if (arg->subpicture_disable_mask & REGRWBITS_DSPACNTR) { | |
1459 | temp = PSB_RVDC32(DSPACNTR); | |
1460 | temp &= ~DISPPLANE_PIXFORMAT_MASK; | |
1461 | temp |= DISPPLANE_32BPP_NO_ALPHA; | |
1462 | PSB_WVDC32(temp, DSPACNTR); | |
1463 | ||
1464 | temp = PSB_RVDC32(DSPABASE); | |
1465 | PSB_WVDC32(temp, DSPABASE); | |
1466 | PSB_RVDC32(DSPABASE); | |
1467 | temp = PSB_RVDC32(DSPASURF); | |
1468 | PSB_WVDC32(temp, DSPASURF); | |
1469 | PSB_RVDC32(DSPASURF); | |
1470 | } | |
1471 | if (arg->subpicture_disable_mask & REGRWBITS_DSPBCNTR) { | |
1472 | temp = PSB_RVDC32(DSPBCNTR); | |
1473 | temp &= ~DISPPLANE_PIXFORMAT_MASK; | |
1474 | temp |= DISPPLANE_32BPP_NO_ALPHA; | |
1475 | PSB_WVDC32(temp, DSPBCNTR); | |
1476 | ||
1477 | temp = PSB_RVDC32(DSPBBASE); | |
1478 | PSB_WVDC32(temp, DSPBBASE); | |
1479 | PSB_RVDC32(DSPBBASE); | |
1480 | temp = PSB_RVDC32(DSPBSURF); | |
1481 | PSB_WVDC32(temp, DSPBSURF); | |
1482 | PSB_RVDC32(DSPBSURF); | |
1483 | } | |
1484 | if (arg->subpicture_disable_mask & REGRWBITS_DSPCCNTR) { | |
1485 | temp = PSB_RVDC32(DSPCCNTR); | |
1486 | temp &= ~DISPPLANE_PIXFORMAT_MASK; | |
1487 | temp |= DISPPLANE_32BPP_NO_ALPHA; | |
1488 | PSB_WVDC32(temp, DSPCCNTR); | |
1489 | ||
1490 | temp = PSB_RVDC32(DSPCBASE); | |
1491 | PSB_WVDC32(temp, DSPCBASE); | |
1492 | PSB_RVDC32(DSPCBASE); | |
1493 | temp = PSB_RVDC32(DSPCSURF); | |
1494 | PSB_WVDC32(temp, DSPCSURF); | |
1495 | PSB_RVDC32(DSPCSURF); | |
1496 | } | |
1497 | ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); | |
1498 | } | |
1499 | } | |
1500 | ||
1501 | return 0; | |
1502 | } | |
1503 | ||
1504 | /* always available as we are SIGIO'd */ | |
1505 | static unsigned int psb_poll(struct file *filp, | |
1506 | struct poll_table_struct *wait) | |
1507 | { | |
1508 | return POLLIN | POLLRDNORM; | |
1509 | } | |
1510 | ||
1511 | /* Not sure what we will need yet - in the PVR driver this disappears into | |
1512 | a tangle of abstracted handlers and per process crap */ | |
1513 | ||
1514 | struct psb_priv { | |
1515 | int dummy; | |
1516 | }; | |
1517 | ||
1518 | static int psb_driver_open(struct drm_device *dev, struct drm_file *priv) | |
1519 | { | |
1520 | struct psb_priv *psb = kzalloc(sizeof(struct psb_priv), GFP_KERNEL); | |
1521 | if (psb == NULL) | |
1522 | return -ENOMEM; | |
1523 | priv->driver_priv = psb; | |
1524 | DRM_DEBUG("\n"); | |
1525 | /*return PVRSRVOpen(dev, priv);*/ | |
1526 | return 0; | |
1527 | } | |
1528 | ||
1529 | static void psb_driver_close(struct drm_device *dev, struct drm_file *priv) | |
1530 | { | |
1531 | kfree(priv->driver_priv); | |
1532 | priv->driver_priv = NULL; | |
1533 | } | |
1534 | ||
1535 | static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, | |
1536 | unsigned long arg) | |
1537 | { | |
1538 | struct drm_file *file_priv = filp->private_data; | |
1539 | struct drm_device *dev = file_priv->minor->dev; | |
1540 | struct drm_psb_private *dev_priv = dev->dev_private; | |
1541 | static unsigned int runtime_allowed; | |
1542 | unsigned int nr = DRM_IOCTL_NR(cmd); | |
1543 | ||
1544 | DRM_DEBUG("cmd = %x, nr = %x\n", cmd, nr); | |
1545 | ||
1546 | if (runtime_allowed == 1 && dev_priv->is_lvds_on) { | |
1547 | runtime_allowed++; | |
1548 | pm_runtime_allow(&dev->pdev->dev); | |
1549 | dev_priv->rpm_enabled = 1; | |
1550 | } | |
1551 | /* | |
1552 | * The driver private ioctls and TTM ioctls should be | |
1553 | * thread-safe. | |
1554 | */ | |
1555 | ||
1556 | if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) | |
1557 | && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { | |
1558 | struct drm_ioctl_desc *ioctl = | |
1559 | &psb_ioctls[nr - DRM_COMMAND_BASE]; | |
1560 | ||
1561 | if (unlikely(ioctl->cmd != cmd)) { | |
1562 | DRM_ERROR( | |
1563 | "Invalid drm cmnd %d ioctl->cmd %x, cmd %x\n", | |
1564 | nr - DRM_COMMAND_BASE, ioctl->cmd, cmd); | |
1565 | return -EINVAL; | |
1566 | } | |
1567 | ||
1568 | return drm_ioctl(filp, cmd, arg); | |
1569 | } | |
1570 | /* | |
1571 | * Not all old drm ioctls are thread-safe. | |
1572 | */ | |
1573 | ||
1574 | return drm_ioctl(filp, cmd, arg); | |
1575 | } | |
1576 | ||
1577 | ||
1578 | /* When a client dies: | |
1579 | * - Check for and clean up flipped page state | |
1580 | */ | |
1581 | void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv) | |
1582 | { | |
1583 | } | |
1584 | ||
1585 | static void psb_remove(struct pci_dev *pdev) | |
1586 | { | |
1587 | struct drm_device *dev = pci_get_drvdata(pdev); | |
1588 | drm_put_dev(dev); | |
1589 | } | |
1590 | ||
1591 | ||
1592 | static const struct dev_pm_ops psb_pm_ops = { | |
1593 | .runtime_suspend = psb_runtime_suspend, | |
1594 | .runtime_resume = psb_runtime_resume, | |
1595 | .runtime_idle = psb_runtime_idle, | |
1596 | }; | |
1597 | ||
1598 | static struct drm_driver driver = { | |
1599 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | \ | |
1600 | DRIVER_IRQ_VBL | DRIVER_MODESET, | |
1601 | .load = psb_driver_load, | |
1602 | .unload = psb_driver_unload, | |
1603 | ||
1604 | .ioctls = psb_ioctls, | |
1605 | .num_ioctls = DRM_ARRAY_SIZE(psb_ioctls), | |
1606 | .device_is_agp = psb_driver_device_is_agp, | |
1607 | .irq_preinstall = psb_irq_preinstall, | |
1608 | .irq_postinstall = psb_irq_postinstall, | |
1609 | .irq_uninstall = psb_irq_uninstall, | |
1610 | .irq_handler = psb_irq_handler, | |
1611 | .enable_vblank = psb_enable_vblank, | |
1612 | .disable_vblank = psb_disable_vblank, | |
1613 | .get_vblank_counter = psb_get_vblank_counter, | |
1614 | .firstopen = NULL, | |
1615 | .lastclose = psb_lastclose, | |
1616 | .open = psb_driver_open, | |
1617 | .postclose = psb_driver_close, | |
1618 | #if 0 /* ACFIXME */ | |
1619 | .get_map_ofs = drm_core_get_map_ofs, | |
1620 | .get_reg_ofs = drm_core_get_reg_ofs, | |
1621 | .proc_init = psb_proc_init, | |
1622 | .proc_cleanup = psb_proc_cleanup, | |
1623 | #endif | |
1624 | .preclose = psb_driver_preclose, | |
1625 | .fops = { | |
1626 | .owner = THIS_MODULE, | |
1627 | .open = psb_open, | |
1628 | .release = psb_release, | |
1629 | .unlocked_ioctl = psb_unlocked_ioctl, | |
1630 | .mmap = psb_mmap, | |
1631 | .poll = psb_poll, | |
1632 | .fasync = drm_fasync, | |
1633 | .read = drm_read, | |
1634 | }, | |
1635 | .pci_driver = { | |
1636 | .name = DRIVER_NAME, | |
1637 | .id_table = pciidlist, | |
1638 | .resume = ospm_power_resume, | |
1639 | .suspend = ospm_power_suspend, | |
1640 | .probe = psb_probe, | |
1641 | .remove = psb_remove, | |
1642 | #ifdef CONFIG_PM | |
1643 | .driver.pm = &psb_pm_ops, | |
1644 | #endif | |
1645 | }, | |
1646 | .name = DRIVER_NAME, | |
1647 | .desc = DRIVER_DESC, | |
1648 | .date = PSB_DRM_DRIVER_DATE, | |
1649 | .major = PSB_DRM_DRIVER_MAJOR, | |
1650 | .minor = PSB_DRM_DRIVER_MINOR, | |
1651 | .patchlevel = PSB_DRM_DRIVER_PATCHLEVEL | |
1652 | }; | |
1653 | ||
1654 | static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |
1655 | { | |
1656 | /* MLD Added this from Inaky's patch */ | |
1657 | if (pci_enable_msi(pdev)) | |
1658 | DRM_ERROR("Enable MSI failed!\n"); | |
1659 | return drm_get_pci_dev(pdev, ent, &driver); | |
1660 | } | |
1661 | ||
1662 | static int __init psb_init(void) | |
1663 | { | |
1664 | return drm_init(&driver); | |
1665 | } | |
1666 | ||
1667 | static void __exit psb_exit(void) | |
1668 | { | |
1669 | drm_exit(&driver); | |
1670 | } | |
1671 | ||
1672 | late_initcall(psb_init); | |
1673 | module_exit(psb_exit); | |
1674 | ||
1675 | MODULE_AUTHOR(DRIVER_AUTHOR); | |
1676 | MODULE_DESCRIPTION(DRIVER_DESC); | |
1677 | MODULE_LICENSE("GPL"); |