aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/mgag200/mgag200_main.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-04-17 10:01:25 -0400
committerDave Airlie <airlied@redhat.com>2012-05-17 05:53:41 -0400
commit414c453106255b11df77ed6b08eedb6d2369c338 (patch)
treea09841da5c2d99c56cf1e848809c246a4008f358 /drivers/gpu/drm/mgag200/mgag200_main.c
parent312fec1405dd546ddb3fa6387d54e78f604dd8f8 (diff)
mgag200: initial g200se driver (v2)
This is a driver for the G200 server engines chips, it doesn't driver any of the Matrix G series desktop cards. It will bind to G200 SE A,B, G200EV, G200WB, G200EH and G200ER cards. Its based on previous work done my Matthew Garrett but remodelled to follow the same style and flow as the AST server driver. It also works along the same lines as the AST server driver wrt memory management. There is no userspace driver planned, xf86-video-modesetting should be used. It also appears these GPUs have no ARGB hw cursors. v2: add missing tagfifo reset + G200 SE memory bw setup pieces. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/mgag200/mgag200_main.c')
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c388
1 files changed, 388 insertions, 0 deletions
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
18static 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
27static 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
34static const struct drm_framebuffer_funcs mga_fb_funcs = {
35 .destroy = mga_user_framebuffer_destroy,
36 .create_handle = mga_user_framebuffer_create_handle,
37};
38
39int 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
54static struct drm_framebuffer *
55mgag200_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
82static 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 */
87static 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
95static 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 */
133static 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
163static 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
208void 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
220int 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);
250out:
251 if (r)
252 mgag200_driver_unload(dev);
253 return r;
254}
255
256int 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
272int 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
295int 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
320int 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
327int mgag200_gem_init_object(struct drm_gem_object *obj)
328{
329 BUG();
330 return 0;
331}
332
333void 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
347void 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
357static inline u64 mgag200_bo_mmap_offset(struct mgag200_bo *bo)
358{
359 return bo->bo.addr_space_offset;
360}
361
362int
363mgag200_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;
384out_unlock:
385 mutex_unlock(&dev->struct_mutex);
386 return ret;
387
388}