diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/Kconfig | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/Makefile | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_drv.c | 114 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_drv.h | 276 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_fb.c | 294 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_i2c.c | 156 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_main.c | 388 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_mode.c | 1533 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_reg.h | 661 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_ttm.c | 452 |
12 files changed, 3895 insertions, 0 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 9c6244c1fff6..8b23bd9d1659 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -189,3 +189,4 @@ source "drivers/gpu/drm/udl/Kconfig" | |||
189 | 189 | ||
190 | source "drivers/gpu/drm/ast/Kconfig" | 190 | source "drivers/gpu/drm/ast/Kconfig" |
191 | 191 | ||
192 | source "drivers/gpu/drm/mgag200/Kconfig" | ||
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index fb3eac8402fe..52c9b5610ca2 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -34,6 +34,7 @@ obj-$(CONFIG_DRM_RADEON)+= radeon/ | |||
34 | obj-$(CONFIG_DRM_MGA) += mga/ | 34 | 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_SIS) += sis/ | 38 | obj-$(CONFIG_DRM_SIS) += sis/ |
38 | obj-$(CONFIG_DRM_SAVAGE)+= savage/ | 39 | obj-$(CONFIG_DRM_SAVAGE)+= savage/ |
39 | obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ | 40 | obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ |
diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig new file mode 100644 index 000000000000..ffffafa1d6d1 --- /dev/null +++ b/drivers/gpu/drm/mgag200/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | config DRM_MGAG200 | ||
2 | tristate "Kernel modesetting driver for MGA G200 server engines" | ||
3 | depends on DRM && PCI && EXPERIMENTAL | ||
4 | select FB_SYS_FILLRECT | ||
5 | select FB_SYS_COPYAREA | ||
6 | select FB_SYS_IMAGEBLIT | ||
7 | select DRM_KMS_HELPER | ||
8 | help | ||
9 | This is a KMS driver for the MGA G200 server chips, it | ||
10 | does not support the original MGA G200 or any of the desktop | ||
11 | chips. It requires 0.3.0 of the modesetting userspace driver, | ||
12 | and a version of mga driver that will fail on KMS enabled | ||
13 | devices. | ||
14 | |||
diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile new file mode 100644 index 000000000000..7db592eedbf1 --- /dev/null +++ b/drivers/gpu/drm/mgag200/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | ccflags-y := -Iinclude/drm | ||
2 | mgag200-y := mgag200_main.o mgag200_mode.o \ | ||
3 | mgag200_drv.o mgag200_fb.o mgag200_i2c.o mgag200_ttm.o | ||
4 | |||
5 | obj-$(CONFIG_DRM_MGAG200) += mgag200.o | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c new file mode 100644 index 000000000000..f03a636d769e --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c | |||
@@ -0,0 +1,114 @@ | |||
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 <linux/console.h> | ||
13 | #include "drmP.h" | ||
14 | #include "drm.h" | ||
15 | |||
16 | #include "mgag200_drv.h" | ||
17 | |||
18 | #include "drm_pciids.h" | ||
19 | |||
20 | /* | ||
21 | * This is the generic driver code. This binds the driver to the drm core, | ||
22 | * which then performs further device association and calls our graphics init | ||
23 | * functions | ||
24 | */ | ||
25 | int mgag200_modeset = -1; | ||
26 | |||
27 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); | ||
28 | module_param_named(modeset, mgag200_modeset, int, 0400); | ||
29 | |||
30 | static struct drm_driver driver; | ||
31 | |||
32 | static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { | ||
33 | { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A }, | ||
34 | { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B }, | ||
35 | { PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV }, | ||
36 | { PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB }, | ||
37 | { PCI_VENDOR_ID_MATROX, 0x533, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EH }, | ||
38 | { PCI_VENDOR_ID_MATROX, 0x534, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_ER }, | ||
39 | {0,} | ||
40 | }; | ||
41 | |||
42 | MODULE_DEVICE_TABLE(pci, pciidlist); | ||
43 | |||
44 | static int __devinit | ||
45 | mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
46 | { | ||
47 | return drm_get_pci_dev(pdev, ent, &driver); | ||
48 | } | ||
49 | |||
50 | static void mga_pci_remove(struct pci_dev *pdev) | ||
51 | { | ||
52 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
53 | |||
54 | drm_put_dev(dev); | ||
55 | } | ||
56 | |||
57 | static const struct file_operations mgag200_driver_fops = { | ||
58 | .owner = THIS_MODULE, | ||
59 | .open = drm_open, | ||
60 | .release = drm_release, | ||
61 | .unlocked_ioctl = drm_ioctl, | ||
62 | .mmap = mgag200_mmap, | ||
63 | .poll = drm_poll, | ||
64 | .fasync = drm_fasync, | ||
65 | .read = drm_read, | ||
66 | }; | ||
67 | |||
68 | static struct drm_driver driver = { | ||
69 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_USE_MTRR, | ||
70 | .load = mgag200_driver_load, | ||
71 | .unload = mgag200_driver_unload, | ||
72 | .fops = &mgag200_driver_fops, | ||
73 | .name = DRIVER_NAME, | ||
74 | .desc = DRIVER_DESC, | ||
75 | .date = DRIVER_DATE, | ||
76 | .major = DRIVER_MAJOR, | ||
77 | .minor = DRIVER_MINOR, | ||
78 | .patchlevel = DRIVER_PATCHLEVEL, | ||
79 | |||
80 | .gem_init_object = mgag200_gem_init_object, | ||
81 | .gem_free_object = mgag200_gem_free_object, | ||
82 | .dumb_create = mgag200_dumb_create, | ||
83 | .dumb_map_offset = mgag200_dumb_mmap_offset, | ||
84 | .dumb_destroy = mgag200_dumb_destroy, | ||
85 | }; | ||
86 | |||
87 | static struct pci_driver mgag200_pci_driver = { | ||
88 | .name = DRIVER_NAME, | ||
89 | .id_table = pciidlist, | ||
90 | .probe = mga_pci_probe, | ||
91 | .remove = mga_pci_remove, | ||
92 | }; | ||
93 | |||
94 | static int __init mgag200_init(void) | ||
95 | { | ||
96 | if (vgacon_text_force() && mgag200_modeset == -1) | ||
97 | return -EINVAL; | ||
98 | |||
99 | if (mgag200_modeset == 0) | ||
100 | return -EINVAL; | ||
101 | return drm_pci_init(&driver, &mgag200_pci_driver); | ||
102 | } | ||
103 | |||
104 | static void __exit mgag200_exit(void) | ||
105 | { | ||
106 | drm_pci_exit(&driver, &mgag200_pci_driver); | ||
107 | } | ||
108 | |||
109 | module_init(mgag200_init); | ||
110 | module_exit(mgag200_exit); | ||
111 | |||
112 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
113 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
114 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h new file mode 100644 index 000000000000..6f13b3563234 --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Matt Turner. | ||
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 | * Matt Turner | ||
11 | * Dave Airlie | ||
12 | */ | ||
13 | #ifndef __MGAG200_DRV_H__ | ||
14 | #define __MGAG200_DRV_H__ | ||
15 | |||
16 | #include <video/vga.h> | ||
17 | |||
18 | #include "drm/drm_fb_helper.h" | ||
19 | #include "ttm/ttm_bo_api.h" | ||
20 | #include "ttm/ttm_bo_driver.h" | ||
21 | #include "ttm/ttm_placement.h" | ||
22 | #include "ttm/ttm_memory.h" | ||
23 | #include "ttm/ttm_module.h" | ||
24 | |||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/i2c-algo-bit.h> | ||
27 | |||
28 | #include "mgag200_reg.h" | ||
29 | |||
30 | #define DRIVER_AUTHOR "Matthew Garrett" | ||
31 | |||
32 | #define DRIVER_NAME "mgag200" | ||
33 | #define DRIVER_DESC "MGA G200 SE" | ||
34 | #define DRIVER_DATE "20110418" | ||
35 | |||
36 | #define DRIVER_MAJOR 1 | ||
37 | #define DRIVER_MINOR 0 | ||
38 | #define DRIVER_PATCHLEVEL 0 | ||
39 | |||
40 | #define MGAG200FB_CONN_LIMIT 1 | ||
41 | |||
42 | #define RREG8(reg) ioread8(((void __iomem *)mdev->rmmio) + (reg)) | ||
43 | #define WREG8(reg, v) iowrite8(v, ((void __iomem *)mdev->rmmio) + (reg)) | ||
44 | #define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg)) | ||
45 | #define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg)) | ||
46 | |||
47 | #define ATTR_INDEX 0x1fc0 | ||
48 | #define ATTR_DATA 0x1fc1 | ||
49 | |||
50 | #define WREG_ATTR(reg, v) \ | ||
51 | do { \ | ||
52 | RREG8(0x1fda); \ | ||
53 | WREG8(ATTR_INDEX, reg); \ | ||
54 | WREG8(ATTR_DATA, v); \ | ||
55 | } while (0) \ | ||
56 | |||
57 | #define WREG_SEQ(reg, v) \ | ||
58 | do { \ | ||
59 | WREG8(MGAREG_SEQ_INDEX, reg); \ | ||
60 | WREG8(MGAREG_SEQ_DATA, v); \ | ||
61 | } while (0) \ | ||
62 | |||
63 | #define WREG_CRT(reg, v) \ | ||
64 | do { \ | ||
65 | WREG8(MGAREG_CRTC_INDEX, reg); \ | ||
66 | WREG8(MGAREG_CRTC_DATA, v); \ | ||
67 | } while (0) \ | ||
68 | |||
69 | |||
70 | #define WREG_ECRT(reg, v) \ | ||
71 | do { \ | ||
72 | WREG8(MGAREG_CRTCEXT_INDEX, reg); \ | ||
73 | WREG8(MGAREG_CRTCEXT_DATA, v); \ | ||
74 | } while (0) \ | ||
75 | |||
76 | #define GFX_INDEX 0x1fce | ||
77 | #define GFX_DATA 0x1fcf | ||
78 | |||
79 | #define WREG_GFX(reg, v) \ | ||
80 | do { \ | ||
81 | WREG8(GFX_INDEX, reg); \ | ||
82 | WREG8(GFX_DATA, v); \ | ||
83 | } while (0) \ | ||
84 | |||
85 | #define DAC_INDEX 0x3c00 | ||
86 | #define DAC_DATA 0x3c0a | ||
87 | |||
88 | #define WREG_DAC(reg, v) \ | ||
89 | do { \ | ||
90 | WREG8(DAC_INDEX, reg); \ | ||
91 | WREG8(DAC_DATA, v); \ | ||
92 | } while (0) \ | ||
93 | |||
94 | #define MGA_MISC_OUT 0x1fc2 | ||
95 | #define MGA_MISC_IN 0x1fcc | ||
96 | |||
97 | #define MGAG200_MAX_FB_HEIGHT 4096 | ||
98 | #define MGAG200_MAX_FB_WIDTH 4096 | ||
99 | |||
100 | #define MATROX_DPMS_CLEARED (-1) | ||
101 | |||
102 | #define to_mga_crtc(x) container_of(x, struct mga_crtc, base) | ||
103 | #define to_mga_encoder(x) container_of(x, struct mga_encoder, base) | ||
104 | #define to_mga_connector(x) container_of(x, struct mga_connector, base) | ||
105 | #define to_mga_framebuffer(x) container_of(x, struct mga_framebuffer, base) | ||
106 | |||
107 | struct mga_framebuffer { | ||
108 | struct drm_framebuffer base; | ||
109 | struct drm_gem_object *obj; | ||
110 | }; | ||
111 | |||
112 | struct mga_fbdev { | ||
113 | struct drm_fb_helper helper; | ||
114 | struct mga_framebuffer mfb; | ||
115 | struct list_head fbdev_list; | ||
116 | void *sysram; | ||
117 | int size; | ||
118 | struct ttm_bo_kmap_obj mapping; | ||
119 | }; | ||
120 | |||
121 | struct mga_crtc { | ||
122 | struct drm_crtc base; | ||
123 | u8 lut_r[256], lut_g[256], lut_b[256]; | ||
124 | int last_dpms; | ||
125 | bool enabled; | ||
126 | }; | ||
127 | |||
128 | struct mga_mode_info { | ||
129 | bool mode_config_initialized; | ||
130 | struct mga_crtc *crtc; | ||
131 | }; | ||
132 | |||
133 | struct mga_encoder { | ||
134 | struct drm_encoder base; | ||
135 | int last_dpms; | ||
136 | }; | ||
137 | |||
138 | |||
139 | struct mga_i2c_chan { | ||
140 | struct i2c_adapter adapter; | ||
141 | struct drm_device *dev; | ||
142 | struct i2c_algo_bit_data bit; | ||
143 | int data, clock; | ||
144 | }; | ||
145 | |||
146 | struct mga_connector { | ||
147 | struct drm_connector base; | ||
148 | struct mga_i2c_chan *i2c; | ||
149 | }; | ||
150 | |||
151 | |||
152 | struct mga_mc { | ||
153 | resource_size_t vram_size; | ||
154 | resource_size_t vram_base; | ||
155 | resource_size_t vram_window; | ||
156 | }; | ||
157 | |||
158 | enum mga_type { | ||
159 | G200_SE_A, | ||
160 | G200_SE_B, | ||
161 | G200_WB, | ||
162 | G200_EV, | ||
163 | G200_EH, | ||
164 | G200_ER, | ||
165 | }; | ||
166 | |||
167 | #define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B) | ||
168 | |||
169 | struct mga_device { | ||
170 | struct drm_device *dev; | ||
171 | unsigned long flags; | ||
172 | |||
173 | resource_size_t rmmio_base; | ||
174 | resource_size_t rmmio_size; | ||
175 | void __iomem *rmmio; | ||
176 | |||
177 | drm_local_map_t *framebuffer; | ||
178 | |||
179 | struct mga_mc mc; | ||
180 | struct mga_mode_info mode_info; | ||
181 | |||
182 | struct mga_fbdev *mfbdev; | ||
183 | |||
184 | bool suspended; | ||
185 | int num_crtc; | ||
186 | enum mga_type type; | ||
187 | int has_sdram; | ||
188 | struct drm_display_mode mode; | ||
189 | |||
190 | int bpp_shifts[4]; | ||
191 | |||
192 | int fb_mtrr; | ||
193 | |||
194 | struct { | ||
195 | struct drm_global_reference mem_global_ref; | ||
196 | struct ttm_bo_global_ref bo_global_ref; | ||
197 | struct ttm_bo_device bdev; | ||
198 | atomic_t validate_sequence; | ||
199 | } ttm; | ||
200 | |||
201 | u32 reg_1e24; /* SE model number */ | ||
202 | }; | ||
203 | |||
204 | |||
205 | struct mgag200_bo { | ||
206 | struct ttm_buffer_object bo; | ||
207 | struct ttm_placement placement; | ||
208 | struct ttm_bo_kmap_obj kmap; | ||
209 | struct drm_gem_object gem; | ||
210 | u32 placements[3]; | ||
211 | int pin_count; | ||
212 | }; | ||
213 | #define gem_to_mga_bo(gobj) container_of((gobj), struct mgag200_bo, gem) | ||
214 | |||
215 | static inline struct mgag200_bo * | ||
216 | mgag200_bo(struct ttm_buffer_object *bo) | ||
217 | { | ||
218 | return container_of(bo, struct mgag200_bo, bo); | ||
219 | } | ||
220 | /* mga_crtc.c */ | ||
221 | void mga_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
222 | u16 blue, int regno); | ||
223 | void mga_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
224 | u16 *blue, int regno); | ||
225 | |||
226 | /* mgag200_mode.c */ | ||
227 | int mgag200_modeset_init(struct mga_device *mdev); | ||
228 | void mgag200_modeset_fini(struct mga_device *mdev); | ||
229 | |||
230 | /* mga_fbdev.c */ | ||
231 | int mgag200_fbdev_init(struct mga_device *mdev); | ||
232 | void mgag200_fbdev_fini(struct mga_device *mdev); | ||
233 | |||
234 | /* mgag200_main.c */ | ||
235 | int mgag200_framebuffer_init(struct drm_device *dev, | ||
236 | struct mga_framebuffer *mfb, | ||
237 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
238 | struct drm_gem_object *obj); | ||
239 | |||
240 | |||
241 | int mgag200_driver_load(struct drm_device *dev, unsigned long flags); | ||
242 | int mgag200_driver_unload(struct drm_device *dev); | ||
243 | int mgag200_gem_create(struct drm_device *dev, | ||
244 | u32 size, bool iskernel, | ||
245 | struct drm_gem_object **obj); | ||
246 | int mgag200_gem_init_object(struct drm_gem_object *obj); | ||
247 | int mgag200_dumb_create(struct drm_file *file, | ||
248 | struct drm_device *dev, | ||
249 | struct drm_mode_create_dumb *args); | ||
250 | int mgag200_dumb_destroy(struct drm_file *file, | ||
251 | struct drm_device *dev, | ||
252 | uint32_t handle); | ||
253 | void mgag200_gem_free_object(struct drm_gem_object *obj); | ||
254 | int | ||
255 | mgag200_dumb_mmap_offset(struct drm_file *file, | ||
256 | struct drm_device *dev, | ||
257 | uint32_t handle, | ||
258 | uint64_t *offset); | ||
259 | /* mga_i2c.c */ | ||
260 | struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev); | ||
261 | void mgag200_i2c_destroy(struct mga_i2c_chan *i2c); | ||
262 | |||
263 | #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) | ||
264 | void mgag200_ttm_placement(struct mgag200_bo *bo, int domain); | ||
265 | |||
266 | int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait); | ||
267 | void mgag200_bo_unreserve(struct mgag200_bo *bo); | ||
268 | int mgag200_bo_create(struct drm_device *dev, int size, int align, | ||
269 | uint32_t flags, struct mgag200_bo **pastbo); | ||
270 | int mgag200_mm_init(struct mga_device *mdev); | ||
271 | void mgag200_mm_fini(struct mga_device *mdev); | ||
272 | int mgag200_mmap(struct file *filp, struct vm_area_struct *vma); | ||
273 | int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr); | ||
274 | int mgag200_bo_unpin(struct mgag200_bo *bo); | ||
275 | int mgag200_bo_push_sysram(struct mgag200_bo *bo); | ||
276 | #endif /* __MGAG200_DRV_H__ */ | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c new file mode 100644 index 000000000000..880d3369760e --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Matt Turner. | ||
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 | * Matt Turner | ||
11 | * Dave Airlie | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include "drmP.h" | ||
15 | #include "drm.h" | ||
16 | #include "drm_fb_helper.h" | ||
17 | |||
18 | #include <linux/fb.h> | ||
19 | |||
20 | #include "mgag200_drv.h" | ||
21 | |||
22 | static void mga_dirty_update(struct mga_fbdev *mfbdev, | ||
23 | int x, int y, int width, int height) | ||
24 | { | ||
25 | int i; | ||
26 | struct drm_gem_object *obj; | ||
27 | struct mgag200_bo *bo; | ||
28 | int src_offset, dst_offset; | ||
29 | int bpp = (mfbdev->mfb.base.bits_per_pixel + 7)/8; | ||
30 | int ret; | ||
31 | bool unmap = false; | ||
32 | |||
33 | obj = mfbdev->mfb.obj; | ||
34 | bo = gem_to_mga_bo(obj); | ||
35 | |||
36 | ret = mgag200_bo_reserve(bo, true); | ||
37 | if (ret) { | ||
38 | DRM_ERROR("failed to reserve fb bo\n"); | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | if (!bo->kmap.virtual) { | ||
43 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
44 | if (ret) { | ||
45 | DRM_ERROR("failed to kmap fb updates\n"); | ||
46 | mgag200_bo_unreserve(bo); | ||
47 | return; | ||
48 | } | ||
49 | unmap = true; | ||
50 | } | ||
51 | for (i = y; i < y + height; i++) { | ||
52 | /* assume equal stride for now */ | ||
53 | src_offset = dst_offset = i * mfbdev->mfb.base.pitches[0] + (x * bpp); | ||
54 | memcpy_toio(bo->kmap.virtual + src_offset, mfbdev->sysram + src_offset, width * bpp); | ||
55 | |||
56 | } | ||
57 | if (unmap) | ||
58 | ttm_bo_kunmap(&bo->kmap); | ||
59 | |||
60 | mgag200_bo_unreserve(bo); | ||
61 | } | ||
62 | |||
63 | static void mga_fillrect(struct fb_info *info, | ||
64 | const struct fb_fillrect *rect) | ||
65 | { | ||
66 | struct mga_fbdev *mfbdev = info->par; | ||
67 | sys_fillrect(info, rect); | ||
68 | mga_dirty_update(mfbdev, rect->dx, rect->dy, rect->width, | ||
69 | rect->height); | ||
70 | } | ||
71 | |||
72 | static void mga_copyarea(struct fb_info *info, | ||
73 | const struct fb_copyarea *area) | ||
74 | { | ||
75 | struct mga_fbdev *mfbdev = info->par; | ||
76 | sys_copyarea(info, area); | ||
77 | mga_dirty_update(mfbdev, area->dx, area->dy, area->width, | ||
78 | area->height); | ||
79 | } | ||
80 | |||
81 | static void mga_imageblit(struct fb_info *info, | ||
82 | const struct fb_image *image) | ||
83 | { | ||
84 | struct mga_fbdev *mfbdev = info->par; | ||
85 | sys_imageblit(info, image); | ||
86 | mga_dirty_update(mfbdev, image->dx, image->dy, image->width, | ||
87 | image->height); | ||
88 | } | ||
89 | |||
90 | |||
91 | static struct fb_ops mgag200fb_ops = { | ||
92 | .owner = THIS_MODULE, | ||
93 | .fb_check_var = drm_fb_helper_check_var, | ||
94 | .fb_set_par = drm_fb_helper_set_par, | ||
95 | .fb_fillrect = mga_fillrect, | ||
96 | .fb_copyarea = mga_copyarea, | ||
97 | .fb_imageblit = mga_imageblit, | ||
98 | .fb_pan_display = drm_fb_helper_pan_display, | ||
99 | .fb_blank = drm_fb_helper_blank, | ||
100 | .fb_setcmap = drm_fb_helper_setcmap, | ||
101 | }; | ||
102 | |||
103 | static int mgag200fb_create_object(struct mga_fbdev *afbdev, | ||
104 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
105 | struct drm_gem_object **gobj_p) | ||
106 | { | ||
107 | struct drm_device *dev = afbdev->helper.dev; | ||
108 | u32 bpp, depth; | ||
109 | u32 size; | ||
110 | struct drm_gem_object *gobj; | ||
111 | |||
112 | int ret = 0; | ||
113 | drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); | ||
114 | |||
115 | size = mode_cmd->pitches[0] * mode_cmd->height; | ||
116 | ret = mgag200_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 mgag200fb_create(struct mga_fbdev *mfbdev, | ||
125 | struct drm_fb_helper_surface_size *sizes) | ||
126 | { | ||
127 | struct drm_device *dev = mfbdev->helper.dev; | ||
128 | struct drm_mode_fb_cmd2 mode_cmd; | ||
129 | struct mga_device *mdev = dev->dev_private; | ||
130 | struct fb_info *info; | ||
131 | struct drm_framebuffer *fb; | ||
132 | struct drm_gem_object *gobj = NULL; | ||
133 | struct device *device = &dev->pdev->dev; | ||
134 | struct mgag200_bo *bo; | ||
135 | int ret; | ||
136 | void *sysram; | ||
137 | int size; | ||
138 | |||
139 | mode_cmd.width = sizes->surface_width; | ||
140 | mode_cmd.height = sizes->surface_height; | ||
141 | mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); | ||
142 | |||
143 | mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, | ||
144 | sizes->surface_depth); | ||
145 | size = mode_cmd.pitches[0] * mode_cmd.height; | ||
146 | |||
147 | ret = mgag200fb_create_object(mfbdev, &mode_cmd, &gobj); | ||
148 | if (ret) { | ||
149 | DRM_ERROR("failed to create fbcon backing object %d\n", ret); | ||
150 | return ret; | ||
151 | } | ||
152 | bo = gem_to_mga_bo(gobj); | ||
153 | |||
154 | sysram = vmalloc(size); | ||
155 | if (!sysram) | ||
156 | return -ENOMEM; | ||
157 | |||
158 | info = framebuffer_alloc(0, device); | ||
159 | if (info == NULL) | ||
160 | return -ENOMEM; | ||
161 | |||
162 | info->par = mfbdev; | ||
163 | |||
164 | ret = mgag200_framebuffer_init(dev, &mfbdev->mfb, &mode_cmd, gobj); | ||
165 | if (ret) | ||
166 | return ret; | ||
167 | |||
168 | mfbdev->sysram = sysram; | ||
169 | mfbdev->size = size; | ||
170 | |||
171 | fb = &mfbdev->mfb.base; | ||
172 | |||
173 | /* setup helper */ | ||
174 | mfbdev->helper.fb = fb; | ||
175 | mfbdev->helper.fbdev = info; | ||
176 | |||
177 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
178 | if (ret) { | ||
179 | DRM_ERROR("%s: can't allocate color map\n", info->fix.id); | ||
180 | ret = -ENOMEM; | ||
181 | goto out; | ||
182 | } | ||
183 | |||
184 | strcpy(info->fix.id, "mgadrmfb"); | ||
185 | |||
186 | info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; | ||
187 | info->fbops = &mgag200fb_ops; | ||
188 | |||
189 | /* setup aperture base/size for vesafb takeover */ | ||
190 | info->apertures = alloc_apertures(1); | ||
191 | if (!info->apertures) { | ||
192 | ret = -ENOMEM; | ||
193 | goto out; | ||
194 | } | ||
195 | info->apertures->ranges[0].base = mdev->dev->mode_config.fb_base; | ||
196 | info->apertures->ranges[0].size = mdev->mc.vram_size; | ||
197 | |||
198 | drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | ||
199 | drm_fb_helper_fill_var(info, &mfbdev->helper, sizes->fb_width, | ||
200 | sizes->fb_height); | ||
201 | |||
202 | info->screen_base = sysram; | ||
203 | info->screen_size = size; | ||
204 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
205 | |||
206 | DRM_DEBUG_KMS("allocated %dx%d\n", | ||
207 | fb->width, fb->height); | ||
208 | return 0; | ||
209 | out: | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static int mga_fb_find_or_create_single(struct drm_fb_helper *helper, | ||
214 | struct drm_fb_helper_surface_size | ||
215 | *sizes) | ||
216 | { | ||
217 | struct mga_fbdev *mfbdev = (struct mga_fbdev *)helper; | ||
218 | int new_fb = 0; | ||
219 | int ret; | ||
220 | |||
221 | if (!helper->fb) { | ||
222 | ret = mgag200fb_create(mfbdev, sizes); | ||
223 | if (ret) | ||
224 | return ret; | ||
225 | new_fb = 1; | ||
226 | } | ||
227 | return new_fb; | ||
228 | } | ||
229 | |||
230 | static int mga_fbdev_destroy(struct drm_device *dev, | ||
231 | struct mga_fbdev *mfbdev) | ||
232 | { | ||
233 | struct fb_info *info; | ||
234 | struct mga_framebuffer *mfb = &mfbdev->mfb; | ||
235 | |||
236 | if (mfbdev->helper.fbdev) { | ||
237 | info = mfbdev->helper.fbdev; | ||
238 | |||
239 | unregister_framebuffer(info); | ||
240 | if (info->cmap.len) | ||
241 | fb_dealloc_cmap(&info->cmap); | ||
242 | framebuffer_release(info); | ||
243 | } | ||
244 | |||
245 | if (mfb->obj) { | ||
246 | drm_gem_object_unreference_unlocked(mfb->obj); | ||
247 | mfb->obj = NULL; | ||
248 | } | ||
249 | drm_fb_helper_fini(&mfbdev->helper); | ||
250 | vfree(mfbdev->sysram); | ||
251 | drm_framebuffer_cleanup(&mfb->base); | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static struct drm_fb_helper_funcs mga_fb_helper_funcs = { | ||
257 | .gamma_set = mga_crtc_fb_gamma_set, | ||
258 | .gamma_get = mga_crtc_fb_gamma_get, | ||
259 | .fb_probe = mga_fb_find_or_create_single, | ||
260 | }; | ||
261 | |||
262 | int mgag200_fbdev_init(struct mga_device *mdev) | ||
263 | { | ||
264 | struct mga_fbdev *mfbdev; | ||
265 | int ret; | ||
266 | |||
267 | mfbdev = kzalloc(sizeof(struct mga_fbdev), GFP_KERNEL); | ||
268 | if (!mfbdev) | ||
269 | return -ENOMEM; | ||
270 | |||
271 | mdev->mfbdev = mfbdev; | ||
272 | mfbdev->helper.funcs = &mga_fb_helper_funcs; | ||
273 | |||
274 | ret = drm_fb_helper_init(mdev->dev, &mfbdev->helper, | ||
275 | mdev->num_crtc, MGAG200FB_CONN_LIMIT); | ||
276 | if (ret) { | ||
277 | kfree(mfbdev); | ||
278 | return ret; | ||
279 | } | ||
280 | drm_fb_helper_single_add_all_connectors(&mfbdev->helper); | ||
281 | drm_fb_helper_initial_config(&mfbdev->helper, 32); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | void mgag200_fbdev_fini(struct mga_device *mdev) | ||
287 | { | ||
288 | if (!mdev->mfbdev) | ||
289 | return; | ||
290 | |||
291 | mga_fbdev_destroy(mdev->dev, mdev->mfbdev); | ||
292 | kfree(mdev->mfbdev); | ||
293 | mdev->mfbdev = NULL; | ||
294 | } | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c new file mode 100644 index 000000000000..dd3568a1b6b0 --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c | |||
@@ -0,0 +1,156 @@ | |||
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 <linux/export.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/i2c-algo-bit.h> | ||
31 | #include "drmP.h" | ||
32 | #include "drm.h" | ||
33 | |||
34 | #include "mgag200_drv.h" | ||
35 | |||
36 | static int mga_i2c_read_gpio(struct mga_device *mdev) | ||
37 | { | ||
38 | WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); | ||
39 | return RREG8(DAC_DATA); | ||
40 | } | ||
41 | |||
42 | static void mga_i2c_set_gpio(struct mga_device *mdev, int mask, int val) | ||
43 | { | ||
44 | int tmp; | ||
45 | |||
46 | WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); | ||
47 | tmp = (RREG8(DAC_DATA) & mask) | val; | ||
48 | WREG_DAC(MGA1064_GEN_IO_CTL, tmp); | ||
49 | WREG_DAC(MGA1064_GEN_IO_DATA, 0); | ||
50 | } | ||
51 | |||
52 | static inline void mga_i2c_set(struct mga_device *mdev, int mask, int state) | ||
53 | { | ||
54 | if (state) | ||
55 | state = 0; | ||
56 | else | ||
57 | state = mask; | ||
58 | mga_i2c_set_gpio(mdev, ~mask, state); | ||
59 | } | ||
60 | |||
61 | static void mga_gpio_setsda(void *data, int state) | ||
62 | { | ||
63 | struct mga_i2c_chan *i2c = data; | ||
64 | struct mga_device *mdev = i2c->dev->dev_private; | ||
65 | mga_i2c_set(mdev, i2c->data, state); | ||
66 | } | ||
67 | |||
68 | static void mga_gpio_setscl(void *data, int state) | ||
69 | { | ||
70 | struct mga_i2c_chan *i2c = data; | ||
71 | struct mga_device *mdev = i2c->dev->dev_private; | ||
72 | mga_i2c_set(mdev, i2c->clock, state); | ||
73 | } | ||
74 | |||
75 | static int mga_gpio_getsda(void *data) | ||
76 | { | ||
77 | struct mga_i2c_chan *i2c = data; | ||
78 | struct mga_device *mdev = i2c->dev->dev_private; | ||
79 | return (mga_i2c_read_gpio(mdev) & i2c->data) ? 1 : 0; | ||
80 | } | ||
81 | |||
82 | static int mga_gpio_getscl(void *data) | ||
83 | { | ||
84 | struct mga_i2c_chan *i2c = data; | ||
85 | struct mga_device *mdev = i2c->dev->dev_private; | ||
86 | return (mga_i2c_read_gpio(mdev) & i2c->clock) ? 1 : 0; | ||
87 | } | ||
88 | |||
89 | struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev) | ||
90 | { | ||
91 | struct mga_device *mdev = dev->dev_private; | ||
92 | struct mga_i2c_chan *i2c; | ||
93 | int ret; | ||
94 | int data, clock; | ||
95 | |||
96 | WREG_DAC(MGA1064_GEN_IO_DATA, 0xff); | ||
97 | WREG_DAC(MGA1064_GEN_IO_CTL, 0); | ||
98 | |||
99 | switch (mdev->type) { | ||
100 | case G200_SE_A: | ||
101 | case G200_SE_B: | ||
102 | case G200_EV: | ||
103 | case G200_WB: | ||
104 | data = 1; | ||
105 | clock = 2; | ||
106 | break; | ||
107 | case G200_EH: | ||
108 | case G200_ER: | ||
109 | data = 2; | ||
110 | clock = 1; | ||
111 | break; | ||
112 | default: | ||
113 | data = 2; | ||
114 | clock = 8; | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | i2c = kzalloc(sizeof(struct mga_i2c_chan), GFP_KERNEL); | ||
119 | if (!i2c) | ||
120 | return NULL; | ||
121 | |||
122 | i2c->data = data; | ||
123 | i2c->clock = clock; | ||
124 | i2c->adapter.owner = THIS_MODULE; | ||
125 | i2c->adapter.class = I2C_CLASS_DDC; | ||
126 | i2c->adapter.dev.parent = &dev->pdev->dev; | ||
127 | i2c->dev = dev; | ||
128 | i2c_set_adapdata(&i2c->adapter, i2c); | ||
129 | snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), "mga i2c"); | ||
130 | |||
131 | i2c->adapter.algo_data = &i2c->bit; | ||
132 | |||
133 | i2c->bit.udelay = 10; | ||
134 | i2c->bit.timeout = 2; | ||
135 | i2c->bit.data = i2c; | ||
136 | i2c->bit.setsda = mga_gpio_setsda; | ||
137 | i2c->bit.setscl = mga_gpio_setscl; | ||
138 | i2c->bit.getsda = mga_gpio_getsda; | ||
139 | i2c->bit.getscl = mga_gpio_getscl; | ||
140 | |||
141 | ret = i2c_bit_add_bus(&i2c->adapter); | ||
142 | if (ret) { | ||
143 | kfree(i2c); | ||
144 | i2c = NULL; | ||
145 | } | ||
146 | return i2c; | ||
147 | } | ||
148 | |||
149 | void mgag200_i2c_destroy(struct mga_i2c_chan *i2c) | ||
150 | { | ||
151 | if (!i2c) | ||
152 | return; | ||
153 | i2c_del_adapter(&i2c->adapter); | ||
154 | kfree(i2c); | ||
155 | } | ||
156 | |||
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c new file mode 100644 index 000000000000..636a81cd2f37 --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_main.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Matt Turner. | ||
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 | * Matt Turner | ||
11 | * Dave Airlie | ||
12 | */ | ||
13 | #include "drmP.h" | ||
14 | #include "drm.h" | ||
15 | #include "drm_crtc_helper.h" | ||
16 | #include "mgag200_drv.h" | ||
17 | |||
18 | static void mga_user_framebuffer_destroy(struct drm_framebuffer *fb) | ||
19 | { | ||
20 | struct mga_framebuffer *mga_fb = to_mga_framebuffer(fb); | ||
21 | if (mga_fb->obj) | ||
22 | drm_gem_object_unreference_unlocked(mga_fb->obj); | ||
23 | drm_framebuffer_cleanup(fb); | ||
24 | kfree(fb); | ||
25 | } | ||
26 | |||
27 | static int mga_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 mga_fb_funcs = { | ||
35 | .destroy = mga_user_framebuffer_destroy, | ||
36 | .create_handle = mga_user_framebuffer_create_handle, | ||
37 | }; | ||
38 | |||
39 | int mgag200_framebuffer_init(struct drm_device *dev, | ||
40 | struct mga_framebuffer *gfb, | ||
41 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
42 | struct drm_gem_object *obj) | ||
43 | { | ||
44 | int ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs); | ||
45 | if (ret) { | ||
46 | DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); | ||
47 | return ret; | ||
48 | } | ||
49 | drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); | ||
50 | gfb->obj = obj; | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static struct drm_framebuffer * | ||
55 | mgag200_user_framebuffer_create(struct drm_device *dev, | ||
56 | struct drm_file *filp, | ||
57 | struct drm_mode_fb_cmd2 *mode_cmd) | ||
58 | { | ||
59 | struct drm_gem_object *obj; | ||
60 | struct mga_framebuffer *mga_fb; | ||
61 | int ret; | ||
62 | |||
63 | obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]); | ||
64 | if (obj == NULL) | ||
65 | return ERR_PTR(-ENOENT); | ||
66 | |||
67 | mga_fb = kzalloc(sizeof(*mga_fb), GFP_KERNEL); | ||
68 | if (!mga_fb) { | ||
69 | drm_gem_object_unreference_unlocked(obj); | ||
70 | return ERR_PTR(-ENOMEM); | ||
71 | } | ||
72 | |||
73 | ret = mgag200_framebuffer_init(dev, mga_fb, mode_cmd, obj); | ||
74 | if (ret) { | ||
75 | drm_gem_object_unreference_unlocked(obj); | ||
76 | kfree(mga_fb); | ||
77 | return ERR_PTR(ret); | ||
78 | } | ||
79 | return &mga_fb->base; | ||
80 | } | ||
81 | |||
82 | static const struct drm_mode_config_funcs mga_mode_funcs = { | ||
83 | .fb_create = mgag200_user_framebuffer_create, | ||
84 | }; | ||
85 | |||
86 | /* Unmap the framebuffer from the core and release the memory */ | ||
87 | static void mga_vram_fini(struct mga_device *mdev) | ||
88 | { | ||
89 | pci_iounmap(mdev->dev->pdev, mdev->rmmio); | ||
90 | mdev->rmmio = NULL; | ||
91 | if (mdev->mc.vram_base) | ||
92 | release_mem_region(mdev->mc.vram_base, mdev->mc.vram_window); | ||
93 | } | ||
94 | |||
95 | static int mga_probe_vram(struct mga_device *mdev, void __iomem *mem) | ||
96 | { | ||
97 | int offset; | ||
98 | int orig; | ||
99 | int test1, test2; | ||
100 | int orig1, orig2; | ||
101 | |||
102 | /* Probe */ | ||
103 | orig = ioread16(mem); | ||
104 | iowrite16(0, mem); | ||
105 | |||
106 | for (offset = 0x100000; offset < mdev->mc.vram_window; offset += 0x4000) { | ||
107 | orig1 = ioread8(mem + offset); | ||
108 | orig2 = ioread8(mem + offset + 0x100); | ||
109 | |||
110 | iowrite16(0xaa55, mem + offset); | ||
111 | iowrite16(0xaa55, mem + offset + 0x100); | ||
112 | |||
113 | test1 = ioread16(mem + offset); | ||
114 | test2 = ioread16(mem); | ||
115 | |||
116 | iowrite16(orig1, mem + offset); | ||
117 | iowrite16(orig2, mem + offset + 0x100); | ||
118 | |||
119 | if (test1 != 0xaa55) { | ||
120 | break; | ||
121 | } | ||
122 | |||
123 | if (test2) { | ||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | iowrite16(orig, mem); | ||
129 | return offset - 65536; | ||
130 | } | ||
131 | |||
132 | /* Map the framebuffer from the card and configure the core */ | ||
133 | static int mga_vram_init(struct mga_device *mdev) | ||
134 | { | ||
135 | void __iomem *mem; | ||
136 | struct apertures_struct *aper = alloc_apertures(1); | ||
137 | |||
138 | /* BAR 0 is VRAM */ | ||
139 | mdev->mc.vram_base = pci_resource_start(mdev->dev->pdev, 0); | ||
140 | mdev->mc.vram_window = pci_resource_len(mdev->dev->pdev, 0); | ||
141 | |||
142 | aper->ranges[0].base = mdev->mc.vram_base; | ||
143 | aper->ranges[0].size = mdev->mc.vram_window; | ||
144 | aper->count = 1; | ||
145 | |||
146 | remove_conflicting_framebuffers(aper, "mgafb", true); | ||
147 | |||
148 | if (!request_mem_region(mdev->mc.vram_base, mdev->mc.vram_window, | ||
149 | "mgadrmfb_vram")) { | ||
150 | DRM_ERROR("can't reserve VRAM\n"); | ||
151 | return -ENXIO; | ||
152 | } | ||
153 | |||
154 | mem = pci_iomap(mdev->dev->pdev, 0, 0); | ||
155 | |||
156 | mdev->mc.vram_size = mga_probe_vram(mdev, mem); | ||
157 | |||
158 | pci_iounmap(mdev->dev->pdev, mem); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int mgag200_device_init(struct drm_device *dev, | ||
164 | uint32_t flags) | ||
165 | { | ||
166 | struct mga_device *mdev = dev->dev_private; | ||
167 | int ret, option; | ||
168 | |||
169 | mdev->type = flags; | ||
170 | |||
171 | /* Hardcode the number of CRTCs to 1 */ | ||
172 | mdev->num_crtc = 1; | ||
173 | |||
174 | pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option); | ||
175 | mdev->has_sdram = !(option & (1 << 14)); | ||
176 | |||
177 | /* BAR 0 is the framebuffer, BAR 1 contains registers */ | ||
178 | mdev->rmmio_base = pci_resource_start(mdev->dev->pdev, 1); | ||
179 | mdev->rmmio_size = pci_resource_len(mdev->dev->pdev, 1); | ||
180 | |||
181 | if (!request_mem_region(mdev->rmmio_base, mdev->rmmio_size, | ||
182 | "mgadrmfb_mmio")) { | ||
183 | DRM_ERROR("can't reserve mmio registers\n"); | ||
184 | return -ENOMEM; | ||
185 | } | ||
186 | |||
187 | mdev->rmmio = pci_iomap(dev->pdev, 1, 0); | ||
188 | if (mdev->rmmio == NULL) | ||
189 | return -ENOMEM; | ||
190 | |||
191 | /* stash G200 SE model number for later use */ | ||
192 | if (IS_G200_SE(mdev)) | ||
193 | mdev->reg_1e24 = RREG32(0x1e24); | ||
194 | |||
195 | ret = mga_vram_init(mdev); | ||
196 | if (ret) { | ||
197 | release_mem_region(mdev->rmmio_base, mdev->rmmio_size); | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | mdev->bpp_shifts[0] = 0; | ||
202 | mdev->bpp_shifts[1] = 1; | ||
203 | mdev->bpp_shifts[2] = 0; | ||
204 | mdev->bpp_shifts[3] = 2; | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | void mgag200_device_fini(struct mga_device *mdev) | ||
209 | { | ||
210 | release_mem_region(mdev->rmmio_base, mdev->rmmio_size); | ||
211 | mga_vram_fini(mdev); | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * Functions here will be called by the core once it's bound the driver to | ||
216 | * a PCI device | ||
217 | */ | ||
218 | |||
219 | |||
220 | int mgag200_driver_load(struct drm_device *dev, unsigned long flags) | ||
221 | { | ||
222 | struct mga_device *mdev; | ||
223 | int r; | ||
224 | |||
225 | mdev = kzalloc(sizeof(struct mga_device), GFP_KERNEL); | ||
226 | if (mdev == NULL) | ||
227 | return -ENOMEM; | ||
228 | dev->dev_private = (void *)mdev; | ||
229 | mdev->dev = dev; | ||
230 | |||
231 | r = mgag200_device_init(dev, flags); | ||
232 | if (r) { | ||
233 | dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r); | ||
234 | goto out; | ||
235 | } | ||
236 | r = mgag200_mm_init(mdev); | ||
237 | if (r) | ||
238 | goto out; | ||
239 | |||
240 | drm_mode_config_init(dev); | ||
241 | dev->mode_config.funcs = (void *)&mga_mode_funcs; | ||
242 | dev->mode_config.min_width = 0; | ||
243 | dev->mode_config.min_height = 0; | ||
244 | dev->mode_config.preferred_depth = 24; | ||
245 | dev->mode_config.prefer_shadow = 1; | ||
246 | |||
247 | r = mgag200_modeset_init(mdev); | ||
248 | if (r) | ||
249 | dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r); | ||
250 | out: | ||
251 | if (r) | ||
252 | mgag200_driver_unload(dev); | ||
253 | return r; | ||
254 | } | ||
255 | |||
256 | int mgag200_driver_unload(struct drm_device *dev) | ||
257 | { | ||
258 | struct mga_device *mdev = dev->dev_private; | ||
259 | |||
260 | if (mdev == NULL) | ||
261 | return 0; | ||
262 | mgag200_modeset_fini(mdev); | ||
263 | mgag200_fbdev_fini(mdev); | ||
264 | drm_mode_config_cleanup(dev); | ||
265 | mgag200_mm_fini(mdev); | ||
266 | mgag200_device_fini(mdev); | ||
267 | kfree(mdev); | ||
268 | dev->dev_private = NULL; | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | int mgag200_gem_create(struct drm_device *dev, | ||
273 | u32 size, bool iskernel, | ||
274 | struct drm_gem_object **obj) | ||
275 | { | ||
276 | struct mgag200_bo *astbo; | ||
277 | int ret; | ||
278 | |||
279 | *obj = NULL; | ||
280 | |||
281 | size = roundup(size, PAGE_SIZE); | ||
282 | if (size == 0) | ||
283 | return -EINVAL; | ||
284 | |||
285 | ret = mgag200_bo_create(dev, size, 0, 0, &astbo); | ||
286 | if (ret) { | ||
287 | if (ret != -ERESTARTSYS) | ||
288 | DRM_ERROR("failed to allocate GEM object\n"); | ||
289 | return ret; | ||
290 | } | ||
291 | *obj = &astbo->gem; | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | int mgag200_dumb_create(struct drm_file *file, | ||
296 | struct drm_device *dev, | ||
297 | struct drm_mode_create_dumb *args) | ||
298 | { | ||
299 | int ret; | ||
300 | struct drm_gem_object *gobj; | ||
301 | u32 handle; | ||
302 | |||
303 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
304 | args->size = args->pitch * args->height; | ||
305 | |||
306 | ret = mgag200_gem_create(dev, args->size, false, | ||
307 | &gobj); | ||
308 | if (ret) | ||
309 | return ret; | ||
310 | |||
311 | ret = drm_gem_handle_create(file, gobj, &handle); | ||
312 | drm_gem_object_unreference_unlocked(gobj); | ||
313 | if (ret) | ||
314 | return ret; | ||
315 | |||
316 | args->handle = handle; | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | int mgag200_dumb_destroy(struct drm_file *file, | ||
321 | struct drm_device *dev, | ||
322 | uint32_t handle) | ||
323 | { | ||
324 | return drm_gem_handle_delete(file, handle); | ||
325 | } | ||
326 | |||
327 | int mgag200_gem_init_object(struct drm_gem_object *obj) | ||
328 | { | ||
329 | BUG(); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | void mgag200_bo_unref(struct mgag200_bo **bo) | ||
334 | { | ||
335 | struct ttm_buffer_object *tbo; | ||
336 | |||
337 | if ((*bo) == NULL) | ||
338 | return; | ||
339 | |||
340 | tbo = &((*bo)->bo); | ||
341 | ttm_bo_unref(&tbo); | ||
342 | if (tbo == NULL) | ||
343 | *bo = NULL; | ||
344 | |||
345 | } | ||
346 | |||
347 | void mgag200_gem_free_object(struct drm_gem_object *obj) | ||
348 | { | ||
349 | struct mgag200_bo *mgag200_bo = gem_to_mga_bo(obj); | ||
350 | |||
351 | if (!mgag200_bo) | ||
352 | return; | ||
353 | mgag200_bo_unref(&mgag200_bo); | ||
354 | } | ||
355 | |||
356 | |||
357 | static inline u64 mgag200_bo_mmap_offset(struct mgag200_bo *bo) | ||
358 | { | ||
359 | return bo->bo.addr_space_offset; | ||
360 | } | ||
361 | |||
362 | int | ||
363 | mgag200_dumb_mmap_offset(struct drm_file *file, | ||
364 | struct drm_device *dev, | ||
365 | uint32_t handle, | ||
366 | uint64_t *offset) | ||
367 | { | ||
368 | struct drm_gem_object *obj; | ||
369 | int ret; | ||
370 | struct mgag200_bo *bo; | ||
371 | |||
372 | mutex_lock(&dev->struct_mutex); | ||
373 | obj = drm_gem_object_lookup(dev, file, handle); | ||
374 | if (obj == NULL) { | ||
375 | ret = -ENOENT; | ||
376 | goto out_unlock; | ||
377 | } | ||
378 | |||
379 | bo = gem_to_mga_bo(obj); | ||
380 | *offset = mgag200_bo_mmap_offset(bo); | ||
381 | |||
382 | drm_gem_object_unreference(obj); | ||
383 | ret = 0; | ||
384 | out_unlock: | ||
385 | mutex_unlock(&dev->struct_mutex); | ||
386 | return ret; | ||
387 | |||
388 | } | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c new file mode 100644 index 000000000000..d303061b251e --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c | |||
@@ -0,0 +1,1533 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Matt Turner. | ||
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 | * Matt Turner | ||
11 | * Dave Airlie | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | |||
16 | #include "drmP.h" | ||
17 | #include "drm.h" | ||
18 | #include "drm_crtc_helper.h" | ||
19 | |||
20 | #include "mgag200_drv.h" | ||
21 | |||
22 | #define MGAG200_LUT_SIZE 256 | ||
23 | |||
24 | /* | ||
25 | * This file contains setup code for the CRTC. | ||
26 | */ | ||
27 | |||
28 | static void mga_crtc_load_lut(struct drm_crtc *crtc) | ||
29 | { | ||
30 | struct mga_crtc *mga_crtc = to_mga_crtc(crtc); | ||
31 | struct drm_device *dev = crtc->dev; | ||
32 | struct mga_device *mdev = dev->dev_private; | ||
33 | int i; | ||
34 | |||
35 | if (!crtc->enabled) | ||
36 | return; | ||
37 | |||
38 | WREG8(DAC_INDEX + MGA1064_INDEX, 0); | ||
39 | |||
40 | for (i = 0; i < MGAG200_LUT_SIZE; i++) { | ||
41 | /* VGA registers */ | ||
42 | WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]); | ||
43 | WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]); | ||
44 | WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_b[i]); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | static inline void mga_wait_vsync(struct mga_device *mdev) | ||
49 | { | ||
50 | unsigned int count = 0; | ||
51 | unsigned int status = 0; | ||
52 | |||
53 | do { | ||
54 | status = RREG32(MGAREG_Status); | ||
55 | count++; | ||
56 | } while ((status & 0x08) && (count < 250000)); | ||
57 | count = 0; | ||
58 | status = 0; | ||
59 | do { | ||
60 | status = RREG32(MGAREG_Status); | ||
61 | count++; | ||
62 | } while (!(status & 0x08) && (count < 250000)); | ||
63 | } | ||
64 | |||
65 | static inline void mga_wait_busy(struct mga_device *mdev) | ||
66 | { | ||
67 | unsigned int count = 0; | ||
68 | unsigned int status = 0; | ||
69 | do { | ||
70 | status = RREG8(MGAREG_Status + 2); | ||
71 | count++; | ||
72 | } while ((status & 0x01) && (count < 500000)); | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * The core passes the desired mode to the CRTC code to see whether any | ||
77 | * CRTC-specific modifications need to be made to it. We're in a position | ||
78 | * to just pass that straight through, so this does nothing | ||
79 | */ | ||
80 | static bool mga_crtc_mode_fixup(struct drm_crtc *crtc, | ||
81 | struct drm_display_mode *mode, | ||
82 | struct drm_display_mode *adjusted_mode) | ||
83 | { | ||
84 | return true; | ||
85 | } | ||
86 | |||
87 | static int mga_g200se_set_plls(struct mga_device *mdev, long clock) | ||
88 | { | ||
89 | unsigned int vcomax, vcomin, pllreffreq; | ||
90 | unsigned int delta, tmpdelta, permitteddelta; | ||
91 | unsigned int testp, testm, testn; | ||
92 | unsigned int p, m, n; | ||
93 | unsigned int computed; | ||
94 | |||
95 | m = n = p = 0; | ||
96 | vcomax = 320000; | ||
97 | vcomin = 160000; | ||
98 | pllreffreq = 25000; | ||
99 | |||
100 | delta = 0xffffffff; | ||
101 | permitteddelta = clock * 5 / 1000; | ||
102 | |||
103 | for (testp = 8; testp > 0; testp /= 2) { | ||
104 | if (clock * testp > vcomax) | ||
105 | continue; | ||
106 | if (clock * testp < vcomin) | ||
107 | continue; | ||
108 | |||
109 | for (testn = 17; testn < 256; testn++) { | ||
110 | for (testm = 1; testm < 32; testm++) { | ||
111 | computed = (pllreffreq * testn) / | ||
112 | (testm * testp); | ||
113 | if (computed > clock) | ||
114 | tmpdelta = computed - clock; | ||
115 | else | ||
116 | tmpdelta = clock - computed; | ||
117 | if (tmpdelta < delta) { | ||
118 | delta = tmpdelta; | ||
119 | m = testm - 1; | ||
120 | n = testn - 1; | ||
121 | p = testp - 1; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | |||
127 | if (delta > permitteddelta) { | ||
128 | printk(KERN_WARNING "PLL delta too large\n"); | ||
129 | return 1; | ||
130 | } | ||
131 | |||
132 | WREG_DAC(MGA1064_PIX_PLLC_M, m); | ||
133 | WREG_DAC(MGA1064_PIX_PLLC_N, n); | ||
134 | WREG_DAC(MGA1064_PIX_PLLC_P, p); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) | ||
139 | { | ||
140 | unsigned int vcomax, vcomin, pllreffreq; | ||
141 | unsigned int delta, tmpdelta, permitteddelta; | ||
142 | unsigned int testp, testm, testn; | ||
143 | unsigned int p, m, n; | ||
144 | unsigned int computed; | ||
145 | int i, j, tmpcount, vcount; | ||
146 | bool pll_locked = false; | ||
147 | u8 tmp; | ||
148 | |||
149 | m = n = p = 0; | ||
150 | vcomax = 550000; | ||
151 | vcomin = 150000; | ||
152 | pllreffreq = 48000; | ||
153 | |||
154 | delta = 0xffffffff; | ||
155 | permitteddelta = clock * 5 / 1000; | ||
156 | |||
157 | for (testp = 1; testp < 9; testp++) { | ||
158 | if (clock * testp > vcomax) | ||
159 | continue; | ||
160 | if (clock * testp < vcomin) | ||
161 | continue; | ||
162 | |||
163 | for (testm = 1; testm < 17; testm++) { | ||
164 | for (testn = 1; testn < 151; testn++) { | ||
165 | computed = (pllreffreq * testn) / | ||
166 | (testm * testp); | ||
167 | if (computed > clock) | ||
168 | tmpdelta = computed - clock; | ||
169 | else | ||
170 | tmpdelta = clock - computed; | ||
171 | if (tmpdelta < delta) { | ||
172 | delta = tmpdelta; | ||
173 | n = testn - 1; | ||
174 | m = (testm - 1) | ((n >> 1) & 0x80); | ||
175 | p = testp - 1; | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | for (i = 0; i <= 32 && pll_locked == false; i++) { | ||
182 | if (i > 0) { | ||
183 | WREG8(MGAREG_CRTC_INDEX, 0x1e); | ||
184 | tmp = RREG8(MGAREG_CRTC_DATA); | ||
185 | if (tmp < 0xff) | ||
186 | WREG8(MGAREG_CRTC_DATA, tmp+1); | ||
187 | } | ||
188 | |||
189 | /* set pixclkdis to 1 */ | ||
190 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
191 | tmp = RREG8(DAC_DATA); | ||
192 | tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; | ||
193 | WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp); | ||
194 | |||
195 | WREG8(DAC_INDEX, MGA1064_REMHEADCTL); | ||
196 | tmp = RREG8(DAC_DATA); | ||
197 | tmp |= MGA1064_REMHEADCTL_CLKDIS; | ||
198 | WREG_DAC(MGA1064_REMHEADCTL, tmp); | ||
199 | |||
200 | /* select PLL Set C */ | ||
201 | tmp = RREG8(MGAREG_MEM_MISC_READ); | ||
202 | tmp |= 0x3 << 2; | ||
203 | WREG8(MGAREG_MEM_MISC_WRITE, tmp); | ||
204 | |||
205 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
206 | tmp = RREG8(DAC_DATA); | ||
207 | tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80; | ||
208 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
209 | |||
210 | udelay(500); | ||
211 | |||
212 | /* reset the PLL */ | ||
213 | WREG8(DAC_INDEX, MGA1064_VREF_CTL); | ||
214 | tmp = RREG8(DAC_DATA); | ||
215 | tmp &= ~0x04; | ||
216 | WREG_DAC(MGA1064_VREF_CTL, tmp); | ||
217 | |||
218 | udelay(50); | ||
219 | |||
220 | /* program pixel pll register */ | ||
221 | WREG_DAC(MGA1064_WB_PIX_PLLC_N, n); | ||
222 | WREG_DAC(MGA1064_WB_PIX_PLLC_M, m); | ||
223 | WREG_DAC(MGA1064_WB_PIX_PLLC_P, p); | ||
224 | |||
225 | udelay(50); | ||
226 | |||
227 | /* turn pll on */ | ||
228 | WREG8(DAC_INDEX, MGA1064_VREF_CTL); | ||
229 | tmp = RREG8(DAC_DATA); | ||
230 | tmp |= 0x04; | ||
231 | WREG_DAC(MGA1064_VREF_CTL, tmp); | ||
232 | |||
233 | udelay(500); | ||
234 | |||
235 | /* select the pixel pll */ | ||
236 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
237 | tmp = RREG8(DAC_DATA); | ||
238 | tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; | ||
239 | tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; | ||
240 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
241 | |||
242 | WREG8(DAC_INDEX, MGA1064_REMHEADCTL); | ||
243 | tmp = RREG8(DAC_DATA); | ||
244 | tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK; | ||
245 | tmp |= MGA1064_REMHEADCTL_CLKSL_PLL; | ||
246 | WREG_DAC(MGA1064_REMHEADCTL, tmp); | ||
247 | |||
248 | /* reset dotclock rate bit */ | ||
249 | WREG8(MGAREG_SEQ_INDEX, 1); | ||
250 | tmp = RREG8(MGAREG_SEQ_DATA); | ||
251 | tmp &= ~0x8; | ||
252 | WREG8(MGAREG_SEQ_DATA, tmp); | ||
253 | |||
254 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
255 | tmp = RREG8(DAC_DATA); | ||
256 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; | ||
257 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
258 | |||
259 | vcount = RREG8(MGAREG_VCOUNT); | ||
260 | |||
261 | for (j = 0; j < 30 && pll_locked == false; j++) { | ||
262 | tmpcount = RREG8(MGAREG_VCOUNT); | ||
263 | if (tmpcount < vcount) | ||
264 | vcount = 0; | ||
265 | if ((tmpcount - vcount) > 2) | ||
266 | pll_locked = true; | ||
267 | else | ||
268 | udelay(5); | ||
269 | } | ||
270 | } | ||
271 | WREG8(DAC_INDEX, MGA1064_REMHEADCTL); | ||
272 | tmp = RREG8(DAC_DATA); | ||
273 | tmp &= ~MGA1064_REMHEADCTL_CLKDIS; | ||
274 | WREG_DAC(MGA1064_REMHEADCTL, tmp); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) | ||
279 | { | ||
280 | unsigned int vcomax, vcomin, pllreffreq; | ||
281 | unsigned int delta, tmpdelta, permitteddelta; | ||
282 | unsigned int testp, testm, testn; | ||
283 | unsigned int p, m, n; | ||
284 | unsigned int computed; | ||
285 | u8 tmp; | ||
286 | |||
287 | m = n = p = 0; | ||
288 | vcomax = 550000; | ||
289 | vcomin = 150000; | ||
290 | pllreffreq = 50000; | ||
291 | |||
292 | delta = 0xffffffff; | ||
293 | permitteddelta = clock * 5 / 1000; | ||
294 | |||
295 | for (testp = 16; testp > 0; testp--) { | ||
296 | if (clock * testp > vcomax) | ||
297 | continue; | ||
298 | if (clock * testp < vcomin) | ||
299 | continue; | ||
300 | |||
301 | for (testn = 1; testn < 257; testn++) { | ||
302 | for (testm = 1; testm < 17; testm++) { | ||
303 | computed = (pllreffreq * testn) / | ||
304 | (testm * testp); | ||
305 | if (computed > clock) | ||
306 | tmpdelta = computed - clock; | ||
307 | else | ||
308 | tmpdelta = clock - computed; | ||
309 | if (tmpdelta < delta) { | ||
310 | delta = tmpdelta; | ||
311 | n = testn - 1; | ||
312 | m = testm - 1; | ||
313 | p = testp - 1; | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | } | ||
318 | |||
319 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
320 | tmp = RREG8(DAC_DATA); | ||
321 | tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; | ||
322 | WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp); | ||
323 | |||
324 | tmp = RREG8(MGAREG_MEM_MISC_READ); | ||
325 | tmp |= 0x3 << 2; | ||
326 | WREG8(MGAREG_MEM_MISC_WRITE, tmp); | ||
327 | |||
328 | WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); | ||
329 | tmp = RREG8(DAC_DATA); | ||
330 | WREG_DAC(MGA1064_PIX_PLL_STAT, tmp & ~0x40); | ||
331 | |||
332 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
333 | tmp = RREG8(DAC_DATA); | ||
334 | tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; | ||
335 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
336 | |||
337 | WREG_DAC(MGA1064_EV_PIX_PLLC_M, m); | ||
338 | WREG_DAC(MGA1064_EV_PIX_PLLC_N, n); | ||
339 | WREG_DAC(MGA1064_EV_PIX_PLLC_P, p); | ||
340 | |||
341 | udelay(50); | ||
342 | |||
343 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
344 | tmp = RREG8(DAC_DATA); | ||
345 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; | ||
346 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
347 | |||
348 | udelay(500); | ||
349 | |||
350 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
351 | tmp = RREG8(DAC_DATA); | ||
352 | tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; | ||
353 | tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; | ||
354 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
355 | |||
356 | WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); | ||
357 | tmp = RREG8(DAC_DATA); | ||
358 | WREG_DAC(MGA1064_PIX_PLL_STAT, tmp | 0x40); | ||
359 | |||
360 | tmp = RREG8(MGAREG_MEM_MISC_READ); | ||
361 | tmp |= (0x3 << 2); | ||
362 | WREG8(MGAREG_MEM_MISC_WRITE, tmp); | ||
363 | |||
364 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
365 | tmp = RREG8(DAC_DATA); | ||
366 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; | ||
367 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) | ||
373 | { | ||
374 | unsigned int vcomax, vcomin, pllreffreq; | ||
375 | unsigned int delta, tmpdelta, permitteddelta; | ||
376 | unsigned int testp, testm, testn; | ||
377 | unsigned int p, m, n; | ||
378 | unsigned int computed; | ||
379 | int i, j, tmpcount, vcount; | ||
380 | u8 tmp; | ||
381 | bool pll_locked = false; | ||
382 | |||
383 | m = n = p = 0; | ||
384 | vcomax = 800000; | ||
385 | vcomin = 400000; | ||
386 | pllreffreq = 3333; | ||
387 | |||
388 | delta = 0xffffffff; | ||
389 | permitteddelta = clock * 5 / 1000; | ||
390 | |||
391 | for (testp = 16; testp > 0; testp--) { | ||
392 | if (clock * testp > vcomax) | ||
393 | continue; | ||
394 | if (clock * testp < vcomin) | ||
395 | continue; | ||
396 | |||
397 | for (testm = 1; testm < 33; testm++) { | ||
398 | for (testn = 1; testn < 257; testn++) { | ||
399 | computed = (pllreffreq * testn) / | ||
400 | (testm * testp); | ||
401 | if (computed > clock) | ||
402 | tmpdelta = computed - clock; | ||
403 | else | ||
404 | tmpdelta = clock - computed; | ||
405 | if (tmpdelta < delta) { | ||
406 | delta = tmpdelta; | ||
407 | n = testn - 1; | ||
408 | m = (testm - 1) | ((n >> 1) & 0x80); | ||
409 | p = testp - 1; | ||
410 | } | ||
411 | if ((clock * testp) >= 600000) | ||
412 | p |= 80; | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | for (i = 0; i <= 32 && pll_locked == false; i++) { | ||
417 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
418 | tmp = RREG8(DAC_DATA); | ||
419 | tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; | ||
420 | WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp); | ||
421 | |||
422 | tmp = RREG8(MGAREG_MEM_MISC_READ); | ||
423 | tmp |= 0x3 << 2; | ||
424 | WREG8(MGAREG_MEM_MISC_WRITE, tmp); | ||
425 | |||
426 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
427 | tmp = RREG8(DAC_DATA); | ||
428 | tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; | ||
429 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
430 | |||
431 | udelay(500); | ||
432 | |||
433 | WREG_DAC(MGA1064_EH_PIX_PLLC_M, m); | ||
434 | WREG_DAC(MGA1064_EH_PIX_PLLC_N, n); | ||
435 | WREG_DAC(MGA1064_EH_PIX_PLLC_P, p); | ||
436 | |||
437 | udelay(500); | ||
438 | |||
439 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
440 | tmp = RREG8(DAC_DATA); | ||
441 | tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; | ||
442 | tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; | ||
443 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
444 | |||
445 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
446 | tmp = RREG8(DAC_DATA); | ||
447 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; | ||
448 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; | ||
449 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
450 | |||
451 | vcount = RREG8(MGAREG_VCOUNT); | ||
452 | |||
453 | for (j = 0; j < 30 && pll_locked == false; j++) { | ||
454 | tmpcount = RREG8(MGAREG_VCOUNT); | ||
455 | if (tmpcount < vcount) | ||
456 | vcount = 0; | ||
457 | if ((tmpcount - vcount) > 2) | ||
458 | pll_locked = true; | ||
459 | else | ||
460 | udelay(5); | ||
461 | } | ||
462 | } | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int mga_g200er_set_plls(struct mga_device *mdev, long clock) | ||
468 | { | ||
469 | unsigned int vcomax, vcomin, pllreffreq; | ||
470 | unsigned int delta, tmpdelta; | ||
471 | unsigned int testr, testn, testm, testo; | ||
472 | unsigned int p, m, n; | ||
473 | unsigned int computed; | ||
474 | int tmp; | ||
475 | |||
476 | m = n = p = 0; | ||
477 | vcomax = 1488000; | ||
478 | vcomin = 1056000; | ||
479 | pllreffreq = 48000; | ||
480 | |||
481 | delta = 0xffffffff; | ||
482 | |||
483 | for (testr = 0; testr < 4; testr++) { | ||
484 | if (delta == 0) | ||
485 | break; | ||
486 | for (testn = 5; testn < 129; testn++) { | ||
487 | if (delta == 0) | ||
488 | break; | ||
489 | for (testm = 3; testm >= 0; testm--) { | ||
490 | if (delta == 0) | ||
491 | break; | ||
492 | for (testo = 5; testo < 33; testo++) { | ||
493 | computed = pllreffreq * (testn + 1) / | ||
494 | (testr + 1); | ||
495 | if (computed < vcomin) | ||
496 | continue; | ||
497 | if (computed > vcomax) | ||
498 | continue; | ||
499 | if (computed > clock) | ||
500 | tmpdelta = computed - clock; | ||
501 | else | ||
502 | tmpdelta = clock - computed; | ||
503 | if (tmpdelta < delta) { | ||
504 | delta = tmpdelta; | ||
505 | m = testm | (testo << 3); | ||
506 | n = testn; | ||
507 | p = testr | (testr << 3); | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | |||
514 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
515 | tmp = RREG8(DAC_DATA); | ||
516 | tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; | ||
517 | WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp); | ||
518 | |||
519 | WREG8(DAC_INDEX, MGA1064_REMHEADCTL); | ||
520 | tmp = RREG8(DAC_DATA); | ||
521 | tmp |= MGA1064_REMHEADCTL_CLKDIS; | ||
522 | WREG_DAC(MGA1064_REMHEADCTL, tmp); | ||
523 | |||
524 | tmp = RREG8(MGAREG_MEM_MISC_READ); | ||
525 | tmp |= (0x3<<2) | 0xc0; | ||
526 | WREG8(MGAREG_MEM_MISC_WRITE, tmp); | ||
527 | |||
528 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); | ||
529 | tmp = RREG8(DAC_DATA); | ||
530 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; | ||
531 | tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; | ||
532 | WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); | ||
533 | |||
534 | udelay(500); | ||
535 | |||
536 | WREG_DAC(MGA1064_ER_PIX_PLLC_N, n); | ||
537 | WREG_DAC(MGA1064_ER_PIX_PLLC_M, m); | ||
538 | WREG_DAC(MGA1064_ER_PIX_PLLC_P, p); | ||
539 | |||
540 | udelay(50); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int mga_crtc_set_plls(struct mga_device *mdev, long clock) | ||
546 | { | ||
547 | switch(mdev->type) { | ||
548 | case G200_SE_A: | ||
549 | case G200_SE_B: | ||
550 | return mga_g200se_set_plls(mdev, clock); | ||
551 | break; | ||
552 | case G200_WB: | ||
553 | return mga_g200wb_set_plls(mdev, clock); | ||
554 | break; | ||
555 | case G200_EV: | ||
556 | return mga_g200ev_set_plls(mdev, clock); | ||
557 | break; | ||
558 | case G200_EH: | ||
559 | return mga_g200eh_set_plls(mdev, clock); | ||
560 | break; | ||
561 | case G200_ER: | ||
562 | return mga_g200er_set_plls(mdev, clock); | ||
563 | break; | ||
564 | } | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static void mga_g200wb_prepare(struct drm_crtc *crtc) | ||
569 | { | ||
570 | struct mga_device *mdev = crtc->dev->dev_private; | ||
571 | u8 tmp; | ||
572 | int iter_max; | ||
573 | |||
574 | /* 1- The first step is to warn the BMC of an upcoming mode change. | ||
575 | * We are putting the misc<0> to output.*/ | ||
576 | |||
577 | WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); | ||
578 | tmp = RREG8(DAC_DATA); | ||
579 | tmp |= 0x10; | ||
580 | WREG_DAC(MGA1064_GEN_IO_CTL, tmp); | ||
581 | |||
582 | /* we are putting a 1 on the misc<0> line */ | ||
583 | WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); | ||
584 | tmp = RREG8(DAC_DATA); | ||
585 | tmp |= 0x10; | ||
586 | WREG_DAC(MGA1064_GEN_IO_DATA, tmp); | ||
587 | |||
588 | /* 2- Second step to mask and further scan request | ||
589 | * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>) | ||
590 | */ | ||
591 | WREG8(DAC_INDEX, MGA1064_SPAREREG); | ||
592 | tmp = RREG8(DAC_DATA); | ||
593 | tmp |= 0x80; | ||
594 | WREG_DAC(MGA1064_SPAREREG, tmp); | ||
595 | |||
596 | /* 3a- the third step is to verifu if there is an active scan | ||
597 | * We are searching for a 0 on remhsyncsts <XSPAREREG<0>) | ||
598 | */ | ||
599 | iter_max = 300; | ||
600 | while (!(tmp & 0x1) && iter_max) { | ||
601 | WREG8(DAC_INDEX, MGA1064_SPAREREG); | ||
602 | tmp = RREG8(DAC_DATA); | ||
603 | udelay(1000); | ||
604 | iter_max--; | ||
605 | } | ||
606 | |||
607 | /* 3b- this step occurs only if the remove is actually scanning | ||
608 | * we are waiting for the end of the frame which is a 1 on | ||
609 | * remvsyncsts (XSPAREREG<1>) | ||
610 | */ | ||
611 | if (iter_max) { | ||
612 | iter_max = 300; | ||
613 | while ((tmp & 0x2) && iter_max) { | ||
614 | WREG8(DAC_INDEX, MGA1064_SPAREREG); | ||
615 | tmp = RREG8(DAC_DATA); | ||
616 | udelay(1000); | ||
617 | iter_max--; | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | |||
622 | static void mga_g200wb_commit(struct drm_crtc *crtc) | ||
623 | { | ||
624 | u8 tmp; | ||
625 | struct mga_device *mdev = crtc->dev->dev_private; | ||
626 | |||
627 | /* 1- The first step is to ensure that the vrsten and hrsten are set */ | ||
628 | WREG8(MGAREG_CRTCEXT_INDEX, 1); | ||
629 | tmp = RREG8(MGAREG_CRTCEXT_DATA); | ||
630 | WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88); | ||
631 | |||
632 | /* 2- second step is to assert the rstlvl2 */ | ||
633 | WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); | ||
634 | tmp = RREG8(DAC_DATA); | ||
635 | tmp |= 0x8; | ||
636 | WREG8(DAC_DATA, tmp); | ||
637 | |||
638 | /* wait 10 us */ | ||
639 | udelay(10); | ||
640 | |||
641 | /* 3- deassert rstlvl2 */ | ||
642 | tmp &= ~0x08; | ||
643 | WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); | ||
644 | WREG8(DAC_DATA, tmp); | ||
645 | |||
646 | /* 4- remove mask of scan request */ | ||
647 | WREG8(DAC_INDEX, MGA1064_SPAREREG); | ||
648 | tmp = RREG8(DAC_DATA); | ||
649 | tmp &= ~0x80; | ||
650 | WREG8(DAC_DATA, tmp); | ||
651 | |||
652 | /* 5- put back a 0 on the misc<0> line */ | ||
653 | WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); | ||
654 | tmp = RREG8(DAC_DATA); | ||
655 | tmp &= ~0x10; | ||
656 | WREG_DAC(MGA1064_GEN_IO_DATA, tmp); | ||
657 | } | ||
658 | |||
659 | |||
660 | void mga_set_start_address(struct drm_crtc *crtc, unsigned offset) | ||
661 | { | ||
662 | struct mga_device *mdev = crtc->dev->dev_private; | ||
663 | u32 addr; | ||
664 | int count; | ||
665 | |||
666 | while (RREG8(0x1fda) & 0x08); | ||
667 | while (!(RREG8(0x1fda) & 0x08)); | ||
668 | |||
669 | count = RREG8(MGAREG_VCOUNT) + 2; | ||
670 | while (RREG8(MGAREG_VCOUNT) < count); | ||
671 | |||
672 | addr = offset >> 2; | ||
673 | WREG_CRT(0x0d, (u8)(addr & 0xff)); | ||
674 | WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff); | ||
675 | WREG_CRT(0xaf, (u8)(addr >> 16) & 0xf); | ||
676 | } | ||
677 | |||
678 | |||
679 | /* ast is different - we will force move buffers out of VRAM */ | ||
680 | static int mga_crtc_do_set_base(struct drm_crtc *crtc, | ||
681 | struct drm_framebuffer *fb, | ||
682 | int x, int y, int atomic) | ||
683 | { | ||
684 | struct mga_device *mdev = crtc->dev->dev_private; | ||
685 | struct drm_gem_object *obj; | ||
686 | struct mga_framebuffer *mga_fb; | ||
687 | struct mgag200_bo *bo; | ||
688 | int ret; | ||
689 | u64 gpu_addr; | ||
690 | |||
691 | /* push the previous fb to system ram */ | ||
692 | if (!atomic && fb) { | ||
693 | mga_fb = to_mga_framebuffer(fb); | ||
694 | obj = mga_fb->obj; | ||
695 | bo = gem_to_mga_bo(obj); | ||
696 | ret = mgag200_bo_reserve(bo, false); | ||
697 | if (ret) | ||
698 | return ret; | ||
699 | mgag200_bo_push_sysram(bo); | ||
700 | mgag200_bo_unreserve(bo); | ||
701 | } | ||
702 | |||
703 | mga_fb = to_mga_framebuffer(crtc->fb); | ||
704 | obj = mga_fb->obj; | ||
705 | bo = gem_to_mga_bo(obj); | ||
706 | |||
707 | ret = mgag200_bo_reserve(bo, false); | ||
708 | if (ret) | ||
709 | return ret; | ||
710 | |||
711 | ret = mgag200_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | ||
712 | if (ret) { | ||
713 | mgag200_bo_unreserve(bo); | ||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | if (&mdev->mfbdev->mfb == mga_fb) { | ||
718 | /* if pushing console in kmap it */ | ||
719 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
720 | if (ret) | ||
721 | DRM_ERROR("failed to kmap fbcon\n"); | ||
722 | |||
723 | } | ||
724 | mgag200_bo_unreserve(bo); | ||
725 | |||
726 | DRM_INFO("mga base %llx\n", gpu_addr); | ||
727 | |||
728 | mga_set_start_address(crtc, (u32)gpu_addr); | ||
729 | |||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | static int mga_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | ||
734 | struct drm_framebuffer *old_fb) | ||
735 | { | ||
736 | return mga_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
737 | } | ||
738 | |||
739 | static int mga_crtc_mode_set(struct drm_crtc *crtc, | ||
740 | struct drm_display_mode *mode, | ||
741 | struct drm_display_mode *adjusted_mode, | ||
742 | int x, int y, struct drm_framebuffer *old_fb) | ||
743 | { | ||
744 | struct drm_device *dev = crtc->dev; | ||
745 | struct mga_device *mdev = dev->dev_private; | ||
746 | int hdisplay, hsyncstart, hsyncend, htotal; | ||
747 | int vdisplay, vsyncstart, vsyncend, vtotal; | ||
748 | int pitch; | ||
749 | int option = 0, option2 = 0; | ||
750 | int i; | ||
751 | unsigned char misc = 0; | ||
752 | unsigned char ext_vga[6]; | ||
753 | unsigned char ext_vga_index24; | ||
754 | unsigned char dac_index90 = 0; | ||
755 | u8 bppshift; | ||
756 | |||
757 | static unsigned char dacvalue[] = { | ||
758 | /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, | ||
759 | /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, | ||
760 | /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0, | ||
761 | /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20, | ||
762 | /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
763 | /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40, | ||
764 | /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83, | ||
765 | /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A, | ||
766 | /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, | ||
767 | /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 | ||
768 | }; | ||
769 | |||
770 | bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1]; | ||
771 | |||
772 | switch (mdev->type) { | ||
773 | case G200_SE_A: | ||
774 | case G200_SE_B: | ||
775 | dacvalue[MGA1064_VREF_CTL] = 0x03; | ||
776 | dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; | ||
777 | dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN | | ||
778 | MGA1064_MISC_CTL_VGA8 | | ||
779 | MGA1064_MISC_CTL_DAC_RAM_CS; | ||
780 | if (mdev->has_sdram) | ||
781 | option = 0x40049120; | ||
782 | else | ||
783 | option = 0x4004d120; | ||
784 | option2 = 0x00008000; | ||
785 | break; | ||
786 | case G200_WB: | ||
787 | dacvalue[MGA1064_VREF_CTL] = 0x07; | ||
788 | option = 0x41049120; | ||
789 | option2 = 0x0000b000; | ||
790 | break; | ||
791 | case G200_EV: | ||
792 | dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; | ||
793 | dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | | ||
794 | MGA1064_MISC_CTL_DAC_RAM_CS; | ||
795 | option = 0x00000120; | ||
796 | option2 = 0x0000b000; | ||
797 | break; | ||
798 | case G200_EH: | ||
799 | dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | | ||
800 | MGA1064_MISC_CTL_DAC_RAM_CS; | ||
801 | option = 0x00000120; | ||
802 | option2 = 0x0000b000; | ||
803 | break; | ||
804 | case G200_ER: | ||
805 | dac_index90 = 0; | ||
806 | break; | ||
807 | } | ||
808 | |||
809 | switch (crtc->fb->bits_per_pixel) { | ||
810 | case 8: | ||
811 | dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits; | ||
812 | break; | ||
813 | case 16: | ||
814 | if (crtc->fb->depth == 15) | ||
815 | dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits; | ||
816 | else | ||
817 | dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits; | ||
818 | break; | ||
819 | case 24: | ||
820 | dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_24bits; | ||
821 | break; | ||
822 | case 32: | ||
823 | dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_32_24bits; | ||
824 | break; | ||
825 | } | ||
826 | |||
827 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
828 | misc |= 0x40; | ||
829 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
830 | misc |= 0x80; | ||
831 | |||
832 | |||
833 | for (i = 0; i < sizeof(dacvalue); i++) { | ||
834 | if ((i <= 0x03) || | ||
835 | (i == 0x07) || | ||
836 | (i == 0x0b) || | ||
837 | (i == 0x0f) || | ||
838 | ((i >= 0x13) && (i <= 0x17)) || | ||
839 | (i == 0x1b) || | ||
840 | (i == 0x1c) || | ||
841 | ((i >= 0x1f) && (i <= 0x29)) || | ||
842 | ((i >= 0x30) && (i <= 0x37))) | ||
843 | continue; | ||
844 | if (IS_G200_SE(mdev) && | ||
845 | ((i == 0x2c) || (i == 0x2d) || (i == 0x2e))) | ||
846 | continue; | ||
847 | if ((mdev->type == G200_EV || mdev->type == G200_WB || mdev->type == G200_EH) && | ||
848 | (i >= 0x44) && (i <= 0x4e)) | ||
849 | continue; | ||
850 | |||
851 | WREG_DAC(i, dacvalue[i]); | ||
852 | } | ||
853 | |||
854 | if (mdev->type == G200_ER) { | ||
855 | WREG_DAC(0x90, dac_index90); | ||
856 | } | ||
857 | |||
858 | |||
859 | if (option) | ||
860 | pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); | ||
861 | if (option2) | ||
862 | pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2); | ||
863 | |||
864 | WREG_SEQ(2, 0xf); | ||
865 | WREG_SEQ(3, 0); | ||
866 | WREG_SEQ(4, 0xe); | ||
867 | |||
868 | pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8); | ||
869 | if (crtc->fb->bits_per_pixel == 24) | ||
870 | pitch = pitch >> (4 - bppshift); | ||
871 | else | ||
872 | pitch = pitch >> (4 - bppshift); | ||
873 | |||
874 | hdisplay = mode->hdisplay / 8 - 1; | ||
875 | hsyncstart = mode->hsync_start / 8 - 1; | ||
876 | hsyncend = mode->hsync_end / 8 - 1; | ||
877 | htotal = mode->htotal / 8 - 1; | ||
878 | |||
879 | /* Work around hardware quirk */ | ||
880 | if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04) | ||
881 | htotal++; | ||
882 | |||
883 | vdisplay = mode->vdisplay - 1; | ||
884 | vsyncstart = mode->vsync_start - 1; | ||
885 | vsyncend = mode->vsync_end - 1; | ||
886 | vtotal = mode->vtotal - 2; | ||
887 | |||
888 | WREG_GFX(0, 0); | ||
889 | WREG_GFX(1, 0); | ||
890 | WREG_GFX(2, 0); | ||
891 | WREG_GFX(3, 0); | ||
892 | WREG_GFX(4, 0); | ||
893 | WREG_GFX(5, 0x40); | ||
894 | WREG_GFX(6, 0x5); | ||
895 | WREG_GFX(7, 0xf); | ||
896 | WREG_GFX(8, 0xf); | ||
897 | |||
898 | WREG_CRT(0, htotal - 4); | ||
899 | WREG_CRT(1, hdisplay); | ||
900 | WREG_CRT(2, hdisplay); | ||
901 | WREG_CRT(3, (htotal & 0x1F) | 0x80); | ||
902 | WREG_CRT(4, hsyncstart); | ||
903 | WREG_CRT(5, ((htotal & 0x20) << 2) | (hsyncend & 0x1F)); | ||
904 | WREG_CRT(6, vtotal & 0xFF); | ||
905 | WREG_CRT(7, ((vtotal & 0x100) >> 8) | | ||
906 | ((vdisplay & 0x100) >> 7) | | ||
907 | ((vsyncstart & 0x100) >> 6) | | ||
908 | ((vdisplay & 0x100) >> 5) | | ||
909 | ((vdisplay & 0x100) >> 4) | /* linecomp */ | ||
910 | ((vtotal & 0x200) >> 4)| | ||
911 | ((vdisplay & 0x200) >> 3) | | ||
912 | ((vsyncstart & 0x200) >> 2)); | ||
913 | WREG_CRT(9, ((vdisplay & 0x200) >> 4) | | ||
914 | ((vdisplay & 0x200) >> 3)); | ||
915 | WREG_CRT(10, 0); | ||
916 | WREG_CRT(11, 0); | ||
917 | WREG_CRT(12, 0); | ||
918 | WREG_CRT(13, 0); | ||
919 | WREG_CRT(14, 0); | ||
920 | WREG_CRT(15, 0); | ||
921 | WREG_CRT(16, vsyncstart & 0xFF); | ||
922 | WREG_CRT(17, (vsyncend & 0x0F) | 0x20); | ||
923 | WREG_CRT(18, vdisplay & 0xFF); | ||
924 | WREG_CRT(19, pitch & 0xFF); | ||
925 | WREG_CRT(20, 0); | ||
926 | WREG_CRT(21, vdisplay & 0xFF); | ||
927 | WREG_CRT(22, (vtotal + 1) & 0xFF); | ||
928 | WREG_CRT(23, 0xc3); | ||
929 | WREG_CRT(24, vdisplay & 0xFF); | ||
930 | |||
931 | ext_vga[0] = 0; | ||
932 | ext_vga[5] = 0; | ||
933 | |||
934 | /* TODO interlace */ | ||
935 | |||
936 | ext_vga[0] |= (pitch & 0x300) >> 4; | ||
937 | ext_vga[1] = (((htotal - 4) & 0x100) >> 8) | | ||
938 | ((hdisplay & 0x100) >> 7) | | ||
939 | ((hsyncstart & 0x100) >> 6) | | ||
940 | (htotal & 0x40); | ||
941 | ext_vga[2] = ((vtotal & 0xc00) >> 10) | | ||
942 | ((vdisplay & 0x400) >> 8) | | ||
943 | ((vdisplay & 0xc00) >> 7) | | ||
944 | ((vsyncstart & 0xc00) >> 5) | | ||
945 | ((vdisplay & 0x400) >> 3); | ||
946 | if (crtc->fb->bits_per_pixel == 24) | ||
947 | ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80; | ||
948 | else | ||
949 | ext_vga[3] = ((1 << bppshift) - 1) | 0x80; | ||
950 | ext_vga[4] = 0; | ||
951 | if (mdev->type == G200_WB) | ||
952 | ext_vga[1] |= 0x88; | ||
953 | |||
954 | ext_vga_index24 = 0x05; | ||
955 | |||
956 | /* Set pixel clocks */ | ||
957 | misc = 0x2d; | ||
958 | WREG8(MGA_MISC_OUT, misc); | ||
959 | |||
960 | mga_crtc_set_plls(mdev, mode->clock); | ||
961 | |||
962 | for (i = 0; i < 6; i++) { | ||
963 | WREG_ECRT(i, ext_vga[i]); | ||
964 | } | ||
965 | |||
966 | if (mdev->type == G200_ER) | ||
967 | WREG_ECRT(24, ext_vga_index24); | ||
968 | |||
969 | if (mdev->type == G200_EV) { | ||
970 | WREG_ECRT(6, 0); | ||
971 | } | ||
972 | |||
973 | WREG_ECRT(0, ext_vga[0]); | ||
974 | /* Enable mga pixel clock */ | ||
975 | misc = 0x2d; | ||
976 | |||
977 | WREG8(MGA_MISC_OUT, misc); | ||
978 | |||
979 | if (adjusted_mode) | ||
980 | memcpy(&mdev->mode, mode, sizeof(struct drm_display_mode)); | ||
981 | |||
982 | mga_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
983 | |||
984 | /* reset tagfifo */ | ||
985 | if (mdev->type == G200_ER) { | ||
986 | u32 mem_ctl = RREG32(MGAREG_MEMCTL); | ||
987 | u8 seq1; | ||
988 | |||
989 | /* screen off */ | ||
990 | WREG8(MGAREG_SEQ_INDEX, 0x01); | ||
991 | seq1 = RREG8(MGAREG_SEQ_DATA) | 0x20; | ||
992 | WREG8(MGAREG_SEQ_DATA, seq1); | ||
993 | |||
994 | WREG32(MGAREG_MEMCTL, mem_ctl | 0x00200000); | ||
995 | udelay(1000); | ||
996 | WREG32(MGAREG_MEMCTL, mem_ctl & ~0x00200000); | ||
997 | |||
998 | WREG8(MGAREG_SEQ_DATA, seq1 & ~0x20); | ||
999 | } | ||
1000 | |||
1001 | |||
1002 | if (IS_G200_SE(mdev)) { | ||
1003 | if (mdev->reg_1e24 >= 0x02) { | ||
1004 | u8 hi_pri_lvl; | ||
1005 | u32 bpp; | ||
1006 | u32 mb; | ||
1007 | |||
1008 | if (crtc->fb->bits_per_pixel > 16) | ||
1009 | bpp = 32; | ||
1010 | else if (crtc->fb->bits_per_pixel > 8) | ||
1011 | bpp = 16; | ||
1012 | else | ||
1013 | bpp = 8; | ||
1014 | |||
1015 | mb = (mode->clock * bpp) / 1000; | ||
1016 | if (mb > 3100) | ||
1017 | hi_pri_lvl = 0; | ||
1018 | else if (mb > 2600) | ||
1019 | hi_pri_lvl = 1; | ||
1020 | else if (mb > 1900) | ||
1021 | hi_pri_lvl = 2; | ||
1022 | else if (mb > 1160) | ||
1023 | hi_pri_lvl = 3; | ||
1024 | else if (mb > 440) | ||
1025 | hi_pri_lvl = 4; | ||
1026 | else | ||
1027 | hi_pri_lvl = 5; | ||
1028 | |||
1029 | WREG8(0x1fde, 0x06); | ||
1030 | WREG8(0x1fdf, hi_pri_lvl); | ||
1031 | } else { | ||
1032 | if (mdev->reg_1e24 >= 0x01) | ||
1033 | WREG8(0x1fdf, 0x03); | ||
1034 | else | ||
1035 | WREG8(0x1fdf, 0x04); | ||
1036 | } | ||
1037 | } | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | #if 0 /* code from mjg to attempt D3 on crtc dpms off - revisit later */ | ||
1042 | static int mga_suspend(struct drm_crtc *crtc) | ||
1043 | { | ||
1044 | struct mga_crtc *mga_crtc = to_mga_crtc(crtc); | ||
1045 | struct drm_device *dev = crtc->dev; | ||
1046 | struct mga_device *mdev = dev->dev_private; | ||
1047 | struct pci_dev *pdev = dev->pdev; | ||
1048 | int option; | ||
1049 | |||
1050 | if (mdev->suspended) | ||
1051 | return 0; | ||
1052 | |||
1053 | WREG_SEQ(1, 0x20); | ||
1054 | WREG_ECRT(1, 0x30); | ||
1055 | /* Disable the pixel clock */ | ||
1056 | WREG_DAC(0x1a, 0x05); | ||
1057 | /* Power down the DAC */ | ||
1058 | WREG_DAC(0x1e, 0x18); | ||
1059 | /* Power down the pixel PLL */ | ||
1060 | WREG_DAC(0x1a, 0x0d); | ||
1061 | |||
1062 | /* Disable PLLs and clocks */ | ||
1063 | pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); | ||
1064 | option &= ~(0x1F8024); | ||
1065 | pci_write_config_dword(pdev, PCI_MGA_OPTION, option); | ||
1066 | pci_set_power_state(pdev, PCI_D3hot); | ||
1067 | pci_disable_device(pdev); | ||
1068 | |||
1069 | mdev->suspended = true; | ||
1070 | |||
1071 | return 0; | ||
1072 | } | ||
1073 | |||
1074 | static int mga_resume(struct drm_crtc *crtc) | ||
1075 | { | ||
1076 | struct mga_crtc *mga_crtc = to_mga_crtc(crtc); | ||
1077 | struct drm_device *dev = crtc->dev; | ||
1078 | struct mga_device *mdev = dev->dev_private; | ||
1079 | struct pci_dev *pdev = dev->pdev; | ||
1080 | int option; | ||
1081 | |||
1082 | if (!mdev->suspended) | ||
1083 | return 0; | ||
1084 | |||
1085 | pci_set_power_state(pdev, PCI_D0); | ||
1086 | pci_enable_device(pdev); | ||
1087 | |||
1088 | /* Disable sysclk */ | ||
1089 | pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); | ||
1090 | option &= ~(0x4); | ||
1091 | pci_write_config_dword(pdev, PCI_MGA_OPTION, option); | ||
1092 | |||
1093 | mdev->suspended = false; | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | #endif | ||
1099 | |||
1100 | static void mga_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
1101 | { | ||
1102 | struct drm_device *dev = crtc->dev; | ||
1103 | struct mga_device *mdev = dev->dev_private; | ||
1104 | u8 seq1 = 0, crtcext1 = 0; | ||
1105 | |||
1106 | switch (mode) { | ||
1107 | case DRM_MODE_DPMS_ON: | ||
1108 | seq1 = 0; | ||
1109 | crtcext1 = 0; | ||
1110 | mga_crtc_load_lut(crtc); | ||
1111 | break; | ||
1112 | case DRM_MODE_DPMS_STANDBY: | ||
1113 | seq1 = 0x20; | ||
1114 | crtcext1 = 0x10; | ||
1115 | break; | ||
1116 | case DRM_MODE_DPMS_SUSPEND: | ||
1117 | seq1 = 0x20; | ||
1118 | crtcext1 = 0x20; | ||
1119 | break; | ||
1120 | case DRM_MODE_DPMS_OFF: | ||
1121 | seq1 = 0x20; | ||
1122 | crtcext1 = 0x30; | ||
1123 | break; | ||
1124 | } | ||
1125 | |||
1126 | #if 0 | ||
1127 | if (mode == DRM_MODE_DPMS_OFF) { | ||
1128 | mga_suspend(crtc); | ||
1129 | } | ||
1130 | #endif | ||
1131 | WREG8(MGAREG_SEQ_INDEX, 0x01); | ||
1132 | seq1 |= RREG8(MGAREG_SEQ_DATA) & ~0x20; | ||
1133 | mga_wait_vsync(mdev); | ||
1134 | mga_wait_busy(mdev); | ||
1135 | WREG8(MGAREG_SEQ_DATA, seq1); | ||
1136 | msleep(20); | ||
1137 | WREG8(MGAREG_CRTCEXT_INDEX, 0x01); | ||
1138 | crtcext1 |= RREG8(MGAREG_CRTCEXT_DATA) & ~0x30; | ||
1139 | WREG8(MGAREG_CRTCEXT_DATA, crtcext1); | ||
1140 | |||
1141 | #if 0 | ||
1142 | if (mode == DRM_MODE_DPMS_ON && mdev->suspended == true) { | ||
1143 | mga_resume(crtc); | ||
1144 | drm_helper_resume_force_mode(dev); | ||
1145 | } | ||
1146 | #endif | ||
1147 | } | ||
1148 | |||
1149 | /* | ||
1150 | * This is called before a mode is programmed. A typical use might be to | ||
1151 | * enable DPMS during the programming to avoid seeing intermediate stages, | ||
1152 | * but that's not relevant to us | ||
1153 | */ | ||
1154 | static void mga_crtc_prepare(struct drm_crtc *crtc) | ||
1155 | { | ||
1156 | struct drm_device *dev = crtc->dev; | ||
1157 | struct mga_device *mdev = dev->dev_private; | ||
1158 | u8 tmp; | ||
1159 | |||
1160 | /* mga_resume(crtc);*/ | ||
1161 | |||
1162 | WREG8(MGAREG_CRTC_INDEX, 0x11); | ||
1163 | tmp = RREG8(MGAREG_CRTC_DATA); | ||
1164 | WREG_CRT(0x11, tmp | 0x80); | ||
1165 | |||
1166 | if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) { | ||
1167 | WREG_SEQ(0, 1); | ||
1168 | msleep(50); | ||
1169 | WREG_SEQ(1, 0x20); | ||
1170 | msleep(20); | ||
1171 | } else { | ||
1172 | WREG8(MGAREG_SEQ_INDEX, 0x1); | ||
1173 | tmp = RREG8(MGAREG_SEQ_DATA); | ||
1174 | |||
1175 | /* start sync reset */ | ||
1176 | WREG_SEQ(0, 1); | ||
1177 | WREG_SEQ(1, tmp | 0x20); | ||
1178 | } | ||
1179 | |||
1180 | if (mdev->type == G200_WB) | ||
1181 | mga_g200wb_prepare(crtc); | ||
1182 | |||
1183 | WREG_CRT(17, 0); | ||
1184 | } | ||
1185 | |||
1186 | /* | ||
1187 | * This is called after a mode is programmed. It should reverse anything done | ||
1188 | * by the prepare function | ||
1189 | */ | ||
1190 | static void mga_crtc_commit(struct drm_crtc *crtc) | ||
1191 | { | ||
1192 | struct drm_device *dev = crtc->dev; | ||
1193 | struct mga_device *mdev = dev->dev_private; | ||
1194 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
1195 | u8 tmp; | ||
1196 | |||
1197 | if (mdev->type == G200_WB) | ||
1198 | mga_g200wb_commit(crtc); | ||
1199 | |||
1200 | if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) { | ||
1201 | msleep(50); | ||
1202 | WREG_SEQ(1, 0x0); | ||
1203 | msleep(20); | ||
1204 | WREG_SEQ(0, 0x3); | ||
1205 | } else { | ||
1206 | WREG8(MGAREG_SEQ_INDEX, 0x1); | ||
1207 | tmp = RREG8(MGAREG_SEQ_DATA); | ||
1208 | |||
1209 | tmp &= ~0x20; | ||
1210 | WREG_SEQ(0x1, tmp); | ||
1211 | WREG_SEQ(0, 3); | ||
1212 | } | ||
1213 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
1214 | } | ||
1215 | |||
1216 | /* | ||
1217 | * The core can pass us a set of gamma values to program. We actually only | ||
1218 | * use this for 8-bit mode so can't perform smooth fades on deeper modes, | ||
1219 | * but it's a requirement that we provide the function | ||
1220 | */ | ||
1221 | static void mga_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
1222 | u16 *blue, uint32_t start, uint32_t size) | ||
1223 | { | ||
1224 | struct mga_crtc *mga_crtc = to_mga_crtc(crtc); | ||
1225 | int end = (start + size > MGAG200_LUT_SIZE) ? MGAG200_LUT_SIZE : start + size; | ||
1226 | int i; | ||
1227 | |||
1228 | for (i = start; i < end; i++) { | ||
1229 | mga_crtc->lut_r[i] = red[i] >> 8; | ||
1230 | mga_crtc->lut_g[i] = green[i] >> 8; | ||
1231 | mga_crtc->lut_b[i] = blue[i] >> 8; | ||
1232 | } | ||
1233 | mga_crtc_load_lut(crtc); | ||
1234 | } | ||
1235 | |||
1236 | /* Simple cleanup function */ | ||
1237 | static void mga_crtc_destroy(struct drm_crtc *crtc) | ||
1238 | { | ||
1239 | struct mga_crtc *mga_crtc = to_mga_crtc(crtc); | ||
1240 | |||
1241 | drm_crtc_cleanup(crtc); | ||
1242 | kfree(mga_crtc); | ||
1243 | } | ||
1244 | |||
1245 | /* These provide the minimum set of functions required to handle a CRTC */ | ||
1246 | static const struct drm_crtc_funcs mga_crtc_funcs = { | ||
1247 | .gamma_set = mga_crtc_gamma_set, | ||
1248 | .set_config = drm_crtc_helper_set_config, | ||
1249 | .destroy = mga_crtc_destroy, | ||
1250 | }; | ||
1251 | |||
1252 | static const struct drm_crtc_helper_funcs mga_helper_funcs = { | ||
1253 | .dpms = mga_crtc_dpms, | ||
1254 | .mode_fixup = mga_crtc_mode_fixup, | ||
1255 | .mode_set = mga_crtc_mode_set, | ||
1256 | .mode_set_base = mga_crtc_mode_set_base, | ||
1257 | .prepare = mga_crtc_prepare, | ||
1258 | .commit = mga_crtc_commit, | ||
1259 | .load_lut = mga_crtc_load_lut, | ||
1260 | }; | ||
1261 | |||
1262 | /* CRTC setup */ | ||
1263 | static void mga_crtc_init(struct drm_device *dev) | ||
1264 | { | ||
1265 | struct mga_device *mdev = dev->dev_private; | ||
1266 | struct mga_crtc *mga_crtc; | ||
1267 | int i; | ||
1268 | |||
1269 | mga_crtc = kzalloc(sizeof(struct mga_crtc) + | ||
1270 | (MGAG200FB_CONN_LIMIT * sizeof(struct drm_connector *)), | ||
1271 | GFP_KERNEL); | ||
1272 | |||
1273 | if (mga_crtc == NULL) | ||
1274 | return; | ||
1275 | |||
1276 | drm_crtc_init(dev, &mga_crtc->base, &mga_crtc_funcs); | ||
1277 | |||
1278 | drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE); | ||
1279 | mdev->mode_info.crtc = mga_crtc; | ||
1280 | |||
1281 | for (i = 0; i < MGAG200_LUT_SIZE; i++) { | ||
1282 | mga_crtc->lut_r[i] = i; | ||
1283 | mga_crtc->lut_g[i] = i; | ||
1284 | mga_crtc->lut_b[i] = i; | ||
1285 | } | ||
1286 | |||
1287 | drm_crtc_helper_add(&mga_crtc->base, &mga_helper_funcs); | ||
1288 | } | ||
1289 | |||
1290 | /** Sets the color ramps on behalf of fbcon */ | ||
1291 | void mga_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
1292 | u16 blue, int regno) | ||
1293 | { | ||
1294 | struct mga_crtc *mga_crtc = to_mga_crtc(crtc); | ||
1295 | |||
1296 | mga_crtc->lut_r[regno] = red >> 8; | ||
1297 | mga_crtc->lut_g[regno] = green >> 8; | ||
1298 | mga_crtc->lut_b[regno] = blue >> 8; | ||
1299 | } | ||
1300 | |||
1301 | /** Gets the color ramps on behalf of fbcon */ | ||
1302 | void mga_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
1303 | u16 *blue, int regno) | ||
1304 | { | ||
1305 | struct mga_crtc *mga_crtc = to_mga_crtc(crtc); | ||
1306 | |||
1307 | *red = (u16)mga_crtc->lut_r[regno] << 8; | ||
1308 | *green = (u16)mga_crtc->lut_g[regno] << 8; | ||
1309 | *blue = (u16)mga_crtc->lut_b[regno] << 8; | ||
1310 | } | ||
1311 | |||
1312 | /* | ||
1313 | * The encoder comes after the CRTC in the output pipeline, but before | ||
1314 | * the connector. It's responsible for ensuring that the digital | ||
1315 | * stream is appropriately converted into the output format. Setup is | ||
1316 | * very simple in this case - all we have to do is inform qemu of the | ||
1317 | * colour depth in order to ensure that it displays appropriately | ||
1318 | */ | ||
1319 | |||
1320 | /* | ||
1321 | * These functions are analagous to those in the CRTC code, but are intended | ||
1322 | * to handle any encoder-specific limitations | ||
1323 | */ | ||
1324 | static bool mga_encoder_mode_fixup(struct drm_encoder *encoder, | ||
1325 | struct drm_display_mode *mode, | ||
1326 | struct drm_display_mode *adjusted_mode) | ||
1327 | { | ||
1328 | return true; | ||
1329 | } | ||
1330 | |||
1331 | static void mga_encoder_mode_set(struct drm_encoder *encoder, | ||
1332 | struct drm_display_mode *mode, | ||
1333 | struct drm_display_mode *adjusted_mode) | ||
1334 | { | ||
1335 | |||
1336 | } | ||
1337 | |||
1338 | static void mga_encoder_dpms(struct drm_encoder *encoder, int state) | ||
1339 | { | ||
1340 | return; | ||
1341 | } | ||
1342 | |||
1343 | static void mga_encoder_prepare(struct drm_encoder *encoder) | ||
1344 | { | ||
1345 | } | ||
1346 | |||
1347 | static void mga_encoder_commit(struct drm_encoder *encoder) | ||
1348 | { | ||
1349 | } | ||
1350 | |||
1351 | void mga_encoder_destroy(struct drm_encoder *encoder) | ||
1352 | { | ||
1353 | struct mga_encoder *mga_encoder = to_mga_encoder(encoder); | ||
1354 | drm_encoder_cleanup(encoder); | ||
1355 | kfree(mga_encoder); | ||
1356 | } | ||
1357 | |||
1358 | static const struct drm_encoder_helper_funcs mga_encoder_helper_funcs = { | ||
1359 | .dpms = mga_encoder_dpms, | ||
1360 | .mode_fixup = mga_encoder_mode_fixup, | ||
1361 | .mode_set = mga_encoder_mode_set, | ||
1362 | .prepare = mga_encoder_prepare, | ||
1363 | .commit = mga_encoder_commit, | ||
1364 | }; | ||
1365 | |||
1366 | static const struct drm_encoder_funcs mga_encoder_encoder_funcs = { | ||
1367 | .destroy = mga_encoder_destroy, | ||
1368 | }; | ||
1369 | |||
1370 | static struct drm_encoder *mga_encoder_init(struct drm_device *dev) | ||
1371 | { | ||
1372 | struct drm_encoder *encoder; | ||
1373 | struct mga_encoder *mga_encoder; | ||
1374 | |||
1375 | mga_encoder = kzalloc(sizeof(struct mga_encoder), GFP_KERNEL); | ||
1376 | if (!mga_encoder) | ||
1377 | return NULL; | ||
1378 | |||
1379 | encoder = &mga_encoder->base; | ||
1380 | encoder->possible_crtcs = 0x1; | ||
1381 | |||
1382 | drm_encoder_init(dev, encoder, &mga_encoder_encoder_funcs, | ||
1383 | DRM_MODE_ENCODER_DAC); | ||
1384 | drm_encoder_helper_add(encoder, &mga_encoder_helper_funcs); | ||
1385 | |||
1386 | return encoder; | ||
1387 | } | ||
1388 | |||
1389 | |||
1390 | static int mga_vga_get_modes(struct drm_connector *connector) | ||
1391 | { | ||
1392 | struct mga_connector *mga_connector = to_mga_connector(connector); | ||
1393 | struct edid *edid; | ||
1394 | int ret = 0; | ||
1395 | |||
1396 | edid = drm_get_edid(connector, &mga_connector->i2c->adapter); | ||
1397 | if (edid) { | ||
1398 | drm_mode_connector_update_edid_property(connector, edid); | ||
1399 | ret = drm_add_edid_modes(connector, edid); | ||
1400 | connector->display_info.raw_edid = NULL; | ||
1401 | kfree(edid); | ||
1402 | } | ||
1403 | return ret; | ||
1404 | } | ||
1405 | |||
1406 | static int mga_vga_mode_valid(struct drm_connector *connector, | ||
1407 | struct drm_display_mode *mode) | ||
1408 | { | ||
1409 | /* FIXME: Add bandwidth and g200se limitations */ | ||
1410 | |||
1411 | if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || | ||
1412 | mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || | ||
1413 | mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || | ||
1414 | mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) { | ||
1415 | return MODE_BAD; | ||
1416 | } | ||
1417 | |||
1418 | return MODE_OK; | ||
1419 | } | ||
1420 | |||
1421 | struct drm_encoder *mga_connector_best_encoder(struct drm_connector | ||
1422 | *connector) | ||
1423 | { | ||
1424 | int enc_id = connector->encoder_ids[0]; | ||
1425 | struct drm_mode_object *obj; | ||
1426 | struct drm_encoder *encoder; | ||
1427 | |||
1428 | /* pick the encoder ids */ | ||
1429 | if (enc_id) { | ||
1430 | obj = | ||
1431 | drm_mode_object_find(connector->dev, enc_id, | ||
1432 | DRM_MODE_OBJECT_ENCODER); | ||
1433 | if (!obj) | ||
1434 | return NULL; | ||
1435 | encoder = obj_to_encoder(obj); | ||
1436 | return encoder; | ||
1437 | } | ||
1438 | return NULL; | ||
1439 | } | ||
1440 | |||
1441 | static enum drm_connector_status mga_vga_detect(struct drm_connector | ||
1442 | *connector, bool force) | ||
1443 | { | ||
1444 | return connector_status_connected; | ||
1445 | } | ||
1446 | |||
1447 | static void mga_connector_destroy(struct drm_connector *connector) | ||
1448 | { | ||
1449 | struct mga_connector *mga_connector = to_mga_connector(connector); | ||
1450 | mgag200_i2c_destroy(mga_connector->i2c); | ||
1451 | drm_connector_cleanup(connector); | ||
1452 | kfree(connector); | ||
1453 | } | ||
1454 | |||
1455 | struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { | ||
1456 | .get_modes = mga_vga_get_modes, | ||
1457 | .mode_valid = mga_vga_mode_valid, | ||
1458 | .best_encoder = mga_connector_best_encoder, | ||
1459 | }; | ||
1460 | |||
1461 | struct drm_connector_funcs mga_vga_connector_funcs = { | ||
1462 | .dpms = drm_helper_connector_dpms, | ||
1463 | .detect = mga_vga_detect, | ||
1464 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
1465 | .destroy = mga_connector_destroy, | ||
1466 | }; | ||
1467 | |||
1468 | static struct drm_connector *mga_vga_init(struct drm_device *dev) | ||
1469 | { | ||
1470 | struct drm_connector *connector; | ||
1471 | struct mga_connector *mga_connector; | ||
1472 | |||
1473 | mga_connector = kzalloc(sizeof(struct mga_connector), GFP_KERNEL); | ||
1474 | if (!mga_connector) | ||
1475 | return NULL; | ||
1476 | |||
1477 | connector = &mga_connector->base; | ||
1478 | |||
1479 | drm_connector_init(dev, connector, | ||
1480 | &mga_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||
1481 | |||
1482 | drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); | ||
1483 | |||
1484 | mga_connector->i2c = mgag200_i2c_create(dev); | ||
1485 | if (!mga_connector->i2c) | ||
1486 | DRM_ERROR("failed to add ddc bus\n"); | ||
1487 | |||
1488 | return connector; | ||
1489 | } | ||
1490 | |||
1491 | |||
1492 | int mgag200_modeset_init(struct mga_device *mdev) | ||
1493 | { | ||
1494 | struct drm_encoder *encoder; | ||
1495 | struct drm_connector *connector; | ||
1496 | int ret; | ||
1497 | |||
1498 | mdev->mode_info.mode_config_initialized = true; | ||
1499 | |||
1500 | mdev->dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; | ||
1501 | mdev->dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; | ||
1502 | |||
1503 | mdev->dev->mode_config.fb_base = mdev->mc.vram_base; | ||
1504 | |||
1505 | mga_crtc_init(mdev->dev); | ||
1506 | |||
1507 | encoder = mga_encoder_init(mdev->dev); | ||
1508 | if (!encoder) { | ||
1509 | DRM_ERROR("mga_encoder_init failed\n"); | ||
1510 | return -1; | ||
1511 | } | ||
1512 | |||
1513 | connector = mga_vga_init(mdev->dev); | ||
1514 | if (!connector) { | ||
1515 | DRM_ERROR("mga_vga_init failed\n"); | ||
1516 | return -1; | ||
1517 | } | ||
1518 | |||
1519 | drm_mode_connector_attach_encoder(connector, encoder); | ||
1520 | |||
1521 | ret = mgag200_fbdev_init(mdev); | ||
1522 | if (ret) { | ||
1523 | DRM_ERROR("mga_fbdev_init failed\n"); | ||
1524 | return ret; | ||
1525 | } | ||
1526 | |||
1527 | return 0; | ||
1528 | } | ||
1529 | |||
1530 | void mgag200_modeset_fini(struct mga_device *mdev) | ||
1531 | { | ||
1532 | |||
1533 | } | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h new file mode 100644 index 000000000000..fb24d8655feb --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_reg.h | |||
@@ -0,0 +1,661 @@ | |||
1 | /* | ||
2 | * MGA Millennium (MGA2064W) functions | ||
3 | * MGA Mystique (MGA1064SG) functions | ||
4 | * | ||
5 | * Copyright 1996 The XFree86 Project, Inc. | ||
6 | * | ||
7 | * Authors | ||
8 | * Dirk Hohndel | ||
9 | * hohndel@XFree86.Org | ||
10 | * David Dawes | ||
11 | * dawes@XFree86.Org | ||
12 | * Contributors: | ||
13 | * Guy DESBIEF, Aix-en-provence, France | ||
14 | * g.desbief@aix.pacwan.net | ||
15 | * MGA1064SG Mystique register file | ||
16 | */ | ||
17 | |||
18 | |||
19 | #ifndef _MGA_REG_H_ | ||
20 | #define _MGA_REG_H_ | ||
21 | |||
22 | #define MGAREG_DWGCTL 0x1c00 | ||
23 | #define MGAREG_MACCESS 0x1c04 | ||
24 | /* the following is a mystique only register */ | ||
25 | #define MGAREG_MCTLWTST 0x1c08 | ||
26 | #define MGAREG_ZORG 0x1c0c | ||
27 | |||
28 | #define MGAREG_PAT0 0x1c10 | ||
29 | #define MGAREG_PAT1 0x1c14 | ||
30 | #define MGAREG_PLNWT 0x1c1c | ||
31 | |||
32 | #define MGAREG_BCOL 0x1c20 | ||
33 | #define MGAREG_FCOL 0x1c24 | ||
34 | |||
35 | #define MGAREG_SRC0 0x1c30 | ||
36 | #define MGAREG_SRC1 0x1c34 | ||
37 | #define MGAREG_SRC2 0x1c38 | ||
38 | #define MGAREG_SRC3 0x1c3c | ||
39 | |||
40 | #define MGAREG_XYSTRT 0x1c40 | ||
41 | #define MGAREG_XYEND 0x1c44 | ||
42 | |||
43 | #define MGAREG_SHIFT 0x1c50 | ||
44 | /* the following is a mystique only register */ | ||
45 | #define MGAREG_DMAPAD 0x1c54 | ||
46 | #define MGAREG_SGN 0x1c58 | ||
47 | #define MGAREG_LEN 0x1c5c | ||
48 | |||
49 | #define MGAREG_AR0 0x1c60 | ||
50 | #define MGAREG_AR1 0x1c64 | ||
51 | #define MGAREG_AR2 0x1c68 | ||
52 | #define MGAREG_AR3 0x1c6c | ||
53 | #define MGAREG_AR4 0x1c70 | ||
54 | #define MGAREG_AR5 0x1c74 | ||
55 | #define MGAREG_AR6 0x1c78 | ||
56 | |||
57 | #define MGAREG_CXBNDRY 0x1c80 | ||
58 | #define MGAREG_FXBNDRY 0x1c84 | ||
59 | #define MGAREG_YDSTLEN 0x1c88 | ||
60 | #define MGAREG_PITCH 0x1c8c | ||
61 | |||
62 | #define MGAREG_YDST 0x1c90 | ||
63 | #define MGAREG_YDSTORG 0x1c94 | ||
64 | #define MGAREG_YTOP 0x1c98 | ||
65 | #define MGAREG_YBOT 0x1c9c | ||
66 | |||
67 | #define MGAREG_CXLEFT 0x1ca0 | ||
68 | #define MGAREG_CXRIGHT 0x1ca4 | ||
69 | #define MGAREG_FXLEFT 0x1ca8 | ||
70 | #define MGAREG_FXRIGHT 0x1cac | ||
71 | |||
72 | #define MGAREG_XDST 0x1cb0 | ||
73 | |||
74 | #define MGAREG_DR0 0x1cc0 | ||
75 | #define MGAREG_DR1 0x1cc4 | ||
76 | #define MGAREG_DR2 0x1cc8 | ||
77 | #define MGAREG_DR3 0x1ccc | ||
78 | |||
79 | #define MGAREG_DR4 0x1cd0 | ||
80 | #define MGAREG_DR5 0x1cd4 | ||
81 | #define MGAREG_DR6 0x1cd8 | ||
82 | #define MGAREG_DR7 0x1cdc | ||
83 | |||
84 | #define MGAREG_DR8 0x1ce0 | ||
85 | #define MGAREG_DR9 0x1ce4 | ||
86 | #define MGAREG_DR10 0x1ce8 | ||
87 | #define MGAREG_DR11 0x1cec | ||
88 | |||
89 | #define MGAREG_DR12 0x1cf0 | ||
90 | #define MGAREG_DR13 0x1cf4 | ||
91 | #define MGAREG_DR14 0x1cf8 | ||
92 | #define MGAREG_DR15 0x1cfc | ||
93 | |||
94 | #define MGAREG_SRCORG 0x2cb4 | ||
95 | #define MGAREG_DSTORG 0x2cb8 | ||
96 | |||
97 | /* add or or this to one of the previous "power registers" to start | ||
98 | the drawing engine */ | ||
99 | |||
100 | #define MGAREG_EXEC 0x0100 | ||
101 | |||
102 | #define MGAREG_FIFOSTATUS 0x1e10 | ||
103 | #define MGAREG_Status 0x1e14 | ||
104 | #define MGAREG_CACHEFLUSH 0x1fff | ||
105 | #define MGAREG_ICLEAR 0x1e18 | ||
106 | #define MGAREG_IEN 0x1e1c | ||
107 | |||
108 | #define MGAREG_VCOUNT 0x1e20 | ||
109 | |||
110 | #define MGAREG_Reset 0x1e40 | ||
111 | |||
112 | #define MGAREG_OPMODE 0x1e54 | ||
113 | |||
114 | /* Warp Registers */ | ||
115 | #define MGAREG_WIADDR 0x1dc0 | ||
116 | #define MGAREG_WIADDR2 0x1dd8 | ||
117 | #define MGAREG_WGETMSB 0x1dc8 | ||
118 | #define MGAREG_WVRTXSZ 0x1dcc | ||
119 | #define MGAREG_WACCEPTSEQ 0x1dd4 | ||
120 | #define MGAREG_WMISC 0x1e70 | ||
121 | |||
122 | #define MGAREG_MEMCTL 0x2e08 | ||
123 | |||
124 | /* OPMODE register additives */ | ||
125 | |||
126 | #define MGAOPM_DMA_GENERAL (0x00 << 2) | ||
127 | #define MGAOPM_DMA_BLIT (0x01 << 2) | ||
128 | #define MGAOPM_DMA_VECTOR (0x10 << 2) | ||
129 | |||
130 | /* MACCESS register additives */ | ||
131 | #define MGAMAC_PW8 0x00 | ||
132 | #define MGAMAC_PW16 0x01 | ||
133 | #define MGAMAC_PW24 0x03 /* not a typo */ | ||
134 | #define MGAMAC_PW32 0x02 /* not a typo */ | ||
135 | #define MGAMAC_BYPASS332 0x10000000 | ||
136 | #define MGAMAC_NODITHER 0x40000000 | ||
137 | #define MGAMAC_DIT555 0x80000000 | ||
138 | |||
139 | /* DWGCTL register additives */ | ||
140 | |||
141 | /* Lines */ | ||
142 | |||
143 | #define MGADWG_LINE_OPEN 0x00 | ||
144 | #define MGADWG_AUTOLINE_OPEN 0x01 | ||
145 | #define MGADWG_LINE_CLOSE 0x02 | ||
146 | #define MGADWG_AUTOLINE_CLOSE 0x03 | ||
147 | |||
148 | /* Trapezoids */ | ||
149 | #define MGADWG_TRAP 0x04 | ||
150 | #define MGADWG_TEXTURE_TRAP 0x06 | ||
151 | |||
152 | /* BitBlts */ | ||
153 | |||
154 | #define MGADWG_BITBLT 0x08 | ||
155 | #define MGADWG_FBITBLT 0x0c | ||
156 | #define MGADWG_ILOAD 0x09 | ||
157 | #define MGADWG_ILOAD_SCALE 0x0d | ||
158 | #define MGADWG_ILOAD_FILTER 0x0f | ||
159 | #define MGADWG_ILOAD_HIQH 0x07 | ||
160 | #define MGADWG_ILOAD_HIQHV 0x0e | ||
161 | #define MGADWG_IDUMP 0x0a | ||
162 | |||
163 | /* atype access to WRAM */ | ||
164 | |||
165 | #define MGADWG_RPL ( 0x00 << 4 ) | ||
166 | #define MGADWG_RSTR ( 0x01 << 4 ) | ||
167 | #define MGADWG_ZI ( 0x03 << 4 ) | ||
168 | #define MGADWG_BLK ( 0x04 << 4 ) | ||
169 | #define MGADWG_I ( 0x07 << 4 ) | ||
170 | |||
171 | /* specifies whether bit blits are linear or xy */ | ||
172 | #define MGADWG_LINEAR ( 0x01 << 7 ) | ||
173 | |||
174 | /* z drawing mode. use MGADWG_NOZCMP for always */ | ||
175 | |||
176 | #define MGADWG_NOZCMP ( 0x00 << 8 ) | ||
177 | #define MGADWG_ZE ( 0x02 << 8 ) | ||
178 | #define MGADWG_ZNE ( 0x03 << 8 ) | ||
179 | #define MGADWG_ZLT ( 0x04 << 8 ) | ||
180 | #define MGADWG_ZLTE ( 0x05 << 8 ) | ||
181 | #define MGADWG_GT ( 0x06 << 8 ) | ||
182 | #define MGADWG_GTE ( 0x07 << 8 ) | ||
183 | |||
184 | /* use this to force colour expansion circuitry to do its stuff */ | ||
185 | |||
186 | #define MGADWG_SOLID ( 0x01 << 11 ) | ||
187 | |||
188 | /* ar register at zero */ | ||
189 | |||
190 | #define MGADWG_ARZERO ( 0x01 << 12 ) | ||
191 | |||
192 | #define MGADWG_SGNZERO ( 0x01 << 13 ) | ||
193 | |||
194 | #define MGADWG_SHIFTZERO ( 0x01 << 14 ) | ||
195 | |||
196 | /* See table on 4-43 for bop ALU operations */ | ||
197 | |||
198 | /* See table on 4-44 for translucidity masks */ | ||
199 | |||
200 | #define MGADWG_BMONOLEF ( 0x00 << 25 ) | ||
201 | #define MGADWG_BMONOWF ( 0x04 << 25 ) | ||
202 | #define MGADWG_BPLAN ( 0x01 << 25 ) | ||
203 | |||
204 | /* note that if bfcol is specified and you're doing a bitblt, it causes | ||
205 | a fbitblt to be performed, so check that you obey the fbitblt rules */ | ||
206 | |||
207 | #define MGADWG_BFCOL ( 0x02 << 25 ) | ||
208 | #define MGADWG_BUYUV ( 0x0e << 25 ) | ||
209 | #define MGADWG_BU32BGR ( 0x03 << 25 ) | ||
210 | #define MGADWG_BU32RGB ( 0x07 << 25 ) | ||
211 | #define MGADWG_BU24BGR ( 0x0b << 25 ) | ||
212 | #define MGADWG_BU24RGB ( 0x0f << 25 ) | ||
213 | |||
214 | #define MGADWG_PATTERN ( 0x01 << 29 ) | ||
215 | #define MGADWG_TRANSC ( 0x01 << 30 ) | ||
216 | #define MGAREG_MISC_WRITE 0x3c2 | ||
217 | #define MGAREG_MISC_READ 0x3cc | ||
218 | #define MGAREG_MEM_MISC_WRITE 0x1fc2 | ||
219 | #define MGAREG_MEM_MISC_READ 0x1fcc | ||
220 | |||
221 | #define MGAREG_MISC_IOADSEL (0x1 << 0) | ||
222 | #define MGAREG_MISC_RAMMAPEN (0x1 << 1) | ||
223 | #define MGAREG_MISC_CLK_SEL_VGA25 (0x0 << 2) | ||
224 | #define MGAREG_MISC_CLK_SEL_VGA28 (0x1 << 2) | ||
225 | #define MGAREG_MISC_CLK_SEL_MGA_PIX (0x2 << 2) | ||
226 | #define MGAREG_MISC_CLK_SEL_MGA_MSK (0x3 << 2) | ||
227 | #define MGAREG_MISC_VIDEO_DIS (0x1 << 4) | ||
228 | #define MGAREG_MISC_HIGH_PG_SEL (0x1 << 5) | ||
229 | |||
230 | /* MMIO VGA registers */ | ||
231 | #define MGAREG_SEQ_INDEX 0x1fc4 | ||
232 | #define MGAREG_SEQ_DATA 0x1fc5 | ||
233 | #define MGAREG_CRTC_INDEX 0x1fd4 | ||
234 | #define MGAREG_CRTC_DATA 0x1fd5 | ||
235 | #define MGAREG_CRTCEXT_INDEX 0x1fde | ||
236 | #define MGAREG_CRTCEXT_DATA 0x1fdf | ||
237 | |||
238 | |||
239 | |||
240 | /* MGA bits for registers PCI_OPTION_REG */ | ||
241 | #define MGA1064_OPT_SYS_CLK_PCI ( 0x00 << 0 ) | ||
242 | #define MGA1064_OPT_SYS_CLK_PLL ( 0x01 << 0 ) | ||
243 | #define MGA1064_OPT_SYS_CLK_EXT ( 0x02 << 0 ) | ||
244 | #define MGA1064_OPT_SYS_CLK_MSK ( 0x03 << 0 ) | ||
245 | |||
246 | #define MGA1064_OPT_SYS_CLK_DIS ( 0x01 << 2 ) | ||
247 | #define MGA1064_OPT_G_CLK_DIV_1 ( 0x01 << 3 ) | ||
248 | #define MGA1064_OPT_M_CLK_DIV_1 ( 0x01 << 4 ) | ||
249 | |||
250 | #define MGA1064_OPT_SYS_PLL_PDN ( 0x01 << 5 ) | ||
251 | #define MGA1064_OPT_VGA_ION ( 0x01 << 8 ) | ||
252 | |||
253 | /* MGA registers in PCI config space */ | ||
254 | #define PCI_MGA_INDEX 0x44 | ||
255 | #define PCI_MGA_DATA 0x48 | ||
256 | #define PCI_MGA_OPTION 0x40 | ||
257 | #define PCI_MGA_OPTION2 0x50 | ||
258 | #define PCI_MGA_OPTION3 0x54 | ||
259 | |||
260 | #define RAMDAC_OFFSET 0x3c00 | ||
261 | |||
262 | /* TVP3026 direct registers */ | ||
263 | |||
264 | #define TVP3026_INDEX 0x00 | ||
265 | #define TVP3026_WADR_PAL 0x00 | ||
266 | #define TVP3026_COL_PAL 0x01 | ||
267 | #define TVP3026_PIX_RD_MSK 0x02 | ||
268 | #define TVP3026_RADR_PAL 0x03 | ||
269 | #define TVP3026_CUR_COL_ADDR 0x04 | ||
270 | #define TVP3026_CUR_COL_DATA 0x05 | ||
271 | #define TVP3026_DATA 0x0a | ||
272 | #define TVP3026_CUR_RAM 0x0b | ||
273 | #define TVP3026_CUR_XLOW 0x0c | ||
274 | #define TVP3026_CUR_XHI 0x0d | ||
275 | #define TVP3026_CUR_YLOW 0x0e | ||
276 | #define TVP3026_CUR_YHI 0x0f | ||
277 | |||
278 | /* TVP3026 indirect registers */ | ||
279 | |||
280 | #define TVP3026_SILICON_REV 0x01 | ||
281 | #define TVP3026_CURSOR_CTL 0x06 | ||
282 | #define TVP3026_LATCH_CTL 0x0f | ||
283 | #define TVP3026_TRUE_COLOR_CTL 0x18 | ||
284 | #define TVP3026_MUX_CTL 0x19 | ||
285 | #define TVP3026_CLK_SEL 0x1a | ||
286 | #define TVP3026_PAL_PAGE 0x1c | ||
287 | #define TVP3026_GEN_CTL 0x1d | ||
288 | #define TVP3026_MISC_CTL 0x1e | ||
289 | #define TVP3026_GEN_IO_CTL 0x2a | ||
290 | #define TVP3026_GEN_IO_DATA 0x2b | ||
291 | #define TVP3026_PLL_ADDR 0x2c | ||
292 | #define TVP3026_PIX_CLK_DATA 0x2d | ||
293 | #define TVP3026_MEM_CLK_DATA 0x2e | ||
294 | #define TVP3026_LOAD_CLK_DATA 0x2f | ||
295 | #define TVP3026_KEY_RED_LOW 0x32 | ||
296 | #define TVP3026_KEY_RED_HI 0x33 | ||
297 | #define TVP3026_KEY_GREEN_LOW 0x34 | ||
298 | #define TVP3026_KEY_GREEN_HI 0x35 | ||
299 | #define TVP3026_KEY_BLUE_LOW 0x36 | ||
300 | #define TVP3026_KEY_BLUE_HI 0x37 | ||
301 | #define TVP3026_KEY_CTL 0x38 | ||
302 | #define TVP3026_MCLK_CTL 0x39 | ||
303 | #define TVP3026_SENSE_TEST 0x3a | ||
304 | #define TVP3026_TEST_DATA 0x3b | ||
305 | #define TVP3026_CRC_LSB 0x3c | ||
306 | #define TVP3026_CRC_MSB 0x3d | ||
307 | #define TVP3026_CRC_CTL 0x3e | ||
308 | #define TVP3026_ID 0x3f | ||
309 | #define TVP3026_RESET 0xff | ||
310 | |||
311 | |||
312 | /* MGA1064 DAC Register file */ | ||
313 | /* MGA1064 direct registers */ | ||
314 | |||
315 | #define MGA1064_INDEX 0x00 | ||
316 | #define MGA1064_WADR_PAL 0x00 | ||
317 | #define MGA1064_SPAREREG 0x00 | ||
318 | #define MGA1064_COL_PAL 0x01 | ||
319 | #define MGA1064_PIX_RD_MSK 0x02 | ||
320 | #define MGA1064_RADR_PAL 0x03 | ||
321 | #define MGA1064_DATA 0x0a | ||
322 | |||
323 | #define MGA1064_CUR_XLOW 0x0c | ||
324 | #define MGA1064_CUR_XHI 0x0d | ||
325 | #define MGA1064_CUR_YLOW 0x0e | ||
326 | #define MGA1064_CUR_YHI 0x0f | ||
327 | |||
328 | /* MGA1064 indirect registers */ | ||
329 | #define MGA1064_DVI_PIPE_CTL 0x03 | ||
330 | #define MGA1064_CURSOR_BASE_ADR_LOW 0x04 | ||
331 | #define MGA1064_CURSOR_BASE_ADR_HI 0x05 | ||
332 | #define MGA1064_CURSOR_CTL 0x06 | ||
333 | #define MGA1064_CURSOR_COL0_RED 0x08 | ||
334 | #define MGA1064_CURSOR_COL0_GREEN 0x09 | ||
335 | #define MGA1064_CURSOR_COL0_BLUE 0x0a | ||
336 | |||
337 | #define MGA1064_CURSOR_COL1_RED 0x0c | ||
338 | #define MGA1064_CURSOR_COL1_GREEN 0x0d | ||
339 | #define MGA1064_CURSOR_COL1_BLUE 0x0e | ||
340 | |||
341 | #define MGA1064_CURSOR_COL2_RED 0x010 | ||
342 | #define MGA1064_CURSOR_COL2_GREEN 0x011 | ||
343 | #define MGA1064_CURSOR_COL2_BLUE 0x012 | ||
344 | |||
345 | #define MGA1064_VREF_CTL 0x018 | ||
346 | |||
347 | #define MGA1064_MUL_CTL 0x19 | ||
348 | #define MGA1064_MUL_CTL_8bits 0x0 | ||
349 | #define MGA1064_MUL_CTL_15bits 0x01 | ||
350 | #define MGA1064_MUL_CTL_16bits 0x02 | ||
351 | #define MGA1064_MUL_CTL_24bits 0x03 | ||
352 | #define MGA1064_MUL_CTL_32bits 0x04 | ||
353 | #define MGA1064_MUL_CTL_2G8V16bits 0x05 | ||
354 | #define MGA1064_MUL_CTL_G16V16bits 0x06 | ||
355 | #define MGA1064_MUL_CTL_32_24bits 0x07 | ||
356 | |||
357 | #define MGA1064_PIX_CLK_CTL 0x1a | ||
358 | #define MGA1064_PIX_CLK_CTL_CLK_DIS ( 0x01 << 2 ) | ||
359 | #define MGA1064_PIX_CLK_CTL_CLK_POW_DOWN ( 0x01 << 3 ) | ||
360 | #define MGA1064_PIX_CLK_CTL_SEL_PCI ( 0x00 << 0 ) | ||
361 | #define MGA1064_PIX_CLK_CTL_SEL_PLL ( 0x01 << 0 ) | ||
362 | #define MGA1064_PIX_CLK_CTL_SEL_EXT ( 0x02 << 0 ) | ||
363 | #define MGA1064_PIX_CLK_CTL_SEL_MSK ( 0x03 << 0 ) | ||
364 | |||
365 | #define MGA1064_GEN_CTL 0x1d | ||
366 | #define MGA1064_GEN_CTL_SYNC_ON_GREEN_DIS (0x01 << 5) | ||
367 | #define MGA1064_MISC_CTL 0x1e | ||
368 | #define MGA1064_MISC_CTL_DAC_EN ( 0x01 << 0 ) | ||
369 | #define MGA1064_MISC_CTL_VGA ( 0x01 << 1 ) | ||
370 | #define MGA1064_MISC_CTL_DIS_CON ( 0x03 << 1 ) | ||
371 | #define MGA1064_MISC_CTL_MAFC ( 0x02 << 1 ) | ||
372 | #define MGA1064_MISC_CTL_VGA8 ( 0x01 << 3 ) | ||
373 | #define MGA1064_MISC_CTL_DAC_RAM_CS ( 0x01 << 4 ) | ||
374 | |||
375 | #define MGA1064_GEN_IO_CTL2 0x29 | ||
376 | #define MGA1064_GEN_IO_CTL 0x2a | ||
377 | #define MGA1064_GEN_IO_DATA 0x2b | ||
378 | #define MGA1064_SYS_PLL_M 0x2c | ||
379 | #define MGA1064_SYS_PLL_N 0x2d | ||
380 | #define MGA1064_SYS_PLL_P 0x2e | ||
381 | #define MGA1064_SYS_PLL_STAT 0x2f | ||
382 | |||
383 | #define MGA1064_REMHEADCTL 0x30 | ||
384 | #define MGA1064_REMHEADCTL_CLKDIS ( 0x01 << 0 ) | ||
385 | #define MGA1064_REMHEADCTL_CLKSL_OFF ( 0x00 << 1 ) | ||
386 | #define MGA1064_REMHEADCTL_CLKSL_PLL ( 0x01 << 1 ) | ||
387 | #define MGA1064_REMHEADCTL_CLKSL_PCI ( 0x02 << 1 ) | ||
388 | #define MGA1064_REMHEADCTL_CLKSL_MSK ( 0x03 << 1 ) | ||
389 | |||
390 | #define MGA1064_REMHEADCTL2 0x31 | ||
391 | |||
392 | #define MGA1064_ZOOM_CTL 0x38 | ||
393 | #define MGA1064_SENSE_TST 0x3a | ||
394 | |||
395 | #define MGA1064_CRC_LSB 0x3c | ||
396 | #define MGA1064_CRC_MSB 0x3d | ||
397 | #define MGA1064_CRC_CTL 0x3e | ||
398 | #define MGA1064_COL_KEY_MSK_LSB 0x40 | ||
399 | #define MGA1064_COL_KEY_MSK_MSB 0x41 | ||
400 | #define MGA1064_COL_KEY_LSB 0x42 | ||
401 | #define MGA1064_COL_KEY_MSB 0x43 | ||
402 | #define MGA1064_PIX_PLLA_M 0x44 | ||
403 | #define MGA1064_PIX_PLLA_N 0x45 | ||
404 | #define MGA1064_PIX_PLLA_P 0x46 | ||
405 | #define MGA1064_PIX_PLLB_M 0x48 | ||
406 | #define MGA1064_PIX_PLLB_N 0x49 | ||
407 | #define MGA1064_PIX_PLLB_P 0x4a | ||
408 | #define MGA1064_PIX_PLLC_M 0x4c | ||
409 | #define MGA1064_PIX_PLLC_N 0x4d | ||
410 | #define MGA1064_PIX_PLLC_P 0x4e | ||
411 | |||
412 | #define MGA1064_PIX_PLL_STAT 0x4f | ||
413 | |||
414 | /*Added for G450 dual head*/ | ||
415 | |||
416 | #define MGA1064_VID_PLL_STAT 0x8c | ||
417 | #define MGA1064_VID_PLL_P 0x8D | ||
418 | #define MGA1064_VID_PLL_M 0x8E | ||
419 | #define MGA1064_VID_PLL_N 0x8F | ||
420 | |||
421 | /* Modified PLL for G200 Winbond (G200WB) */ | ||
422 | #define MGA1064_WB_PIX_PLLC_M 0xb7 | ||
423 | #define MGA1064_WB_PIX_PLLC_N 0xb6 | ||
424 | #define MGA1064_WB_PIX_PLLC_P 0xb8 | ||
425 | |||
426 | /* Modified PLL for G200 Maxim (G200EV) */ | ||
427 | #define MGA1064_EV_PIX_PLLC_M 0xb6 | ||
428 | #define MGA1064_EV_PIX_PLLC_N 0xb7 | ||
429 | #define MGA1064_EV_PIX_PLLC_P 0xb8 | ||
430 | |||
431 | /* Modified PLL for G200 EH */ | ||
432 | #define MGA1064_EH_PIX_PLLC_M 0xb6 | ||
433 | #define MGA1064_EH_PIX_PLLC_N 0xb7 | ||
434 | #define MGA1064_EH_PIX_PLLC_P 0xb8 | ||
435 | |||
436 | /* Modified PLL for G200 Maxim (G200ER) */ | ||
437 | #define MGA1064_ER_PIX_PLLC_M 0xb7 | ||
438 | #define MGA1064_ER_PIX_PLLC_N 0xb6 | ||
439 | #define MGA1064_ER_PIX_PLLC_P 0xb8 | ||
440 | |||
441 | #define MGA1064_DISP_CTL 0x8a | ||
442 | #define MGA1064_DISP_CTL_DAC1OUTSEL_MASK 0x01 | ||
443 | #define MGA1064_DISP_CTL_DAC1OUTSEL_DIS 0x00 | ||
444 | #define MGA1064_DISP_CTL_DAC1OUTSEL_EN 0x01 | ||
445 | #define MGA1064_DISP_CTL_DAC2OUTSEL_MASK (0x03 << 2) | ||
446 | #define MGA1064_DISP_CTL_DAC2OUTSEL_DIS 0x00 | ||
447 | #define MGA1064_DISP_CTL_DAC2OUTSEL_CRTC1 (0x01 << 2) | ||
448 | #define MGA1064_DISP_CTL_DAC2OUTSEL_CRTC2 (0x02 << 2) | ||
449 | #define MGA1064_DISP_CTL_DAC2OUTSEL_TVE (0x03 << 2) | ||
450 | #define MGA1064_DISP_CTL_PANOUTSEL_MASK (0x03 << 5) | ||
451 | #define MGA1064_DISP_CTL_PANOUTSEL_DIS 0x00 | ||
452 | #define MGA1064_DISP_CTL_PANOUTSEL_CRTC1 (0x01 << 5) | ||
453 | #define MGA1064_DISP_CTL_PANOUTSEL_CRTC2RGB (0x02 << 5) | ||
454 | #define MGA1064_DISP_CTL_PANOUTSEL_CRTC2656 (0x03 << 5) | ||
455 | |||
456 | #define MGA1064_SYNC_CTL 0x8b | ||
457 | |||
458 | #define MGA1064_PWR_CTL 0xa0 | ||
459 | #define MGA1064_PWR_CTL_DAC2_EN (0x01 << 0) | ||
460 | #define MGA1064_PWR_CTL_VID_PLL_EN (0x01 << 1) | ||
461 | #define MGA1064_PWR_CTL_PANEL_EN (0x01 << 2) | ||
462 | #define MGA1064_PWR_CTL_RFIFO_EN (0x01 << 3) | ||
463 | #define MGA1064_PWR_CTL_CFIFO_EN (0x01 << 4) | ||
464 | |||
465 | #define MGA1064_PAN_CTL 0xa2 | ||
466 | |||
467 | /* Using crtc2 */ | ||
468 | #define MGAREG2_C2CTL 0x10 | ||
469 | #define MGAREG2_C2HPARAM 0x14 | ||
470 | #define MGAREG2_C2HSYNC 0x18 | ||
471 | #define MGAREG2_C2VPARAM 0x1c | ||
472 | #define MGAREG2_C2VSYNC 0x20 | ||
473 | #define MGAREG2_C2STARTADD0 0x28 | ||
474 | |||
475 | #define MGAREG2_C2OFFSET 0x40 | ||
476 | #define MGAREG2_C2DATACTL 0x4c | ||
477 | |||
478 | #define MGAREG_C2CTL 0x3c10 | ||
479 | #define MGAREG_C2CTL_C2_EN 0x01 | ||
480 | |||
481 | #define MGAREG_C2_HIPRILVL_M (0x07 << 4) | ||
482 | #define MGAREG_C2_MAXHIPRI_M (0x07 << 8) | ||
483 | |||
484 | #define MGAREG_C2CTL_PIXCLKSEL_MASK (0x03 << 1) | ||
485 | #define MGAREG_C2CTL_PIXCLKSELH_MASK (0x01 << 14) | ||
486 | #define MGAREG_C2CTL_PIXCLKSEL_PCICLK 0x00 | ||
487 | #define MGAREG_C2CTL_PIXCLKSEL_VDOCLK (0x01 << 1) | ||
488 | #define MGAREG_C2CTL_PIXCLKSEL_PIXELPLL (0x02 << 1) | ||
489 | #define MGAREG_C2CTL_PIXCLKSEL_VIDEOPLL (0x03 << 1) | ||
490 | #define MGAREG_C2CTL_PIXCLKSEL_VDCLK (0x01 << 14) | ||
491 | |||
492 | #define MGAREG_C2CTL_PIXCLKSEL_CRISTAL (0x01 << 1) | (0x01 << 14) | ||
493 | #define MGAREG_C2CTL_PIXCLKSEL_SYSTEMPLL (0x02 << 1) | (0x01 << 14) | ||
494 | |||
495 | #define MGAREG_C2CTL_PIXCLKDIS_MASK (0x01 << 3) | ||
496 | #define MGAREG_C2CTL_PIXCLKDIS_DISABLE (0x01 << 3) | ||
497 | |||
498 | #define MGAREG_C2CTL_CRTCDACSEL_MASK (0x01 << 20) | ||
499 | #define MGAREG_C2CTL_CRTCDACSEL_CRTC1 0x00 | ||
500 | #define MGAREG_C2CTL_CRTCDACSEL_CRTC2 (0x01 << 20) | ||
501 | |||
502 | #define MGAREG_C2HPARAM 0x3c14 | ||
503 | #define MGAREG_C2HSYNC 0x3c18 | ||
504 | #define MGAREG_C2VPARAM 0x3c1c | ||
505 | #define MGAREG_C2VSYNC 0x3c20 | ||
506 | #define MGAREG_C2STARTADD0 0x3c28 | ||
507 | |||
508 | #define MGAREG_C2OFFSET 0x3c40 | ||
509 | #define MGAREG_C2DATACTL 0x3c4c | ||
510 | |||
511 | /* video register */ | ||
512 | |||
513 | #define MGAREG_BESA1C3ORG 0x3d60 | ||
514 | #define MGAREG_BESA1CORG 0x3d10 | ||
515 | #define MGAREG_BESA1ORG 0x3d00 | ||
516 | #define MGAREG_BESCTL 0x3d20 | ||
517 | #define MGAREG_BESGLOBCTL 0x3dc0 | ||
518 | #define MGAREG_BESHCOORD 0x3d28 | ||
519 | #define MGAREG_BESHISCAL 0x3d30 | ||
520 | #define MGAREG_BESHSRCEND 0x3d3c | ||
521 | #define MGAREG_BESHSRCLST 0x3d50 | ||
522 | #define MGAREG_BESHSRCST 0x3d38 | ||
523 | #define MGAREG_BESLUMACTL 0x3d40 | ||
524 | #define MGAREG_BESPITCH 0x3d24 | ||
525 | #define MGAREG_BESV1SRCLST 0x3d54 | ||
526 | #define MGAREG_BESV1WGHT 0x3d48 | ||
527 | #define MGAREG_BESVCOORD 0x3d2c | ||
528 | #define MGAREG_BESVISCAL 0x3d34 | ||
529 | |||
530 | /* texture engine registers */ | ||
531 | |||
532 | #define MGAREG_TMR0 0x2c00 | ||
533 | #define MGAREG_TMR1 0x2c04 | ||
534 | #define MGAREG_TMR2 0x2c08 | ||
535 | #define MGAREG_TMR3 0x2c0c | ||
536 | #define MGAREG_TMR4 0x2c10 | ||
537 | #define MGAREG_TMR5 0x2c14 | ||
538 | #define MGAREG_TMR6 0x2c18 | ||
539 | #define MGAREG_TMR7 0x2c1c | ||
540 | #define MGAREG_TMR8 0x2c20 | ||
541 | #define MGAREG_TEXORG 0x2c24 | ||
542 | #define MGAREG_TEXWIDTH 0x2c28 | ||
543 | #define MGAREG_TEXHEIGHT 0x2c2c | ||
544 | #define MGAREG_TEXCTL 0x2c30 | ||
545 | # define MGA_TW4 (0x00000000) | ||
546 | # define MGA_TW8 (0x00000001) | ||
547 | # define MGA_TW15 (0x00000002) | ||
548 | # define MGA_TW16 (0x00000003) | ||
549 | # define MGA_TW12 (0x00000004) | ||
550 | # define MGA_TW32 (0x00000006) | ||
551 | # define MGA_TW8A (0x00000007) | ||
552 | # define MGA_TW8AL (0x00000008) | ||
553 | # define MGA_TW422 (0x0000000A) | ||
554 | # define MGA_TW422UYVY (0x0000000B) | ||
555 | # define MGA_PITCHLIN (0x00000100) | ||
556 | # define MGA_NOPERSPECTIVE (0x00200000) | ||
557 | # define MGA_TAKEY (0x02000000) | ||
558 | # define MGA_TAMASK (0x04000000) | ||
559 | # define MGA_CLAMPUV (0x18000000) | ||
560 | # define MGA_TEXMODULATE (0x20000000) | ||
561 | #define MGAREG_TEXCTL2 0x2c3c | ||
562 | # define MGA_G400_TC2_MAGIC (0x00008000) | ||
563 | # define MGA_TC2_DECALBLEND (0x00000001) | ||
564 | # define MGA_TC2_IDECAL (0x00000002) | ||
565 | # define MGA_TC2_DECALDIS (0x00000004) | ||
566 | # define MGA_TC2_CKSTRANSDIS (0x00000010) | ||
567 | # define MGA_TC2_BORDEREN (0x00000020) | ||
568 | # define MGA_TC2_SPECEN (0x00000040) | ||
569 | # define MGA_TC2_DUALTEX (0x00000080) | ||
570 | # define MGA_TC2_TABLEFOG (0x00000100) | ||
571 | # define MGA_TC2_BUMPMAP (0x00000200) | ||
572 | # define MGA_TC2_SELECT_TMU1 (0x80000000) | ||
573 | #define MGAREG_TEXTRANS 0x2c34 | ||
574 | #define MGAREG_TEXTRANSHIGH 0x2c38 | ||
575 | #define MGAREG_TEXFILTER 0x2c58 | ||
576 | # define MGA_MIN_NRST (0x00000000) | ||
577 | # define MGA_MIN_BILIN (0x00000002) | ||
578 | # define MGA_MIN_ANISO (0x0000000D) | ||
579 | # define MGA_MAG_NRST (0x00000000) | ||
580 | # define MGA_MAG_BILIN (0x00000020) | ||
581 | # define MGA_FILTERALPHA (0x00100000) | ||
582 | #define MGAREG_ALPHASTART 0x2c70 | ||
583 | #define MGAREG_ALPHAXINC 0x2c74 | ||
584 | #define MGAREG_ALPHAYINC 0x2c78 | ||
585 | #define MGAREG_ALPHACTRL 0x2c7c | ||
586 | # define MGA_SRC_ZERO (0x00000000) | ||
587 | # define MGA_SRC_ONE (0x00000001) | ||
588 | # define MGA_SRC_DST_COLOR (0x00000002) | ||
589 | # define MGA_SRC_ONE_MINUS_DST_COLOR (0x00000003) | ||
590 | # define MGA_SRC_ALPHA (0x00000004) | ||
591 | # define MGA_SRC_ONE_MINUS_SRC_ALPHA (0x00000005) | ||
592 | # define MGA_SRC_DST_ALPHA (0x00000006) | ||
593 | # define MGA_SRC_ONE_MINUS_DST_ALPHA (0x00000007) | ||
594 | # define MGA_SRC_SRC_ALPHA_SATURATE (0x00000008) | ||
595 | # define MGA_SRC_BLEND_MASK (0x0000000f) | ||
596 | # define MGA_DST_ZERO (0x00000000) | ||
597 | # define MGA_DST_ONE (0x00000010) | ||
598 | # define MGA_DST_SRC_COLOR (0x00000020) | ||
599 | # define MGA_DST_ONE_MINUS_SRC_COLOR (0x00000030) | ||
600 | # define MGA_DST_SRC_ALPHA (0x00000040) | ||
601 | # define MGA_DST_ONE_MINUS_SRC_ALPHA (0x00000050) | ||
602 | # define MGA_DST_DST_ALPHA (0x00000060) | ||
603 | # define MGA_DST_ONE_MINUS_DST_ALPHA (0x00000070) | ||
604 | # define MGA_DST_BLEND_MASK (0x00000070) | ||
605 | # define MGA_ALPHACHANNEL (0x00000100) | ||
606 | # define MGA_VIDEOALPHA (0x00000200) | ||
607 | # define MGA_DIFFUSEDALPHA (0x01000000) | ||
608 | # define MGA_MODULATEDALPHA (0x02000000) | ||
609 | #define MGAREG_TDUALSTAGE0 (0x2CF8) | ||
610 | #define MGAREG_TDUALSTAGE1 (0x2CFC) | ||
611 | # define MGA_TDS_COLOR_ARG2_DIFFUSE (0x00000000) | ||
612 | # define MGA_TDS_COLOR_ARG2_SPECULAR (0x00000001) | ||
613 | # define MGA_TDS_COLOR_ARG2_FCOL (0x00000002) | ||
614 | # define MGA_TDS_COLOR_ARG2_PREVSTAGE (0x00000003) | ||
615 | # define MGA_TDS_COLOR_ALPHA_DIFFUSE (0x00000000) | ||
616 | # define MGA_TDS_COLOR_ALPHA_FCOL (0x00000004) | ||
617 | # define MGA_TDS_COLOR_ALPHA_CURRTEX (0x00000008) | ||
618 | # define MGA_TDS_COLOR_ALPHA_PREVTEX (0x0000000c) | ||
619 | # define MGA_TDS_COLOR_ALPHA_PREVSTAGE (0x00000010) | ||
620 | # define MGA_TDS_COLOR_ARG1_REPLICATEALPHA (0x00000020) | ||
621 | # define MGA_TDS_COLOR_ARG1_INV (0x00000040) | ||
622 | # define MGA_TDS_COLOR_ARG2_REPLICATEALPHA (0x00000080) | ||
623 | # define MGA_TDS_COLOR_ARG2_INV (0x00000100) | ||
624 | # define MGA_TDS_COLOR_ALPHA1INV (0x00000200) | ||
625 | # define MGA_TDS_COLOR_ALPHA2INV (0x00000400) | ||
626 | # define MGA_TDS_COLOR_ARG1MUL_ALPHA1 (0x00000800) | ||
627 | # define MGA_TDS_COLOR_ARG2MUL_ALPHA2 (0x00001000) | ||
628 | # define MGA_TDS_COLOR_ARG1ADD_MULOUT (0x00002000) | ||
629 | # define MGA_TDS_COLOR_ARG2ADD_MULOUT (0x00004000) | ||
630 | # define MGA_TDS_COLOR_MODBRIGHT_2X (0x00008000) | ||
631 | # define MGA_TDS_COLOR_MODBRIGHT_4X (0x00010000) | ||
632 | # define MGA_TDS_COLOR_ADD_SUB (0x00000000) | ||
633 | # define MGA_TDS_COLOR_ADD_ADD (0x00020000) | ||
634 | # define MGA_TDS_COLOR_ADD2X (0x00040000) | ||
635 | # define MGA_TDS_COLOR_ADDBIAS (0x00080000) | ||
636 | # define MGA_TDS_COLOR_BLEND (0x00100000) | ||
637 | # define MGA_TDS_COLOR_SEL_ARG1 (0x00000000) | ||
638 | # define MGA_TDS_COLOR_SEL_ARG2 (0x00200000) | ||
639 | # define MGA_TDS_COLOR_SEL_ADD (0x00400000) | ||
640 | # define MGA_TDS_COLOR_SEL_MUL (0x00600000) | ||
641 | # define MGA_TDS_ALPHA_ARG1_INV (0x00800000) | ||
642 | # define MGA_TDS_ALPHA_ARG2_DIFFUSE (0x00000000) | ||
643 | # define MGA_TDS_ALPHA_ARG2_FCOL (0x01000000) | ||
644 | # define MGA_TDS_ALPHA_ARG2_PREVTEX (0x02000000) | ||
645 | # define MGA_TDS_ALPHA_ARG2_PREVSTAGE (0x03000000) | ||
646 | # define MGA_TDS_ALPHA_ARG2_INV (0x04000000) | ||
647 | # define MGA_TDS_ALPHA_ADD (0x08000000) | ||
648 | # define MGA_TDS_ALPHA_ADDBIAS (0x10000000) | ||
649 | # define MGA_TDS_ALPHA_ADD2X (0x20000000) | ||
650 | # define MGA_TDS_ALPHA_SEL_ARG1 (0x00000000) | ||
651 | # define MGA_TDS_ALPHA_SEL_ARG2 (0x40000000) | ||
652 | # define MGA_TDS_ALPHA_SEL_ADD (0x80000000) | ||
653 | # define MGA_TDS_ALPHA_SEL_MUL (0xc0000000) | ||
654 | |||
655 | #define MGAREG_DWGSYNC 0x2c4c | ||
656 | |||
657 | #define MGAREG_AGP_PLL 0x1e4c | ||
658 | #define MGA_AGP2XPLL_ENABLE 0x1 | ||
659 | #define MGA_AGP2XPLL_DISABLE 0x0 | ||
660 | |||
661 | #endif | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c new file mode 100644 index 000000000000..12264793108f --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c | |||
@@ -0,0 +1,452 @@ | |||
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 "mgag200_drv.h" | ||
30 | #include <ttm/ttm_page_alloc.h> | ||
31 | |||
32 | static inline struct mga_device * | ||
33 | mgag200_bdev(struct ttm_bo_device *bd) | ||
34 | { | ||
35 | return container_of(bd, struct mga_device, ttm.bdev); | ||
36 | } | ||
37 | |||
38 | static int | ||
39 | mgag200_ttm_mem_global_init(struct drm_global_reference *ref) | ||
40 | { | ||
41 | return ttm_mem_global_init(ref->object); | ||
42 | } | ||
43 | |||
44 | static void | ||
45 | mgag200_ttm_mem_global_release(struct drm_global_reference *ref) | ||
46 | { | ||
47 | ttm_mem_global_release(ref->object); | ||
48 | } | ||
49 | |||
50 | static int mgag200_ttm_global_init(struct mga_device *ast) | ||
51 | { | ||
52 | struct drm_global_reference *global_ref; | ||
53 | int r; | ||
54 | |||
55 | global_ref = &ast->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 = &mgag200_ttm_mem_global_init; | ||
59 | global_ref->release = &mgag200_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 | ast->ttm.bo_global_ref.mem_glob = | ||
68 | ast->ttm.mem_global_ref.object; | ||
69 | global_ref = &ast->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(&ast->ttm.mem_global_ref); | ||
78 | return r; | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | void | ||
84 | mgag200_ttm_global_release(struct mga_device *ast) | ||
85 | { | ||
86 | if (ast->ttm.mem_global_ref.release == NULL) | ||
87 | return; | ||
88 | |||
89 | drm_global_item_unref(&ast->ttm.bo_global_ref.ref); | ||
90 | drm_global_item_unref(&ast->ttm.mem_global_ref); | ||
91 | ast->ttm.mem_global_ref.release = NULL; | ||
92 | } | ||
93 | |||
94 | |||
95 | static void mgag200_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
96 | { | ||
97 | struct mgag200_bo *bo; | ||
98 | |||
99 | bo = container_of(tbo, struct mgag200_bo, bo); | ||
100 | |||
101 | drm_gem_object_release(&bo->gem); | ||
102 | kfree(bo); | ||
103 | } | ||
104 | |||
105 | bool mgag200_ttm_bo_is_mgag200_bo(struct ttm_buffer_object *bo) | ||
106 | { | ||
107 | if (bo->destroy == &mgag200_bo_ttm_destroy) | ||
108 | return true; | ||
109 | return false; | ||
110 | } | ||
111 | |||
112 | static int | ||
113 | mgag200_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 | mgag200_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
139 | { | ||
140 | struct mgag200_bo *mgabo = mgag200_bo(bo); | ||
141 | |||
142 | if (!mgag200_ttm_bo_is_mgag200_bo(bo)) | ||
143 | return; | ||
144 | |||
145 | mgag200_ttm_placement(mgabo, TTM_PL_FLAG_SYSTEM); | ||
146 | *pl = mgabo->placement; | ||
147 | } | ||
148 | |||
149 | static int mgag200_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | ||
150 | { | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int mgag200_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 mga_device *mdev = mgag200_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(mdev->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 mgag200_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | ||
184 | { | ||
185 | } | ||
186 | |||
187 | static int mgag200_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 mgag200_ttm_backend_destroy(struct ttm_tt *tt) | ||
199 | { | ||
200 | ttm_tt_fini(tt); | ||
201 | kfree(tt); | ||
202 | } | ||
203 | |||
204 | static struct ttm_backend_func mgag200_tt_backend_func = { | ||
205 | .destroy = &mgag200_ttm_backend_destroy, | ||
206 | }; | ||
207 | |||
208 | |||
209 | struct ttm_tt *mgag200_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 = &mgag200_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 mgag200_ttm_tt_populate(struct ttm_tt *ttm) | ||
227 | { | ||
228 | return ttm_pool_populate(ttm); | ||
229 | } | ||
230 | |||
231 | static void mgag200_ttm_tt_unpopulate(struct ttm_tt *ttm) | ||
232 | { | ||
233 | ttm_pool_unpopulate(ttm); | ||
234 | } | ||
235 | |||
236 | struct ttm_bo_driver mgag200_bo_driver = { | ||
237 | .ttm_tt_create = mgag200_ttm_tt_create, | ||
238 | .ttm_tt_populate = mgag200_ttm_tt_populate, | ||
239 | .ttm_tt_unpopulate = mgag200_ttm_tt_unpopulate, | ||
240 | .init_mem_type = mgag200_bo_init_mem_type, | ||
241 | .evict_flags = mgag200_bo_evict_flags, | ||
242 | .move = mgag200_bo_move, | ||
243 | .verify_access = mgag200_bo_verify_access, | ||
244 | .io_mem_reserve = &mgag200_ttm_io_mem_reserve, | ||
245 | .io_mem_free = &mgag200_ttm_io_mem_free, | ||
246 | }; | ||
247 | |||
248 | int mgag200_mm_init(struct mga_device *mdev) | ||
249 | { | ||
250 | int ret; | ||
251 | struct drm_device *dev = mdev->dev; | ||
252 | struct ttm_bo_device *bdev = &mdev->ttm.bdev; | ||
253 | |||
254 | ret = mgag200_ttm_global_init(mdev); | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | ret = ttm_bo_device_init(&mdev->ttm.bdev, | ||
259 | mdev->ttm.bo_global_ref.ref.object, | ||
260 | &mgag200_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, mdev->mc.vram_size >> PAGE_SHIFT); | ||
268 | if (ret) { | ||
269 | DRM_ERROR("Failed ttm VRAM init: %d\n", ret); | ||
270 | return ret; | ||
271 | } | ||
272 | |||
273 | mdev->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), | ||
274 | pci_resource_len(dev->pdev, 0), | ||
275 | DRM_MTRR_WC); | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | void mgag200_mm_fini(struct mga_device *mdev) | ||
281 | { | ||
282 | struct drm_device *dev = mdev->dev; | ||
283 | ttm_bo_device_release(&mdev->ttm.bdev); | ||
284 | |||
285 | mgag200_ttm_global_release(mdev); | ||
286 | |||
287 | if (mdev->fb_mtrr >= 0) { | ||
288 | drm_mtrr_del(mdev->fb_mtrr, | ||
289 | pci_resource_start(dev->pdev, 0), | ||
290 | pci_resource_len(dev->pdev, 0), DRM_MTRR_WC); | ||
291 | mdev->fb_mtrr = -1; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | void mgag200_ttm_placement(struct mgag200_bo *bo, int domain) | ||
296 | { | ||
297 | u32 c = 0; | ||
298 | bo->placement.fpfn = 0; | ||
299 | bo->placement.lpfn = 0; | ||
300 | bo->placement.placement = bo->placements; | ||
301 | bo->placement.busy_placement = bo->placements; | ||
302 | if (domain & TTM_PL_FLAG_VRAM) | ||
303 | bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; | ||
304 | if (domain & TTM_PL_FLAG_SYSTEM) | ||
305 | bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
306 | if (!c) | ||
307 | bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
308 | bo->placement.num_placement = c; | ||
309 | bo->placement.num_busy_placement = c; | ||
310 | } | ||
311 | |||
312 | int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait) | ||
313 | { | ||
314 | int ret; | ||
315 | |||
316 | ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); | ||
317 | if (ret) { | ||
318 | if (ret != -ERESTARTSYS) | ||
319 | DRM_ERROR("reserve failed %p\n", bo); | ||
320 | return ret; | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | void mgag200_bo_unreserve(struct mgag200_bo *bo) | ||
326 | { | ||
327 | ttm_bo_unreserve(&bo->bo); | ||
328 | } | ||
329 | |||
330 | int mgag200_bo_create(struct drm_device *dev, int size, int align, | ||
331 | uint32_t flags, struct mgag200_bo **pmgabo) | ||
332 | { | ||
333 | struct mga_device *mdev = dev->dev_private; | ||
334 | struct mgag200_bo *mgabo; | ||
335 | size_t acc_size; | ||
336 | int ret; | ||
337 | |||
338 | mgabo = kzalloc(sizeof(struct mgag200_bo), GFP_KERNEL); | ||
339 | if (!mgabo) | ||
340 | return -ENOMEM; | ||
341 | |||
342 | ret = drm_gem_object_init(dev, &mgabo->gem, size); | ||
343 | if (ret) { | ||
344 | kfree(mgabo); | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | mgabo->gem.driver_private = NULL; | ||
349 | mgabo->bo.bdev = &mdev->ttm.bdev; | ||
350 | |||
351 | mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
352 | |||
353 | acc_size = ttm_bo_dma_acc_size(&mdev->ttm.bdev, size, | ||
354 | sizeof(struct mgag200_bo)); | ||
355 | |||
356 | ret = ttm_bo_init(&mdev->ttm.bdev, &mgabo->bo, size, | ||
357 | ttm_bo_type_device, &mgabo->placement, | ||
358 | align >> PAGE_SHIFT, 0, false, NULL, acc_size, | ||
359 | mgag200_bo_ttm_destroy); | ||
360 | if (ret) | ||
361 | return ret; | ||
362 | |||
363 | *pmgabo = mgabo; | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static inline u64 mgag200_bo_gpu_offset(struct mgag200_bo *bo) | ||
368 | { | ||
369 | return bo->bo.offset; | ||
370 | } | ||
371 | |||
372 | int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr) | ||
373 | { | ||
374 | int i, ret; | ||
375 | |||
376 | if (bo->pin_count) { | ||
377 | bo->pin_count++; | ||
378 | if (gpu_addr) | ||
379 | *gpu_addr = mgag200_bo_gpu_offset(bo); | ||
380 | } | ||
381 | |||
382 | mgag200_ttm_placement(bo, pl_flag); | ||
383 | for (i = 0; i < bo->placement.num_placement; i++) | ||
384 | bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; | ||
385 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
386 | if (ret) | ||
387 | return ret; | ||
388 | |||
389 | bo->pin_count = 1; | ||
390 | if (gpu_addr) | ||
391 | *gpu_addr = mgag200_bo_gpu_offset(bo); | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | int mgag200_bo_unpin(struct mgag200_bo *bo) | ||
396 | { | ||
397 | int i, ret; | ||
398 | if (!bo->pin_count) { | ||
399 | DRM_ERROR("unpin bad %p\n", bo); | ||
400 | return 0; | ||
401 | } | ||
402 | bo->pin_count--; | ||
403 | if (bo->pin_count) | ||
404 | return 0; | ||
405 | |||
406 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
407 | bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; | ||
408 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
409 | if (ret) | ||
410 | return ret; | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | int mgag200_bo_push_sysram(struct mgag200_bo *bo) | ||
416 | { | ||
417 | int i, ret; | ||
418 | if (!bo->pin_count) { | ||
419 | DRM_ERROR("unpin bad %p\n", bo); | ||
420 | return 0; | ||
421 | } | ||
422 | bo->pin_count--; | ||
423 | if (bo->pin_count) | ||
424 | return 0; | ||
425 | |||
426 | if (bo->kmap.virtual) | ||
427 | ttm_bo_kunmap(&bo->kmap); | ||
428 | |||
429 | mgag200_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); | ||
430 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
431 | bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; | ||
432 | |||
433 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
434 | if (ret) { | ||
435 | DRM_ERROR("pushing to VRAM failed\n"); | ||
436 | return ret; | ||
437 | } | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | int mgag200_mmap(struct file *filp, struct vm_area_struct *vma) | ||
442 | { | ||
443 | struct drm_file *file_priv; | ||
444 | struct mga_device *mdev; | ||
445 | |||
446 | if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) | ||
447 | return drm_mmap(filp, vma); | ||
448 | |||
449 | file_priv = filp->private_data; | ||
450 | mdev = file_priv->minor->dev->dev_private; | ||
451 | return ttm_bo_mmap(filp, vma, &mdev->ttm.bdev); | ||
452 | } | ||