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; |