diff options
| -rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 104 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_drv.c | 1 | ||||
| -rw-r--r-- | include/drm/drm.h | 1 | ||||
| -rw-r--r-- | include/drm/drm_crtc.h | 19 | ||||
| -rw-r--r-- | include/drm/drm_mode.h | 44 |
5 files changed, 169 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 32756e67dd56..4fe321dc900c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
| @@ -125,6 +125,15 @@ static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = | |||
| 125 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, | 125 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, |
| 126 | drm_tv_subconnector_enum_list) | 126 | drm_tv_subconnector_enum_list) |
| 127 | 127 | ||
| 128 | static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { | ||
| 129 | { DRM_MODE_DIRTY_OFF, "Off" }, | ||
| 130 | { DRM_MODE_DIRTY_ON, "On" }, | ||
| 131 | { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, | ||
| 132 | }; | ||
| 133 | |||
| 134 | DRM_ENUM_NAME_FN(drm_get_dirty_info_name, | ||
| 135 | drm_dirty_info_enum_list) | ||
| 136 | |||
| 128 | struct drm_conn_prop_enum_list { | 137 | struct drm_conn_prop_enum_list { |
| 129 | int type; | 138 | int type; |
| 130 | char *name; | 139 | char *name; |
| @@ -802,6 +811,36 @@ int drm_mode_create_dithering_property(struct drm_device *dev) | |||
| 802 | EXPORT_SYMBOL(drm_mode_create_dithering_property); | 811 | EXPORT_SYMBOL(drm_mode_create_dithering_property); |
| 803 | 812 | ||
| 804 | /** | 813 | /** |
| 814 | * drm_mode_create_dirty_property - create dirty property | ||
| 815 | * @dev: DRM device | ||
| 816 | * | ||
| 817 | * Called by a driver the first time it's needed, must be attached to desired | ||
| 818 | * connectors. | ||
| 819 | */ | ||
| 820 | int drm_mode_create_dirty_info_property(struct drm_device *dev) | ||
| 821 | { | ||
| 822 | struct drm_property *dirty_info; | ||
| 823 | int i; | ||
| 824 | |||
| 825 | if (dev->mode_config.dirty_info_property) | ||
| 826 | return 0; | ||
| 827 | |||
| 828 | dirty_info = | ||
| 829 | drm_property_create(dev, DRM_MODE_PROP_ENUM | | ||
| 830 | DRM_MODE_PROP_IMMUTABLE, | ||
| 831 | "dirty", | ||
| 832 | ARRAY_SIZE(drm_dirty_info_enum_list)); | ||
| 833 | for (i = 0; i < ARRAY_SIZE(drm_dirty_info_enum_list); i++) | ||
| 834 | drm_property_add_enum(dirty_info, i, | ||
| 835 | drm_dirty_info_enum_list[i].type, | ||
| 836 | drm_dirty_info_enum_list[i].name); | ||
| 837 | dev->mode_config.dirty_info_property = dirty_info; | ||
| 838 | |||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | EXPORT_SYMBOL(drm_mode_create_dirty_info_property); | ||
| 842 | |||
| 843 | /** | ||
| 805 | * drm_mode_config_init - initialize DRM mode_configuration structure | 844 | * drm_mode_config_init - initialize DRM mode_configuration structure |
| 806 | * @dev: DRM device | 845 | * @dev: DRM device |
| 807 | * | 846 | * |
| @@ -1753,6 +1792,71 @@ out: | |||
| 1753 | return ret; | 1792 | return ret; |
| 1754 | } | 1793 | } |
| 1755 | 1794 | ||
| 1795 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | ||
| 1796 | void *data, struct drm_file *file_priv) | ||
| 1797 | { | ||
| 1798 | struct drm_clip_rect __user *clips_ptr; | ||
| 1799 | struct drm_clip_rect *clips = NULL; | ||
| 1800 | struct drm_mode_fb_dirty_cmd *r = data; | ||
| 1801 | struct drm_mode_object *obj; | ||
| 1802 | struct drm_framebuffer *fb; | ||
| 1803 | unsigned flags; | ||
| 1804 | int num_clips; | ||
| 1805 | int ret = 0; | ||
| 1806 | |||
| 1807 | mutex_lock(&dev->mode_config.mutex); | ||
| 1808 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | ||
| 1809 | if (!obj) { | ||
| 1810 | DRM_ERROR("invalid framebuffer id\n"); | ||
| 1811 | ret = -EINVAL; | ||
| 1812 | goto out_err1; | ||
| 1813 | } | ||
| 1814 | fb = obj_to_fb(obj); | ||
| 1815 | |||
| 1816 | num_clips = r->num_clips; | ||
| 1817 | clips_ptr = (struct drm_clip_rect *)(unsigned long)r->clips_ptr; | ||
| 1818 | |||
| 1819 | if (!num_clips != !clips_ptr) { | ||
| 1820 | ret = -EINVAL; | ||
| 1821 | goto out_err1; | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; | ||
| 1825 | |||
| 1826 | /* If userspace annotates copy, clips must come in pairs */ | ||
| 1827 | if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { | ||
| 1828 | ret = -EINVAL; | ||
| 1829 | goto out_err1; | ||
| 1830 | } | ||
| 1831 | |||
| 1832 | if (num_clips && clips_ptr) { | ||
| 1833 | clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); | ||
| 1834 | if (!clips) { | ||
| 1835 | ret = -ENOMEM; | ||
| 1836 | goto out_err1; | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | ret = copy_from_user(clips, clips_ptr, | ||
| 1840 | num_clips * sizeof(*clips)); | ||
| 1841 | if (ret) | ||
| 1842 | goto out_err2; | ||
| 1843 | } | ||
| 1844 | |||
| 1845 | if (fb->funcs->dirty) { | ||
| 1846 | ret = fb->funcs->dirty(fb, flags, r->color, clips, num_clips); | ||
| 1847 | } else { | ||
| 1848 | ret = -ENOSYS; | ||
| 1849 | goto out_err2; | ||
| 1850 | } | ||
| 1851 | |||
| 1852 | out_err2: | ||
| 1853 | kfree(clips); | ||
| 1854 | out_err1: | ||
| 1855 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1856 | return ret; | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | |||
| 1756 | /** | 1860 | /** |
| 1757 | * drm_fb_release - remove and free the FBs on this file | 1861 | * drm_fb_release - remove and free the FBs on this file |
| 1758 | * @filp: file * from the ioctl | 1862 | * @filp: file * from the ioctl |
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index bfaf59b02bda..ff2f1042cb44 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
| @@ -146,6 +146,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { | |||
| 146 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), | 146 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), |
| 147 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), | 147 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), |
| 148 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), | 148 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), |
| 149 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW) | ||
| 149 | }; | 150 | }; |
| 150 | 151 | ||
| 151 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) | 152 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) |
diff --git a/include/drm/drm.h b/include/drm/drm.h index 0114ac94f969..43a35b092f04 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h | |||
| @@ -697,6 +697,7 @@ struct drm_gem_open { | |||
| 697 | #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) | 697 | #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) |
| 698 | #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) | 698 | #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) |
| 699 | #define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) | 699 | #define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) |
| 700 | #define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xB1, struct drm_mode_fb_dirty_cmd) | ||
| 700 | 701 | ||
| 701 | /** | 702 | /** |
| 702 | * Device specific ioctls should only be in their respective headers | 703 | * Device specific ioctls should only be in their respective headers |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 938f327a2a3b..219f075d2733 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
| @@ -242,6 +242,21 @@ struct drm_framebuffer_funcs { | |||
| 242 | int (*create_handle)(struct drm_framebuffer *fb, | 242 | int (*create_handle)(struct drm_framebuffer *fb, |
| 243 | struct drm_file *file_priv, | 243 | struct drm_file *file_priv, |
| 244 | unsigned int *handle); | 244 | unsigned int *handle); |
| 245 | /** | ||
| 246 | * Optinal callback for the dirty fb ioctl. | ||
| 247 | * | ||
| 248 | * Userspace can notify the driver via this callback | ||
| 249 | * that a area of the framebuffer has changed and should | ||
| 250 | * be flushed to the display hardware. | ||
| 251 | * | ||
| 252 | * See documentation in drm_mode.h for the struct | ||
| 253 | * drm_mode_fb_dirty_cmd for more information as all | ||
| 254 | * the semantics and arguments have a one to one mapping | ||
| 255 | * on this function. | ||
| 256 | */ | ||
| 257 | int (*dirty)(struct drm_framebuffer *framebuffer, unsigned flags, | ||
| 258 | unsigned color, struct drm_clip_rect *clips, | ||
| 259 | unsigned num_clips); | ||
| 245 | }; | 260 | }; |
| 246 | 261 | ||
| 247 | struct drm_framebuffer { | 262 | struct drm_framebuffer { |
| @@ -610,6 +625,7 @@ struct drm_mode_config { | |||
| 610 | /* Optional properties */ | 625 | /* Optional properties */ |
| 611 | struct drm_property *scaling_mode_property; | 626 | struct drm_property *scaling_mode_property; |
| 612 | struct drm_property *dithering_mode_property; | 627 | struct drm_property *dithering_mode_property; |
| 628 | struct drm_property *dirty_info_property; | ||
| 613 | }; | 629 | }; |
| 614 | 630 | ||
| 615 | #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) | 631 | #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) |
| @@ -718,6 +734,7 @@ extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats | |||
| 718 | char *formats[]); | 734 | char *formats[]); |
| 719 | extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); | 735 | extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); |
| 720 | extern int drm_mode_create_dithering_property(struct drm_device *dev); | 736 | extern int drm_mode_create_dithering_property(struct drm_device *dev); |
| 737 | extern int drm_mode_create_dirty_info_property(struct drm_device *dev); | ||
| 721 | extern char *drm_get_encoder_name(struct drm_encoder *encoder); | 738 | extern char *drm_get_encoder_name(struct drm_encoder *encoder); |
| 722 | 739 | ||
| 723 | extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, | 740 | extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, |
| @@ -745,6 +762,8 @@ extern int drm_mode_rmfb(struct drm_device *dev, | |||
| 745 | void *data, struct drm_file *file_priv); | 762 | void *data, struct drm_file *file_priv); |
| 746 | extern int drm_mode_getfb(struct drm_device *dev, | 763 | extern int drm_mode_getfb(struct drm_device *dev, |
| 747 | void *data, struct drm_file *file_priv); | 764 | void *data, struct drm_file *file_priv); |
| 765 | extern int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | ||
| 766 | void *data, struct drm_file *file_priv); | ||
| 748 | extern int drm_mode_addmode_ioctl(struct drm_device *dev, | 767 | extern int drm_mode_addmode_ioctl(struct drm_device *dev, |
| 749 | void *data, struct drm_file *file_priv); | 768 | void *data, struct drm_file *file_priv); |
| 750 | extern int drm_mode_rmmode_ioctl(struct drm_device *dev, | 769 | extern int drm_mode_rmmode_ioctl(struct drm_device *dev, |
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index 09ca6adf4dd5..43009bc2e757 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h | |||
| @@ -75,6 +75,11 @@ | |||
| 75 | #define DRM_MODE_DITHERING_OFF 0 | 75 | #define DRM_MODE_DITHERING_OFF 0 |
| 76 | #define DRM_MODE_DITHERING_ON 1 | 76 | #define DRM_MODE_DITHERING_ON 1 |
| 77 | 77 | ||
| 78 | /* Dirty info options */ | ||
| 79 | #define DRM_MODE_DIRTY_OFF 0 | ||
| 80 | #define DRM_MODE_DIRTY_ON 1 | ||
| 81 | #define DRM_MODE_DIRTY_ANNOTATE 2 | ||
| 82 | |||
| 78 | struct drm_mode_modeinfo { | 83 | struct drm_mode_modeinfo { |
| 79 | __u32 clock; | 84 | __u32 clock; |
| 80 | __u16 hdisplay, hsync_start, hsync_end, htotal, hskew; | 85 | __u16 hdisplay, hsync_start, hsync_end, htotal, hskew; |
| @@ -222,6 +227,45 @@ struct drm_mode_fb_cmd { | |||
| 222 | __u32 handle; | 227 | __u32 handle; |
| 223 | }; | 228 | }; |
| 224 | 229 | ||
| 230 | #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 | ||
| 231 | #define DRM_MODE_FB_DIRTY_ANNOTATE_FILL 0x02 | ||
| 232 | #define DRM_MODE_FB_DIRTY_FLAGS 0x03 | ||
| 233 | |||
| 234 | /* | ||
| 235 | * Mark a region of a framebuffer as dirty. | ||
| 236 | * | ||
| 237 | * Some hardware does not automatically update display contents | ||
| 238 | * as a hardware or software draw to a framebuffer. This ioctl | ||
| 239 | * allows userspace to tell the kernel and the hardware what | ||
| 240 | * regions of the framebuffer have changed. | ||
| 241 | * | ||
| 242 | * The kernel or hardware is free to update more then just the | ||
| 243 | * region specified by the clip rects. The kernel or hardware | ||
| 244 | * may also delay and/or coalesce several calls to dirty into a | ||
| 245 | * single update. | ||
| 246 | * | ||
| 247 | * Userspace may annotate the updates, the annotates are a | ||
| 248 | * promise made by the caller that the change is either a copy | ||
| 249 | * of pixels or a fill of a single color in the region specified. | ||
| 250 | * | ||
| 251 | * If the DRM_MODE_FB_DIRTY_ANNOTATE_COPY flag is given then | ||
| 252 | * the number of updated regions are half of num_clips given, | ||
| 253 | * where the clip rects are paired in src and dst. The width and | ||
| 254 | * height of each one of the pairs must match. | ||
| 255 | * | ||
| 256 | * If the DRM_MODE_FB_DIRTY_ANNOTATE_FILL flag is given the caller | ||
| 257 | * promises that the region specified of the clip rects is filled | ||
| 258 | * completely with a single color as given in the color argument. | ||
| 259 | */ | ||
| 260 | |||
| 261 | struct drm_mode_fb_dirty_cmd { | ||
| 262 | __u32 fb_id; | ||
| 263 | __u32 flags; | ||
| 264 | __u32 color; | ||
| 265 | __u32 num_clips; | ||
| 266 | __u64 clips_ptr; | ||
| 267 | }; | ||
| 268 | |||
| 225 | struct drm_mode_mode_cmd { | 269 | struct drm_mode_mode_cmd { |
| 226 | __u32 connector_id; | 270 | __u32 connector_id; |
| 227 | struct drm_mode_modeinfo mode; | 271 | struct drm_mode_modeinfo mode; |
