diff options
-rw-r--r-- | drivers/gpu/drm/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/Kconfig | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/Makefile | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_drv.c | 106 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_drv.h | 246 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_fbdev.c | 307 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_main.c | 335 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_mode.c | 629 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_ttm.c | 453 |
10 files changed, 2095 insertions, 0 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 8b23bd9d1659..23120c00a881 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -190,3 +190,5 @@ source "drivers/gpu/drm/udl/Kconfig" | |||
190 | source "drivers/gpu/drm/ast/Kconfig" | 190 | source "drivers/gpu/drm/ast/Kconfig" |
191 | 191 | ||
192 | source "drivers/gpu/drm/mgag200/Kconfig" | 192 | source "drivers/gpu/drm/mgag200/Kconfig" |
193 | |||
194 | source "drivers/gpu/drm/cirrus/Kconfig" | ||
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 52c9b5610ca2..f65f65ed0ddf 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -35,6 +35,7 @@ obj-$(CONFIG_DRM_MGA) += mga/ | |||
35 | obj-$(CONFIG_DRM_I810) += i810/ | 35 | obj-$(CONFIG_DRM_I810) += i810/ |
36 | obj-$(CONFIG_DRM_I915) += i915/ | 36 | obj-$(CONFIG_DRM_I915) += i915/ |
37 | obj-$(CONFIG_DRM_MGAG200) += mgag200/ | 37 | obj-$(CONFIG_DRM_MGAG200) += mgag200/ |
38 | obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/ | ||
38 | obj-$(CONFIG_DRM_SIS) += sis/ | 39 | obj-$(CONFIG_DRM_SIS) += sis/ |
39 | obj-$(CONFIG_DRM_SAVAGE)+= savage/ | 40 | obj-$(CONFIG_DRM_SAVAGE)+= savage/ |
40 | obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ | 41 | obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ |
diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig new file mode 100644 index 000000000000..0303257ca136 --- /dev/null +++ b/drivers/gpu/drm/cirrus/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | config DRM_CIRRUS_QEMU | ||
2 | tristate "Cirrus driver for QEMU emulated device" | ||
3 | depends on DRM && PCI && EXPERIMENTAL | ||
4 | select FB_CFB_FILLRECT | ||
5 | select FB_CFB_COPYAREA | ||
6 | select FB_CFB_IMAGEBLIT | ||
7 | select DRM_KMS_HELPER | ||
8 | help | ||
9 | This is a KMS driver for emulated cirrus device in qemu. | ||
10 | It is *NOT* intended for real cirrus devices. This requires | ||
11 | the modesetting userspace X.org driver. | ||
diff --git a/drivers/gpu/drm/cirrus/Makefile b/drivers/gpu/drm/cirrus/Makefile new file mode 100644 index 000000000000..69ffe7006d55 --- /dev/null +++ b/drivers/gpu/drm/cirrus/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | ccflags-y := -Iinclude/drm | ||
2 | cirrus-y := cirrus_main.o cirrus_mode.o \ | ||
3 | cirrus_drv.o cirrus_fbdev.o cirrus_ttm.o | ||
4 | |||
5 | obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c new file mode 100644 index 000000000000..2e1f925b5caf --- /dev/null +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat <mjg@redhat.com> | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General | ||
5 | * Public License version 2. See the file COPYING in the main | ||
6 | * directory of this archive for more details. | ||
7 | * | ||
8 | * Authors: Matthew Garrett | ||
9 | * Dave Airlie | ||
10 | */ | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/console.h> | ||
13 | #include "drmP.h" | ||
14 | #include "drm.h" | ||
15 | |||
16 | #include "cirrus_drv.h" | ||
17 | |||
18 | int cirrus_modeset = -1; | ||
19 | |||
20 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); | ||
21 | module_param_named(modeset, cirrus_modeset, int, 0400); | ||
22 | |||
23 | /* | ||
24 | * This is the generic driver code. This binds the driver to the drm core, | ||
25 | * which then performs further device association and calls our graphics init | ||
26 | * functions | ||
27 | */ | ||
28 | |||
29 | static struct drm_driver driver; | ||
30 | |||
31 | /* only bind to the cirrus chip in qemu */ | ||
32 | static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { | ||
33 | { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, 0x1af4, 0x1100, 0, | ||
34 | 0, 0 }, | ||
35 | {0,} | ||
36 | }; | ||
37 | |||
38 | static int __devinit | ||
39 | cirrus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
40 | { | ||
41 | return drm_get_pci_dev(pdev, ent, &driver); | ||
42 | } | ||
43 | |||
44 | static void cirrus_pci_remove(struct pci_dev *pdev) | ||
45 | { | ||
46 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
47 | |||
48 | drm_put_dev(dev); | ||
49 | } | ||
50 | |||
51 | static const struct file_operations cirrus_driver_fops = { | ||
52 | .owner = THIS_MODULE, | ||
53 | .open = drm_open, | ||
54 | .release = drm_release, | ||
55 | .unlocked_ioctl = drm_ioctl, | ||
56 | .mmap = cirrus_mmap, | ||
57 | .poll = drm_poll, | ||
58 | .fasync = drm_fasync, | ||
59 | }; | ||
60 | static struct drm_driver driver = { | ||
61 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_USE_MTRR, | ||
62 | .load = cirrus_driver_load, | ||
63 | .unload = cirrus_driver_unload, | ||
64 | .fops = &cirrus_driver_fops, | ||
65 | .name = DRIVER_NAME, | ||
66 | .desc = DRIVER_DESC, | ||
67 | .date = DRIVER_DATE, | ||
68 | .major = DRIVER_MAJOR, | ||
69 | .minor = DRIVER_MINOR, | ||
70 | .patchlevel = DRIVER_PATCHLEVEL, | ||
71 | .gem_init_object = cirrus_gem_init_object, | ||
72 | .gem_free_object = cirrus_gem_free_object, | ||
73 | .dumb_create = cirrus_dumb_create, | ||
74 | .dumb_map_offset = cirrus_dumb_mmap_offset, | ||
75 | .dumb_destroy = cirrus_dumb_destroy, | ||
76 | }; | ||
77 | |||
78 | static struct pci_driver cirrus_pci_driver = { | ||
79 | .name = DRIVER_NAME, | ||
80 | .id_table = pciidlist, | ||
81 | .probe = cirrus_pci_probe, | ||
82 | .remove = cirrus_pci_remove, | ||
83 | }; | ||
84 | |||
85 | static int __init cirrus_init(void) | ||
86 | { | ||
87 | if (vgacon_text_force() && cirrus_modeset == -1) | ||
88 | return -EINVAL; | ||
89 | |||
90 | if (cirrus_modeset == 0) | ||
91 | return -EINVAL; | ||
92 | return drm_pci_init(&driver, &cirrus_pci_driver); | ||
93 | } | ||
94 | |||
95 | static void __exit cirrus_exit(void) | ||
96 | { | ||
97 | drm_pci_exit(&driver, &cirrus_pci_driver); | ||
98 | } | ||
99 | |||
100 | module_init(cirrus_init); | ||
101 | module_exit(cirrus_exit); | ||
102 | |||
103 | MODULE_DEVICE_TABLE(pci, pciidlist); | ||
104 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
105 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
106 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h new file mode 100644 index 000000000000..21bdfa8836f7 --- /dev/null +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General | ||
5 | * Public License version 2. See the file COPYING in the main | ||
6 | * directory of this archive for more details. | ||
7 | * | ||
8 | * Authors: Matthew Garrett | ||
9 | * Dave Airlie | ||
10 | */ | ||
11 | #ifndef __CIRRUS_DRV_H__ | ||
12 | #define __CIRRUS_DRV_H__ | ||
13 | |||
14 | #include <video/vga.h> | ||
15 | |||
16 | #include <drm/drm_fb_helper.h> | ||
17 | |||
18 | #include "ttm/ttm_bo_api.h" | ||
19 | #include "ttm/ttm_bo_driver.h" | ||
20 | #include "ttm/ttm_placement.h" | ||
21 | #include "ttm/ttm_memory.h" | ||
22 | #include "ttm/ttm_module.h" | ||
23 | |||
24 | #define DRIVER_AUTHOR "Matthew Garrett" | ||
25 | |||
26 | #define DRIVER_NAME "cirrus" | ||
27 | #define DRIVER_DESC "qemu Cirrus emulation" | ||
28 | #define DRIVER_DATE "20110418" | ||
29 | |||
30 | #define DRIVER_MAJOR 1 | ||
31 | #define DRIVER_MINOR 0 | ||
32 | #define DRIVER_PATCHLEVEL 0 | ||
33 | |||
34 | #define CIRRUSFB_CONN_LIMIT 1 | ||
35 | |||
36 | #define RREG8(reg) ioread8(((void __iomem *)cdev->rmmio) + (reg)) | ||
37 | #define WREG8(reg, v) iowrite8(v, ((void __iomem *)cdev->rmmio) + (reg)) | ||
38 | #define RREG32(reg) ioread32(((void __iomem *)cdev->rmmio) + (reg)) | ||
39 | #define WREG32(reg, v) iowrite32(v, ((void __iomem *)cdev->rmmio) + (reg)) | ||
40 | |||
41 | #define SEQ_INDEX 4 | ||
42 | #define SEQ_DATA 5 | ||
43 | |||
44 | #define WREG_SEQ(reg, v) \ | ||
45 | do { \ | ||
46 | WREG8(SEQ_INDEX, reg); \ | ||
47 | WREG8(SEQ_DATA, v); \ | ||
48 | } while (0) \ | ||
49 | |||
50 | #define CRT_INDEX 0x14 | ||
51 | #define CRT_DATA 0x15 | ||
52 | |||
53 | #define WREG_CRT(reg, v) \ | ||
54 | do { \ | ||
55 | WREG8(CRT_INDEX, reg); \ | ||
56 | WREG8(CRT_DATA, v); \ | ||
57 | } while (0) \ | ||
58 | |||
59 | #define GFX_INDEX 0xe | ||
60 | #define GFX_DATA 0xf | ||
61 | |||
62 | #define WREG_GFX(reg, v) \ | ||
63 | do { \ | ||
64 | WREG8(GFX_INDEX, reg); \ | ||
65 | WREG8(GFX_DATA, v); \ | ||
66 | } while (0) \ | ||
67 | |||
68 | /* | ||
69 | * Cirrus has a "hidden" DAC register that can be accessed by writing to | ||
70 | * the pixel mask register to reset the state, then reading from the register | ||
71 | * four times. The next write will then pass to the DAC | ||
72 | */ | ||
73 | #define VGA_DAC_MASK 0x6 | ||
74 | |||
75 | #define WREG_HDR(v) \ | ||
76 | do { \ | ||
77 | RREG8(VGA_DAC_MASK); \ | ||
78 | RREG8(VGA_DAC_MASK); \ | ||
79 | RREG8(VGA_DAC_MASK); \ | ||
80 | RREG8(VGA_DAC_MASK); \ | ||
81 | WREG8(VGA_DAC_MASK, v); \ | ||
82 | } while (0) \ | ||
83 | |||
84 | |||
85 | #define CIRRUS_MAX_FB_HEIGHT 4096 | ||
86 | #define CIRRUS_MAX_FB_WIDTH 4096 | ||
87 | |||
88 | #define CIRRUS_DPMS_CLEARED (-1) | ||
89 | |||
90 | #define to_cirrus_crtc(x) container_of(x, struct cirrus_crtc, base) | ||
91 | #define to_cirrus_encoder(x) container_of(x, struct cirrus_encoder, base) | ||
92 | #define to_cirrus_framebuffer(x) container_of(x, struct cirrus_framebuffer, base) | ||
93 | |||
94 | struct cirrus_crtc { | ||
95 | struct drm_crtc base; | ||
96 | u8 lut_r[256], lut_g[256], lut_b[256]; | ||
97 | int last_dpms; | ||
98 | bool enabled; | ||
99 | }; | ||
100 | |||
101 | struct cirrus_fbdev; | ||
102 | struct cirrus_mode_info { | ||
103 | bool mode_config_initialized; | ||
104 | struct cirrus_crtc *crtc; | ||
105 | /* pointer to fbdev info structure */ | ||
106 | struct cirrus_fbdev *gfbdev; | ||
107 | }; | ||
108 | |||
109 | struct cirrus_encoder { | ||
110 | struct drm_encoder base; | ||
111 | int last_dpms; | ||
112 | }; | ||
113 | |||
114 | struct cirrus_connector { | ||
115 | struct drm_connector base; | ||
116 | }; | ||
117 | |||
118 | struct cirrus_framebuffer { | ||
119 | struct drm_framebuffer base; | ||
120 | struct drm_gem_object *obj; | ||
121 | }; | ||
122 | |||
123 | struct cirrus_mc { | ||
124 | resource_size_t vram_size; | ||
125 | resource_size_t vram_base; | ||
126 | }; | ||
127 | |||
128 | struct cirrus_device { | ||
129 | struct drm_device *dev; | ||
130 | unsigned long flags; | ||
131 | |||
132 | resource_size_t rmmio_base; | ||
133 | resource_size_t rmmio_size; | ||
134 | void __iomem *rmmio; | ||
135 | |||
136 | struct cirrus_mc mc; | ||
137 | struct cirrus_mode_info mode_info; | ||
138 | |||
139 | int num_crtc; | ||
140 | int fb_mtrr; | ||
141 | |||
142 | struct { | ||
143 | struct drm_global_reference mem_global_ref; | ||
144 | struct ttm_bo_global_ref bo_global_ref; | ||
145 | struct ttm_bo_device bdev; | ||
146 | atomic_t validate_sequence; | ||
147 | } ttm; | ||
148 | |||
149 | }; | ||
150 | |||
151 | |||
152 | struct cirrus_fbdev { | ||
153 | struct drm_fb_helper helper; | ||
154 | struct cirrus_framebuffer gfb; | ||
155 | struct list_head fbdev_list; | ||
156 | void *sysram; | ||
157 | int size; | ||
158 | }; | ||
159 | |||
160 | struct cirrus_bo { | ||
161 | struct ttm_buffer_object bo; | ||
162 | struct ttm_placement placement; | ||
163 | struct ttm_bo_kmap_obj kmap; | ||
164 | struct drm_gem_object gem; | ||
165 | u32 placements[3]; | ||
166 | int pin_count; | ||
167 | }; | ||
168 | #define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem) | ||
169 | |||
170 | static inline struct cirrus_bo * | ||
171 | cirrus_bo(struct ttm_buffer_object *bo) | ||
172 | { | ||
173 | return container_of(bo, struct cirrus_bo, bo); | ||
174 | } | ||
175 | |||
176 | |||
177 | #define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base) | ||
178 | #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) | ||
179 | |||
180 | /* cirrus_mode.c */ | ||
181 | void cirrus_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
182 | u16 blue, int regno); | ||
183 | void cirrus_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
184 | u16 *blue, int regno); | ||
185 | |||
186 | |||
187 | /* cirrus_main.c */ | ||
188 | int cirrus_device_init(struct cirrus_device *cdev, | ||
189 | struct drm_device *ddev, | ||
190 | struct pci_dev *pdev, | ||
191 | uint32_t flags); | ||
192 | void cirrus_device_fini(struct cirrus_device *cdev); | ||
193 | int cirrus_gem_init_object(struct drm_gem_object *obj); | ||
194 | void cirrus_gem_free_object(struct drm_gem_object *obj); | ||
195 | int cirrus_dumb_mmap_offset(struct drm_file *file, | ||
196 | struct drm_device *dev, | ||
197 | uint32_t handle, | ||
198 | uint64_t *offset); | ||
199 | int cirrus_gem_create(struct drm_device *dev, | ||
200 | u32 size, bool iskernel, | ||
201 | struct drm_gem_object **obj); | ||
202 | int cirrus_dumb_create(struct drm_file *file, | ||
203 | struct drm_device *dev, | ||
204 | struct drm_mode_create_dumb *args); | ||
205 | int cirrus_dumb_destroy(struct drm_file *file, | ||
206 | struct drm_device *dev, | ||
207 | uint32_t handle); | ||
208 | |||
209 | int cirrus_framebuffer_init(struct drm_device *dev, | ||
210 | struct cirrus_framebuffer *gfb, | ||
211 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
212 | struct drm_gem_object *obj); | ||
213 | |||
214 | /* cirrus_display.c */ | ||
215 | int cirrus_modeset_init(struct cirrus_device *cdev); | ||
216 | void cirrus_modeset_fini(struct cirrus_device *cdev); | ||
217 | |||
218 | /* cirrus_fbdev.c */ | ||
219 | int cirrus_fbdev_init(struct cirrus_device *cdev); | ||
220 | void cirrus_fbdev_fini(struct cirrus_device *cdev); | ||
221 | |||
222 | |||
223 | |||
224 | /* cirrus_irq.c */ | ||
225 | void cirrus_driver_irq_preinstall(struct drm_device *dev); | ||
226 | int cirrus_driver_irq_postinstall(struct drm_device *dev); | ||
227 | void cirrus_driver_irq_uninstall(struct drm_device *dev); | ||
228 | irqreturn_t cirrus_driver_irq_handler(DRM_IRQ_ARGS); | ||
229 | |||
230 | /* cirrus_kms.c */ | ||
231 | int cirrus_driver_load(struct drm_device *dev, unsigned long flags); | ||
232 | int cirrus_driver_unload(struct drm_device *dev); | ||
233 | extern struct drm_ioctl_desc cirrus_ioctls[]; | ||
234 | extern int cirrus_max_ioctl; | ||
235 | |||
236 | int cirrus_mm_init(struct cirrus_device *cirrus); | ||
237 | void cirrus_mm_fini(struct cirrus_device *cirrus); | ||
238 | void cirrus_ttm_placement(struct cirrus_bo *bo, int domain); | ||
239 | int cirrus_bo_create(struct drm_device *dev, int size, int align, | ||
240 | uint32_t flags, struct cirrus_bo **pcirrusbo); | ||
241 | int cirrus_mmap(struct file *filp, struct vm_area_struct *vma); | ||
242 | int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait); | ||
243 | void cirrus_bo_unreserve(struct cirrus_bo *bo); | ||
244 | int cirrus_bo_push_sysram(struct cirrus_bo *bo); | ||
245 | int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr); | ||
246 | #endif /* __CIRRUS_DRV_H__ */ | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c new file mode 100644 index 000000000000..9a276a536992 --- /dev/null +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General | ||
5 | * Public License version 2. See the file COPYING in the main | ||
6 | * directory of this archive for more details. | ||
7 | * | ||
8 | * Authors: Matthew Garrett | ||
9 | * Dave Airlie | ||
10 | */ | ||
11 | #include <linux/module.h> | ||
12 | #include "drmP.h" | ||
13 | #include "drm.h" | ||
14 | #include "drm_fb_helper.h" | ||
15 | |||
16 | #include <linux/fb.h> | ||
17 | |||
18 | #include "cirrus_drv.h" | ||
19 | |||
20 | static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, | ||
21 | int x, int y, int width, int height) | ||
22 | { | ||
23 | int i; | ||
24 | struct drm_gem_object *obj; | ||
25 | struct cirrus_bo *bo; | ||
26 | int src_offset, dst_offset; | ||
27 | int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8; | ||
28 | int ret; | ||
29 | bool unmap = false; | ||
30 | |||
31 | obj = afbdev->gfb.obj; | ||
32 | bo = gem_to_cirrus_bo(obj); | ||
33 | |||
34 | ret = cirrus_bo_reserve(bo, true); | ||
35 | if (ret) { | ||
36 | DRM_ERROR("failed to reserve fb bo\n"); | ||
37 | return; | ||
38 | } | ||
39 | |||
40 | if (!bo->kmap.virtual) { | ||
41 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
42 | if (ret) { | ||
43 | DRM_ERROR("failed to kmap fb updates\n"); | ||
44 | cirrus_bo_unreserve(bo); | ||
45 | return; | ||
46 | } | ||
47 | unmap = true; | ||
48 | } | ||
49 | for (i = y; i < y + height; i++) { | ||
50 | /* assume equal stride for now */ | ||
51 | src_offset = dst_offset = i * afbdev->gfb.base.pitches[0] + (x * bpp); | ||
52 | memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); | ||
53 | |||
54 | } | ||
55 | if (unmap) | ||
56 | ttm_bo_kunmap(&bo->kmap); | ||
57 | |||
58 | cirrus_bo_unreserve(bo); | ||
59 | } | ||
60 | |||
61 | static void cirrus_fillrect(struct fb_info *info, | ||
62 | const struct fb_fillrect *rect) | ||
63 | { | ||
64 | struct cirrus_fbdev *afbdev = info->par; | ||
65 | sys_fillrect(info, rect); | ||
66 | cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width, | ||
67 | rect->height); | ||
68 | } | ||
69 | |||
70 | static void cirrus_copyarea(struct fb_info *info, | ||
71 | const struct fb_copyarea *area) | ||
72 | { | ||
73 | struct cirrus_fbdev *afbdev = info->par; | ||
74 | sys_copyarea(info, area); | ||
75 | cirrus_dirty_update(afbdev, area->dx, area->dy, area->width, | ||
76 | area->height); | ||
77 | } | ||
78 | |||
79 | static void cirrus_imageblit(struct fb_info *info, | ||
80 | const struct fb_image *image) | ||
81 | { | ||
82 | struct cirrus_fbdev *afbdev = info->par; | ||
83 | sys_imageblit(info, image); | ||
84 | cirrus_dirty_update(afbdev, image->dx, image->dy, image->width, | ||
85 | image->height); | ||
86 | } | ||
87 | |||
88 | |||
89 | static struct fb_ops cirrusfb_ops = { | ||
90 | .owner = THIS_MODULE, | ||
91 | .fb_check_var = drm_fb_helper_check_var, | ||
92 | .fb_set_par = drm_fb_helper_set_par, | ||
93 | .fb_fillrect = cirrus_fillrect, | ||
94 | .fb_copyarea = cirrus_copyarea, | ||
95 | .fb_imageblit = cirrus_imageblit, | ||
96 | .fb_pan_display = drm_fb_helper_pan_display, | ||
97 | .fb_blank = drm_fb_helper_blank, | ||
98 | .fb_setcmap = drm_fb_helper_setcmap, | ||
99 | }; | ||
100 | |||
101 | static int cirrusfb_create_object(struct cirrus_fbdev *afbdev, | ||
102 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
103 | struct drm_gem_object **gobj_p) | ||
104 | { | ||
105 | struct drm_device *dev = afbdev->helper.dev; | ||
106 | u32 bpp, depth; | ||
107 | u32 size; | ||
108 | struct drm_gem_object *gobj; | ||
109 | |||
110 | int ret = 0; | ||
111 | drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); | ||
112 | |||
113 | if (bpp > 24) | ||
114 | return -EINVAL; | ||
115 | size = mode_cmd->pitches[0] * mode_cmd->height; | ||
116 | ret = cirrus_gem_create(dev, size, true, &gobj); | ||
117 | if (ret) | ||
118 | return ret; | ||
119 | |||
120 | *gobj_p = gobj; | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | static int cirrusfb_create(struct cirrus_fbdev *gfbdev, | ||
125 | struct drm_fb_helper_surface_size *sizes) | ||
126 | { | ||
127 | struct drm_device *dev = gfbdev->helper.dev; | ||
128 | struct cirrus_device *cdev = gfbdev->helper.dev->dev_private; | ||
129 | struct fb_info *info; | ||
130 | struct drm_framebuffer *fb; | ||
131 | struct drm_mode_fb_cmd2 mode_cmd; | ||
132 | struct device *device = &dev->pdev->dev; | ||
133 | void *sysram; | ||
134 | struct drm_gem_object *gobj = NULL; | ||
135 | struct cirrus_bo *bo = NULL; | ||
136 | int size, ret; | ||
137 | |||
138 | mode_cmd.width = sizes->surface_width; | ||
139 | mode_cmd.height = sizes->surface_height; | ||
140 | mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); | ||
141 | mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, | ||
142 | sizes->surface_depth); | ||
143 | size = mode_cmd.pitches[0] * mode_cmd.height; | ||
144 | |||
145 | ret = cirrusfb_create_object(gfbdev, &mode_cmd, &gobj); | ||
146 | if (ret) { | ||
147 | DRM_ERROR("failed to create fbcon backing object %d\n", ret); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | bo = gem_to_cirrus_bo(gobj); | ||
152 | |||
153 | sysram = vmalloc(size); | ||
154 | if (!sysram) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | info = framebuffer_alloc(0, device); | ||
158 | if (info == NULL) | ||
159 | return -ENOMEM; | ||
160 | |||
161 | info->par = gfbdev; | ||
162 | |||
163 | ret = cirrus_framebuffer_init(cdev->dev, &gfbdev->gfb, &mode_cmd, gobj); | ||
164 | if (ret) | ||
165 | return ret; | ||
166 | |||
167 | gfbdev->sysram = sysram; | ||
168 | gfbdev->size = size; | ||
169 | |||
170 | fb = &gfbdev->gfb.base; | ||
171 | if (!fb) { | ||
172 | DRM_INFO("fb is NULL\n"); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | /* setup helper */ | ||
177 | gfbdev->helper.fb = fb; | ||
178 | gfbdev->helper.fbdev = info; | ||
179 | |||
180 | strcpy(info->fix.id, "cirrusdrmfb"); | ||
181 | |||
182 | |||
183 | info->flags = FBINFO_DEFAULT; | ||
184 | info->fbops = &cirrusfb_ops; | ||
185 | |||
186 | drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | ||
187 | drm_fb_helper_fill_var(info, &gfbdev->helper, sizes->fb_width, | ||
188 | sizes->fb_height); | ||
189 | |||
190 | /* setup aperture base/size for vesafb takeover */ | ||
191 | info->apertures = alloc_apertures(1); | ||
192 | if (!info->apertures) { | ||
193 | ret = -ENOMEM; | ||
194 | goto out_iounmap; | ||
195 | } | ||
196 | info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base; | ||
197 | info->apertures->ranges[0].size = cdev->mc.vram_size; | ||
198 | |||
199 | info->screen_base = sysram; | ||
200 | info->screen_size = size; | ||
201 | |||
202 | info->fix.mmio_start = 0; | ||
203 | info->fix.mmio_len = 0; | ||
204 | |||
205 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
206 | if (ret) { | ||
207 | DRM_ERROR("%s: can't allocate color map\n", info->fix.id); | ||
208 | ret = -ENOMEM; | ||
209 | goto out_iounmap; | ||
210 | } | ||
211 | |||
212 | DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); | ||
213 | DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start); | ||
214 | DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len); | ||
215 | DRM_INFO("fb depth is %d\n", fb->depth); | ||
216 | DRM_INFO(" pitch is %d\n", fb->pitches[0]); | ||
217 | |||
218 | return 0; | ||
219 | out_iounmap: | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static int cirrus_fb_find_or_create_single(struct drm_fb_helper *helper, | ||
224 | struct drm_fb_helper_surface_size | ||
225 | *sizes) | ||
226 | { | ||
227 | struct cirrus_fbdev *gfbdev = (struct cirrus_fbdev *)helper; | ||
228 | int new_fb = 0; | ||
229 | int ret; | ||
230 | |||
231 | if (!helper->fb) { | ||
232 | ret = cirrusfb_create(gfbdev, sizes); | ||
233 | if (ret) | ||
234 | return ret; | ||
235 | new_fb = 1; | ||
236 | } | ||
237 | return new_fb; | ||
238 | } | ||
239 | |||
240 | static int cirrus_fbdev_destroy(struct drm_device *dev, | ||
241 | struct cirrus_fbdev *gfbdev) | ||
242 | { | ||
243 | struct fb_info *info; | ||
244 | struct cirrus_framebuffer *gfb = &gfbdev->gfb; | ||
245 | |||
246 | if (gfbdev->helper.fbdev) { | ||
247 | info = gfbdev->helper.fbdev; | ||
248 | |||
249 | unregister_framebuffer(info); | ||
250 | if (info->cmap.len) | ||
251 | fb_dealloc_cmap(&info->cmap); | ||
252 | framebuffer_release(info); | ||
253 | } | ||
254 | |||
255 | if (gfb->obj) { | ||
256 | drm_gem_object_unreference_unlocked(gfb->obj); | ||
257 | gfb->obj = NULL; | ||
258 | } | ||
259 | |||
260 | vfree(gfbdev->sysram); | ||
261 | drm_fb_helper_fini(&gfbdev->helper); | ||
262 | drm_framebuffer_cleanup(&gfb->base); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static struct drm_fb_helper_funcs cirrus_fb_helper_funcs = { | ||
268 | .gamma_set = cirrus_crtc_fb_gamma_set, | ||
269 | .gamma_get = cirrus_crtc_fb_gamma_get, | ||
270 | .fb_probe = cirrus_fb_find_or_create_single, | ||
271 | }; | ||
272 | |||
273 | int cirrus_fbdev_init(struct cirrus_device *cdev) | ||
274 | { | ||
275 | struct cirrus_fbdev *gfbdev; | ||
276 | int ret; | ||
277 | int bpp_sel = 24; | ||
278 | |||
279 | /*bpp_sel = 8;*/ | ||
280 | gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL); | ||
281 | if (!gfbdev) | ||
282 | return -ENOMEM; | ||
283 | |||
284 | cdev->mode_info.gfbdev = gfbdev; | ||
285 | gfbdev->helper.funcs = &cirrus_fb_helper_funcs; | ||
286 | |||
287 | ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, | ||
288 | cdev->num_crtc, CIRRUSFB_CONN_LIMIT); | ||
289 | if (ret) { | ||
290 | kfree(gfbdev); | ||
291 | return ret; | ||
292 | } | ||
293 | drm_fb_helper_single_add_all_connectors(&gfbdev->helper); | ||
294 | drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | void cirrus_fbdev_fini(struct cirrus_device *cdev) | ||
300 | { | ||
301 | if (!cdev->mode_info.gfbdev) | ||
302 | return; | ||
303 | |||
304 | cirrus_fbdev_destroy(cdev->dev, cdev->mode_info.gfbdev); | ||
305 | kfree(cdev->mode_info.gfbdev); | ||
306 | cdev->mode_info.gfbdev = NULL; | ||
307 | } | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c new file mode 100644 index 000000000000..e3c122578417 --- /dev/null +++ b/drivers/gpu/drm/cirrus/cirrus_main.c | |||
@@ -0,0 +1,335 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General | ||
5 | * Public License version 2. See the file COPYING in the main | ||
6 | * directory of this archive for more details. | ||
7 | * | ||
8 | * Authors: Matthew Garrett | ||
9 | * Dave Airlie | ||
10 | */ | ||
11 | #include "drmP.h" | ||
12 | #include "drm.h" | ||
13 | #include "drm_crtc_helper.h" | ||
14 | |||
15 | #include "cirrus_drv.h" | ||
16 | |||
17 | |||
18 | static void cirrus_user_framebuffer_destroy(struct drm_framebuffer *fb) | ||
19 | { | ||
20 | struct cirrus_framebuffer *cirrus_fb = to_cirrus_framebuffer(fb); | ||
21 | if (cirrus_fb->obj) | ||
22 | drm_gem_object_unreference_unlocked(cirrus_fb->obj); | ||
23 | drm_framebuffer_cleanup(fb); | ||
24 | kfree(fb); | ||
25 | } | ||
26 | |||
27 | static int cirrus_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
28 | struct drm_file *file_priv, | ||
29 | unsigned int *handle) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static const struct drm_framebuffer_funcs cirrus_fb_funcs = { | ||
35 | .destroy = cirrus_user_framebuffer_destroy, | ||
36 | .create_handle = cirrus_user_framebuffer_create_handle, | ||
37 | }; | ||
38 | |||
39 | int cirrus_framebuffer_init(struct drm_device *dev, | ||
40 | struct cirrus_framebuffer *gfb, | ||
41 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
42 | struct drm_gem_object *obj) | ||
43 | { | ||
44 | int ret; | ||
45 | |||
46 | ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs); | ||
47 | if (ret) { | ||
48 | DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); | ||
49 | return ret; | ||
50 | } | ||
51 | drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); | ||
52 | gfb->obj = obj; | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static struct drm_framebuffer * | ||
57 | cirrus_user_framebuffer_create(struct drm_device *dev, | ||
58 | struct drm_file *filp, | ||
59 | struct drm_mode_fb_cmd2 *mode_cmd) | ||
60 | { | ||
61 | struct drm_gem_object *obj; | ||
62 | struct cirrus_framebuffer *cirrus_fb; | ||
63 | int ret; | ||
64 | u32 bpp, depth; | ||
65 | |||
66 | drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); | ||
67 | /* cirrus can't handle > 24bpp framebuffers at all */ | ||
68 | if (bpp > 24) | ||
69 | return ERR_PTR(-EINVAL); | ||
70 | |||
71 | obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]); | ||
72 | if (obj == NULL) | ||
73 | return ERR_PTR(-ENOENT); | ||
74 | |||
75 | cirrus_fb = kzalloc(sizeof(*cirrus_fb), GFP_KERNEL); | ||
76 | if (!cirrus_fb) { | ||
77 | drm_gem_object_unreference_unlocked(obj); | ||
78 | return ERR_PTR(-ENOMEM); | ||
79 | } | ||
80 | |||
81 | ret = cirrus_framebuffer_init(dev, cirrus_fb, mode_cmd, obj); | ||
82 | if (ret) { | ||
83 | drm_gem_object_unreference_unlocked(obj); | ||
84 | kfree(cirrus_fb); | ||
85 | return ERR_PTR(ret); | ||
86 | } | ||
87 | return &cirrus_fb->base; | ||
88 | } | ||
89 | |||
90 | static const struct drm_mode_config_funcs cirrus_mode_funcs = { | ||
91 | .fb_create = cirrus_user_framebuffer_create, | ||
92 | }; | ||
93 | |||
94 | /* Unmap the framebuffer from the core and release the memory */ | ||
95 | static void cirrus_vram_fini(struct cirrus_device *cdev) | ||
96 | { | ||
97 | iounmap(cdev->rmmio); | ||
98 | cdev->rmmio = NULL; | ||
99 | if (cdev->mc.vram_base) | ||
100 | release_mem_region(cdev->mc.vram_base, cdev->mc.vram_size); | ||
101 | } | ||
102 | |||
103 | /* Map the framebuffer from the card and configure the core */ | ||
104 | static int cirrus_vram_init(struct cirrus_device *cdev) | ||
105 | { | ||
106 | /* BAR 0 is VRAM */ | ||
107 | cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0); | ||
108 | /* We have 4MB of VRAM */ | ||
109 | cdev->mc.vram_size = 4 * 1024 * 1024; | ||
110 | |||
111 | if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size, | ||
112 | "cirrusdrmfb_vram")) { | ||
113 | DRM_ERROR("can't reserve VRAM\n"); | ||
114 | return -ENXIO; | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * Our emulated hardware has two sets of memory. One is video RAM and can | ||
122 | * simply be used as a linear framebuffer - the other provides mmio access | ||
123 | * to the display registers. The latter can also be accessed via IO port | ||
124 | * access, but we map the range and use mmio to program them instead | ||
125 | */ | ||
126 | |||
127 | int cirrus_device_init(struct cirrus_device *cdev, | ||
128 | struct drm_device *ddev, | ||
129 | struct pci_dev *pdev, uint32_t flags) | ||
130 | { | ||
131 | int ret; | ||
132 | |||
133 | cdev->dev = ddev; | ||
134 | cdev->flags = flags; | ||
135 | |||
136 | /* Hardcode the number of CRTCs to 1 */ | ||
137 | cdev->num_crtc = 1; | ||
138 | |||
139 | /* BAR 0 is the framebuffer, BAR 1 contains registers */ | ||
140 | cdev->rmmio_base = pci_resource_start(cdev->dev->pdev, 1); | ||
141 | cdev->rmmio_size = pci_resource_len(cdev->dev->pdev, 1); | ||
142 | |||
143 | if (!request_mem_region(cdev->rmmio_base, cdev->rmmio_size, | ||
144 | "cirrusdrmfb_mmio")) { | ||
145 | DRM_ERROR("can't reserve mmio registers\n"); | ||
146 | return -ENOMEM; | ||
147 | } | ||
148 | |||
149 | cdev->rmmio = ioremap(cdev->rmmio_base, cdev->rmmio_size); | ||
150 | |||
151 | if (cdev->rmmio == NULL) | ||
152 | return -ENOMEM; | ||
153 | |||
154 | ret = cirrus_vram_init(cdev); | ||
155 | if (ret) { | ||
156 | release_mem_region(cdev->rmmio_base, cdev->rmmio_size); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | void cirrus_device_fini(struct cirrus_device *cdev) | ||
164 | { | ||
165 | release_mem_region(cdev->rmmio_base, cdev->rmmio_size); | ||
166 | cirrus_vram_fini(cdev); | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * Functions here will be called by the core once it's bound the driver to | ||
171 | * a PCI device | ||
172 | */ | ||
173 | |||
174 | int cirrus_driver_load(struct drm_device *dev, unsigned long flags) | ||
175 | { | ||
176 | struct cirrus_device *cdev; | ||
177 | int r; | ||
178 | |||
179 | cdev = kzalloc(sizeof(struct cirrus_device), GFP_KERNEL); | ||
180 | if (cdev == NULL) | ||
181 | return -ENOMEM; | ||
182 | dev->dev_private = (void *)cdev; | ||
183 | |||
184 | r = cirrus_device_init(cdev, dev, dev->pdev, flags); | ||
185 | if (r) { | ||
186 | dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r); | ||
187 | goto out; | ||
188 | } | ||
189 | |||
190 | r = cirrus_mm_init(cdev); | ||
191 | if (r) | ||
192 | dev_err(&dev->pdev->dev, "fatal err on mm init\n"); | ||
193 | |||
194 | r = cirrus_modeset_init(cdev); | ||
195 | if (r) | ||
196 | dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r); | ||
197 | |||
198 | dev->mode_config.funcs = (void *)&cirrus_mode_funcs; | ||
199 | out: | ||
200 | if (r) | ||
201 | cirrus_driver_unload(dev); | ||
202 | return r; | ||
203 | } | ||
204 | |||
205 | int cirrus_driver_unload(struct drm_device *dev) | ||
206 | { | ||
207 | struct cirrus_device *cdev = dev->dev_private; | ||
208 | |||
209 | if (cdev == NULL) | ||
210 | return 0; | ||
211 | cirrus_modeset_fini(cdev); | ||
212 | cirrus_mm_fini(cdev); | ||
213 | cirrus_device_fini(cdev); | ||
214 | kfree(cdev); | ||
215 | dev->dev_private = NULL; | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | int cirrus_gem_create(struct drm_device *dev, | ||
220 | u32 size, bool iskernel, | ||
221 | struct drm_gem_object **obj) | ||
222 | { | ||
223 | struct cirrus_bo *cirrusbo; | ||
224 | int ret; | ||
225 | |||
226 | *obj = NULL; | ||
227 | |||
228 | size = roundup(size, PAGE_SIZE); | ||
229 | if (size == 0) | ||
230 | return -EINVAL; | ||
231 | |||
232 | ret = cirrus_bo_create(dev, size, 0, 0, &cirrusbo); | ||
233 | if (ret) { | ||
234 | if (ret != -ERESTARTSYS) | ||
235 | DRM_ERROR("failed to allocate GEM object\n"); | ||
236 | return ret; | ||
237 | } | ||
238 | *obj = &cirrusbo->gem; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | int cirrus_dumb_create(struct drm_file *file, | ||
243 | struct drm_device *dev, | ||
244 | struct drm_mode_create_dumb *args) | ||
245 | { | ||
246 | int ret; | ||
247 | struct drm_gem_object *gobj; | ||
248 | u32 handle; | ||
249 | |||
250 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
251 | args->size = args->pitch * args->height; | ||
252 | |||
253 | ret = cirrus_gem_create(dev, args->size, false, | ||
254 | &gobj); | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | ret = drm_gem_handle_create(file, gobj, &handle); | ||
259 | drm_gem_object_unreference_unlocked(gobj); | ||
260 | if (ret) | ||
261 | return ret; | ||
262 | |||
263 | args->handle = handle; | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | int cirrus_dumb_destroy(struct drm_file *file, | ||
268 | struct drm_device *dev, | ||
269 | uint32_t handle) | ||
270 | { | ||
271 | return drm_gem_handle_delete(file, handle); | ||
272 | } | ||
273 | |||
274 | int cirrus_gem_init_object(struct drm_gem_object *obj) | ||
275 | { | ||
276 | BUG(); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | void cirrus_bo_unref(struct cirrus_bo **bo) | ||
281 | { | ||
282 | struct ttm_buffer_object *tbo; | ||
283 | |||
284 | if ((*bo) == NULL) | ||
285 | return; | ||
286 | |||
287 | tbo = &((*bo)->bo); | ||
288 | ttm_bo_unref(&tbo); | ||
289 | if (tbo == NULL) | ||
290 | *bo = NULL; | ||
291 | |||
292 | } | ||
293 | |||
294 | void cirrus_gem_free_object(struct drm_gem_object *obj) | ||
295 | { | ||
296 | struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj); | ||
297 | |||
298 | if (!cirrus_bo) | ||
299 | return; | ||
300 | cirrus_bo_unref(&cirrus_bo); | ||
301 | } | ||
302 | |||
303 | |||
304 | static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo) | ||
305 | { | ||
306 | return bo->bo.addr_space_offset; | ||
307 | } | ||
308 | |||
309 | int | ||
310 | cirrus_dumb_mmap_offset(struct drm_file *file, | ||
311 | struct drm_device *dev, | ||
312 | uint32_t handle, | ||
313 | uint64_t *offset) | ||
314 | { | ||
315 | struct drm_gem_object *obj; | ||
316 | int ret; | ||
317 | struct cirrus_bo *bo; | ||
318 | |||
319 | mutex_lock(&dev->struct_mutex); | ||
320 | obj = drm_gem_object_lookup(dev, file, handle); | ||
321 | if (obj == NULL) { | ||
322 | ret = -ENOENT; | ||
323 | goto out_unlock; | ||
324 | } | ||
325 | |||
326 | bo = gem_to_cirrus_bo(obj); | ||
327 | *offset = cirrus_bo_mmap_offset(bo); | ||
328 | |||
329 | drm_gem_object_unreference(obj); | ||
330 | ret = 0; | ||
331 | out_unlock: | ||
332 | mutex_unlock(&dev->struct_mutex); | ||
333 | return ret; | ||
334 | |||
335 | } | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c new file mode 100644 index 000000000000..100f6308c509 --- /dev/null +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c | |||
@@ -0,0 +1,629 @@ | |||
1 | |||
2 | /* | ||
3 | * Copyright 2012 Red Hat | ||
4 | * | ||
5 | * This file is subject to the terms and conditions of the GNU General | ||
6 | * Public License version 2. See the file COPYING in the main | ||
7 | * directory of this archive for more details. | ||
8 | * | ||
9 | * Authors: Matthew Garrett | ||
10 | * Dave Airlie | ||
11 | * | ||
12 | * Portions of this code derived from cirrusfb.c: | ||
13 | * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets | ||
14 | * | ||
15 | * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com> | ||
16 | */ | ||
17 | #include "drmP.h" | ||
18 | #include "drm.h" | ||
19 | #include "drm_crtc_helper.h" | ||
20 | |||
21 | #include <video/cirrus.h> | ||
22 | |||
23 | #include "cirrus_drv.h" | ||
24 | |||
25 | #define CIRRUS_LUT_SIZE 256 | ||
26 | |||
27 | #define PALETTE_INDEX 0x8 | ||
28 | #define PALETTE_DATA 0x9 | ||
29 | |||
30 | /* | ||
31 | * This file contains setup code for the CRTC. | ||
32 | */ | ||
33 | |||
34 | static void cirrus_crtc_load_lut(struct drm_crtc *crtc) | ||
35 | { | ||
36 | struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); | ||
37 | struct drm_device *dev = crtc->dev; | ||
38 | struct cirrus_device *cdev = dev->dev_private; | ||
39 | int i; | ||
40 | |||
41 | if (!crtc->enabled) | ||
42 | return; | ||
43 | |||
44 | for (i = 0; i < CIRRUS_LUT_SIZE; i++) { | ||
45 | /* VGA registers */ | ||
46 | WREG8(PALETTE_INDEX, i); | ||
47 | WREG8(PALETTE_DATA, cirrus_crtc->lut_r[i]); | ||
48 | WREG8(PALETTE_DATA, cirrus_crtc->lut_g[i]); | ||
49 | WREG8(PALETTE_DATA, cirrus_crtc->lut_b[i]); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * The DRM core requires DPMS functions, but they make little sense in our | ||
55 | * case and so are just stubs | ||
56 | */ | ||
57 | |||
58 | static void cirrus_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
59 | { | ||
60 | struct drm_device *dev = crtc->dev; | ||
61 | struct cirrus_device *cdev = dev->dev_private; | ||
62 | u8 sr01, gr0e; | ||
63 | |||
64 | switch (mode) { | ||
65 | case DRM_MODE_DPMS_ON: | ||
66 | sr01 = 0x00; | ||
67 | gr0e = 0x00; | ||
68 | break; | ||
69 | case DRM_MODE_DPMS_STANDBY: | ||
70 | sr01 = 0x20; | ||
71 | gr0e = 0x02; | ||
72 | break; | ||
73 | case DRM_MODE_DPMS_SUSPEND: | ||
74 | sr01 = 0x20; | ||
75 | gr0e = 0x04; | ||
76 | break; | ||
77 | case DRM_MODE_DPMS_OFF: | ||
78 | sr01 = 0x20; | ||
79 | gr0e = 0x06; | ||
80 | break; | ||
81 | default: | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | WREG8(SEQ_INDEX, 0x1); | ||
86 | sr01 |= RREG8(SEQ_DATA) & ~0x20; | ||
87 | WREG_SEQ(0x1, sr01); | ||
88 | |||
89 | WREG8(GFX_INDEX, 0xe); | ||
90 | gr0e |= RREG8(GFX_DATA) & ~0x06; | ||
91 | WREG_GFX(0xe, gr0e); | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * The core passes the desired mode to the CRTC code to see whether any | ||
96 | * CRTC-specific modifications need to be made to it. We're in a position | ||
97 | * to just pass that straight through, so this does nothing | ||
98 | */ | ||
99 | static bool cirrus_crtc_mode_fixup(struct drm_crtc *crtc, | ||
100 | struct drm_display_mode *mode, | ||
101 | struct drm_display_mode *adjusted_mode) | ||
102 | { | ||
103 | return true; | ||
104 | } | ||
105 | |||
106 | void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset) | ||
107 | { | ||
108 | struct cirrus_device *cdev = crtc->dev->dev_private; | ||
109 | u32 addr; | ||
110 | u8 tmp; | ||
111 | |||
112 | addr = offset >> 2; | ||
113 | WREG_CRT(0x0c, (u8)((addr >> 8) & 0xff)); | ||
114 | WREG_CRT(0x0d, (u8)(addr & 0xff)); | ||
115 | |||
116 | WREG8(CRT_INDEX, 0x1b); | ||
117 | tmp = RREG8(CRT_DATA); | ||
118 | tmp &= 0xf2; | ||
119 | tmp |= (addr >> 16) & 0x01; | ||
120 | tmp |= (addr >> 15) & 0x0c; | ||
121 | WREG_CRT(0x1b, tmp); | ||
122 | WREG8(CRT_INDEX, 0x1d); | ||
123 | tmp = RREG8(CRT_DATA); | ||
124 | tmp &= 0x7f; | ||
125 | tmp |= (addr >> 12) & 0x80; | ||
126 | WREG_CRT(0x1d, tmp); | ||
127 | } | ||
128 | |||
129 | /* cirrus is different - we will force move buffers out of VRAM */ | ||
130 | static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, | ||
131 | struct drm_framebuffer *fb, | ||
132 | int x, int y, int atomic) | ||
133 | { | ||
134 | struct cirrus_device *cdev = crtc->dev->dev_private; | ||
135 | struct drm_gem_object *obj; | ||
136 | struct cirrus_framebuffer *cirrus_fb; | ||
137 | struct cirrus_bo *bo; | ||
138 | int ret; | ||
139 | u64 gpu_addr; | ||
140 | |||
141 | /* push the previous fb to system ram */ | ||
142 | if (!atomic && fb) { | ||
143 | cirrus_fb = to_cirrus_framebuffer(fb); | ||
144 | obj = cirrus_fb->obj; | ||
145 | bo = gem_to_cirrus_bo(obj); | ||
146 | ret = cirrus_bo_reserve(bo, false); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | cirrus_bo_push_sysram(bo); | ||
150 | cirrus_bo_unreserve(bo); | ||
151 | } | ||
152 | |||
153 | cirrus_fb = to_cirrus_framebuffer(crtc->fb); | ||
154 | obj = cirrus_fb->obj; | ||
155 | bo = gem_to_cirrus_bo(obj); | ||
156 | |||
157 | ret = cirrus_bo_reserve(bo, false); | ||
158 | if (ret) | ||
159 | return ret; | ||
160 | |||
161 | ret = cirrus_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | ||
162 | if (ret) { | ||
163 | cirrus_bo_unreserve(bo); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | if (&cdev->mode_info.gfbdev->gfb == cirrus_fb) { | ||
168 | /* if pushing console in kmap it */ | ||
169 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
170 | if (ret) | ||
171 | DRM_ERROR("failed to kmap fbcon\n"); | ||
172 | } | ||
173 | cirrus_bo_unreserve(bo); | ||
174 | |||
175 | cirrus_set_start_address(crtc, (u32)gpu_addr); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int cirrus_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | ||
180 | struct drm_framebuffer *old_fb) | ||
181 | { | ||
182 | return cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * The meat of this driver. The core passes us a mode and we have to program | ||
187 | * it. The modesetting here is the bare minimum required to satisfy the qemu | ||
188 | * emulation of this hardware, and running this against a real device is | ||
189 | * likely to result in an inadequately programmed mode. We've already had | ||
190 | * the opportunity to modify the mode, so whatever we receive here should | ||
191 | * be something that can be correctly programmed and displayed | ||
192 | */ | ||
193 | static int cirrus_crtc_mode_set(struct drm_crtc *crtc, | ||
194 | struct drm_display_mode *mode, | ||
195 | struct drm_display_mode *adjusted_mode, | ||
196 | int x, int y, struct drm_framebuffer *old_fb) | ||
197 | { | ||
198 | struct drm_device *dev = crtc->dev; | ||
199 | struct cirrus_device *cdev = dev->dev_private; | ||
200 | int hsyncstart, hsyncend, htotal, hdispend; | ||
201 | int vtotal, vdispend; | ||
202 | int tmp; | ||
203 | int sr07 = 0, hdr = 0; | ||
204 | |||
205 | htotal = mode->htotal / 8; | ||
206 | hsyncend = mode->hsync_end / 8; | ||
207 | hsyncstart = mode->hsync_start / 8; | ||
208 | hdispend = mode->hdisplay / 8; | ||
209 | |||
210 | vtotal = mode->vtotal; | ||
211 | vdispend = mode->vdisplay; | ||
212 | |||
213 | vdispend -= 1; | ||
214 | vtotal -= 2; | ||
215 | |||
216 | htotal -= 5; | ||
217 | hdispend -= 1; | ||
218 | hsyncstart += 1; | ||
219 | hsyncend += 1; | ||
220 | |||
221 | WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20); | ||
222 | WREG_CRT(VGA_CRTC_H_TOTAL, htotal); | ||
223 | WREG_CRT(VGA_CRTC_H_DISP, hdispend); | ||
224 | WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart); | ||
225 | WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend); | ||
226 | WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff); | ||
227 | WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff); | ||
228 | |||
229 | tmp = 0x40; | ||
230 | if ((vdispend + 1) & 512) | ||
231 | tmp |= 0x20; | ||
232 | WREG_CRT(VGA_CRTC_MAX_SCAN, tmp); | ||
233 | |||
234 | /* | ||
235 | * Overflow bits for values that don't fit in the standard registers | ||
236 | */ | ||
237 | tmp = 16; | ||
238 | if (vtotal & 256) | ||
239 | tmp |= 1; | ||
240 | if (vdispend & 256) | ||
241 | tmp |= 2; | ||
242 | if ((vdispend + 1) & 256) | ||
243 | tmp |= 8; | ||
244 | if (vtotal & 512) | ||
245 | tmp |= 32; | ||
246 | if (vdispend & 512) | ||
247 | tmp |= 64; | ||
248 | WREG_CRT(VGA_CRTC_OVERFLOW, tmp); | ||
249 | |||
250 | tmp = 0; | ||
251 | |||
252 | /* More overflow bits */ | ||
253 | |||
254 | if ((htotal + 5) & 64) | ||
255 | tmp |= 16; | ||
256 | if ((htotal + 5) & 128) | ||
257 | tmp |= 32; | ||
258 | if (vtotal & 256) | ||
259 | tmp |= 64; | ||
260 | if (vtotal & 512) | ||
261 | tmp |= 128; | ||
262 | |||
263 | WREG_CRT(CL_CRT1A, tmp); | ||
264 | |||
265 | /* Disable Hercules/CGA compatibility */ | ||
266 | WREG_CRT(VGA_CRTC_MODE, 0x03); | ||
267 | |||
268 | WREG8(SEQ_INDEX, 0x7); | ||
269 | sr07 = RREG8(SEQ_DATA); | ||
270 | sr07 &= 0xe0; | ||
271 | hdr = 0; | ||
272 | switch (crtc->fb->bits_per_pixel) { | ||
273 | case 8: | ||
274 | sr07 |= 0x11; | ||
275 | break; | ||
276 | case 16: | ||
277 | sr07 |= 0xc1; | ||
278 | hdr = 0xc0; | ||
279 | break; | ||
280 | case 24: | ||
281 | sr07 |= 0x15; | ||
282 | hdr = 0xc5; | ||
283 | break; | ||
284 | case 32: | ||
285 | sr07 |= 0x19; | ||
286 | hdr = 0xc5; | ||
287 | break; | ||
288 | default: | ||
289 | return -1; | ||
290 | } | ||
291 | |||
292 | WREG_SEQ(0x7, sr07); | ||
293 | |||
294 | /* Program the pitch */ | ||
295 | tmp = crtc->fb->pitches[0] / 8; | ||
296 | WREG_CRT(VGA_CRTC_OFFSET, tmp); | ||
297 | |||
298 | /* Enable extended blanking and pitch bits, and enable full memory */ | ||
299 | tmp = 0x22; | ||
300 | tmp |= (crtc->fb->pitches[0] >> 7) & 0x10; | ||
301 | tmp |= (crtc->fb->pitches[0] >> 6) & 0x40; | ||
302 | WREG_CRT(0x1b, tmp); | ||
303 | |||
304 | /* Enable high-colour modes */ | ||
305 | WREG_GFX(VGA_GFX_MODE, 0x40); | ||
306 | |||
307 | /* And set graphics mode */ | ||
308 | WREG_GFX(VGA_GFX_MISC, 0x01); | ||
309 | |||
310 | WREG_HDR(hdr); | ||
311 | cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * This is called before a mode is programmed. A typical use might be to | ||
317 | * enable DPMS during the programming to avoid seeing intermediate stages, | ||
318 | * but that's not relevant to us | ||
319 | */ | ||
320 | static void cirrus_crtc_prepare(struct drm_crtc *crtc) | ||
321 | { | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * This is called after a mode is programmed. It should reverse anything done | ||
326 | * by the prepare function | ||
327 | */ | ||
328 | static void cirrus_crtc_commit(struct drm_crtc *crtc) | ||
329 | { | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * The core can pass us a set of gamma values to program. We actually only | ||
334 | * use this for 8-bit mode so can't perform smooth fades on deeper modes, | ||
335 | * but it's a requirement that we provide the function | ||
336 | */ | ||
337 | static void cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
338 | u16 *blue, uint32_t start, uint32_t size) | ||
339 | { | ||
340 | struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); | ||
341 | int i; | ||
342 | |||
343 | if (size != CIRRUS_LUT_SIZE) | ||
344 | return; | ||
345 | |||
346 | for (i = 0; i < CIRRUS_LUT_SIZE; i++) { | ||
347 | cirrus_crtc->lut_r[i] = red[i]; | ||
348 | cirrus_crtc->lut_g[i] = green[i]; | ||
349 | cirrus_crtc->lut_b[i] = blue[i]; | ||
350 | } | ||
351 | cirrus_crtc_load_lut(crtc); | ||
352 | } | ||
353 | |||
354 | /* Simple cleanup function */ | ||
355 | static void cirrus_crtc_destroy(struct drm_crtc *crtc) | ||
356 | { | ||
357 | struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); | ||
358 | |||
359 | drm_crtc_cleanup(crtc); | ||
360 | kfree(cirrus_crtc); | ||
361 | } | ||
362 | |||
363 | /* These provide the minimum set of functions required to handle a CRTC */ | ||
364 | static const struct drm_crtc_funcs cirrus_crtc_funcs = { | ||
365 | .gamma_set = cirrus_crtc_gamma_set, | ||
366 | .set_config = drm_crtc_helper_set_config, | ||
367 | .destroy = cirrus_crtc_destroy, | ||
368 | }; | ||
369 | |||
370 | static const struct drm_crtc_helper_funcs cirrus_helper_funcs = { | ||
371 | .dpms = cirrus_crtc_dpms, | ||
372 | .mode_fixup = cirrus_crtc_mode_fixup, | ||
373 | .mode_set = cirrus_crtc_mode_set, | ||
374 | .mode_set_base = cirrus_crtc_mode_set_base, | ||
375 | .prepare = cirrus_crtc_prepare, | ||
376 | .commit = cirrus_crtc_commit, | ||
377 | .load_lut = cirrus_crtc_load_lut, | ||
378 | }; | ||
379 | |||
380 | /* CRTC setup */ | ||
381 | static void cirrus_crtc_init(struct drm_device *dev) | ||
382 | { | ||
383 | struct cirrus_device *cdev = dev->dev_private; | ||
384 | struct cirrus_crtc *cirrus_crtc; | ||
385 | int i; | ||
386 | |||
387 | cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) + | ||
388 | (CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)), | ||
389 | GFP_KERNEL); | ||
390 | |||
391 | if (cirrus_crtc == NULL) | ||
392 | return; | ||
393 | |||
394 | drm_crtc_init(dev, &cirrus_crtc->base, &cirrus_crtc_funcs); | ||
395 | |||
396 | drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE); | ||
397 | cdev->mode_info.crtc = cirrus_crtc; | ||
398 | |||
399 | for (i = 0; i < CIRRUS_LUT_SIZE; i++) { | ||
400 | cirrus_crtc->lut_r[i] = i; | ||
401 | cirrus_crtc->lut_g[i] = i; | ||
402 | cirrus_crtc->lut_b[i] = i; | ||
403 | } | ||
404 | |||
405 | drm_crtc_helper_add(&cirrus_crtc->base, &cirrus_helper_funcs); | ||
406 | } | ||
407 | |||
408 | /** Sets the color ramps on behalf of fbcon */ | ||
409 | void cirrus_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
410 | u16 blue, int regno) | ||
411 | { | ||
412 | struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); | ||
413 | |||
414 | cirrus_crtc->lut_r[regno] = red; | ||
415 | cirrus_crtc->lut_g[regno] = green; | ||
416 | cirrus_crtc->lut_b[regno] = blue; | ||
417 | } | ||
418 | |||
419 | /** Gets the color ramps on behalf of fbcon */ | ||
420 | void cirrus_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
421 | u16 *blue, int regno) | ||
422 | { | ||
423 | struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); | ||
424 | |||
425 | *red = cirrus_crtc->lut_r[regno]; | ||
426 | *green = cirrus_crtc->lut_g[regno]; | ||
427 | *blue = cirrus_crtc->lut_b[regno]; | ||
428 | } | ||
429 | |||
430 | |||
431 | static bool cirrus_encoder_mode_fixup(struct drm_encoder *encoder, | ||
432 | struct drm_display_mode *mode, | ||
433 | struct drm_display_mode *adjusted_mode) | ||
434 | { | ||
435 | return true; | ||
436 | } | ||
437 | |||
438 | static void cirrus_encoder_mode_set(struct drm_encoder *encoder, | ||
439 | struct drm_display_mode *mode, | ||
440 | struct drm_display_mode *adjusted_mode) | ||
441 | { | ||
442 | } | ||
443 | |||
444 | static void cirrus_encoder_dpms(struct drm_encoder *encoder, int state) | ||
445 | { | ||
446 | return; | ||
447 | } | ||
448 | |||
449 | static void cirrus_encoder_prepare(struct drm_encoder *encoder) | ||
450 | { | ||
451 | } | ||
452 | |||
453 | static void cirrus_encoder_commit(struct drm_encoder *encoder) | ||
454 | { | ||
455 | } | ||
456 | |||
457 | void cirrus_encoder_destroy(struct drm_encoder *encoder) | ||
458 | { | ||
459 | struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder); | ||
460 | drm_encoder_cleanup(encoder); | ||
461 | kfree(cirrus_encoder); | ||
462 | } | ||
463 | |||
464 | static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = { | ||
465 | .dpms = cirrus_encoder_dpms, | ||
466 | .mode_fixup = cirrus_encoder_mode_fixup, | ||
467 | .mode_set = cirrus_encoder_mode_set, | ||
468 | .prepare = cirrus_encoder_prepare, | ||
469 | .commit = cirrus_encoder_commit, | ||
470 | }; | ||
471 | |||
472 | static const struct drm_encoder_funcs cirrus_encoder_encoder_funcs = { | ||
473 | .destroy = cirrus_encoder_destroy, | ||
474 | }; | ||
475 | |||
476 | static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev) | ||
477 | { | ||
478 | struct drm_encoder *encoder; | ||
479 | struct cirrus_encoder *cirrus_encoder; | ||
480 | |||
481 | cirrus_encoder = kzalloc(sizeof(struct cirrus_encoder), GFP_KERNEL); | ||
482 | if (!cirrus_encoder) | ||
483 | return NULL; | ||
484 | |||
485 | encoder = &cirrus_encoder->base; | ||
486 | encoder->possible_crtcs = 0x1; | ||
487 | |||
488 | drm_encoder_init(dev, encoder, &cirrus_encoder_encoder_funcs, | ||
489 | DRM_MODE_ENCODER_DAC); | ||
490 | drm_encoder_helper_add(encoder, &cirrus_encoder_helper_funcs); | ||
491 | |||
492 | return encoder; | ||
493 | } | ||
494 | |||
495 | |||
496 | int cirrus_vga_get_modes(struct drm_connector *connector) | ||
497 | { | ||
498 | /* Just add a static list of modes */ | ||
499 | drm_add_modes_noedid(connector, 640, 480); | ||
500 | drm_add_modes_noedid(connector, 800, 600); | ||
501 | drm_add_modes_noedid(connector, 1024, 768); | ||
502 | drm_add_modes_noedid(connector, 1280, 1024); | ||
503 | |||
504 | return 4; | ||
505 | } | ||
506 | |||
507 | static int cirrus_vga_mode_valid(struct drm_connector *connector, | ||
508 | struct drm_display_mode *mode) | ||
509 | { | ||
510 | /* Any mode we've added is valid */ | ||
511 | return MODE_OK; | ||
512 | } | ||
513 | |||
514 | struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector | ||
515 | *connector) | ||
516 | { | ||
517 | int enc_id = connector->encoder_ids[0]; | ||
518 | struct drm_mode_object *obj; | ||
519 | struct drm_encoder *encoder; | ||
520 | |||
521 | /* pick the encoder ids */ | ||
522 | if (enc_id) { | ||
523 | obj = | ||
524 | drm_mode_object_find(connector->dev, enc_id, | ||
525 | DRM_MODE_OBJECT_ENCODER); | ||
526 | if (!obj) | ||
527 | return NULL; | ||
528 | encoder = obj_to_encoder(obj); | ||
529 | return encoder; | ||
530 | } | ||
531 | return NULL; | ||
532 | } | ||
533 | |||
534 | static enum drm_connector_status cirrus_vga_detect(struct drm_connector | ||
535 | *connector, bool force) | ||
536 | { | ||
537 | return connector_status_connected; | ||
538 | } | ||
539 | |||
540 | static void cirrus_connector_destroy(struct drm_connector *connector) | ||
541 | { | ||
542 | drm_connector_cleanup(connector); | ||
543 | kfree(connector); | ||
544 | } | ||
545 | |||
546 | struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = { | ||
547 | .get_modes = cirrus_vga_get_modes, | ||
548 | .mode_valid = cirrus_vga_mode_valid, | ||
549 | .best_encoder = cirrus_connector_best_encoder, | ||
550 | }; | ||
551 | |||
552 | struct drm_connector_funcs cirrus_vga_connector_funcs = { | ||
553 | .dpms = drm_helper_connector_dpms, | ||
554 | .detect = cirrus_vga_detect, | ||
555 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
556 | .destroy = cirrus_connector_destroy, | ||
557 | }; | ||
558 | |||
559 | static struct drm_connector *cirrus_vga_init(struct drm_device *dev) | ||
560 | { | ||
561 | struct drm_connector *connector; | ||
562 | struct cirrus_connector *cirrus_connector; | ||
563 | |||
564 | cirrus_connector = kzalloc(sizeof(struct cirrus_connector), GFP_KERNEL); | ||
565 | if (!cirrus_connector) | ||
566 | return NULL; | ||
567 | |||
568 | connector = &cirrus_connector->base; | ||
569 | |||
570 | drm_connector_init(dev, connector, | ||
571 | &cirrus_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||
572 | |||
573 | drm_connector_helper_add(connector, &cirrus_vga_connector_helper_funcs); | ||
574 | |||
575 | return connector; | ||
576 | } | ||
577 | |||
578 | |||
579 | int cirrus_modeset_init(struct cirrus_device *cdev) | ||
580 | { | ||
581 | struct drm_encoder *encoder; | ||
582 | struct drm_connector *connector; | ||
583 | int ret; | ||
584 | |||
585 | drm_mode_config_init(cdev->dev); | ||
586 | cdev->mode_info.mode_config_initialized = true; | ||
587 | |||
588 | cdev->dev->mode_config.max_width = CIRRUS_MAX_FB_WIDTH; | ||
589 | cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT; | ||
590 | |||
591 | cdev->dev->mode_config.fb_base = cdev->mc.vram_base; | ||
592 | cdev->dev->mode_config.preferred_depth = 24; | ||
593 | /* don't prefer a shadow on virt GPU */ | ||
594 | cdev->dev->mode_config.prefer_shadow = 0; | ||
595 | |||
596 | cirrus_crtc_init(cdev->dev); | ||
597 | |||
598 | encoder = cirrus_encoder_init(cdev->dev); | ||
599 | if (!encoder) { | ||
600 | DRM_ERROR("cirrus_encoder_init failed\n"); | ||
601 | return -1; | ||
602 | } | ||
603 | |||
604 | connector = cirrus_vga_init(cdev->dev); | ||
605 | if (!connector) { | ||
606 | DRM_ERROR("cirrus_vga_init failed\n"); | ||
607 | return -1; | ||
608 | } | ||
609 | |||
610 | drm_mode_connector_attach_encoder(connector, encoder); | ||
611 | |||
612 | ret = cirrus_fbdev_init(cdev); | ||
613 | if (ret) { | ||
614 | DRM_ERROR("cirrus_fbdev_init failed\n"); | ||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | void cirrus_modeset_fini(struct cirrus_device *cdev) | ||
622 | { | ||
623 | cirrus_fbdev_fini(cdev); | ||
624 | |||
625 | if (cdev->mode_info.mode_config_initialized) { | ||
626 | drm_mode_config_cleanup(cdev->dev); | ||
627 | cdev->mode_info.mode_config_initialized = false; | ||
628 | } | ||
629 | } | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c new file mode 100644 index 000000000000..ae2f08ff3808 --- /dev/null +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c | |||
@@ -0,0 +1,453 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the | ||
6 | * "Software"), to deal in the Software without restriction, including | ||
7 | * without limitation the rights to use, copy, modify, merge, publish, | ||
8 | * distribute, sub license, and/or sell copies of the Software, and to | ||
9 | * permit persons to whom the Software is furnished to do so, subject to | ||
10 | * the following conditions: | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
19 | * | ||
20 | * The above copyright notice and this permission notice (including the | ||
21 | * next paragraph) shall be included in all copies or substantial portions | ||
22 | * of the Software. | ||
23 | * | ||
24 | */ | ||
25 | /* | ||
26 | * Authors: Dave Airlie <airlied@redhat.com> | ||
27 | */ | ||
28 | #include "drmP.h" | ||
29 | #include "cirrus_drv.h" | ||
30 | #include <ttm/ttm_page_alloc.h> | ||
31 | |||
32 | static inline struct cirrus_device * | ||
33 | cirrus_bdev(struct ttm_bo_device *bd) | ||
34 | { | ||
35 | return container_of(bd, struct cirrus_device, ttm.bdev); | ||
36 | } | ||
37 | |||
38 | static int | ||
39 | cirrus_ttm_mem_global_init(struct drm_global_reference *ref) | ||
40 | { | ||
41 | return ttm_mem_global_init(ref->object); | ||
42 | } | ||
43 | |||
44 | static void | ||
45 | cirrus_ttm_mem_global_release(struct drm_global_reference *ref) | ||
46 | { | ||
47 | ttm_mem_global_release(ref->object); | ||
48 | } | ||
49 | |||
50 | static int cirrus_ttm_global_init(struct cirrus_device *cirrus) | ||
51 | { | ||
52 | struct drm_global_reference *global_ref; | ||
53 | int r; | ||
54 | |||
55 | global_ref = &cirrus->ttm.mem_global_ref; | ||
56 | global_ref->global_type = DRM_GLOBAL_TTM_MEM; | ||
57 | global_ref->size = sizeof(struct ttm_mem_global); | ||
58 | global_ref->init = &cirrus_ttm_mem_global_init; | ||
59 | global_ref->release = &cirrus_ttm_mem_global_release; | ||
60 | r = drm_global_item_ref(global_ref); | ||
61 | if (r != 0) { | ||
62 | DRM_ERROR("Failed setting up TTM memory accounting " | ||
63 | "subsystem.\n"); | ||
64 | return r; | ||
65 | } | ||
66 | |||
67 | cirrus->ttm.bo_global_ref.mem_glob = | ||
68 | cirrus->ttm.mem_global_ref.object; | ||
69 | global_ref = &cirrus->ttm.bo_global_ref.ref; | ||
70 | global_ref->global_type = DRM_GLOBAL_TTM_BO; | ||
71 | global_ref->size = sizeof(struct ttm_bo_global); | ||
72 | global_ref->init = &ttm_bo_global_init; | ||
73 | global_ref->release = &ttm_bo_global_release; | ||
74 | r = drm_global_item_ref(global_ref); | ||
75 | if (r != 0) { | ||
76 | DRM_ERROR("Failed setting up TTM BO subsystem.\n"); | ||
77 | drm_global_item_unref(&cirrus->ttm.mem_global_ref); | ||
78 | return r; | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | void | ||
84 | cirrus_ttm_global_release(struct cirrus_device *cirrus) | ||
85 | { | ||
86 | if (cirrus->ttm.mem_global_ref.release == NULL) | ||
87 | return; | ||
88 | |||
89 | drm_global_item_unref(&cirrus->ttm.bo_global_ref.ref); | ||
90 | drm_global_item_unref(&cirrus->ttm.mem_global_ref); | ||
91 | cirrus->ttm.mem_global_ref.release = NULL; | ||
92 | } | ||
93 | |||
94 | |||
95 | static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
96 | { | ||
97 | struct cirrus_bo *bo; | ||
98 | |||
99 | bo = container_of(tbo, struct cirrus_bo, bo); | ||
100 | |||
101 | drm_gem_object_release(&bo->gem); | ||
102 | kfree(bo); | ||
103 | } | ||
104 | |||
105 | bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo) | ||
106 | { | ||
107 | if (bo->destroy == &cirrus_bo_ttm_destroy) | ||
108 | return true; | ||
109 | return false; | ||
110 | } | ||
111 | |||
112 | static int | ||
113 | cirrus_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | ||
114 | struct ttm_mem_type_manager *man) | ||
115 | { | ||
116 | switch (type) { | ||
117 | case TTM_PL_SYSTEM: | ||
118 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
119 | man->available_caching = TTM_PL_MASK_CACHING; | ||
120 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
121 | break; | ||
122 | case TTM_PL_VRAM: | ||
123 | man->func = &ttm_bo_manager_func; | ||
124 | man->flags = TTM_MEMTYPE_FLAG_FIXED | | ||
125 | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
126 | man->available_caching = TTM_PL_FLAG_UNCACHED | | ||
127 | TTM_PL_FLAG_WC; | ||
128 | man->default_caching = TTM_PL_FLAG_WC; | ||
129 | break; | ||
130 | default: | ||
131 | DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | cirrus_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
139 | { | ||
140 | struct cirrus_bo *cirrusbo = cirrus_bo(bo); | ||
141 | |||
142 | if (!cirrus_ttm_bo_is_cirrus_bo(bo)) | ||
143 | return; | ||
144 | |||
145 | cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_SYSTEM); | ||
146 | *pl = cirrusbo->placement; | ||
147 | } | ||
148 | |||
149 | static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | ||
150 | { | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | ||
155 | struct ttm_mem_reg *mem) | ||
156 | { | ||
157 | struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | ||
158 | struct cirrus_device *cirrus = cirrus_bdev(bdev); | ||
159 | |||
160 | mem->bus.addr = NULL; | ||
161 | mem->bus.offset = 0; | ||
162 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
163 | mem->bus.base = 0; | ||
164 | mem->bus.is_iomem = false; | ||
165 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
166 | return -EINVAL; | ||
167 | switch (mem->mem_type) { | ||
168 | case TTM_PL_SYSTEM: | ||
169 | /* system memory */ | ||
170 | return 0; | ||
171 | case TTM_PL_VRAM: | ||
172 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
173 | mem->bus.base = pci_resource_start(cirrus->dev->pdev, 0); | ||
174 | mem->bus.is_iomem = true; | ||
175 | break; | ||
176 | default: | ||
177 | return -EINVAL; | ||
178 | break; | ||
179 | } | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static void cirrus_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | ||
184 | { | ||
185 | } | ||
186 | |||
187 | static int cirrus_bo_move(struct ttm_buffer_object *bo, | ||
188 | bool evict, bool interruptible, | ||
189 | bool no_wait_reserve, bool no_wait_gpu, | ||
190 | struct ttm_mem_reg *new_mem) | ||
191 | { | ||
192 | int r; | ||
193 | r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); | ||
194 | return r; | ||
195 | } | ||
196 | |||
197 | |||
198 | static void cirrus_ttm_backend_destroy(struct ttm_tt *tt) | ||
199 | { | ||
200 | ttm_tt_fini(tt); | ||
201 | kfree(tt); | ||
202 | } | ||
203 | |||
204 | static struct ttm_backend_func cirrus_tt_backend_func = { | ||
205 | .destroy = &cirrus_ttm_backend_destroy, | ||
206 | }; | ||
207 | |||
208 | |||
209 | struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev, | ||
210 | unsigned long size, uint32_t page_flags, | ||
211 | struct page *dummy_read_page) | ||
212 | { | ||
213 | struct ttm_tt *tt; | ||
214 | |||
215 | tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); | ||
216 | if (tt == NULL) | ||
217 | return NULL; | ||
218 | tt->func = &cirrus_tt_backend_func; | ||
219 | if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { | ||
220 | kfree(tt); | ||
221 | return NULL; | ||
222 | } | ||
223 | return tt; | ||
224 | } | ||
225 | |||
226 | static int cirrus_ttm_tt_populate(struct ttm_tt *ttm) | ||
227 | { | ||
228 | return ttm_pool_populate(ttm); | ||
229 | } | ||
230 | |||
231 | static void cirrus_ttm_tt_unpopulate(struct ttm_tt *ttm) | ||
232 | { | ||
233 | ttm_pool_unpopulate(ttm); | ||
234 | } | ||
235 | |||
236 | struct ttm_bo_driver cirrus_bo_driver = { | ||
237 | .ttm_tt_create = cirrus_ttm_tt_create, | ||
238 | .ttm_tt_populate = cirrus_ttm_tt_populate, | ||
239 | .ttm_tt_unpopulate = cirrus_ttm_tt_unpopulate, | ||
240 | .init_mem_type = cirrus_bo_init_mem_type, | ||
241 | .evict_flags = cirrus_bo_evict_flags, | ||
242 | .move = cirrus_bo_move, | ||
243 | .verify_access = cirrus_bo_verify_access, | ||
244 | .io_mem_reserve = &cirrus_ttm_io_mem_reserve, | ||
245 | .io_mem_free = &cirrus_ttm_io_mem_free, | ||
246 | }; | ||
247 | |||
248 | int cirrus_mm_init(struct cirrus_device *cirrus) | ||
249 | { | ||
250 | int ret; | ||
251 | struct drm_device *dev = cirrus->dev; | ||
252 | struct ttm_bo_device *bdev = &cirrus->ttm.bdev; | ||
253 | |||
254 | ret = cirrus_ttm_global_init(cirrus); | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | ret = ttm_bo_device_init(&cirrus->ttm.bdev, | ||
259 | cirrus->ttm.bo_global_ref.ref.object, | ||
260 | &cirrus_bo_driver, DRM_FILE_PAGE_OFFSET, | ||
261 | true); | ||
262 | if (ret) { | ||
263 | DRM_ERROR("Error initialising bo driver; %d\n", ret); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, | ||
268 | cirrus->mc.vram_size >> PAGE_SHIFT); | ||
269 | if (ret) { | ||
270 | DRM_ERROR("Failed ttm VRAM init: %d\n", ret); | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | cirrus->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), | ||
275 | pci_resource_len(dev->pdev, 0), | ||
276 | DRM_MTRR_WC); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | void cirrus_mm_fini(struct cirrus_device *cirrus) | ||
282 | { | ||
283 | struct drm_device *dev = cirrus->dev; | ||
284 | ttm_bo_device_release(&cirrus->ttm.bdev); | ||
285 | |||
286 | cirrus_ttm_global_release(cirrus); | ||
287 | |||
288 | if (cirrus->fb_mtrr >= 0) { | ||
289 | drm_mtrr_del(cirrus->fb_mtrr, | ||
290 | pci_resource_start(dev->pdev, 0), | ||
291 | pci_resource_len(dev->pdev, 0), DRM_MTRR_WC); | ||
292 | cirrus->fb_mtrr = -1; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | void cirrus_ttm_placement(struct cirrus_bo *bo, int domain) | ||
297 | { | ||
298 | u32 c = 0; | ||
299 | bo->placement.fpfn = 0; | ||
300 | bo->placement.lpfn = 0; | ||
301 | bo->placement.placement = bo->placements; | ||
302 | bo->placement.busy_placement = bo->placements; | ||
303 | if (domain & TTM_PL_FLAG_VRAM) | ||
304 | bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; | ||
305 | if (domain & TTM_PL_FLAG_SYSTEM) | ||
306 | bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
307 | if (!c) | ||
308 | bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
309 | bo->placement.num_placement = c; | ||
310 | bo->placement.num_busy_placement = c; | ||
311 | } | ||
312 | |||
313 | int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait) | ||
314 | { | ||
315 | int ret; | ||
316 | |||
317 | ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); | ||
318 | if (ret) { | ||
319 | if (ret != -ERESTARTSYS) | ||
320 | DRM_ERROR("reserve failed %p\n", bo); | ||
321 | return ret; | ||
322 | } | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | void cirrus_bo_unreserve(struct cirrus_bo *bo) | ||
327 | { | ||
328 | ttm_bo_unreserve(&bo->bo); | ||
329 | } | ||
330 | |||
331 | int cirrus_bo_create(struct drm_device *dev, int size, int align, | ||
332 | uint32_t flags, struct cirrus_bo **pcirrusbo) | ||
333 | { | ||
334 | struct cirrus_device *cirrus = dev->dev_private; | ||
335 | struct cirrus_bo *cirrusbo; | ||
336 | size_t acc_size; | ||
337 | int ret; | ||
338 | |||
339 | cirrusbo = kzalloc(sizeof(struct cirrus_bo), GFP_KERNEL); | ||
340 | if (!cirrusbo) | ||
341 | return -ENOMEM; | ||
342 | |||
343 | ret = drm_gem_object_init(dev, &cirrusbo->gem, size); | ||
344 | if (ret) { | ||
345 | kfree(cirrusbo); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | cirrusbo->gem.driver_private = NULL; | ||
350 | cirrusbo->bo.bdev = &cirrus->ttm.bdev; | ||
351 | |||
352 | cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
353 | |||
354 | acc_size = ttm_bo_dma_acc_size(&cirrus->ttm.bdev, size, | ||
355 | sizeof(struct cirrus_bo)); | ||
356 | |||
357 | ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size, | ||
358 | ttm_bo_type_device, &cirrusbo->placement, | ||
359 | align >> PAGE_SHIFT, 0, false, NULL, acc_size, | ||
360 | cirrus_bo_ttm_destroy); | ||
361 | if (ret) | ||
362 | return ret; | ||
363 | |||
364 | *pcirrusbo = cirrusbo; | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static inline u64 cirrus_bo_gpu_offset(struct cirrus_bo *bo) | ||
369 | { | ||
370 | return bo->bo.offset; | ||
371 | } | ||
372 | |||
373 | int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr) | ||
374 | { | ||
375 | int i, ret; | ||
376 | |||
377 | if (bo->pin_count) { | ||
378 | bo->pin_count++; | ||
379 | if (gpu_addr) | ||
380 | *gpu_addr = cirrus_bo_gpu_offset(bo); | ||
381 | } | ||
382 | |||
383 | cirrus_ttm_placement(bo, pl_flag); | ||
384 | for (i = 0; i < bo->placement.num_placement; i++) | ||
385 | bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; | ||
386 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
387 | if (ret) | ||
388 | return ret; | ||
389 | |||
390 | bo->pin_count = 1; | ||
391 | if (gpu_addr) | ||
392 | *gpu_addr = cirrus_bo_gpu_offset(bo); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | int cirrus_bo_unpin(struct cirrus_bo *bo) | ||
397 | { | ||
398 | int i, ret; | ||
399 | if (!bo->pin_count) { | ||
400 | DRM_ERROR("unpin bad %p\n", bo); | ||
401 | return 0; | ||
402 | } | ||
403 | bo->pin_count--; | ||
404 | if (bo->pin_count) | ||
405 | return 0; | ||
406 | |||
407 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
408 | bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; | ||
409 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
410 | if (ret) | ||
411 | return ret; | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | int cirrus_bo_push_sysram(struct cirrus_bo *bo) | ||
417 | { | ||
418 | int i, ret; | ||
419 | if (!bo->pin_count) { | ||
420 | DRM_ERROR("unpin bad %p\n", bo); | ||
421 | return 0; | ||
422 | } | ||
423 | bo->pin_count--; | ||
424 | if (bo->pin_count) | ||
425 | return 0; | ||
426 | |||
427 | if (bo->kmap.virtual) | ||
428 | ttm_bo_kunmap(&bo->kmap); | ||
429 | |||
430 | cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); | ||
431 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
432 | bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; | ||
433 | |||
434 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
435 | if (ret) { | ||
436 | DRM_ERROR("pushing to VRAM failed\n"); | ||
437 | return ret; | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | int cirrus_mmap(struct file *filp, struct vm_area_struct *vma) | ||
443 | { | ||
444 | struct drm_file *file_priv; | ||
445 | struct cirrus_device *cirrus; | ||
446 | |||
447 | if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) | ||
448 | return drm_mmap(filp, vma); | ||
449 | |||
450 | file_priv = filp->private_data; | ||
451 | cirrus = file_priv->minor->dev->dev_private; | ||
452 | return ttm_bo_mmap(filp, vma, &cirrus->ttm.bdev); | ||
453 | } | ||