aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/r600_cp.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2009-09-07 20:10:24 -0400
committerDave Airlie <airlied@redhat.com>2009-09-07 21:15:52 -0400
commit3ce0a23d2d253185df24e22e3d5f89800bb3dd1c (patch)
tree4b4defdbe33aec7317101cce0f89c33083f8d17b /drivers/gpu/drm/radeon/r600_cp.c
parent4ce001abafafe77e5dd943d1480fc9f87894e96f (diff)
drm/radeon/kms: add r600 KMS support
This adds the r600 KMS + CS support to the Linux kernel. The r600 TTM support is quite basic and still needs more work esp around using interrupts, but the polled fencing should work okay for now. Also currently TTM is using memcpy to do VRAM moves, the code is here to use a 3D blit to do this, but isn't fully debugged yet. Authors: Alex Deucher <alexdeucher@gmail.com> Dave Airlie <airlied@redhat.com> Jerome Glisse <jglisse@redhat.com> Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/r600_cp.c')
-rw-r--r--drivers/gpu/drm/radeon/r600_cp.c252
1 files changed, 248 insertions, 4 deletions
diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c
index 8327912de964..6d5a711c2e91 100644
--- a/drivers/gpu/drm/radeon/r600_cp.c
+++ b/drivers/gpu/drm/radeon/r600_cp.c
@@ -58,6 +58,12 @@ MODULE_FIRMWARE("radeon/RV730_me.bin");
58MODULE_FIRMWARE("radeon/RV710_pfp.bin"); 58MODULE_FIRMWARE("radeon/RV710_pfp.bin");
59MODULE_FIRMWARE("radeon/RV710_me.bin"); 59MODULE_FIRMWARE("radeon/RV710_me.bin");
60 60
61
62int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
63 unsigned family, u32 *ib, int *l);
64void r600_cs_legacy_init(void);
65
66
61# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ 67# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
62# define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1)) 68# define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1))
63 69
@@ -1857,6 +1863,8 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
1857 1863
1858 DRM_DEBUG("\n"); 1864 DRM_DEBUG("\n");
1859 1865
1866 mutex_init(&dev_priv->cs_mutex);
1867 r600_cs_legacy_init();
1860 /* if we require new memory map but we don't have it fail */ 1868 /* if we require new memory map but we don't have it fail */
1861 if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) { 1869 if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
1862 DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n"); 1870 DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
@@ -1888,7 +1896,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
1888 /* Enable vblank on CRTC1 for older X servers 1896 /* Enable vblank on CRTC1 for older X servers
1889 */ 1897 */
1890 dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1; 1898 dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;
1891 1899 dev_priv->do_boxes = 0;
1892 dev_priv->cp_mode = init->cp_mode; 1900 dev_priv->cp_mode = init->cp_mode;
1893 1901
1894 /* We don't support anything other than bus-mastering ring mode, 1902 /* We don't support anything other than bus-mastering ring mode,
@@ -1974,11 +1982,11 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
1974 } else 1982 } else
1975#endif 1983#endif
1976 { 1984 {
1977 dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset; 1985 dev_priv->cp_ring->handle = (void *)(unsigned long)dev_priv->cp_ring->offset;
1978 dev_priv->ring_rptr->handle = 1986 dev_priv->ring_rptr->handle =
1979 (void *)dev_priv->ring_rptr->offset; 1987 (void *)(unsigned long)dev_priv->ring_rptr->offset;
1980 dev->agp_buffer_map->handle = 1988 dev->agp_buffer_map->handle =
1981 (void *)dev->agp_buffer_map->offset; 1989 (void *)(unsigned long)dev->agp_buffer_map->offset;
1982 1990
1983 DRM_DEBUG("dev_priv->cp_ring->handle %p\n", 1991 DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
1984 dev_priv->cp_ring->handle); 1992 dev_priv->cp_ring->handle);
@@ -2282,3 +2290,239 @@ int r600_cp_dispatch_indirect(struct drm_device *dev,
2282 2290
2283 return 0; 2291 return 0;
2284} 2292}
2293
2294void r600_cp_dispatch_swap(struct drm_device *dev, struct drm_file *file_priv)
2295{
2296 drm_radeon_private_t *dev_priv = dev->dev_private;
2297 struct drm_master *master = file_priv->master;
2298 struct drm_radeon_master_private *master_priv = master->driver_priv;
2299 drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
2300 int nbox = sarea_priv->nbox;
2301 struct drm_clip_rect *pbox = sarea_priv->boxes;
2302 int i, cpp, src_pitch, dst_pitch;
2303 uint64_t src, dst;
2304 RING_LOCALS;
2305 DRM_DEBUG("\n");
2306
2307 if (dev_priv->color_fmt == RADEON_COLOR_FORMAT_ARGB8888)
2308 cpp = 4;
2309 else
2310 cpp = 2;
2311
2312 if (sarea_priv->pfCurrentPage == 0) {
2313 src_pitch = dev_priv->back_pitch;
2314 dst_pitch = dev_priv->front_pitch;
2315 src = dev_priv->back_offset + dev_priv->fb_location;
2316 dst = dev_priv->front_offset + dev_priv->fb_location;
2317 } else {
2318 src_pitch = dev_priv->front_pitch;
2319 dst_pitch = dev_priv->back_pitch;
2320 src = dev_priv->front_offset + dev_priv->fb_location;
2321 dst = dev_priv->back_offset + dev_priv->fb_location;
2322 }
2323
2324 if (r600_prepare_blit_copy(dev, file_priv)) {
2325 DRM_ERROR("unable to allocate vertex buffer for swap buffer\n");
2326 return;
2327 }
2328 for (i = 0; i < nbox; i++) {
2329 int x = pbox[i].x1;
2330 int y = pbox[i].y1;
2331 int w = pbox[i].x2 - x;
2332 int h = pbox[i].y2 - y;
2333
2334 DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h);
2335
2336 r600_blit_swap(dev,
2337 src, dst,
2338 x, y, x, y, w, h,
2339 src_pitch, dst_pitch, cpp);
2340 }
2341 r600_done_blit_copy(dev);
2342
2343 /* Increment the frame counter. The client-side 3D driver must
2344 * throttle the framerate by waiting for this value before
2345 * performing the swapbuffer ioctl.
2346 */
2347 sarea_priv->last_frame++;
2348
2349 BEGIN_RING(3);
2350 R600_FRAME_AGE(sarea_priv->last_frame);
2351 ADVANCE_RING();
2352}
2353
2354int r600_cp_dispatch_texture(struct drm_device *dev,
2355 struct drm_file *file_priv,
2356 drm_radeon_texture_t *tex,
2357 drm_radeon_tex_image_t *image)
2358{
2359 drm_radeon_private_t *dev_priv = dev->dev_private;
2360 struct drm_buf *buf;
2361 u32 *buffer;
2362 const u8 __user *data;
2363 int size, pass_size;
2364 u64 src_offset, dst_offset;
2365
2366 if (!radeon_check_offset(dev_priv, tex->offset)) {
2367 DRM_ERROR("Invalid destination offset\n");
2368 return -EINVAL;
2369 }
2370
2371 /* this might fail for zero-sized uploads - are those illegal? */
2372 if (!radeon_check_offset(dev_priv, tex->offset + tex->height * tex->pitch - 1)) {
2373 DRM_ERROR("Invalid final destination offset\n");
2374 return -EINVAL;
2375 }
2376
2377 size = tex->height * tex->pitch;
2378
2379 if (size == 0)
2380 return 0;
2381
2382 dst_offset = tex->offset;
2383
2384 if (r600_prepare_blit_copy(dev, file_priv)) {
2385 DRM_ERROR("unable to allocate vertex buffer for swap buffer\n");
2386 return -EAGAIN;
2387 }
2388 do {
2389 data = (const u8 __user *)image->data;
2390 pass_size = size;
2391
2392 buf = radeon_freelist_get(dev);
2393 if (!buf) {
2394 DRM_DEBUG("EAGAIN\n");
2395 if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
2396 return -EFAULT;
2397 return -EAGAIN;
2398 }
2399
2400 if (pass_size > buf->total)
2401 pass_size = buf->total;
2402
2403 /* Dispatch the indirect buffer.
2404 */
2405 buffer =
2406 (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
2407
2408 if (DRM_COPY_FROM_USER(buffer, data, pass_size)) {
2409 DRM_ERROR("EFAULT on pad, %d bytes\n", pass_size);
2410 return -EFAULT;
2411 }
2412
2413 buf->file_priv = file_priv;
2414 buf->used = pass_size;
2415 src_offset = dev_priv->gart_buffers_offset + buf->offset;
2416
2417 r600_blit_copy(dev, src_offset, dst_offset, pass_size);
2418
2419 radeon_cp_discard_buffer(dev, file_priv->master, buf);
2420
2421 /* Update the input parameters for next time */
2422 image->data = (const u8 __user *)image->data + pass_size;
2423 dst_offset += pass_size;
2424 size -= pass_size;
2425 } while (size > 0);
2426 r600_done_blit_copy(dev);
2427
2428 return 0;
2429}
2430
2431/*
2432 * Legacy cs ioctl
2433 */
2434static u32 radeon_cs_id_get(struct drm_radeon_private *radeon)
2435{
2436 /* FIXME: check if wrap affect last reported wrap & sequence */
2437 radeon->cs_id_scnt = (radeon->cs_id_scnt + 1) & 0x00FFFFFF;
2438 if (!radeon->cs_id_scnt) {
2439 /* increment wrap counter */
2440 radeon->cs_id_wcnt += 0x01000000;
2441 /* valid sequence counter start at 1 */
2442 radeon->cs_id_scnt = 1;
2443 }
2444 return (radeon->cs_id_scnt | radeon->cs_id_wcnt);
2445}
2446
2447static void r600_cs_id_emit(drm_radeon_private_t *dev_priv, u32 *id)
2448{
2449 RING_LOCALS;
2450
2451 *id = radeon_cs_id_get(dev_priv);
2452
2453 /* SCRATCH 2 */
2454 BEGIN_RING(3);
2455 R600_CLEAR_AGE(*id);
2456 ADVANCE_RING();
2457 COMMIT_RING();
2458}
2459
2460static int r600_ib_get(struct drm_device *dev,
2461 struct drm_file *fpriv,
2462 struct drm_buf **buffer)
2463{
2464 struct drm_buf *buf;
2465
2466 *buffer = NULL;
2467 buf = radeon_freelist_get(dev);
2468 if (!buf) {
2469 return -EBUSY;
2470 }
2471 buf->file_priv = fpriv;
2472 *buffer = buf;
2473 return 0;
2474}
2475
2476static void r600_ib_free(struct drm_device *dev, struct drm_buf *buf,
2477 struct drm_file *fpriv, int l, int r)
2478{
2479 drm_radeon_private_t *dev_priv = dev->dev_private;
2480
2481 if (buf) {
2482 if (!r)
2483 r600_cp_dispatch_indirect(dev, buf, 0, l * 4);
2484 radeon_cp_discard_buffer(dev, fpriv->master, buf);
2485 COMMIT_RING();
2486 }
2487}
2488
2489int r600_cs_legacy_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv)
2490{
2491 struct drm_radeon_private *dev_priv = dev->dev_private;
2492 struct drm_radeon_cs *cs = data;
2493 struct drm_buf *buf;
2494 unsigned family;
2495 int l, r = 0;
2496 u32 *ib, cs_id = 0;
2497
2498 if (dev_priv == NULL) {
2499 DRM_ERROR("called with no initialization\n");
2500 return -EINVAL;
2501 }
2502 family = dev_priv->flags & RADEON_FAMILY_MASK;
2503 if (family < CHIP_R600) {
2504 DRM_ERROR("cs ioctl valid only for R6XX & R7XX in legacy mode\n");
2505 return -EINVAL;
2506 }
2507 mutex_lock(&dev_priv->cs_mutex);
2508 /* get ib */
2509 r = r600_ib_get(dev, fpriv, &buf);
2510 if (r) {
2511 DRM_ERROR("ib_get failed\n");
2512 goto out;
2513 }
2514 ib = dev->agp_buffer_map->handle + buf->offset;
2515 /* now parse command stream */
2516 r = r600_cs_legacy(dev, data, fpriv, family, ib, &l);
2517 if (r) {
2518 goto out;
2519 }
2520
2521out:
2522 r600_ib_free(dev, buf, fpriv, l, r);
2523 /* emit cs id sequence */
2524 r600_cs_id_emit(dev_priv, &cs_id);
2525 cs->cs_id = cs_id;
2526 mutex_unlock(&dev_priv->cs_mutex);
2527 return r;
2528}