1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /************************************************************************** |
3 | * Copyright (c) 2007-2011, Intel Corporation. |
4 | * All Rights Reserved. |
5 | * Copyright (c) 2008, Tungsten Graphics, Inc. Cedar Park, TX., USA. |
6 | * All Rights Reserved. |
7 | * |
8 | **************************************************************************/ |
9 | |
10 | #include <linux/aperture.h> |
11 | #include <linux/cpu.h> |
12 | #include <linux/module.h> |
13 | #include <linux/notifier.h> |
14 | #include <linux/pm_runtime.h> |
15 | #include <linux/spinlock.h> |
16 | #include <linux/delay.h> |
17 | |
18 | #include <asm/set_memory.h> |
19 | |
20 | #include <acpi/video.h> |
21 | |
22 | #include <drm/drm.h> |
23 | #include <drm/drm_drv.h> |
24 | #include <drm/drm_file.h> |
25 | #include <drm/drm_ioctl.h> |
26 | #include <drm/drm_pciids.h> |
27 | #include <drm/drm_vblank.h> |
28 | |
29 | #include "framebuffer.h" |
30 | #include "gem.h" |
31 | #include "intel_bios.h" |
32 | #include "mid_bios.h" |
33 | #include "power.h" |
34 | #include "psb_drv.h" |
35 | #include "psb_intel_reg.h" |
36 | #include "psb_irq.h" |
37 | #include "psb_reg.h" |
38 | |
39 | static const struct drm_driver driver; |
40 | static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); |
41 | |
42 | /* |
43 | * The table below contains a mapping of the PCI vendor ID and the PCI Device ID |
44 | * to the different groups of PowerVR 5-series chip designs |
45 | * |
46 | * 0x8086 = Intel Corporation |
47 | * |
48 | * PowerVR SGX535 - Poulsbo - Intel GMA 500, Intel Atom Z5xx |
49 | * PowerVR SGX535 - Moorestown - Intel GMA 600 |
50 | * PowerVR SGX535 - Oaktrail - Intel GMA 600, Intel Atom Z6xx, E6xx |
51 | * PowerVR SGX545 - Cedartrail - Intel GMA 3600, Intel Atom D2500, N2600 |
52 | * PowerVR SGX545 - Cedartrail - Intel GMA 3650, Intel Atom D2550, D2700, |
53 | * N2800 |
54 | */ |
55 | static const struct pci_device_id pciidlist[] = { |
56 | /* Poulsbo */ |
57 | { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, |
58 | { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, |
59 | /* Oak Trail */ |
60 | { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
61 | { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
62 | { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
63 | { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
64 | { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
65 | { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
66 | { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
67 | { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
68 | { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, |
69 | /* Cedar Trail */ |
70 | { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
71 | { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
72 | { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
73 | { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
74 | { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
75 | { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
76 | { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
77 | { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
78 | { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
79 | { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
80 | { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
81 | { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
82 | { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
83 | { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
84 | { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
85 | { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, |
86 | { 0, } |
87 | }; |
88 | MODULE_DEVICE_TABLE(pci, pciidlist); |
89 | |
90 | /* |
91 | * Standard IOCTLs. |
92 | */ |
93 | static const struct drm_ioctl_desc psb_ioctls[] = { |
94 | }; |
95 | |
96 | /** |
97 | * psb_spank - reset the 2D engine |
98 | * @dev_priv: our PSB DRM device |
99 | * |
100 | * Soft reset the graphics engine and then reload the necessary registers. |
101 | */ |
102 | static void psb_spank(struct drm_psb_private *dev_priv) |
103 | { |
104 | PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET | |
105 | _PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET | |
106 | _PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET | |
107 | _PSB_CS_RESET_TWOD_RESET, PSB_CR_SOFT_RESET); |
108 | PSB_RSGX32(PSB_CR_SOFT_RESET); |
109 | |
110 | msleep(msecs: 1); |
111 | |
112 | PSB_WSGX32(0, PSB_CR_SOFT_RESET); |
113 | wmb(); |
114 | PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT, |
115 | PSB_CR_BIF_CTRL); |
116 | wmb(); |
117 | (void) PSB_RSGX32(PSB_CR_BIF_CTRL); |
118 | |
119 | msleep(msecs: 1); |
120 | PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_CB_CTRL_CLEAR_FAULT, |
121 | PSB_CR_BIF_CTRL); |
122 | (void) PSB_RSGX32(PSB_CR_BIF_CTRL); |
123 | PSB_WSGX32(dev_priv->gtt.gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); |
124 | } |
125 | |
126 | static int psb_do_init(struct drm_device *dev) |
127 | { |
128 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
129 | struct psb_gtt *pg = &dev_priv->gtt; |
130 | |
131 | uint32_t stolen_gtt; |
132 | |
133 | if (pg->mmu_gatt_start & 0x0FFFFFFF) { |
134 | dev_err(dev->dev, "Gatt must be 256M aligned. This is a bug.\n" ); |
135 | return -EINVAL; |
136 | } |
137 | |
138 | stolen_gtt = (pg->stolen_size >> PAGE_SHIFT) * 4; |
139 | stolen_gtt = (stolen_gtt + PAGE_SIZE - 1) >> PAGE_SHIFT; |
140 | stolen_gtt = (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; |
141 | |
142 | dev_priv->gatt_free_offset = pg->mmu_gatt_start + |
143 | (stolen_gtt << PAGE_SHIFT) * 1024; |
144 | |
145 | spin_lock_init(&dev_priv->irqmask_lock); |
146 | |
147 | PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK0); |
148 | PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK1); |
149 | PSB_RSGX32(PSB_CR_BIF_BANK1); |
150 | |
151 | /* Do not bypass any MMU access, let them pagefault instead */ |
152 | PSB_WSGX32((PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_MMU_ER_MASK), |
153 | PSB_CR_BIF_CTRL); |
154 | PSB_RSGX32(PSB_CR_BIF_CTRL); |
155 | |
156 | psb_spank(dev_priv); |
157 | |
158 | /* mmu_gatt ?? */ |
159 | PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); |
160 | PSB_RSGX32(PSB_CR_BIF_TWOD_REQ_BASE); /* Post */ |
161 | |
162 | return 0; |
163 | } |
164 | |
165 | static void psb_driver_unload(struct drm_device *dev) |
166 | { |
167 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
168 | |
169 | /* TODO: Kill vblank etc here */ |
170 | |
171 | gma_backlight_exit(dev); |
172 | psb_modeset_cleanup(dev); |
173 | |
174 | gma_irq_uninstall(dev); |
175 | |
176 | if (dev_priv->ops->chip_teardown) |
177 | dev_priv->ops->chip_teardown(dev); |
178 | |
179 | psb_intel_opregion_fini(dev); |
180 | |
181 | if (dev_priv->pf_pd) { |
182 | psb_mmu_free_pagedir(pd: dev_priv->pf_pd); |
183 | dev_priv->pf_pd = NULL; |
184 | } |
185 | if (dev_priv->mmu) { |
186 | struct psb_gtt *pg = &dev_priv->gtt; |
187 | |
188 | psb_mmu_remove_pfn_sequence( |
189 | pd: psb_mmu_get_default_pd |
190 | (driver: dev_priv->mmu), |
191 | address: pg->mmu_gatt_start, |
192 | num_pages: dev_priv->vram_stolen_size >> PAGE_SHIFT); |
193 | psb_mmu_driver_takedown(driver: dev_priv->mmu); |
194 | dev_priv->mmu = NULL; |
195 | } |
196 | psb_gem_mm_fini(dev); |
197 | psb_gtt_fini(dev); |
198 | if (dev_priv->scratch_page) { |
199 | set_pages_wb(page: dev_priv->scratch_page, numpages: 1); |
200 | __free_page(dev_priv->scratch_page); |
201 | dev_priv->scratch_page = NULL; |
202 | } |
203 | if (dev_priv->vdc_reg) { |
204 | iounmap(addr: dev_priv->vdc_reg); |
205 | dev_priv->vdc_reg = NULL; |
206 | } |
207 | if (dev_priv->sgx_reg) { |
208 | iounmap(addr: dev_priv->sgx_reg); |
209 | dev_priv->sgx_reg = NULL; |
210 | } |
211 | if (dev_priv->aux_reg) { |
212 | iounmap(addr: dev_priv->aux_reg); |
213 | dev_priv->aux_reg = NULL; |
214 | } |
215 | pci_dev_put(dev: dev_priv->aux_pdev); |
216 | pci_dev_put(dev: dev_priv->lpc_pdev); |
217 | |
218 | /* Destroy VBT data */ |
219 | psb_intel_destroy_bios(dev); |
220 | |
221 | gma_power_uninit(dev); |
222 | } |
223 | |
224 | static void psb_device_release(void *data) |
225 | { |
226 | struct drm_device *dev = data; |
227 | |
228 | psb_driver_unload(dev); |
229 | } |
230 | |
231 | static int psb_driver_load(struct drm_device *dev, unsigned long flags) |
232 | { |
233 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
234 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
235 | unsigned long resource_start, resource_len; |
236 | unsigned long irqflags; |
237 | struct drm_connector_list_iter conn_iter; |
238 | struct drm_connector *connector; |
239 | struct gma_encoder *gma_encoder; |
240 | struct psb_gtt *pg; |
241 | int ret = -ENOMEM; |
242 | |
243 | /* initializing driver private data */ |
244 | |
245 | dev_priv->ops = (struct psb_ops *)flags; |
246 | |
247 | pg = &dev_priv->gtt; |
248 | |
249 | pci_set_master(dev: pdev); |
250 | |
251 | dev_priv->num_pipe = dev_priv->ops->pipes; |
252 | |
253 | resource_start = pci_resource_start(pdev, PSB_MMIO_RESOURCE); |
254 | |
255 | dev_priv->vdc_reg = |
256 | ioremap(offset: resource_start + PSB_VDC_OFFSET, PSB_VDC_SIZE); |
257 | if (!dev_priv->vdc_reg) |
258 | goto out_err; |
259 | |
260 | dev_priv->sgx_reg = ioremap(offset: resource_start + dev_priv->ops->sgx_offset, |
261 | PSB_SGX_SIZE); |
262 | if (!dev_priv->sgx_reg) |
263 | goto out_err; |
264 | |
265 | if (IS_MRST(dev)) { |
266 | int domain = pci_domain_nr(bus: pdev->bus); |
267 | |
268 | dev_priv->aux_pdev = |
269 | pci_get_domain_bus_and_slot(domain, bus: 0, |
270 | PCI_DEVFN(3, 0)); |
271 | |
272 | if (dev_priv->aux_pdev) { |
273 | resource_start = pci_resource_start(dev_priv->aux_pdev, |
274 | PSB_AUX_RESOURCE); |
275 | resource_len = pci_resource_len(dev_priv->aux_pdev, |
276 | PSB_AUX_RESOURCE); |
277 | dev_priv->aux_reg = ioremap(offset: resource_start, |
278 | size: resource_len); |
279 | if (!dev_priv->aux_reg) |
280 | goto out_err; |
281 | |
282 | DRM_DEBUG_KMS("Found aux vdc" ); |
283 | } else { |
284 | /* Couldn't find the aux vdc so map to primary vdc */ |
285 | dev_priv->aux_reg = dev_priv->vdc_reg; |
286 | DRM_DEBUG_KMS("Couldn't find aux pci device" ); |
287 | } |
288 | dev_priv->gmbus_reg = dev_priv->aux_reg; |
289 | |
290 | dev_priv->lpc_pdev = |
291 | pci_get_domain_bus_and_slot(domain, bus: 0, |
292 | PCI_DEVFN(31, 0)); |
293 | if (dev_priv->lpc_pdev) { |
294 | pci_read_config_word(dev: dev_priv->lpc_pdev, PSB_LPC_GBA, |
295 | val: &dev_priv->lpc_gpio_base); |
296 | pci_write_config_dword(dev: dev_priv->lpc_pdev, PSB_LPC_GBA, |
297 | val: (u32)dev_priv->lpc_gpio_base | (1L<<31)); |
298 | pci_read_config_word(dev: dev_priv->lpc_pdev, PSB_LPC_GBA, |
299 | val: &dev_priv->lpc_gpio_base); |
300 | dev_priv->lpc_gpio_base &= 0xffc0; |
301 | if (dev_priv->lpc_gpio_base) |
302 | DRM_DEBUG_KMS("Found LPC GPIO at 0x%04x\n" , |
303 | dev_priv->lpc_gpio_base); |
304 | else { |
305 | pci_dev_put(dev: dev_priv->lpc_pdev); |
306 | dev_priv->lpc_pdev = NULL; |
307 | } |
308 | } |
309 | } else { |
310 | dev_priv->gmbus_reg = dev_priv->vdc_reg; |
311 | } |
312 | |
313 | psb_intel_opregion_setup(dev); |
314 | |
315 | ret = dev_priv->ops->chip_setup(dev); |
316 | if (ret) |
317 | goto out_err; |
318 | |
319 | /* Init OSPM support */ |
320 | gma_power_init(dev); |
321 | |
322 | ret = -ENOMEM; |
323 | |
324 | dev_priv->scratch_page = alloc_page(GFP_DMA32 | __GFP_ZERO); |
325 | if (!dev_priv->scratch_page) |
326 | goto out_err; |
327 | |
328 | set_pages_uc(page: dev_priv->scratch_page, numpages: 1); |
329 | |
330 | ret = psb_gtt_init(dev); |
331 | if (ret) |
332 | goto out_err; |
333 | ret = psb_gem_mm_init(dev); |
334 | if (ret) |
335 | goto out_err; |
336 | |
337 | ret = -ENOMEM; |
338 | |
339 | dev_priv->mmu = psb_mmu_driver_init(dev, trap_pagefaults: 1, invalid_type: 0, NULL); |
340 | if (!dev_priv->mmu) |
341 | goto out_err; |
342 | |
343 | dev_priv->pf_pd = psb_mmu_alloc_pd(driver: dev_priv->mmu, trap_pagefaults: 1, invalid_type: 0); |
344 | if (!dev_priv->pf_pd) |
345 | goto out_err; |
346 | |
347 | ret = psb_do_init(dev); |
348 | if (ret) |
349 | return ret; |
350 | |
351 | /* Add stolen memory to SGX MMU */ |
352 | ret = psb_mmu_insert_pfn_sequence(pd: psb_mmu_get_default_pd(driver: dev_priv->mmu), |
353 | start_pfn: dev_priv->stolen_base >> PAGE_SHIFT, |
354 | address: pg->gatt_start, |
355 | num_pages: pg->stolen_size >> PAGE_SHIFT, type: 0); |
356 | |
357 | psb_mmu_set_pd_context(pd: psb_mmu_get_default_pd(driver: dev_priv->mmu), hw_context: 0); |
358 | psb_mmu_set_pd_context(pd: dev_priv->pf_pd, hw_context: 1); |
359 | |
360 | PSB_WSGX32(0x20000000, PSB_CR_PDS_EXEC_BASE); |
361 | PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE); |
362 | |
363 | acpi_video_register(); |
364 | |
365 | /* Setup vertical blanking handling */ |
366 | ret = drm_vblank_init(dev, num_crtcs: dev_priv->num_pipe); |
367 | if (ret) |
368 | goto out_err; |
369 | |
370 | /* |
371 | * Install interrupt handlers prior to powering off SGX or else we will |
372 | * crash. |
373 | */ |
374 | dev_priv->vdc_irq_mask = 0; |
375 | dev_priv->pipestat[0] = 0; |
376 | dev_priv->pipestat[1] = 0; |
377 | dev_priv->pipestat[2] = 0; |
378 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); |
379 | PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); |
380 | PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); |
381 | PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R); |
382 | spin_unlock_irqrestore(lock: &dev_priv->irqmask_lock, flags: irqflags); |
383 | |
384 | gma_irq_install(dev); |
385 | |
386 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ |
387 | |
388 | psb_modeset_init(dev); |
389 | drm_kms_helper_poll_init(dev); |
390 | |
391 | /* Only add backlight support if we have LVDS or MIPI output */ |
392 | drm_connector_list_iter_begin(dev, iter: &conn_iter); |
393 | drm_for_each_connector_iter(connector, &conn_iter) { |
394 | gma_encoder = gma_attached_encoder(connector); |
395 | |
396 | if (gma_encoder->type == INTEL_OUTPUT_LVDS || |
397 | gma_encoder->type == INTEL_OUTPUT_MIPI) { |
398 | ret = gma_backlight_init(dev); |
399 | if (ret == 0) |
400 | acpi_video_register_backlight(); |
401 | break; |
402 | } |
403 | } |
404 | drm_connector_list_iter_end(iter: &conn_iter); |
405 | |
406 | if (ret) |
407 | return ret; |
408 | psb_intel_opregion_enable_asle(dev); |
409 | |
410 | return devm_add_action_or_reset(dev->dev, psb_device_release, dev); |
411 | |
412 | out_err: |
413 | psb_driver_unload(dev); |
414 | return ret; |
415 | } |
416 | |
417 | /* |
418 | * Hardware for gma500 is a hybrid device, which both acts as a PCI |
419 | * device (for legacy vga functionality) but also more like an |
420 | * integrated display on a SoC where the framebuffer simply |
421 | * resides in main memory and not in a special PCI bar (that |
422 | * internally redirects to a stolen range of main memory) like all |
423 | * other integrated PCI display devices implement it. |
424 | * |
425 | * To catch all cases we need to remove conflicting firmware devices |
426 | * for the stolen system memory and for the VGA functionality. As we |
427 | * currently cannot easily find the framebuffer's location in stolen |
428 | * memory, we remove all framebuffers here. |
429 | * |
430 | * TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then |
431 | * we might be able to read the framebuffer range from the |
432 | * device. |
433 | */ |
434 | static int gma_remove_conflicting_framebuffers(struct pci_dev *pdev, |
435 | const struct drm_driver *req_driver) |
436 | { |
437 | resource_size_t base = 0; |
438 | resource_size_t size = U32_MAX; /* 4 GiB HW limit */ |
439 | const char *name = req_driver->name; |
440 | int ret; |
441 | |
442 | ret = aperture_remove_conflicting_devices(base, size, name); |
443 | if (ret) |
444 | return ret; |
445 | |
446 | return __aperture_remove_legacy_vga_devices(pdev); |
447 | } |
448 | |
449 | static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
450 | { |
451 | struct drm_psb_private *dev_priv; |
452 | struct drm_device *dev; |
453 | int ret; |
454 | |
455 | ret = gma_remove_conflicting_framebuffers(pdev, req_driver: &driver); |
456 | if (ret) |
457 | return ret; |
458 | |
459 | ret = pcim_enable_device(pdev); |
460 | if (ret) |
461 | return ret; |
462 | |
463 | dev_priv = devm_drm_dev_alloc(&pdev->dev, &driver, struct drm_psb_private, dev); |
464 | if (IS_ERR(ptr: dev_priv)) |
465 | return PTR_ERR(ptr: dev_priv); |
466 | dev = &dev_priv->dev; |
467 | |
468 | pci_set_drvdata(pdev, data: dev); |
469 | |
470 | ret = psb_driver_load(dev, flags: ent->driver_data); |
471 | if (ret) |
472 | return ret; |
473 | |
474 | ret = drm_dev_register(dev, flags: ent->driver_data); |
475 | if (ret) |
476 | return ret; |
477 | |
478 | psb_fbdev_setup(dev_priv); |
479 | |
480 | return 0; |
481 | } |
482 | |
483 | static void psb_pci_remove(struct pci_dev *pdev) |
484 | { |
485 | struct drm_device *dev = pci_get_drvdata(pdev); |
486 | |
487 | drm_dev_unregister(dev); |
488 | } |
489 | |
490 | static DEFINE_RUNTIME_DEV_PM_OPS(psb_pm_ops, gma_power_suspend, gma_power_resume, NULL); |
491 | |
492 | static const struct file_operations psb_gem_fops = { |
493 | .owner = THIS_MODULE, |
494 | .open = drm_open, |
495 | .release = drm_release, |
496 | .unlocked_ioctl = drm_ioctl, |
497 | .compat_ioctl = drm_compat_ioctl, |
498 | .mmap = drm_gem_mmap, |
499 | .poll = drm_poll, |
500 | .read = drm_read, |
501 | }; |
502 | |
503 | static const struct drm_driver driver = { |
504 | .driver_features = DRIVER_MODESET | DRIVER_GEM, |
505 | |
506 | .num_ioctls = ARRAY_SIZE(psb_ioctls), |
507 | |
508 | .dumb_create = psb_gem_dumb_create, |
509 | .ioctls = psb_ioctls, |
510 | .fops = &psb_gem_fops, |
511 | .name = DRIVER_NAME, |
512 | .desc = DRIVER_DESC, |
513 | .date = DRIVER_DATE, |
514 | .major = DRIVER_MAJOR, |
515 | .minor = DRIVER_MINOR, |
516 | .patchlevel = DRIVER_PATCHLEVEL |
517 | }; |
518 | |
519 | static struct pci_driver psb_pci_driver = { |
520 | .name = DRIVER_NAME, |
521 | .id_table = pciidlist, |
522 | .probe = psb_pci_probe, |
523 | .remove = psb_pci_remove, |
524 | .driver.pm = &psb_pm_ops, |
525 | }; |
526 | |
527 | static int __init psb_init(void) |
528 | { |
529 | if (drm_firmware_drivers_only()) |
530 | return -ENODEV; |
531 | |
532 | return pci_register_driver(&psb_pci_driver); |
533 | } |
534 | |
535 | static void __exit psb_exit(void) |
536 | { |
537 | pci_unregister_driver(dev: &psb_pci_driver); |
538 | } |
539 | |
540 | late_initcall(psb_init); |
541 | module_exit(psb_exit); |
542 | |
543 | MODULE_AUTHOR(DRIVER_AUTHOR); |
544 | MODULE_DESCRIPTION(DRIVER_DESC); |
545 | MODULE_LICENSE("GPL" ); |
546 | |