aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/ast/ast_main.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-02-29 08:40:04 -0500
committerDave Airlie <airlied@redhat.com>2012-05-17 05:53:37 -0400
commit312fec1405dd546ddb3fa6387d54e78f604dd8f8 (patch)
tree83bbeed68d15aba65a326fff1846472a045ae76e /drivers/gpu/drm/ast/ast_main.c
parentdb2e034d2c55e1f273ed820cc3edcdbc73d0292c (diff)
drm: Initial KMS driver for AST (ASpeed Technologies) 2000 series (v2)
This is the initial driver for the Aspeed Technologies chips found in servers. This driver supports the AST 2000, 2100, 2200, 2150 and 2300. It doesn't support the AST11xx due to lack of hw to test it on, and them requiring different codepaths. This driver is intended to be used with xf86-video-modesetting in userspace. This driver has a slightly different design than other KMS drivers, but future server chips will probably share similiar setup. As these GPUs commonly have low video RAM, it doesn't make sense to put the kms console in VRAM always. This driver places the kms console into system RAM, and does dirty updates to a copy in video RAM. When userspace sets a new scanout buffer, it forcefully evicts the video RAM console, and X can create a framebuffer that can use all of of video RAM. This driver uses TTM but in a very simple fashion to control the eviction to system RAM of the console, and multiple servers. v2: add s/r support, fix Kconfig. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/ast/ast_main.c')
-rw-r--r--drivers/gpu/drm/ast/ast_main.c527
1 files changed, 527 insertions, 0 deletions
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
new file mode 100644
index 000000000000..95ae55b8214b
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -0,0 +1,527 @@
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 "ast_drv.h"
30
31
32#include "drm_fb_helper.h"
33#include "drm_crtc_helper.h"
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;
69
70 if (dev->pdev->device == PCI_CHIP_AST1180) {
71 ast->chip = AST1100;
72 DRM_INFO("AST 1180 detected\n");
73 } else {
74 if (dev->pdev->revision >= 0x20) {
75 ast->chip = AST2300;
76 DRM_INFO("AST 2300 detected\n");
77 } else if (dev->pdev->revision >= 0x10) {
78 uint32_t data;
79 ast_write32(ast, 0xf004, 0x1e6e0000);
80 ast_write32(ast, 0xf000, 0x1);
81
82 data = ast_read32(ast, 0x1207c);
83 switch (data & 0x0300) {
84 case 0x0200:
85 ast->chip = AST1100;
86 DRM_INFO("AST 1100 detected\n");
87 break;
88 case 0x0100:
89 ast->chip = AST2200;
90 DRM_INFO("AST 2200 detected\n");
91 break;
92 case 0x0000:
93 ast->chip = AST2150;
94 DRM_INFO("AST 2150 detected\n");
95 break;
96 default:
97 ast->chip = AST2100;
98 DRM_INFO("AST 2100 detected\n");
99 break;
100 }
101 ast->vga2_clone = false;
102 } else {
103 ast->chip = 2000;
104 DRM_INFO("AST 2000 detected\n");
105 }
106 }
107 return 0;
108}
109
110static int ast_get_dram_info(struct drm_device *dev)
111{
112 struct ast_private *ast = dev->dev_private;
113 uint32_t data, data2;
114 uint32_t denum, num, div, ref_pll;
115
116 ast_write32(ast, 0xf004, 0x1e6e0000);
117 ast_write32(ast, 0xf000, 0x1);
118
119
120 ast_write32(ast, 0x10000, 0xfc600309);
121
122 do {
123 ;
124 } while (ast_read32(ast, 0x10000) != 0x01);
125 data = ast_read32(ast, 0x10004);
126
127 if (data & 0x400)
128 ast->dram_bus_width = 16;
129 else
130 ast->dram_bus_width = 32;
131
132 if (ast->chip == AST2300) {
133 switch (data & 0x03) {
134 case 0:
135 ast->dram_type = AST_DRAM_512Mx16;
136 break;
137 default:
138 case 1:
139 ast->dram_type = AST_DRAM_1Gx16;
140 break;
141 case 2:
142 ast->dram_type = AST_DRAM_2Gx16;
143 break;
144 case 3:
145 ast->dram_type = AST_DRAM_4Gx16;
146 break;
147 }
148 } else {
149 switch (data & 0x0c) {
150 case 0:
151 case 4:
152 ast->dram_type = AST_DRAM_512Mx16;
153 break;
154 case 8:
155 if (data & 0x40)
156 ast->dram_type = AST_DRAM_1Gx16;
157 else
158 ast->dram_type = AST_DRAM_512Mx32;
159 break;
160 case 0xc:
161 ast->dram_type = AST_DRAM_1Gx32;
162 break;
163 }
164 }
165
166 data = ast_read32(ast, 0x10120);
167 data2 = ast_read32(ast, 0x10170);
168 if (data2 & 0x2000)
169 ref_pll = 14318;
170 else
171 ref_pll = 12000;
172
173 denum = data & 0x1f;
174 num = (data & 0x3fe0) >> 5;
175 data = (data & 0xc000) >> 14;
176 switch (data) {
177 case 3:
178 div = 0x4;
179 break;
180 case 2:
181 case 1:
182 div = 0x2;
183 break;
184 default:
185 div = 0x1;
186 break;
187 }
188 ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000);
189 return 0;
190}
191
192uint32_t ast_get_max_dclk(struct drm_device *dev, int bpp)
193{
194 struct ast_private *ast = dev->dev_private;
195 uint32_t dclk, jreg;
196 uint32_t dram_bus_width, mclk, dram_bandwidth, actual_dram_bandwidth, dram_efficency = 500;
197
198 dram_bus_width = ast->dram_bus_width;
199 mclk = ast->mclk;
200
201 if (ast->chip == AST2100 ||
202 ast->chip == AST1100 ||
203 ast->chip == AST2200 ||
204 ast->chip == AST2150 ||
205 ast->dram_bus_width == 16)
206 dram_efficency = 600;
207 else if (ast->chip == AST2300)
208 dram_efficency = 400;
209
210 dram_bandwidth = mclk * dram_bus_width * 2 / 8;
211 actual_dram_bandwidth = dram_bandwidth * dram_efficency / 1000;
212
213 if (ast->chip == AST1180)
214 dclk = actual_dram_bandwidth / ((bpp + 1) / 8);
215 else {
216 jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
217 if ((jreg & 0x08) && (ast->chip == AST2000))
218 dclk = actual_dram_bandwidth / ((bpp + 1 + 16) / 8);
219 else if ((jreg & 0x08) && (bpp == 8))
220 dclk = actual_dram_bandwidth / ((bpp + 1 + 24) / 8);
221 else
222 dclk = actual_dram_bandwidth / ((bpp + 1) / 8);
223 }
224
225 if (ast->chip == AST2100 ||
226 ast->chip == AST2200 ||
227 ast->chip == AST2300 ||
228 ast->chip == AST1180) {
229 if (dclk > 200)
230 dclk = 200;
231 } else {
232 if (dclk > 165)
233 dclk = 165;
234 }
235
236 return dclk;
237}
238
239static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb)
240{
241 struct ast_framebuffer *ast_fb = to_ast_framebuffer(fb);
242 if (ast_fb->obj)
243 drm_gem_object_unreference_unlocked(ast_fb->obj);
244
245 drm_framebuffer_cleanup(fb);
246 kfree(fb);
247}
248
249static int ast_user_framebuffer_create_handle(struct drm_framebuffer *fb,
250 struct drm_file *file,
251 unsigned int *handle)
252{
253 return -EINVAL;
254}
255
256static const struct drm_framebuffer_funcs ast_fb_funcs = {
257 .destroy = ast_user_framebuffer_destroy,
258 .create_handle = ast_user_framebuffer_create_handle,
259};
260
261
262int ast_framebuffer_init(struct drm_device *dev,
263 struct ast_framebuffer *ast_fb,
264 struct drm_mode_fb_cmd2 *mode_cmd,
265 struct drm_gem_object *obj)
266{
267 int ret;
268
269 ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs);
270 if (ret) {
271 DRM_ERROR("framebuffer init failed %d\n", ret);
272 return ret;
273 }
274 drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
275 ast_fb->obj = obj;
276 return 0;
277}
278
279static struct drm_framebuffer *
280ast_user_framebuffer_create(struct drm_device *dev,
281 struct drm_file *filp,
282 struct drm_mode_fb_cmd2 *mode_cmd)
283{
284 struct drm_gem_object *obj;
285 struct ast_framebuffer *ast_fb;
286 int ret;
287
288 obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
289 if (obj == NULL)
290 return ERR_PTR(-ENOENT);
291
292 ast_fb = kzalloc(sizeof(*ast_fb), GFP_KERNEL);
293 if (!ast_fb) {
294 drm_gem_object_unreference_unlocked(obj);
295 return ERR_PTR(-ENOMEM);
296 }
297
298 ret = ast_framebuffer_init(dev, ast_fb, mode_cmd, obj);
299 if (ret) {
300 drm_gem_object_unreference_unlocked(obj);
301 kfree(ast_fb);
302 return ERR_PTR(ret);
303 }
304 return &ast_fb->base;
305}
306
307static const struct drm_mode_config_funcs ast_mode_funcs = {
308 .fb_create = ast_user_framebuffer_create,
309};
310
311static u32 ast_get_vram_info(struct drm_device *dev)
312{
313 struct ast_private *ast = dev->dev_private;
314 u8 jreg;
315
316 ast_open_key(ast);
317
318 jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff);
319 switch (jreg & 3) {
320 case 0: return AST_VIDMEM_SIZE_8M;
321 case 1: return AST_VIDMEM_SIZE_16M;
322 case 2: return AST_VIDMEM_SIZE_32M;
323 case 3: return AST_VIDMEM_SIZE_64M;
324 }
325 return AST_VIDMEM_DEFAULT_SIZE;
326}
327
328int ast_driver_load(struct drm_device *dev, unsigned long flags)
329{
330 struct ast_private *ast;
331 int ret = 0;
332
333 ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
334 if (!ast)
335 return -ENOMEM;
336
337 dev->dev_private = ast;
338 ast->dev = dev;
339
340 ast->regs = pci_iomap(dev->pdev, 1, 0);
341 if (!ast->regs) {
342 ret = -EIO;
343 goto out_free;
344 }
345 ast->ioregs = pci_iomap(dev->pdev, 2, 0);
346 if (!ast->ioregs) {
347 ret = -EIO;
348 goto out_free;
349 }
350
351 ast_detect_chip(dev);
352
353 if (ast->chip != AST1180) {
354 ast_get_dram_info(dev);
355 ast->vram_size = ast_get_vram_info(dev);
356 DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size);
357 }
358
359 ret = ast_mm_init(ast);
360 if (ret)
361 goto out_free;
362
363 drm_mode_config_init(dev);
364
365 dev->mode_config.funcs = (void *)&ast_mode_funcs;
366 dev->mode_config.min_width = 0;
367 dev->mode_config.min_height = 0;
368 dev->mode_config.preferred_depth = 24;
369 dev->mode_config.prefer_shadow = 1;
370
371 if (ast->chip == AST2100 ||
372 ast->chip == AST2200 ||
373 ast->chip == AST2300 ||
374 ast->chip == AST1180) {
375 dev->mode_config.max_width = 1920;
376 dev->mode_config.max_height = 2048;
377 } else {
378 dev->mode_config.max_width = 1600;
379 dev->mode_config.max_height = 1200;
380 }
381
382 ret = ast_mode_init(dev);
383 if (ret)
384 goto out_free;
385
386 ret = ast_fbdev_init(dev);
387 if (ret)
388 goto out_free;
389
390 return 0;
391out_free:
392 kfree(ast);
393 dev->dev_private = NULL;
394 return ret;
395}
396
397int ast_driver_unload(struct drm_device *dev)
398{
399 struct ast_private *ast = dev->dev_private;
400
401 ast_mode_fini(dev);
402 ast_fbdev_fini(dev);
403 drm_mode_config_cleanup(dev);
404
405 ast_mm_fini(ast);
406 pci_iounmap(dev->pdev, ast->ioregs);
407 pci_iounmap(dev->pdev, ast->regs);
408 kfree(ast);
409 return 0;
410}
411
412int ast_gem_create(struct drm_device *dev,
413 u32 size, bool iskernel,
414 struct drm_gem_object **obj)
415{
416 struct ast_bo *astbo;
417 int ret;
418
419 *obj = NULL;
420
421 size = roundup(size, PAGE_SIZE);
422 if (size == 0)
423 return -EINVAL;
424
425 ret = ast_bo_create(dev, size, 0, 0, &astbo);
426 if (ret) {
427 if (ret != -ERESTARTSYS)
428 DRM_ERROR("failed to allocate GEM object\n");
429 return ret;
430 }
431 *obj = &astbo->gem;
432 return 0;
433}
434
435int ast_dumb_create(struct drm_file *file,
436 struct drm_device *dev,
437 struct drm_mode_create_dumb *args)
438{
439 int ret;
440 struct drm_gem_object *gobj;
441 u32 handle;
442
443 args->pitch = args->width * ((args->bpp + 7) / 8);
444 args->size = args->pitch * args->height;
445
446 ret = ast_gem_create(dev, args->size, false,
447 &gobj);
448 if (ret)
449 return ret;
450
451 ret = drm_gem_handle_create(file, gobj, &handle);
452 drm_gem_object_unreference_unlocked(gobj);
453 if (ret)
454 return ret;
455
456 args->handle = handle;
457 return 0;
458}
459
460int ast_dumb_destroy(struct drm_file *file,
461 struct drm_device *dev,
462 uint32_t handle)
463{
464 return drm_gem_handle_delete(file, handle);
465}
466
467int ast_gem_init_object(struct drm_gem_object *obj)
468{
469 BUG();
470 return 0;
471}
472
473void ast_bo_unref(struct ast_bo **bo)
474{
475 struct ttm_buffer_object *tbo;
476
477 if ((*bo) == NULL)
478 return;
479
480 tbo = &((*bo)->bo);
481 ttm_bo_unref(&tbo);
482 if (tbo == NULL)
483 *bo = NULL;
484
485}
486void ast_gem_free_object(struct drm_gem_object *obj)
487{
488 struct ast_bo *ast_bo = gem_to_ast_bo(obj);
489
490 if (!ast_bo)
491 return;
492 ast_bo_unref(&ast_bo);
493}
494
495
496static inline u64 ast_bo_mmap_offset(struct ast_bo *bo)
497{
498 return bo->bo.addr_space_offset;
499}
500int
501ast_dumb_mmap_offset(struct drm_file *file,
502 struct drm_device *dev,
503 uint32_t handle,
504 uint64_t *offset)
505{
506 struct drm_gem_object *obj;
507 int ret;
508 struct ast_bo *bo;
509
510 mutex_lock(&dev->struct_mutex);
511 obj = drm_gem_object_lookup(dev, file, handle);
512 if (obj == NULL) {
513 ret = -ENOENT;
514 goto out_unlock;
515 }
516
517 bo = gem_to_ast_bo(obj);
518 *offset = ast_bo_mmap_offset(bo);
519
520 drm_gem_object_unreference(obj);
521 ret = 0;
522out_unlock:
523 mutex_unlock(&dev->struct_mutex);
524 return ret;
525
526}
527