drm/ast: add widescreen + rb modes from X.org driver (v2)
[deliverable/linux.git] / drivers / gpu / drm / ast / ast_main.c
CommitLineData
312fec14
DA
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 */
760285e7 28#include <drm/drmP.h>
312fec14
DA
29#include "ast_drv.h"
30
31
760285e7
DH
32#include <drm/drm_fb_helper.h>
33#include <drm/drm_crtc_helper.h>
312fec14
DA
34
35#include "ast_dram_tables.h"
36
37void ast_set_index_reg_mask(struct ast_private *ast,
38 uint32_t base, uint8_t index,
39 uint8_t mask, uint8_t val)
40{
41 u8 tmp;
42 ast_io_write8(ast, base, index);
43 tmp = (ast_io_read8(ast, base + 1) & mask) | val;
44 ast_set_index_reg(ast, base, index, tmp);
45}
46
47uint8_t ast_get_index_reg(struct ast_private *ast,
48 uint32_t base, uint8_t index)
49{
50 uint8_t ret;
51 ast_io_write8(ast, base, index);
52 ret = ast_io_read8(ast, base + 1);
53 return ret;
54}
55
56uint8_t ast_get_index_reg_mask(struct ast_private *ast,
57 uint32_t base, uint8_t index, uint8_t mask)
58{
59 uint8_t ret;
60 ast_io_write8(ast, base, index);
61 ret = ast_io_read8(ast, base + 1) & mask;
62 return ret;
63}
64
65
66static int ast_detect_chip(struct drm_device *dev)
67{
68 struct ast_private *ast = dev->dev_private;
f1f62f2c 69 uint32_t data, jreg;
312fec14
DA
70
71 if (dev->pdev->device == PCI_CHIP_AST1180) {
72 ast->chip = AST1100;
73 DRM_INFO("AST 1180 detected\n");
74 } else {
75 if (dev->pdev->revision >= 0x20) {
76 ast->chip = AST2300;
77 DRM_INFO("AST 2300 detected\n");
78 } else if (dev->pdev->revision >= 0x10) {
79 uint32_t data;
80 ast_write32(ast, 0xf004, 0x1e6e0000);
81 ast_write32(ast, 0xf000, 0x1);
82
83 data = ast_read32(ast, 0x1207c);
84 switch (data & 0x0300) {
85 case 0x0200:
86 ast->chip = AST1100;
87 DRM_INFO("AST 1100 detected\n");
88 break;
89 case 0x0100:
90 ast->chip = AST2200;
91 DRM_INFO("AST 2200 detected\n");
92 break;
93 case 0x0000:
94 ast->chip = AST2150;
95 DRM_INFO("AST 2150 detected\n");
96 break;
97 default:
98 ast->chip = AST2100;
99 DRM_INFO("AST 2100 detected\n");
100 break;
101 }
102 ast->vga2_clone = false;
103 } else {
104 ast->chip = 2000;
105 DRM_INFO("AST 2000 detected\n");
106 }
107 }
f1f62f2c
DA
108
109 switch (ast->chip) {
110 case AST1180:
111 ast->support_wide_screen = true;
112 break;
113 case AST2000:
114 ast->support_wide_screen = false;
115 break;
116 default:
117 jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
118 if (!(jreg & 0x80))
119 ast->support_wide_screen = true;
120 else if (jreg & 0x01)
121 ast->support_wide_screen = true;
122 else {
123 ast->support_wide_screen = false;
124 if (ast->chip == AST2300) {
125 ast_write32(ast, 0xf004, 0x1e6e0000);
126 ast_write32(ast, 0xf000, 0x1);
127 data = ast_read32(ast, 0x1207c);
128 if ((data & 0x300) == 0) /* ast1300 */
129 ast->support_wide_screen = true;
130 }
131 }
132 break;
133 }
134
312fec14
DA
135 return 0;
136}
137
138static int ast_get_dram_info(struct drm_device *dev)
139{
140 struct ast_private *ast = dev->dev_private;
141 uint32_t data, data2;
142 uint32_t denum, num, div, ref_pll;
143
144 ast_write32(ast, 0xf004, 0x1e6e0000);
145 ast_write32(ast, 0xf000, 0x1);
146
147
148 ast_write32(ast, 0x10000, 0xfc600309);
149
150 do {
151 ;
152 } while (ast_read32(ast, 0x10000) != 0x01);
153 data = ast_read32(ast, 0x10004);
154
155 if (data & 0x400)
156 ast->dram_bus_width = 16;
157 else
158 ast->dram_bus_width = 32;
159
160 if (ast->chip == AST2300) {
161 switch (data & 0x03) {
162 case 0:
163 ast->dram_type = AST_DRAM_512Mx16;
164 break;
165 default:
166 case 1:
167 ast->dram_type = AST_DRAM_1Gx16;
168 break;
169 case 2:
170 ast->dram_type = AST_DRAM_2Gx16;
171 break;
172 case 3:
173 ast->dram_type = AST_DRAM_4Gx16;
174 break;
175 }
176 } else {
177 switch (data & 0x0c) {
178 case 0:
179 case 4:
180 ast->dram_type = AST_DRAM_512Mx16;
181 break;
182 case 8:
183 if (data & 0x40)
184 ast->dram_type = AST_DRAM_1Gx16;
185 else
186 ast->dram_type = AST_DRAM_512Mx32;
187 break;
188 case 0xc:
189 ast->dram_type = AST_DRAM_1Gx32;
190 break;
191 }
192 }
193
194 data = ast_read32(ast, 0x10120);
195 data2 = ast_read32(ast, 0x10170);
196 if (data2 & 0x2000)
197 ref_pll = 14318;
198 else
199 ref_pll = 12000;
200
201 denum = data & 0x1f;
202 num = (data & 0x3fe0) >> 5;
203 data = (data & 0xc000) >> 14;
204 switch (data) {
205 case 3:
206 div = 0x4;
207 break;
208 case 2:
209 case 1:
210 div = 0x2;
211 break;
212 default:
213 div = 0x1;
214 break;
215 }
216 ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000);
217 return 0;
218}
219
312fec14
DA
220static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb)
221{
222 struct ast_framebuffer *ast_fb = to_ast_framebuffer(fb);
223 if (ast_fb->obj)
224 drm_gem_object_unreference_unlocked(ast_fb->obj);
225
226 drm_framebuffer_cleanup(fb);
227 kfree(fb);
228}
229
312fec14
DA
230static const struct drm_framebuffer_funcs ast_fb_funcs = {
231 .destroy = ast_user_framebuffer_destroy,
312fec14
DA
232};
233
234
235int ast_framebuffer_init(struct drm_device *dev,
236 struct ast_framebuffer *ast_fb,
237 struct drm_mode_fb_cmd2 *mode_cmd,
238 struct drm_gem_object *obj)
239{
240 int ret;
241
c7d73f6a
DV
242 drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
243 ast_fb->obj = obj;
312fec14
DA
244 ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs);
245 if (ret) {
246 DRM_ERROR("framebuffer init failed %d\n", ret);
247 return ret;
248 }
312fec14
DA
249 return 0;
250}
251
252static struct drm_framebuffer *
253ast_user_framebuffer_create(struct drm_device *dev,
254 struct drm_file *filp,
255 struct drm_mode_fb_cmd2 *mode_cmd)
256{
257 struct drm_gem_object *obj;
258 struct ast_framebuffer *ast_fb;
259 int ret;
260
261 obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
262 if (obj == NULL)
263 return ERR_PTR(-ENOENT);
264
265 ast_fb = kzalloc(sizeof(*ast_fb), GFP_KERNEL);
266 if (!ast_fb) {
267 drm_gem_object_unreference_unlocked(obj);
268 return ERR_PTR(-ENOMEM);
269 }
270
271 ret = ast_framebuffer_init(dev, ast_fb, mode_cmd, obj);
272 if (ret) {
273 drm_gem_object_unreference_unlocked(obj);
274 kfree(ast_fb);
275 return ERR_PTR(ret);
276 }
277 return &ast_fb->base;
278}
279
280static const struct drm_mode_config_funcs ast_mode_funcs = {
281 .fb_create = ast_user_framebuffer_create,
282};
283
284static u32 ast_get_vram_info(struct drm_device *dev)
285{
286 struct ast_private *ast = dev->dev_private;
287 u8 jreg;
288
289 ast_open_key(ast);
290
291 jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff);
292 switch (jreg & 3) {
293 case 0: return AST_VIDMEM_SIZE_8M;
294 case 1: return AST_VIDMEM_SIZE_16M;
295 case 2: return AST_VIDMEM_SIZE_32M;
296 case 3: return AST_VIDMEM_SIZE_64M;
297 }
298 return AST_VIDMEM_DEFAULT_SIZE;
299}
300
301int ast_driver_load(struct drm_device *dev, unsigned long flags)
302{
303 struct ast_private *ast;
304 int ret = 0;
305
306 ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
307 if (!ast)
308 return -ENOMEM;
309
310 dev->dev_private = ast;
311 ast->dev = dev;
312
313 ast->regs = pci_iomap(dev->pdev, 1, 0);
314 if (!ast->regs) {
315 ret = -EIO;
316 goto out_free;
317 }
318 ast->ioregs = pci_iomap(dev->pdev, 2, 0);
319 if (!ast->ioregs) {
320 ret = -EIO;
321 goto out_free;
322 }
323
324 ast_detect_chip(dev);
325
326 if (ast->chip != AST1180) {
327 ast_get_dram_info(dev);
328 ast->vram_size = ast_get_vram_info(dev);
329 DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size);
330 }
331
332 ret = ast_mm_init(ast);
333 if (ret)
334 goto out_free;
335
336 drm_mode_config_init(dev);
337
338 dev->mode_config.funcs = (void *)&ast_mode_funcs;
339 dev->mode_config.min_width = 0;
340 dev->mode_config.min_height = 0;
341 dev->mode_config.preferred_depth = 24;
342 dev->mode_config.prefer_shadow = 1;
343
344 if (ast->chip == AST2100 ||
345 ast->chip == AST2200 ||
346 ast->chip == AST2300 ||
347 ast->chip == AST1180) {
348 dev->mode_config.max_width = 1920;
349 dev->mode_config.max_height = 2048;
350 } else {
351 dev->mode_config.max_width = 1600;
352 dev->mode_config.max_height = 1200;
353 }
354
355 ret = ast_mode_init(dev);
356 if (ret)
357 goto out_free;
358
359 ret = ast_fbdev_init(dev);
360 if (ret)
361 goto out_free;
362
363 return 0;
364out_free:
365 kfree(ast);
366 dev->dev_private = NULL;
367 return ret;
368}
369
370int ast_driver_unload(struct drm_device *dev)
371{
372 struct ast_private *ast = dev->dev_private;
373
374 ast_mode_fini(dev);
375 ast_fbdev_fini(dev);
376 drm_mode_config_cleanup(dev);
377
378 ast_mm_fini(ast);
379 pci_iounmap(dev->pdev, ast->ioregs);
380 pci_iounmap(dev->pdev, ast->regs);
381 kfree(ast);
382 return 0;
383}
384
385int ast_gem_create(struct drm_device *dev,
386 u32 size, bool iskernel,
387 struct drm_gem_object **obj)
388{
389 struct ast_bo *astbo;
390 int ret;
391
392 *obj = NULL;
393
394 size = roundup(size, PAGE_SIZE);
395 if (size == 0)
396 return -EINVAL;
397
398 ret = ast_bo_create(dev, size, 0, 0, &astbo);
399 if (ret) {
400 if (ret != -ERESTARTSYS)
401 DRM_ERROR("failed to allocate GEM object\n");
402 return ret;
403 }
404 *obj = &astbo->gem;
405 return 0;
406}
407
408int ast_dumb_create(struct drm_file *file,
409 struct drm_device *dev,
410 struct drm_mode_create_dumb *args)
411{
412 int ret;
413 struct drm_gem_object *gobj;
414 u32 handle;
415
416 args->pitch = args->width * ((args->bpp + 7) / 8);
417 args->size = args->pitch * args->height;
418
419 ret = ast_gem_create(dev, args->size, false,
420 &gobj);
421 if (ret)
422 return ret;
423
424 ret = drm_gem_handle_create(file, gobj, &handle);
425 drm_gem_object_unreference_unlocked(gobj);
426 if (ret)
427 return ret;
428
429 args->handle = handle;
430 return 0;
431}
432
f6109803 433static void ast_bo_unref(struct ast_bo **bo)
312fec14
DA
434{
435 struct ttm_buffer_object *tbo;
436
437 if ((*bo) == NULL)
438 return;
439
440 tbo = &((*bo)->bo);
441 ttm_bo_unref(&tbo);
442 if (tbo == NULL)
443 *bo = NULL;
444
445}
446void ast_gem_free_object(struct drm_gem_object *obj)
447{
448 struct ast_bo *ast_bo = gem_to_ast_bo(obj);
449
450 if (!ast_bo)
451 return;
452 ast_bo_unref(&ast_bo);
453}
454
455
456static inline u64 ast_bo_mmap_offset(struct ast_bo *bo)
457{
72525b3f 458 return drm_vma_node_offset_addr(&bo->bo.vma_node);
312fec14
DA
459}
460int
461ast_dumb_mmap_offset(struct drm_file *file,
462 struct drm_device *dev,
463 uint32_t handle,
464 uint64_t *offset)
465{
466 struct drm_gem_object *obj;
467 int ret;
468 struct ast_bo *bo;
469
470 mutex_lock(&dev->struct_mutex);
471 obj = drm_gem_object_lookup(dev, file, handle);
472 if (obj == NULL) {
473 ret = -ENOENT;
474 goto out_unlock;
475 }
476
477 bo = gem_to_ast_bo(obj);
478 *offset = ast_bo_mmap_offset(bo);
479
480 drm_gem_object_unreference(obj);
481 ret = 0;
482out_unlock:
483 mutex_unlock(&dev->struct_mutex);
484 return ret;
485
486}
487
This page took 0.133696 seconds and 5 git commands to generate.