diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-11-14 17:51:27 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-11-15 14:53:10 -0500 |
commit | 8cf5c9177151537e73ff1816540e4ba24b174391 (patch) | |
tree | 0b805659ef5b68550b37166c5d98319c4fde5639 /drivers/gpu | |
parent | e08e96de986ceb2c6b683df0bd0c4ddd4f91dcfd (diff) |
drm: add plane support v3
Planes are a bit like half-CRTCs. They have a location and fb, but
don't drive outputs directly. Add support for handling them to the core
KMS code.
v2: fix ABI of get_plane - move format_type_ptr to the end
v3: add 'flags' field for interlaced support (from Ville)
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Reviewed-by: Rob Clark <rob.clark@linaro.org>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 257 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_drv.c | 3 |
2 files changed, 258 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 9a2e2a14b3bb..5e1df76c8f72 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -324,6 +324,7 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) | |||
324 | { | 324 | { |
325 | struct drm_device *dev = fb->dev; | 325 | struct drm_device *dev = fb->dev; |
326 | struct drm_crtc *crtc; | 326 | struct drm_crtc *crtc; |
327 | struct drm_plane *plane; | ||
327 | struct drm_mode_set set; | 328 | struct drm_mode_set set; |
328 | int ret; | 329 | int ret; |
329 | 330 | ||
@@ -340,6 +341,15 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) | |||
340 | } | 341 | } |
341 | } | 342 | } |
342 | 343 | ||
344 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) { | ||
345 | if (plane->fb == fb) { | ||
346 | /* should turn off the crtc */ | ||
347 | ret = plane->funcs->disable_plane(plane); | ||
348 | if (ret) | ||
349 | DRM_ERROR("failed to disable plane with busy fb\n"); | ||
350 | } | ||
351 | } | ||
352 | |||
343 | drm_mode_object_put(dev, &fb->base); | 353 | drm_mode_object_put(dev, &fb->base); |
344 | list_del(&fb->head); | 354 | list_del(&fb->head); |
345 | dev->mode_config.num_fb--; | 355 | dev->mode_config.num_fb--; |
@@ -540,6 +550,50 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) | |||
540 | } | 550 | } |
541 | EXPORT_SYMBOL(drm_encoder_cleanup); | 551 | EXPORT_SYMBOL(drm_encoder_cleanup); |
542 | 552 | ||
553 | int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, | ||
554 | unsigned long possible_crtcs, | ||
555 | const struct drm_plane_funcs *funcs, | ||
556 | uint32_t *formats, uint32_t format_count) | ||
557 | { | ||
558 | mutex_lock(&dev->mode_config.mutex); | ||
559 | |||
560 | plane->dev = dev; | ||
561 | drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | ||
562 | plane->funcs = funcs; | ||
563 | plane->format_types = kmalloc(sizeof(uint32_t) * format_count, | ||
564 | GFP_KERNEL); | ||
565 | if (!plane->format_types) { | ||
566 | DRM_DEBUG_KMS("out of memory when allocating plane\n"); | ||
567 | drm_mode_object_put(dev, &plane->base); | ||
568 | return -ENOMEM; | ||
569 | } | ||
570 | |||
571 | memcpy(plane->format_types, formats, format_count); | ||
572 | plane->format_count = format_count; | ||
573 | plane->possible_crtcs = possible_crtcs; | ||
574 | |||
575 | list_add_tail(&plane->head, &dev->mode_config.plane_list); | ||
576 | dev->mode_config.num_plane++; | ||
577 | |||
578 | mutex_unlock(&dev->mode_config.mutex); | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | EXPORT_SYMBOL(drm_plane_init); | ||
583 | |||
584 | void drm_plane_cleanup(struct drm_plane *plane) | ||
585 | { | ||
586 | struct drm_device *dev = plane->dev; | ||
587 | |||
588 | mutex_lock(&dev->mode_config.mutex); | ||
589 | kfree(plane->format_types); | ||
590 | drm_mode_object_put(dev, &plane->base); | ||
591 | list_del(&plane->head); | ||
592 | dev->mode_config.num_plane--; | ||
593 | mutex_unlock(&dev->mode_config.mutex); | ||
594 | } | ||
595 | EXPORT_SYMBOL(drm_plane_cleanup); | ||
596 | |||
543 | /** | 597 | /** |
544 | * drm_mode_create - create a new display mode | 598 | * drm_mode_create - create a new display mode |
545 | * @dev: DRM device | 599 | * @dev: DRM device |
@@ -871,6 +925,7 @@ void drm_mode_config_init(struct drm_device *dev) | |||
871 | INIT_LIST_HEAD(&dev->mode_config.encoder_list); | 925 | INIT_LIST_HEAD(&dev->mode_config.encoder_list); |
872 | INIT_LIST_HEAD(&dev->mode_config.property_list); | 926 | INIT_LIST_HEAD(&dev->mode_config.property_list); |
873 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); | 927 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); |
928 | INIT_LIST_HEAD(&dev->mode_config.plane_list); | ||
874 | idr_init(&dev->mode_config.crtc_idr); | 929 | idr_init(&dev->mode_config.crtc_idr); |
875 | 930 | ||
876 | mutex_lock(&dev->mode_config.mutex); | 931 | mutex_lock(&dev->mode_config.mutex); |
@@ -947,6 +1002,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
947 | struct drm_encoder *encoder, *enct; | 1002 | struct drm_encoder *encoder, *enct; |
948 | struct drm_framebuffer *fb, *fbt; | 1003 | struct drm_framebuffer *fb, *fbt; |
949 | struct drm_property *property, *pt; | 1004 | struct drm_property *property, *pt; |
1005 | struct drm_plane *plane, *plt; | ||
950 | 1006 | ||
951 | list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, | 1007 | list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, |
952 | head) { | 1008 | head) { |
@@ -971,6 +1027,10 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
971 | crtc->funcs->destroy(crtc); | 1027 | crtc->funcs->destroy(crtc); |
972 | } | 1028 | } |
973 | 1029 | ||
1030 | list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, | ||
1031 | head) { | ||
1032 | plane->funcs->destroy(plane); | ||
1033 | } | ||
974 | } | 1034 | } |
975 | EXPORT_SYMBOL(drm_mode_config_cleanup); | 1035 | EXPORT_SYMBOL(drm_mode_config_cleanup); |
976 | 1036 | ||
@@ -1471,6 +1531,197 @@ out: | |||
1471 | } | 1531 | } |
1472 | 1532 | ||
1473 | /** | 1533 | /** |
1534 | * drm_mode_getplane_res - get plane info | ||
1535 | * @dev: DRM device | ||
1536 | * @data: ioctl data | ||
1537 | * @file_priv: DRM file info | ||
1538 | * | ||
1539 | * Return an plane count and set of IDs. | ||
1540 | */ | ||
1541 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | ||
1542 | struct drm_file *file_priv) | ||
1543 | { | ||
1544 | struct drm_mode_get_plane_res *plane_resp = data; | ||
1545 | struct drm_mode_config *config; | ||
1546 | struct drm_plane *plane; | ||
1547 | uint32_t __user *plane_ptr; | ||
1548 | int copied = 0, ret = 0; | ||
1549 | |||
1550 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1551 | return -EINVAL; | ||
1552 | |||
1553 | mutex_lock(&dev->mode_config.mutex); | ||
1554 | config = &dev->mode_config; | ||
1555 | |||
1556 | /* | ||
1557 | * This ioctl is called twice, once to determine how much space is | ||
1558 | * needed, and the 2nd time to fill it. | ||
1559 | */ | ||
1560 | if (config->num_plane && | ||
1561 | (plane_resp->count_planes >= config->num_plane)) { | ||
1562 | plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr; | ||
1563 | |||
1564 | list_for_each_entry(plane, &config->plane_list, head) { | ||
1565 | if (put_user(plane->base.id, plane_ptr + copied)) { | ||
1566 | ret = -EFAULT; | ||
1567 | goto out; | ||
1568 | } | ||
1569 | copied++; | ||
1570 | } | ||
1571 | } | ||
1572 | plane_resp->count_planes = config->num_plane; | ||
1573 | |||
1574 | out: | ||
1575 | mutex_unlock(&dev->mode_config.mutex); | ||
1576 | return ret; | ||
1577 | } | ||
1578 | |||
1579 | /** | ||
1580 | * drm_mode_getplane - get plane info | ||
1581 | * @dev: DRM device | ||
1582 | * @data: ioctl data | ||
1583 | * @file_priv: DRM file info | ||
1584 | * | ||
1585 | * Return plane info, including formats supported, gamma size, any | ||
1586 | * current fb, etc. | ||
1587 | */ | ||
1588 | int drm_mode_getplane(struct drm_device *dev, void *data, | ||
1589 | struct drm_file *file_priv) | ||
1590 | { | ||
1591 | struct drm_mode_get_plane *plane_resp = data; | ||
1592 | struct drm_mode_object *obj; | ||
1593 | struct drm_plane *plane; | ||
1594 | uint32_t __user *format_ptr; | ||
1595 | int ret = 0; | ||
1596 | |||
1597 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1598 | return -EINVAL; | ||
1599 | |||
1600 | mutex_lock(&dev->mode_config.mutex); | ||
1601 | obj = drm_mode_object_find(dev, plane_resp->plane_id, | ||
1602 | DRM_MODE_OBJECT_PLANE); | ||
1603 | if (!obj) { | ||
1604 | ret = -ENOENT; | ||
1605 | goto out; | ||
1606 | } | ||
1607 | plane = obj_to_plane(obj); | ||
1608 | |||
1609 | if (plane->crtc) | ||
1610 | plane_resp->crtc_id = plane->crtc->base.id; | ||
1611 | else | ||
1612 | plane_resp->crtc_id = 0; | ||
1613 | |||
1614 | if (plane->fb) | ||
1615 | plane_resp->fb_id = plane->fb->base.id; | ||
1616 | else | ||
1617 | plane_resp->fb_id = 0; | ||
1618 | |||
1619 | plane_resp->plane_id = plane->base.id; | ||
1620 | plane_resp->possible_crtcs = plane->possible_crtcs; | ||
1621 | plane_resp->gamma_size = plane->gamma_size; | ||
1622 | |||
1623 | /* | ||
1624 | * This ioctl is called twice, once to determine how much space is | ||
1625 | * needed, and the 2nd time to fill it. | ||
1626 | */ | ||
1627 | if (plane->format_count && | ||
1628 | (plane_resp->count_format_types >= plane->format_count)) { | ||
1629 | format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr; | ||
1630 | if (copy_to_user(format_ptr, | ||
1631 | plane->format_types, | ||
1632 | sizeof(uint32_t) * plane->format_count)) { | ||
1633 | ret = -EFAULT; | ||
1634 | goto out; | ||
1635 | } | ||
1636 | } | ||
1637 | plane_resp->count_format_types = plane->format_count; | ||
1638 | |||
1639 | out: | ||
1640 | mutex_unlock(&dev->mode_config.mutex); | ||
1641 | return ret; | ||
1642 | } | ||
1643 | |||
1644 | /** | ||
1645 | * drm_mode_setplane - set up or tear down an plane | ||
1646 | * @dev: DRM device | ||
1647 | * @data: ioctl data* | ||
1648 | * @file_prive: DRM file info | ||
1649 | * | ||
1650 | * Set plane info, including placement, fb, scaling, and other factors. | ||
1651 | * Or pass a NULL fb to disable. | ||
1652 | */ | ||
1653 | int drm_mode_setplane(struct drm_device *dev, void *data, | ||
1654 | struct drm_file *file_priv) | ||
1655 | { | ||
1656 | struct drm_mode_set_plane *plane_req = data; | ||
1657 | struct drm_mode_object *obj; | ||
1658 | struct drm_plane *plane; | ||
1659 | struct drm_crtc *crtc; | ||
1660 | struct drm_framebuffer *fb; | ||
1661 | int ret = 0; | ||
1662 | |||
1663 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1664 | return -EINVAL; | ||
1665 | |||
1666 | mutex_lock(&dev->mode_config.mutex); | ||
1667 | |||
1668 | /* | ||
1669 | * First, find the plane, crtc, and fb objects. If not available, | ||
1670 | * we don't bother to call the driver. | ||
1671 | */ | ||
1672 | obj = drm_mode_object_find(dev, plane_req->plane_id, | ||
1673 | DRM_MODE_OBJECT_PLANE); | ||
1674 | if (!obj) { | ||
1675 | DRM_DEBUG_KMS("Unknown plane ID %d\n", | ||
1676 | plane_req->plane_id); | ||
1677 | ret = -ENOENT; | ||
1678 | goto out; | ||
1679 | } | ||
1680 | plane = obj_to_plane(obj); | ||
1681 | |||
1682 | /* No fb means shut it down */ | ||
1683 | if (!plane_req->fb_id) { | ||
1684 | plane->funcs->disable_plane(plane); | ||
1685 | goto out; | ||
1686 | } | ||
1687 | |||
1688 | obj = drm_mode_object_find(dev, plane_req->crtc_id, | ||
1689 | DRM_MODE_OBJECT_CRTC); | ||
1690 | if (!obj) { | ||
1691 | DRM_DEBUG_KMS("Unknown crtc ID %d\n", | ||
1692 | plane_req->crtc_id); | ||
1693 | ret = -ENOENT; | ||
1694 | goto out; | ||
1695 | } | ||
1696 | crtc = obj_to_crtc(obj); | ||
1697 | |||
1698 | obj = drm_mode_object_find(dev, plane_req->fb_id, | ||
1699 | DRM_MODE_OBJECT_FB); | ||
1700 | if (!obj) { | ||
1701 | DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", | ||
1702 | plane_req->fb_id); | ||
1703 | ret = -ENOENT; | ||
1704 | goto out; | ||
1705 | } | ||
1706 | fb = obj_to_fb(obj); | ||
1707 | |||
1708 | ret = plane->funcs->update_plane(plane, crtc, fb, | ||
1709 | plane_req->crtc_x, plane_req->crtc_y, | ||
1710 | plane_req->crtc_w, plane_req->crtc_h, | ||
1711 | plane_req->src_x, plane_req->src_y, | ||
1712 | plane_req->src_w, plane_req->src_h); | ||
1713 | if (!ret) { | ||
1714 | plane->crtc = crtc; | ||
1715 | plane->fb = fb; | ||
1716 | } | ||
1717 | |||
1718 | out: | ||
1719 | mutex_unlock(&dev->mode_config.mutex); | ||
1720 | |||
1721 | return ret; | ||
1722 | } | ||
1723 | |||
1724 | /** | ||
1474 | * drm_mode_setcrtc - set CRTC configuration | 1725 | * drm_mode_setcrtc - set CRTC configuration |
1475 | * @inode: inode from the ioctl | 1726 | * @inode: inode from the ioctl |
1476 | * @filp: file * from the ioctl | 1727 | * @filp: file * from the ioctl |
@@ -1693,11 +1944,13 @@ int drm_mode_addfb(struct drm_device *dev, | |||
1693 | return -EINVAL; | 1944 | return -EINVAL; |
1694 | 1945 | ||
1695 | if ((config->min_width > r->width) || (r->width > config->max_width)) { | 1946 | if ((config->min_width > r->width) || (r->width > config->max_width)) { |
1696 | DRM_ERROR("mode new framebuffer width not within limits\n"); | 1947 | DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n", |
1948 | r->width, config->min_width, config->max_width); | ||
1697 | return -EINVAL; | 1949 | return -EINVAL; |
1698 | } | 1950 | } |
1699 | if ((config->min_height > r->height) || (r->height > config->max_height)) { | 1951 | if ((config->min_height > r->height) || (r->height > config->max_height)) { |
1700 | DRM_ERROR("mode new framebuffer height not within limits\n"); | 1952 | DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n", |
1953 | r->height, config->min_height, config->max_height); | ||
1701 | return -EINVAL; | 1954 | return -EINVAL; |
1702 | } | 1955 | } |
1703 | 1956 | ||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index fc81af9dbf42..4f25989b0d4a 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
@@ -136,8 +136,11 @@ static struct drm_ioctl_desc drm_ioctls[] = { | |||
136 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED), | 136 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED), |
137 | 137 | ||
138 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 138 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
139 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||
139 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 140 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
140 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 141 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
142 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||
143 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||
141 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 144 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
142 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED), | 145 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED), |
143 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), | 146 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), |