diff options
Diffstat (limited to 'drivers/gpu/drm')
51 files changed, 842 insertions, 417 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index e3d70772b531..9b34a3410c32 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | |||
| @@ -745,7 +745,8 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, | |||
| 745 | * | 745 | * |
| 746 | */ | 746 | */ |
| 747 | int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, | 747 | int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, |
| 748 | int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) | 748 | int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, |
| 749 | const struct drm_display_mode *mode) | ||
| 749 | { | 750 | { |
| 750 | u32 vbl = 0, position = 0; | 751 | u32 vbl = 0, position = 0; |
| 751 | int vbl_start, vbl_end, vtotal, ret = 0; | 752 | int vbl_start, vbl_end, vtotal, ret = 0; |
| @@ -781,7 +782,7 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl | |||
| 781 | } | 782 | } |
| 782 | else { | 783 | else { |
| 783 | /* No: Fake something reasonable which gives at least ok results. */ | 784 | /* No: Fake something reasonable which gives at least ok results. */ |
| 784 | vbl_start = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; | 785 | vbl_start = mode->crtc_vdisplay; |
| 785 | vbl_end = 0; | 786 | vbl_end = 0; |
| 786 | } | 787 | } |
| 787 | 788 | ||
| @@ -797,7 +798,7 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl | |||
| 797 | 798 | ||
| 798 | /* Inside "upper part" of vblank area? Apply corrective offset if so: */ | 799 | /* Inside "upper part" of vblank area? Apply corrective offset if so: */ |
| 799 | if (in_vbl && (*vpos >= vbl_start)) { | 800 | if (in_vbl && (*vpos >= vbl_start)) { |
| 800 | vtotal = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; | 801 | vtotal = mode->crtc_vtotal; |
| 801 | *vpos = *vpos - vtotal; | 802 | *vpos = *vpos - vtotal; |
| 802 | } | 803 | } |
| 803 | 804 | ||
| @@ -819,8 +820,8 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl | |||
| 819 | * We only do this if DRM_CALLED_FROM_VBLIRQ. | 820 | * We only do this if DRM_CALLED_FROM_VBLIRQ. |
| 820 | */ | 821 | */ |
| 821 | if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { | 822 | if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { |
| 822 | vbl_start = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; | 823 | vbl_start = mode->crtc_vdisplay; |
| 823 | vtotal = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; | 824 | vtotal = mode->crtc_vtotal; |
| 824 | 825 | ||
| 825 | if (vbl_start - *vpos < vtotal / 100) { | 826 | if (vbl_start - *vpos < vtotal / 100) { |
| 826 | *vpos -= vtotal; | 827 | *vpos -= vtotal; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 8c735f544b66..275f1c3dbba0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | |||
| @@ -682,7 +682,7 @@ int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, | |||
| 682 | /* Helper routine in DRM core does all the work: */ | 682 | /* Helper routine in DRM core does all the work: */ |
| 683 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, | 683 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, |
| 684 | vblank_time, flags, | 684 | vblank_time, flags, |
| 685 | drmcrtc, &drmcrtc->hwmode); | 685 | &drmcrtc->hwmode); |
| 686 | } | 686 | } |
| 687 | 687 | ||
| 688 | const struct drm_ioctl_desc amdgpu_ioctls_kms[] = { | 688 | const struct drm_ioctl_desc amdgpu_ioctls_kms[] = { |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 64efe5b52e65..2b03425f9740 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | |||
| @@ -543,7 +543,8 @@ void amdgpu_encoder_set_active_device(struct drm_encoder *encoder); | |||
| 543 | int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, | 543 | int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, |
| 544 | unsigned int flags, | 544 | unsigned int flags, |
| 545 | int *vpos, int *hpos, ktime_t *stime, | 545 | int *vpos, int *hpos, ktime_t *stime, |
| 546 | ktime_t *etime); | 546 | ktime_t *etime, |
| 547 | const struct drm_display_mode *mode); | ||
| 547 | 548 | ||
| 548 | int amdgpu_framebuffer_init(struct drm_device *dev, | 549 | int amdgpu_framebuffer_init(struct drm_device *dev, |
| 549 | struct amdgpu_framebuffer *rfb, | 550 | struct amdgpu_framebuffer *rfb, |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index be9fa8220499..36fda86b3518 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | |||
| @@ -712,11 +712,13 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, | |||
| 712 | } | 712 | } |
| 713 | 713 | ||
| 714 | static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p, | 714 | static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p, |
| 715 | struct drm_framebuffer *fb, | ||
| 716 | const struct drm_plane_state *new_state) | 715 | const struct drm_plane_state *new_state) |
| 717 | { | 716 | { |
| 718 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); | 717 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
| 719 | 718 | ||
| 719 | if (!new_state->fb) | ||
| 720 | return 0; | ||
| 721 | |||
| 720 | return atmel_hlcdc_layer_update_start(&plane->layer); | 722 | return atmel_hlcdc_layer_update_start(&plane->layer); |
| 721 | } | 723 | } |
| 722 | 724 | ||
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f7d5166f89b2..7bb3845d9974 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
| @@ -438,7 +438,8 @@ EXPORT_SYMBOL(drm_atomic_crtc_set_property); | |||
| 438 | * consistent behavior you must call this function rather than the | 438 | * consistent behavior you must call this function rather than the |
| 439 | * driver hook directly. | 439 | * driver hook directly. |
| 440 | */ | 440 | */ |
| 441 | int drm_atomic_crtc_get_property(struct drm_crtc *crtc, | 441 | static int |
| 442 | drm_atomic_crtc_get_property(struct drm_crtc *crtc, | ||
| 442 | const struct drm_crtc_state *state, | 443 | const struct drm_crtc_state *state, |
| 443 | struct drm_property *property, uint64_t *val) | 444 | struct drm_property *property, uint64_t *val) |
| 444 | { | 445 | { |
| @@ -663,6 +664,25 @@ drm_atomic_plane_get_property(struct drm_plane *plane, | |||
| 663 | return 0; | 664 | return 0; |
| 664 | } | 665 | } |
| 665 | 666 | ||
| 667 | static bool | ||
| 668 | plane_switching_crtc(struct drm_atomic_state *state, | ||
| 669 | struct drm_plane *plane, | ||
| 670 | struct drm_plane_state *plane_state) | ||
| 671 | { | ||
| 672 | if (!plane->state->crtc || !plane_state->crtc) | ||
| 673 | return false; | ||
| 674 | |||
| 675 | if (plane->state->crtc == plane_state->crtc) | ||
| 676 | return false; | ||
| 677 | |||
| 678 | /* This could be refined, but currently there's no helper or driver code | ||
| 679 | * to implement direct switching of active planes nor userspace to take | ||
| 680 | * advantage of more direct plane switching without the intermediate | ||
| 681 | * full OFF state. | ||
| 682 | */ | ||
| 683 | return true; | ||
| 684 | } | ||
| 685 | |||
| 666 | /** | 686 | /** |
| 667 | * drm_atomic_plane_check - check plane state | 687 | * drm_atomic_plane_check - check plane state |
| 668 | * @plane: plane to check | 688 | * @plane: plane to check |
| @@ -734,6 +754,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane, | |||
| 734 | return -ENOSPC; | 754 | return -ENOSPC; |
| 735 | } | 755 | } |
| 736 | 756 | ||
| 757 | if (plane_switching_crtc(state->state, plane, state)) { | ||
| 758 | DRM_DEBUG_ATOMIC("[PLANE:%d] switching CRTC directly\n", | ||
| 759 | plane->base.id); | ||
| 760 | return -EINVAL; | ||
| 761 | } | ||
| 762 | |||
| 737 | return 0; | 763 | return 0; |
| 738 | } | 764 | } |
| 739 | 765 | ||
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index aecb5d69bc2d..87a2a446d2b7 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
| @@ -42,14 +42,14 @@ | |||
| 42 | * add their own additional internal state. | 42 | * add their own additional internal state. |
| 43 | * | 43 | * |
| 44 | * This library also provides default implementations for the check callback in | 44 | * This library also provides default implementations for the check callback in |
| 45 | * drm_atomic_helper_check and for the commit callback with | 45 | * drm_atomic_helper_check() and for the commit callback with |
| 46 | * drm_atomic_helper_commit. But the individual stages and callbacks are expose | 46 | * drm_atomic_helper_commit(). But the individual stages and callbacks are |
| 47 | * to allow drivers to mix and match and e.g. use the plane helpers only | 47 | * exposed to allow drivers to mix and match and e.g. use the plane helpers only |
| 48 | * together with a driver private modeset implementation. | 48 | * together with a driver private modeset implementation. |
| 49 | * | 49 | * |
| 50 | * This library also provides implementations for all the legacy driver | 50 | * This library also provides implementations for all the legacy driver |
| 51 | * interfaces on top of the atomic interface. See drm_atomic_helper_set_config, | 51 | * interfaces on top of the atomic interface. See drm_atomic_helper_set_config(), |
| 52 | * drm_atomic_helper_disable_plane, drm_atomic_helper_disable_plane and the | 52 | * drm_atomic_helper_disable_plane(), drm_atomic_helper_disable_plane() and the |
| 53 | * various functions to implement set_property callbacks. New drivers must not | 53 | * various functions to implement set_property callbacks. New drivers must not |
| 54 | * implement these functions themselves but must use the provided helpers. | 54 | * implement these functions themselves but must use the provided helpers. |
| 55 | */ | 55 | */ |
| @@ -993,6 +993,22 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); | |||
| 993 | * object. This can still fail when e.g. the framebuffer reservation fails. For | 993 | * object. This can still fail when e.g. the framebuffer reservation fails. For |
| 994 | * now this doesn't implement asynchronous commits. | 994 | * now this doesn't implement asynchronous commits. |
| 995 | * | 995 | * |
| 996 | * Note that right now this function does not support async commits, and hence | ||
| 997 | * driver writers must implement their own version for now. Also note that the | ||
| 998 | * default ordering of how the various stages are called is to match the legacy | ||
| 999 | * modeset helper library closest. One peculiarity of that is that it doesn't | ||
| 1000 | * mesh well with runtime PM at all. | ||
| 1001 | * | ||
| 1002 | * For drivers supporting runtime PM the recommended sequence is | ||
| 1003 | * | ||
| 1004 | * drm_atomic_helper_commit_modeset_disables(dev, state); | ||
| 1005 | * | ||
| 1006 | * drm_atomic_helper_commit_modeset_enables(dev, state); | ||
| 1007 | * | ||
| 1008 | * drm_atomic_helper_commit_planes(dev, state, true); | ||
| 1009 | * | ||
| 1010 | * See the kerneldoc entries for these three functions for more details. | ||
| 1011 | * | ||
| 996 | * RETURNS | 1012 | * RETURNS |
| 997 | * Zero for success or -errno. | 1013 | * Zero for success or -errno. |
| 998 | */ | 1014 | */ |
| @@ -1037,7 +1053,7 @@ int drm_atomic_helper_commit(struct drm_device *dev, | |||
| 1037 | 1053 | ||
| 1038 | drm_atomic_helper_commit_modeset_disables(dev, state); | 1054 | drm_atomic_helper_commit_modeset_disables(dev, state); |
| 1039 | 1055 | ||
| 1040 | drm_atomic_helper_commit_planes(dev, state); | 1056 | drm_atomic_helper_commit_planes(dev, state, false); |
| 1041 | 1057 | ||
| 1042 | drm_atomic_helper_commit_modeset_enables(dev, state); | 1058 | drm_atomic_helper_commit_modeset_enables(dev, state); |
| 1043 | 1059 | ||
| @@ -1077,7 +1093,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit); | |||
| 1077 | * work item, which allows nice concurrent updates on disjoint sets of crtcs. | 1093 | * work item, which allows nice concurrent updates on disjoint sets of crtcs. |
| 1078 | * | 1094 | * |
| 1079 | * 3. The software state is updated synchronously with | 1095 | * 3. The software state is updated synchronously with |
| 1080 | * drm_atomic_helper_swap_state. Doing this under the protection of all modeset | 1096 | * drm_atomic_helper_swap_state(). Doing this under the protection of all modeset |
| 1081 | * locks means concurrent callers never see inconsistent state. And doing this | 1097 | * locks means concurrent callers never see inconsistent state. And doing this |
| 1082 | * while it's guaranteed that no relevant async worker runs means that async | 1098 | * while it's guaranteed that no relevant async worker runs means that async |
| 1083 | * workers do not need grab any locks. Actually they must not grab locks, for | 1099 | * workers do not need grab any locks. Actually they must not grab locks, for |
| @@ -1111,17 +1127,14 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev, | |||
| 1111 | const struct drm_plane_helper_funcs *funcs; | 1127 | const struct drm_plane_helper_funcs *funcs; |
| 1112 | struct drm_plane *plane = state->planes[i]; | 1128 | struct drm_plane *plane = state->planes[i]; |
| 1113 | struct drm_plane_state *plane_state = state->plane_states[i]; | 1129 | struct drm_plane_state *plane_state = state->plane_states[i]; |
| 1114 | struct drm_framebuffer *fb; | ||
| 1115 | 1130 | ||
| 1116 | if (!plane) | 1131 | if (!plane) |
| 1117 | continue; | 1132 | continue; |
| 1118 | 1133 | ||
| 1119 | funcs = plane->helper_private; | 1134 | funcs = plane->helper_private; |
| 1120 | 1135 | ||
| 1121 | fb = plane_state->fb; | 1136 | if (funcs->prepare_fb) { |
| 1122 | 1137 | ret = funcs->prepare_fb(plane, plane_state); | |
| 1123 | if (fb && funcs->prepare_fb) { | ||
| 1124 | ret = funcs->prepare_fb(plane, fb, plane_state); | ||
| 1125 | if (ret) | 1138 | if (ret) |
| 1126 | goto fail; | 1139 | goto fail; |
| 1127 | } | 1140 | } |
| @@ -1134,17 +1147,14 @@ fail: | |||
| 1134 | const struct drm_plane_helper_funcs *funcs; | 1147 | const struct drm_plane_helper_funcs *funcs; |
| 1135 | struct drm_plane *plane = state->planes[i]; | 1148 | struct drm_plane *plane = state->planes[i]; |
| 1136 | struct drm_plane_state *plane_state = state->plane_states[i]; | 1149 | struct drm_plane_state *plane_state = state->plane_states[i]; |
| 1137 | struct drm_framebuffer *fb; | ||
| 1138 | 1150 | ||
| 1139 | if (!plane) | 1151 | if (!plane) |
| 1140 | continue; | 1152 | continue; |
| 1141 | 1153 | ||
| 1142 | funcs = plane->helper_private; | 1154 | funcs = plane->helper_private; |
| 1143 | 1155 | ||
| 1144 | fb = state->plane_states[i]->fb; | 1156 | if (funcs->cleanup_fb) |
| 1145 | 1157 | funcs->cleanup_fb(plane, plane_state); | |
| 1146 | if (fb && funcs->cleanup_fb) | ||
| 1147 | funcs->cleanup_fb(plane, fb, plane_state); | ||
| 1148 | 1158 | ||
| 1149 | } | 1159 | } |
| 1150 | 1160 | ||
| @@ -1152,10 +1162,16 @@ fail: | |||
| 1152 | } | 1162 | } |
| 1153 | EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); | 1163 | EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); |
| 1154 | 1164 | ||
| 1165 | bool plane_crtc_active(struct drm_plane_state *state) | ||
| 1166 | { | ||
| 1167 | return state->crtc && state->crtc->state->active; | ||
| 1168 | } | ||
| 1169 | |||
| 1155 | /** | 1170 | /** |
| 1156 | * drm_atomic_helper_commit_planes - commit plane state | 1171 | * drm_atomic_helper_commit_planes - commit plane state |
| 1157 | * @dev: DRM device | 1172 | * @dev: DRM device |
| 1158 | * @old_state: atomic state object with old state structures | 1173 | * @old_state: atomic state object with old state structures |
| 1174 | * @active_only: Only commit on active CRTC if set | ||
| 1159 | * | 1175 | * |
| 1160 | * This function commits the new plane state using the plane and atomic helper | 1176 | * This function commits the new plane state using the plane and atomic helper |
| 1161 | * functions for planes and crtcs. It assumes that the atomic state has already | 1177 | * functions for planes and crtcs. It assumes that the atomic state has already |
| @@ -1168,9 +1184,26 @@ EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); | |||
| 1168 | * Note that this function does all plane updates across all CRTCs in one step. | 1184 | * Note that this function does all plane updates across all CRTCs in one step. |
| 1169 | * If the hardware can't support this approach look at | 1185 | * If the hardware can't support this approach look at |
| 1170 | * drm_atomic_helper_commit_planes_on_crtc() instead. | 1186 | * drm_atomic_helper_commit_planes_on_crtc() instead. |
| 1187 | * | ||
| 1188 | * Plane parameters can be updated by applications while the associated CRTC is | ||
| 1189 | * disabled. The DRM/KMS core will store the parameters in the plane state, | ||
| 1190 | * which will be available to the driver when the CRTC is turned on. As a result | ||
| 1191 | * most drivers don't need to be immediately notified of plane updates for a | ||
| 1192 | * disabled CRTC. | ||
| 1193 | * | ||
| 1194 | * Unless otherwise needed, drivers are advised to set the @active_only | ||
| 1195 | * parameters to true in order not to receive plane update notifications related | ||
| 1196 | * to a disabled CRTC. This avoids the need to manually ignore plane updates in | ||
| 1197 | * driver code when the driver and/or hardware can't or just don't need to deal | ||
| 1198 | * with updates on disabled CRTCs, for example when supporting runtime PM. | ||
| 1199 | * | ||
| 1200 | * The drm_atomic_helper_commit() default implementation only sets @active_only | ||
| 1201 | * to false to most closely match the behaviour of the legacy helpers. This should | ||
| 1202 | * not be copied blindly by drivers. | ||
| 1171 | */ | 1203 | */ |
| 1172 | void drm_atomic_helper_commit_planes(struct drm_device *dev, | 1204 | void drm_atomic_helper_commit_planes(struct drm_device *dev, |
| 1173 | struct drm_atomic_state *old_state) | 1205 | struct drm_atomic_state *old_state, |
| 1206 | bool active_only) | ||
| 1174 | { | 1207 | { |
| 1175 | struct drm_crtc *crtc; | 1208 | struct drm_crtc *crtc; |
| 1176 | struct drm_crtc_state *old_crtc_state; | 1209 | struct drm_crtc_state *old_crtc_state; |
| @@ -1186,25 +1219,43 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, | |||
| 1186 | if (!funcs || !funcs->atomic_begin) | 1219 | if (!funcs || !funcs->atomic_begin) |
| 1187 | continue; | 1220 | continue; |
| 1188 | 1221 | ||
| 1222 | if (active_only && !crtc->state->active) | ||
| 1223 | continue; | ||
| 1224 | |||
| 1189 | funcs->atomic_begin(crtc, old_crtc_state); | 1225 | funcs->atomic_begin(crtc, old_crtc_state); |
| 1190 | } | 1226 | } |
| 1191 | 1227 | ||
| 1192 | for_each_plane_in_state(old_state, plane, old_plane_state, i) { | 1228 | for_each_plane_in_state(old_state, plane, old_plane_state, i) { |
| 1193 | const struct drm_plane_helper_funcs *funcs; | 1229 | const struct drm_plane_helper_funcs *funcs; |
| 1230 | bool disabling; | ||
| 1194 | 1231 | ||
| 1195 | funcs = plane->helper_private; | 1232 | funcs = plane->helper_private; |
| 1196 | 1233 | ||
| 1197 | if (!funcs) | 1234 | if (!funcs) |
| 1198 | continue; | 1235 | continue; |
| 1199 | 1236 | ||
| 1237 | disabling = drm_atomic_plane_disabling(plane, old_plane_state); | ||
| 1238 | |||
| 1239 | if (active_only) { | ||
| 1240 | /* | ||
| 1241 | * Skip planes related to inactive CRTCs. If the plane | ||
| 1242 | * is enabled use the state of the current CRTC. If the | ||
| 1243 | * plane is being disabled use the state of the old | ||
| 1244 | * CRTC to avoid skipping planes being disabled on an | ||
| 1245 | * active CRTC. | ||
| 1246 | */ | ||
| 1247 | if (!disabling && !plane_crtc_active(plane->state)) | ||
| 1248 | continue; | ||
| 1249 | if (disabling && !plane_crtc_active(old_plane_state)) | ||
| 1250 | continue; | ||
| 1251 | } | ||
| 1252 | |||
| 1200 | /* | 1253 | /* |
| 1201 | * Special-case disabling the plane if drivers support it. | 1254 | * Special-case disabling the plane if drivers support it. |
| 1202 | */ | 1255 | */ |
| 1203 | if (drm_atomic_plane_disabling(plane, old_plane_state) && | 1256 | if (disabling && funcs->atomic_disable) |
| 1204 | funcs->atomic_disable) | ||
| 1205 | funcs->atomic_disable(plane, old_plane_state); | 1257 | funcs->atomic_disable(plane, old_plane_state); |
| 1206 | else if (plane->state->crtc || | 1258 | else if (plane->state->crtc || disabling) |
| 1207 | drm_atomic_plane_disabling(plane, old_plane_state)) | ||
| 1208 | funcs->atomic_update(plane, old_plane_state); | 1259 | funcs->atomic_update(plane, old_plane_state); |
| 1209 | } | 1260 | } |
| 1210 | 1261 | ||
| @@ -1216,6 +1267,9 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, | |||
| 1216 | if (!funcs || !funcs->atomic_flush) | 1267 | if (!funcs || !funcs->atomic_flush) |
| 1217 | continue; | 1268 | continue; |
| 1218 | 1269 | ||
| 1270 | if (active_only && !crtc->state->active) | ||
| 1271 | continue; | ||
| 1272 | |||
| 1219 | funcs->atomic_flush(crtc, old_crtc_state); | 1273 | funcs->atomic_flush(crtc, old_crtc_state); |
| 1220 | } | 1274 | } |
| 1221 | } | 1275 | } |
| @@ -1300,14 +1354,11 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev, | |||
| 1300 | 1354 | ||
| 1301 | for_each_plane_in_state(old_state, plane, plane_state, i) { | 1355 | for_each_plane_in_state(old_state, plane, plane_state, i) { |
| 1302 | const struct drm_plane_helper_funcs *funcs; | 1356 | const struct drm_plane_helper_funcs *funcs; |
| 1303 | struct drm_framebuffer *old_fb; | ||
| 1304 | 1357 | ||
| 1305 | funcs = plane->helper_private; | 1358 | funcs = plane->helper_private; |
| 1306 | 1359 | ||
| 1307 | old_fb = plane_state->fb; | 1360 | if (funcs->cleanup_fb) |
| 1308 | 1361 | funcs->cleanup_fb(plane, plane_state); | |
| 1309 | if (old_fb && funcs->cleanup_fb) | ||
| 1310 | funcs->cleanup_fb(plane, old_fb, plane_state); | ||
| 1311 | } | 1362 | } |
| 1312 | } | 1363 | } |
| 1313 | EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); | 1364 | EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); |
| @@ -1334,7 +1385,7 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); | |||
| 1334 | * | 1385 | * |
| 1335 | * 4. Actually commit the hardware state. | 1386 | * 4. Actually commit the hardware state. |
| 1336 | * | 1387 | * |
| 1337 | * 5. Call drm_atomic_helper_cleanup_planes with @state, which since step 3 | 1388 | * 5. Call drm_atomic_helper_cleanup_planes() with @state, which since step 3 |
| 1338 | * contains the old state. Also do any other cleanup required with that state. | 1389 | * contains the old state. Also do any other cleanup required with that state. |
| 1339 | */ | 1390 | */ |
| 1340 | void drm_atomic_helper_swap_state(struct drm_device *dev, | 1391 | void drm_atomic_helper_swap_state(struct drm_device *dev, |
| @@ -1502,21 +1553,9 @@ retry: | |||
| 1502 | goto fail; | 1553 | goto fail; |
| 1503 | } | 1554 | } |
| 1504 | 1555 | ||
| 1505 | ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); | 1556 | ret = __drm_atomic_helper_disable_plane(plane, plane_state); |
| 1506 | if (ret != 0) | 1557 | if (ret != 0) |
| 1507 | goto fail; | 1558 | goto fail; |
| 1508 | drm_atomic_set_fb_for_plane(plane_state, NULL); | ||
| 1509 | plane_state->crtc_x = 0; | ||
| 1510 | plane_state->crtc_y = 0; | ||
| 1511 | plane_state->crtc_h = 0; | ||
| 1512 | plane_state->crtc_w = 0; | ||
| 1513 | plane_state->src_x = 0; | ||
| 1514 | plane_state->src_y = 0; | ||
| 1515 | plane_state->src_h = 0; | ||
| 1516 | plane_state->src_w = 0; | ||
| 1517 | |||
| 1518 | if (plane == plane->crtc->cursor) | ||
| 1519 | state->legacy_cursor_update = true; | ||
| 1520 | 1559 | ||
| 1521 | ret = drm_atomic_commit(state); | 1560 | ret = drm_atomic_commit(state); |
| 1522 | if (ret != 0) | 1561 | if (ret != 0) |
| @@ -1546,6 +1585,32 @@ backoff: | |||
| 1546 | } | 1585 | } |
| 1547 | EXPORT_SYMBOL(drm_atomic_helper_disable_plane); | 1586 | EXPORT_SYMBOL(drm_atomic_helper_disable_plane); |
| 1548 | 1587 | ||
| 1588 | /* just used from fb-helper and atomic-helper: */ | ||
| 1589 | int __drm_atomic_helper_disable_plane(struct drm_plane *plane, | ||
| 1590 | struct drm_plane_state *plane_state) | ||
| 1591 | { | ||
| 1592 | int ret; | ||
| 1593 | |||
| 1594 | ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); | ||
| 1595 | if (ret != 0) | ||
| 1596 | return ret; | ||
| 1597 | |||
| 1598 | drm_atomic_set_fb_for_plane(plane_state, NULL); | ||
| 1599 | plane_state->crtc_x = 0; | ||
| 1600 | plane_state->crtc_y = 0; | ||
| 1601 | plane_state->crtc_h = 0; | ||
| 1602 | plane_state->crtc_w = 0; | ||
| 1603 | plane_state->src_x = 0; | ||
| 1604 | plane_state->src_y = 0; | ||
| 1605 | plane_state->src_h = 0; | ||
| 1606 | plane_state->src_w = 0; | ||
| 1607 | |||
| 1608 | if (plane->crtc && (plane == plane->crtc->cursor)) | ||
| 1609 | plane_state->state->legacy_cursor_update = true; | ||
| 1610 | |||
| 1611 | return 0; | ||
| 1612 | } | ||
| 1613 | |||
| 1549 | static int update_output_state(struct drm_atomic_state *state, | 1614 | static int update_output_state(struct drm_atomic_state *state, |
| 1550 | struct drm_mode_set *set) | 1615 | struct drm_mode_set *set) |
| 1551 | { | 1616 | { |
| @@ -1629,8 +1694,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set) | |||
| 1629 | { | 1694 | { |
| 1630 | struct drm_atomic_state *state; | 1695 | struct drm_atomic_state *state; |
| 1631 | struct drm_crtc *crtc = set->crtc; | 1696 | struct drm_crtc *crtc = set->crtc; |
| 1632 | struct drm_crtc_state *crtc_state; | ||
| 1633 | struct drm_plane_state *primary_state; | ||
| 1634 | int ret = 0; | 1697 | int ret = 0; |
| 1635 | 1698 | ||
| 1636 | state = drm_atomic_state_alloc(crtc->dev); | 1699 | state = drm_atomic_state_alloc(crtc->dev); |
| @@ -1639,17 +1702,54 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set) | |||
| 1639 | 1702 | ||
| 1640 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); | 1703 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); |
| 1641 | retry: | 1704 | retry: |
| 1642 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | 1705 | ret = __drm_atomic_helper_set_config(set, state); |
| 1643 | if (IS_ERR(crtc_state)) { | 1706 | if (ret != 0) |
| 1644 | ret = PTR_ERR(crtc_state); | ||
| 1645 | goto fail; | 1707 | goto fail; |
| 1646 | } | ||
| 1647 | 1708 | ||
| 1648 | primary_state = drm_atomic_get_plane_state(state, crtc->primary); | 1709 | ret = drm_atomic_commit(state); |
| 1649 | if (IS_ERR(primary_state)) { | 1710 | if (ret != 0) |
| 1650 | ret = PTR_ERR(primary_state); | ||
| 1651 | goto fail; | 1711 | goto fail; |
| 1652 | } | 1712 | |
| 1713 | /* Driver takes ownership of state on successful commit. */ | ||
| 1714 | return 0; | ||
| 1715 | fail: | ||
| 1716 | if (ret == -EDEADLK) | ||
| 1717 | goto backoff; | ||
| 1718 | |||
| 1719 | drm_atomic_state_free(state); | ||
| 1720 | |||
| 1721 | return ret; | ||
| 1722 | backoff: | ||
| 1723 | drm_atomic_state_clear(state); | ||
| 1724 | drm_atomic_legacy_backoff(state); | ||
| 1725 | |||
| 1726 | /* | ||
| 1727 | * Someone might have exchanged the framebuffer while we dropped locks | ||
| 1728 | * in the backoff code. We need to fix up the fb refcount tracking the | ||
| 1729 | * core does for us. | ||
| 1730 | */ | ||
| 1731 | crtc->primary->old_fb = crtc->primary->fb; | ||
| 1732 | |||
| 1733 | goto retry; | ||
| 1734 | } | ||
| 1735 | EXPORT_SYMBOL(drm_atomic_helper_set_config); | ||
| 1736 | |||
| 1737 | /* just used from fb-helper and atomic-helper: */ | ||
| 1738 | int __drm_atomic_helper_set_config(struct drm_mode_set *set, | ||
| 1739 | struct drm_atomic_state *state) | ||
| 1740 | { | ||
| 1741 | struct drm_crtc_state *crtc_state; | ||
| 1742 | struct drm_plane_state *primary_state; | ||
| 1743 | struct drm_crtc *crtc = set->crtc; | ||
| 1744 | int ret; | ||
| 1745 | |||
| 1746 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
| 1747 | if (IS_ERR(crtc_state)) | ||
| 1748 | return PTR_ERR(crtc_state); | ||
| 1749 | |||
| 1750 | primary_state = drm_atomic_get_plane_state(state, crtc->primary); | ||
| 1751 | if (IS_ERR(primary_state)) | ||
| 1752 | return PTR_ERR(primary_state); | ||
| 1653 | 1753 | ||
| 1654 | if (!set->mode) { | 1754 | if (!set->mode) { |
| 1655 | WARN_ON(set->fb); | 1755 | WARN_ON(set->fb); |
| @@ -1657,13 +1757,13 @@ retry: | |||
| 1657 | 1757 | ||
| 1658 | ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); | 1758 | ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); |
| 1659 | if (ret != 0) | 1759 | if (ret != 0) |
| 1660 | goto fail; | 1760 | return ret; |
| 1661 | 1761 | ||
| 1662 | crtc_state->active = false; | 1762 | crtc_state->active = false; |
| 1663 | 1763 | ||
| 1664 | ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); | 1764 | ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); |
| 1665 | if (ret != 0) | 1765 | if (ret != 0) |
| 1666 | goto fail; | 1766 | return ret; |
| 1667 | 1767 | ||
| 1668 | drm_atomic_set_fb_for_plane(primary_state, NULL); | 1768 | drm_atomic_set_fb_for_plane(primary_state, NULL); |
| 1669 | 1769 | ||
| @@ -1675,13 +1775,14 @@ retry: | |||
| 1675 | 1775 | ||
| 1676 | ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); | 1776 | ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); |
| 1677 | if (ret != 0) | 1777 | if (ret != 0) |
| 1678 | goto fail; | 1778 | return ret; |
| 1679 | 1779 | ||
| 1680 | crtc_state->active = true; | 1780 | crtc_state->active = true; |
| 1681 | 1781 | ||
| 1682 | ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); | 1782 | ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); |
| 1683 | if (ret != 0) | 1783 | if (ret != 0) |
| 1684 | goto fail; | 1784 | return ret; |
| 1785 | |||
| 1685 | drm_atomic_set_fb_for_plane(primary_state, set->fb); | 1786 | drm_atomic_set_fb_for_plane(primary_state, set->fb); |
| 1686 | primary_state->crtc_x = 0; | 1787 | primary_state->crtc_x = 0; |
| 1687 | primary_state->crtc_y = 0; | 1788 | primary_state->crtc_y = 0; |
| @@ -1695,35 +1796,10 @@ retry: | |||
| 1695 | commit: | 1796 | commit: |
| 1696 | ret = update_output_state(state, set); | 1797 | ret = update_output_state(state, set); |
| 1697 | if (ret) | 1798 | if (ret) |
| 1698 | goto fail; | 1799 | return ret; |
| 1699 | |||
| 1700 | ret = drm_atomic_commit(state); | ||
| 1701 | if (ret != 0) | ||
| 1702 | goto fail; | ||
| 1703 | 1800 | ||
| 1704 | /* Driver takes ownership of state on successful commit. */ | ||
| 1705 | return 0; | 1801 | return 0; |
| 1706 | fail: | ||
| 1707 | if (ret == -EDEADLK) | ||
| 1708 | goto backoff; | ||
| 1709 | |||
| 1710 | drm_atomic_state_free(state); | ||
| 1711 | |||
| 1712 | return ret; | ||
| 1713 | backoff: | ||
| 1714 | drm_atomic_state_clear(state); | ||
| 1715 | drm_atomic_legacy_backoff(state); | ||
| 1716 | |||
| 1717 | /* | ||
| 1718 | * Someone might have exchanged the framebuffer while we dropped locks | ||
| 1719 | * in the backoff code. We need to fix up the fb refcount tracking the | ||
| 1720 | * core does for us. | ||
| 1721 | */ | ||
| 1722 | crtc->primary->old_fb = crtc->primary->fb; | ||
| 1723 | |||
| 1724 | goto retry; | ||
| 1725 | } | 1802 | } |
| 1726 | EXPORT_SYMBOL(drm_atomic_helper_set_config); | ||
| 1727 | 1803 | ||
| 1728 | /** | 1804 | /** |
| 1729 | * drm_atomic_helper_crtc_set_property - helper for crtc properties | 1805 | * drm_atomic_helper_crtc_set_property - helper for crtc properties |
| @@ -2333,6 +2409,84 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) | |||
| 2333 | EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); | 2409 | EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); |
| 2334 | 2410 | ||
| 2335 | /** | 2411 | /** |
| 2412 | * drm_atomic_helper_duplicate_state - duplicate an atomic state object | ||
| 2413 | * @dev: DRM device | ||
| 2414 | * @ctx: lock acquisition context | ||
| 2415 | * | ||
| 2416 | * Makes a copy of the current atomic state by looping over all objects and | ||
| 2417 | * duplicating their respective states. | ||
| 2418 | * | ||
| 2419 | * Note that this treats atomic state as persistent between save and restore. | ||
| 2420 | * Drivers must make sure that this is possible and won't result in confusion | ||
| 2421 | * or erroneous behaviour. | ||
| 2422 | * | ||
| 2423 | * Note that if callers haven't already acquired all modeset locks this might | ||
| 2424 | * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). | ||
| 2425 | * | ||
| 2426 | * Returns: | ||
| 2427 | * A pointer to the copy of the atomic state object on success or an | ||
| 2428 | * ERR_PTR()-encoded error code on failure. | ||
| 2429 | */ | ||
| 2430 | struct drm_atomic_state * | ||
| 2431 | drm_atomic_helper_duplicate_state(struct drm_device *dev, | ||
| 2432 | struct drm_modeset_acquire_ctx *ctx) | ||
| 2433 | { | ||
| 2434 | struct drm_atomic_state *state; | ||
| 2435 | struct drm_connector *conn; | ||
| 2436 | struct drm_plane *plane; | ||
| 2437 | struct drm_crtc *crtc; | ||
| 2438 | int err = 0; | ||
| 2439 | |||
| 2440 | state = drm_atomic_state_alloc(dev); | ||
| 2441 | if (!state) | ||
| 2442 | return ERR_PTR(-ENOMEM); | ||
| 2443 | |||
| 2444 | state->acquire_ctx = ctx; | ||
| 2445 | |||
| 2446 | drm_for_each_crtc(crtc, dev) { | ||
| 2447 | struct drm_crtc_state *crtc_state; | ||
| 2448 | |||
| 2449 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
| 2450 | if (IS_ERR(crtc_state)) { | ||
| 2451 | err = PTR_ERR(crtc_state); | ||
| 2452 | goto free; | ||
| 2453 | } | ||
| 2454 | } | ||
| 2455 | |||
| 2456 | drm_for_each_plane(plane, dev) { | ||
| 2457 | struct drm_plane_state *plane_state; | ||
| 2458 | |||
| 2459 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
| 2460 | if (IS_ERR(plane_state)) { | ||
| 2461 | err = PTR_ERR(plane_state); | ||
| 2462 | goto free; | ||
| 2463 | } | ||
| 2464 | } | ||
| 2465 | |||
| 2466 | drm_for_each_connector(conn, dev) { | ||
| 2467 | struct drm_connector_state *conn_state; | ||
| 2468 | |||
| 2469 | conn_state = drm_atomic_get_connector_state(state, conn); | ||
| 2470 | if (IS_ERR(conn_state)) { | ||
| 2471 | err = PTR_ERR(conn_state); | ||
| 2472 | goto free; | ||
| 2473 | } | ||
| 2474 | } | ||
| 2475 | |||
| 2476 | /* clear the acquire context so that it isn't accidentally reused */ | ||
| 2477 | state->acquire_ctx = NULL; | ||
| 2478 | |||
| 2479 | free: | ||
| 2480 | if (err < 0) { | ||
| 2481 | drm_atomic_state_free(state); | ||
| 2482 | state = ERR_PTR(err); | ||
| 2483 | } | ||
| 2484 | |||
| 2485 | return state; | ||
| 2486 | } | ||
| 2487 | EXPORT_SYMBOL(drm_atomic_helper_duplicate_state); | ||
| 2488 | |||
| 2489 | /** | ||
| 2336 | * __drm_atomic_helper_connector_destroy_state - release connector state | 2490 | * __drm_atomic_helper_connector_destroy_state - release connector state |
| 2337 | * @connector: connector object | 2491 | * @connector: connector object |
| 2338 | * @state: connector state object to release | 2492 | * @state: connector state object to release |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 33d877c65ced..e600a5fb2b60 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
| @@ -538,7 +538,12 @@ EXPORT_SYMBOL(drm_framebuffer_reference); | |||
| 538 | */ | 538 | */ |
| 539 | void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) | 539 | void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) |
| 540 | { | 540 | { |
| 541 | struct drm_device *dev = fb->dev; | 541 | struct drm_device *dev; |
| 542 | |||
| 543 | if (!fb) | ||
| 544 | return; | ||
| 545 | |||
| 546 | dev = fb->dev; | ||
| 542 | 547 | ||
| 543 | mutex_lock(&dev->mode_config.fb_lock); | 548 | mutex_lock(&dev->mode_config.fb_lock); |
| 544 | /* Mark fb as reaped and drop idr ref. */ | 549 | /* Mark fb as reaped and drop idr ref. */ |
| @@ -589,12 +594,17 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup); | |||
| 589 | */ | 594 | */ |
| 590 | void drm_framebuffer_remove(struct drm_framebuffer *fb) | 595 | void drm_framebuffer_remove(struct drm_framebuffer *fb) |
| 591 | { | 596 | { |
| 592 | struct drm_device *dev = fb->dev; | 597 | struct drm_device *dev; |
| 593 | struct drm_crtc *crtc; | 598 | struct drm_crtc *crtc; |
| 594 | struct drm_plane *plane; | 599 | struct drm_plane *plane; |
| 595 | struct drm_mode_set set; | 600 | struct drm_mode_set set; |
| 596 | int ret; | 601 | int ret; |
| 597 | 602 | ||
| 603 | if (!fb) | ||
| 604 | return; | ||
| 605 | |||
| 606 | dev = fb->dev; | ||
| 607 | |||
| 598 | WARN_ON(!list_empty(&fb->filp_head)); | 608 | WARN_ON(!list_empty(&fb->filp_head)); |
| 599 | 609 | ||
| 600 | /* | 610 | /* |
| @@ -1509,7 +1519,7 @@ EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); | |||
| 1509 | */ | 1519 | */ |
| 1510 | int drm_mode_create_tv_properties(struct drm_device *dev, | 1520 | int drm_mode_create_tv_properties(struct drm_device *dev, |
| 1511 | unsigned int num_modes, | 1521 | unsigned int num_modes, |
| 1512 | char *modes[]) | 1522 | const char * const modes[]) |
| 1513 | { | 1523 | { |
| 1514 | struct drm_property *tv_selector; | 1524 | struct drm_property *tv_selector; |
| 1515 | struct drm_property *tv_subconnector; | 1525 | struct drm_property *tv_subconnector; |
| @@ -3310,14 +3320,11 @@ int drm_mode_rmfb(struct drm_device *dev, | |||
| 3310 | if (!found) | 3320 | if (!found) |
| 3311 | goto fail_lookup; | 3321 | goto fail_lookup; |
| 3312 | 3322 | ||
| 3313 | /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ | ||
| 3314 | __drm_framebuffer_unregister(dev, fb); | ||
| 3315 | |||
| 3316 | list_del_init(&fb->filp_head); | 3323 | list_del_init(&fb->filp_head); |
| 3317 | mutex_unlock(&dev->mode_config.fb_lock); | 3324 | mutex_unlock(&dev->mode_config.fb_lock); |
| 3318 | mutex_unlock(&file_priv->fbs_lock); | 3325 | mutex_unlock(&file_priv->fbs_lock); |
| 3319 | 3326 | ||
| 3320 | drm_framebuffer_remove(fb); | 3327 | drm_framebuffer_unreference(fb); |
| 3321 | 3328 | ||
| 3322 | return 0; | 3329 | return 0; |
| 3323 | 3330 | ||
| @@ -3484,7 +3491,6 @@ out_err1: | |||
| 3484 | */ | 3491 | */ |
| 3485 | void drm_fb_release(struct drm_file *priv) | 3492 | void drm_fb_release(struct drm_file *priv) |
| 3486 | { | 3493 | { |
| 3487 | struct drm_device *dev = priv->minor->dev; | ||
| 3488 | struct drm_framebuffer *fb, *tfb; | 3494 | struct drm_framebuffer *fb, *tfb; |
| 3489 | 3495 | ||
| 3490 | /* | 3496 | /* |
| @@ -3498,16 +3504,10 @@ void drm_fb_release(struct drm_file *priv) | |||
| 3498 | * at it any more. | 3504 | * at it any more. |
| 3499 | */ | 3505 | */ |
| 3500 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { | 3506 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { |
| 3501 | |||
| 3502 | mutex_lock(&dev->mode_config.fb_lock); | ||
| 3503 | /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ | ||
| 3504 | __drm_framebuffer_unregister(dev, fb); | ||
| 3505 | mutex_unlock(&dev->mode_config.fb_lock); | ||
| 3506 | |||
| 3507 | list_del_init(&fb->filp_head); | 3507 | list_del_init(&fb->filp_head); |
| 3508 | 3508 | ||
| 3509 | /* This will also drop the fpriv->fbs reference. */ | 3509 | /* This drops the fpriv->fbs reference. */ |
| 3510 | drm_framebuffer_remove(fb); | 3510 | drm_framebuffer_unreference(fb); |
| 3511 | } | 3511 | } |
| 3512 | } | 3512 | } |
| 3513 | 3513 | ||
| @@ -5732,7 +5732,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
| 5732 | */ | 5732 | */ |
| 5733 | WARN_ON(!list_empty(&dev->mode_config.fb_list)); | 5733 | WARN_ON(!list_empty(&dev->mode_config.fb_list)); |
| 5734 | list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { | 5734 | list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { |
| 5735 | drm_framebuffer_remove(fb); | 5735 | drm_framebuffer_free(&fb->refcount); |
| 5736 | } | 5736 | } |
| 5737 | 5737 | ||
| 5738 | list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, | 5738 | list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, |
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 291734e87fca..9535c5b60387 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
| @@ -424,6 +424,19 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) | |||
| 424 | I2C_FUNC_10BIT_ADDR; | 424 | I2C_FUNC_10BIT_ADDR; |
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | static void drm_dp_i2c_msg_write_status_update(struct drm_dp_aux_msg *msg) | ||
| 428 | { | ||
| 429 | /* | ||
| 430 | * In case of i2c defer or short i2c ack reply to a write, | ||
| 431 | * we need to switch to WRITE_STATUS_UPDATE to drain the | ||
| 432 | * rest of the message | ||
| 433 | */ | ||
| 434 | if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE) { | ||
| 435 | msg->request &= DP_AUX_I2C_MOT; | ||
| 436 | msg->request |= DP_AUX_I2C_WRITE_STATUS_UPDATE; | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 427 | #define AUX_PRECHARGE_LEN 10 /* 10 to 16 */ | 440 | #define AUX_PRECHARGE_LEN 10 /* 10 to 16 */ |
| 428 | #define AUX_SYNC_LEN (16 + 4) /* preamble + AUX_SYNC_END */ | 441 | #define AUX_SYNC_LEN (16 + 4) /* preamble + AUX_SYNC_END */ |
| 429 | #define AUX_STOP_LEN 4 | 442 | #define AUX_STOP_LEN 4 |
| @@ -579,6 +592,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
| 579 | * Both native ACK and I2C ACK replies received. We | 592 | * Both native ACK and I2C ACK replies received. We |
| 580 | * can assume the transfer was successful. | 593 | * can assume the transfer was successful. |
| 581 | */ | 594 | */ |
| 595 | if (ret != msg->size) | ||
| 596 | drm_dp_i2c_msg_write_status_update(msg); | ||
| 582 | return ret; | 597 | return ret; |
| 583 | 598 | ||
| 584 | case DP_AUX_I2C_REPLY_NACK: | 599 | case DP_AUX_I2C_REPLY_NACK: |
| @@ -596,6 +611,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
| 596 | if (defer_i2c < 7) | 611 | if (defer_i2c < 7) |
| 597 | defer_i2c++; | 612 | defer_i2c++; |
| 598 | usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); | 613 | usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); |
| 614 | drm_dp_i2c_msg_write_status_update(msg); | ||
| 615 | |||
| 599 | continue; | 616 | continue; |
| 600 | 617 | ||
| 601 | default: | 618 | default: |
| @@ -608,6 +625,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
| 608 | return -EREMOTEIO; | 625 | return -EREMOTEIO; |
| 609 | } | 626 | } |
| 610 | 627 | ||
| 628 | static void drm_dp_i2c_msg_set_request(struct drm_dp_aux_msg *msg, | ||
| 629 | const struct i2c_msg *i2c_msg) | ||
| 630 | { | ||
| 631 | msg->request = (i2c_msg->flags & I2C_M_RD) ? | ||
| 632 | DP_AUX_I2C_READ : DP_AUX_I2C_WRITE; | ||
| 633 | msg->request |= DP_AUX_I2C_MOT; | ||
| 634 | } | ||
| 635 | |||
| 611 | /* | 636 | /* |
| 612 | * Keep retrying drm_dp_i2c_do_msg until all data has been transferred. | 637 | * Keep retrying drm_dp_i2c_do_msg until all data has been transferred. |
| 613 | * | 638 | * |
| @@ -661,10 +686,7 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | |||
| 661 | 686 | ||
| 662 | for (i = 0; i < num; i++) { | 687 | for (i = 0; i < num; i++) { |
| 663 | msg.address = msgs[i].addr; | 688 | msg.address = msgs[i].addr; |
| 664 | msg.request = (msgs[i].flags & I2C_M_RD) ? | 689 | drm_dp_i2c_msg_set_request(&msg, &msgs[i]); |
| 665 | DP_AUX_I2C_READ : | ||
| 666 | DP_AUX_I2C_WRITE; | ||
| 667 | msg.request |= DP_AUX_I2C_MOT; | ||
| 668 | /* Send a bare address packet to start the transaction. | 690 | /* Send a bare address packet to start the transaction. |
| 669 | * Zero sized messages specify an address only (bare | 691 | * Zero sized messages specify an address only (bare |
| 670 | * address) transaction. | 692 | * address) transaction. |
| @@ -672,6 +694,13 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | |||
| 672 | msg.buffer = NULL; | 694 | msg.buffer = NULL; |
| 673 | msg.size = 0; | 695 | msg.size = 0; |
| 674 | err = drm_dp_i2c_do_msg(aux, &msg); | 696 | err = drm_dp_i2c_do_msg(aux, &msg); |
| 697 | |||
| 698 | /* | ||
| 699 | * Reset msg.request in case in case it got | ||
| 700 | * changed into a WRITE_STATUS_UPDATE. | ||
| 701 | */ | ||
| 702 | drm_dp_i2c_msg_set_request(&msg, &msgs[i]); | ||
| 703 | |||
| 675 | if (err < 0) | 704 | if (err < 0) |
| 676 | break; | 705 | break; |
| 677 | /* We want each transaction to be as large as possible, but | 706 | /* We want each transaction to be as large as possible, but |
| @@ -684,6 +713,13 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | |||
| 684 | msg.size = min(transfer_size, msgs[i].len - j); | 713 | msg.size = min(transfer_size, msgs[i].len - j); |
| 685 | 714 | ||
| 686 | err = drm_dp_i2c_drain_msg(aux, &msg); | 715 | err = drm_dp_i2c_drain_msg(aux, &msg); |
| 716 | |||
| 717 | /* | ||
| 718 | * Reset msg.request in case in case it got | ||
| 719 | * changed into a WRITE_STATUS_UPDATE. | ||
| 720 | */ | ||
| 721 | drm_dp_i2c_msg_set_request(&msg, &msgs[i]); | ||
| 722 | |||
| 687 | if (err < 0) | 723 | if (err < 0) |
| 688 | break; | 724 | break; |
| 689 | transfer_size = err; | 725 | transfer_size = err; |
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 53d09a19f7e1..9ad823fcde87 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
| @@ -55,7 +55,6 @@ module_param_named(debug, drm_debug, int, 0600); | |||
| 55 | static DEFINE_SPINLOCK(drm_minor_lock); | 55 | static DEFINE_SPINLOCK(drm_minor_lock); |
| 56 | static struct idr drm_minors_idr; | 56 | static struct idr drm_minors_idr; |
| 57 | 57 | ||
| 58 | struct class *drm_class; | ||
| 59 | static struct dentry *drm_debugfs_root; | 58 | static struct dentry *drm_debugfs_root; |
| 60 | 59 | ||
| 61 | void drm_err(const char *format, ...) | 60 | void drm_err(const char *format, ...) |
| @@ -566,6 +565,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, | |||
| 566 | ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); | 565 | ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); |
| 567 | if (ret) | 566 | if (ret) |
| 568 | goto err_minors; | 567 | goto err_minors; |
| 568 | |||
| 569 | WARN_ON(driver->suspend || driver->resume); | ||
| 569 | } | 570 | } |
| 570 | 571 | ||
| 571 | if (drm_core_check_feature(dev, DRIVER_RENDER)) { | 572 | if (drm_core_check_feature(dev, DRIVER_RENDER)) { |
| @@ -839,10 +840,9 @@ static int __init drm_core_init(void) | |||
| 839 | if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) | 840 | if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) |
| 840 | goto err_p1; | 841 | goto err_p1; |
| 841 | 842 | ||
| 842 | drm_class = drm_sysfs_create(THIS_MODULE, "drm"); | 843 | ret = drm_sysfs_init(); |
| 843 | if (IS_ERR(drm_class)) { | 844 | if (ret < 0) { |
| 844 | printk(KERN_ERR "DRM: Error creating drm class.\n"); | 845 | printk(KERN_ERR "DRM: Error creating drm class.\n"); |
| 845 | ret = PTR_ERR(drm_class); | ||
| 846 | goto err_p2; | 846 | goto err_p2; |
| 847 | } | 847 | } |
| 848 | 848 | ||
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 05bb7311ac5d..d895556be4f0 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
| @@ -2044,7 +2044,7 @@ mode_in_range(const struct drm_display_mode *mode, struct edid *edid, | |||
| 2044 | static bool valid_inferred_mode(const struct drm_connector *connector, | 2044 | static bool valid_inferred_mode(const struct drm_connector *connector, |
| 2045 | const struct drm_display_mode *mode) | 2045 | const struct drm_display_mode *mode) |
| 2046 | { | 2046 | { |
| 2047 | struct drm_display_mode *m; | 2047 | const struct drm_display_mode *m; |
| 2048 | bool ok = false; | 2048 | bool ok = false; |
| 2049 | 2049 | ||
| 2050 | list_for_each_entry(m, &connector->probed_modes, head) { | 2050 | list_for_each_entry(m, &connector->probed_modes, head) { |
| @@ -3361,7 +3361,7 @@ EXPORT_SYMBOL(drm_edid_to_speaker_allocation); | |||
| 3361 | * the sink doesn't support audio or video. | 3361 | * the sink doesn't support audio or video. |
| 3362 | */ | 3362 | */ |
| 3363 | int drm_av_sync_delay(struct drm_connector *connector, | 3363 | int drm_av_sync_delay(struct drm_connector *connector, |
| 3364 | struct drm_display_mode *mode) | 3364 | const struct drm_display_mode *mode) |
| 3365 | { | 3365 | { |
| 3366 | int i = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); | 3366 | int i = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); |
| 3367 | int a, v; | 3367 | int a, v; |
| @@ -3396,7 +3396,6 @@ EXPORT_SYMBOL(drm_av_sync_delay); | |||
| 3396 | /** | 3396 | /** |
| 3397 | * drm_select_eld - select one ELD from multiple HDMI/DP sinks | 3397 | * drm_select_eld - select one ELD from multiple HDMI/DP sinks |
| 3398 | * @encoder: the encoder just changed display mode | 3398 | * @encoder: the encoder just changed display mode |
| 3399 | * @mode: the adjusted display mode | ||
| 3400 | * | 3399 | * |
| 3401 | * It's possible for one encoder to be associated with multiple HDMI/DP sinks. | 3400 | * It's possible for one encoder to be associated with multiple HDMI/DP sinks. |
| 3402 | * The policy is now hard coded to simply use the first HDMI/DP sink's ELD. | 3401 | * The policy is now hard coded to simply use the first HDMI/DP sink's ELD. |
| @@ -3404,8 +3403,7 @@ EXPORT_SYMBOL(drm_av_sync_delay); | |||
| 3404 | * Return: The connector associated with the first HDMI/DP sink that has ELD | 3403 | * Return: The connector associated with the first HDMI/DP sink that has ELD |
| 3405 | * attached to it. | 3404 | * attached to it. |
| 3406 | */ | 3405 | */ |
| 3407 | struct drm_connector *drm_select_eld(struct drm_encoder *encoder, | 3406 | struct drm_connector *drm_select_eld(struct drm_encoder *encoder) |
| 3408 | struct drm_display_mode *mode) | ||
| 3409 | { | 3407 | { |
| 3410 | struct drm_connector *connector; | 3408 | struct drm_connector *connector; |
| 3411 | struct drm_device *dev = encoder->dev; | 3409 | struct drm_device *dev = encoder->dev; |
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index c5605fe4907e..698b8c3b09d9 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c | |||
| @@ -32,7 +32,7 @@ MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " | |||
| 32 | "from built-in data or /lib/firmware instead. "); | 32 | "from built-in data or /lib/firmware instead. "); |
| 33 | 33 | ||
| 34 | #define GENERIC_EDIDS 6 | 34 | #define GENERIC_EDIDS 6 |
| 35 | static const char *generic_edid_name[GENERIC_EDIDS] = { | 35 | static const char * const generic_edid_name[GENERIC_EDIDS] = { |
| 36 | "edid/800x600.bin", | 36 | "edid/800x600.bin", |
| 37 | "edid/1024x768.bin", | 37 | "edid/1024x768.bin", |
| 38 | "edid/1280x1024.bin", | 38 | "edid/1280x1024.bin", |
| @@ -264,20 +264,43 @@ out: | |||
| 264 | int drm_load_edid_firmware(struct drm_connector *connector) | 264 | int drm_load_edid_firmware(struct drm_connector *connector) |
| 265 | { | 265 | { |
| 266 | const char *connector_name = connector->name; | 266 | const char *connector_name = connector->name; |
| 267 | char *edidname = edid_firmware, *last, *colon; | 267 | char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL; |
| 268 | int ret; | 268 | int ret; |
| 269 | struct edid *edid; | 269 | struct edid *edid; |
| 270 | 270 | ||
| 271 | if (*edidname == '\0') | 271 | if (edid_firmware[0] == '\0') |
| 272 | return 0; | 272 | return 0; |
| 273 | 273 | ||
| 274 | colon = strchr(edidname, ':'); | 274 | /* |
| 275 | if (colon != NULL) { | 275 | * If there are multiple edid files specified and separated |
| 276 | if (strncmp(connector_name, edidname, colon - edidname)) | 276 | * by commas, search through the list looking for one that |
| 277 | return 0; | 277 | * matches the connector. |
| 278 | edidname = colon + 1; | 278 | * |
| 279 | if (*edidname == '\0') | 279 | * If there's one or more that don't't specify a connector, keep |
| 280 | * the last one found one as a fallback. | ||
| 281 | */ | ||
| 282 | fwstr = kstrdup(edid_firmware, GFP_KERNEL); | ||
| 283 | edidstr = fwstr; | ||
| 284 | |||
| 285 | while ((edidname = strsep(&edidstr, ","))) { | ||
| 286 | colon = strchr(edidname, ':'); | ||
| 287 | if (colon != NULL) { | ||
| 288 | if (strncmp(connector_name, edidname, colon - edidname)) | ||
| 289 | continue; | ||
| 290 | edidname = colon + 1; | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | |||
| 294 | if (*edidname != '\0') /* corner case: multiple ',' */ | ||
| 295 | fallback = edidname; | ||
| 296 | } | ||
| 297 | |||
| 298 | if (!edidname) { | ||
| 299 | if (!fallback) { | ||
| 300 | kfree(fwstr); | ||
| 280 | return 0; | 301 | return 0; |
| 302 | } | ||
| 303 | edidname = fallback; | ||
| 281 | } | 304 | } |
| 282 | 305 | ||
| 283 | last = edidname + strlen(edidname) - 1; | 306 | last = edidname + strlen(edidname) - 1; |
| @@ -285,6 +308,8 @@ int drm_load_edid_firmware(struct drm_connector *connector) | |||
| 285 | *last = '\0'; | 308 | *last = '\0'; |
| 286 | 309 | ||
| 287 | edid = edid_load(connector, edidname, connector_name); | 310 | edid = edid_load(connector, edidname, connector_name); |
| 311 | kfree(fwstr); | ||
| 312 | |||
| 288 | if (IS_ERR_OR_NULL(edid)) | 313 | if (IS_ERR_OR_NULL(edid)) |
| 289 | return 0; | 314 | return 0; |
| 290 | 315 | ||
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 418d299f3b12..abe9793d548d 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
| @@ -38,6 +38,13 @@ | |||
| 38 | #include <drm/drm_crtc.h> | 38 | #include <drm/drm_crtc.h> |
| 39 | #include <drm/drm_fb_helper.h> | 39 | #include <drm/drm_fb_helper.h> |
| 40 | #include <drm/drm_crtc_helper.h> | 40 | #include <drm/drm_crtc_helper.h> |
| 41 | #include <drm/drm_atomic.h> | ||
| 42 | #include <drm/drm_atomic_helper.h> | ||
| 43 | |||
| 44 | static bool drm_fbdev_emulation = true; | ||
| 45 | module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600); | ||
| 46 | MODULE_PARM_DESC(fbdev_emulation, | ||
| 47 | "Enable legacy fbdev emulation [default=true]"); | ||
| 41 | 48 | ||
| 42 | static LIST_HEAD(kernel_fb_helper_list); | 49 | static LIST_HEAD(kernel_fb_helper_list); |
| 43 | 50 | ||
| @@ -99,6 +106,9 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) | |||
| 99 | struct drm_connector *connector; | 106 | struct drm_connector *connector; |
| 100 | int i; | 107 | int i; |
| 101 | 108 | ||
| 109 | if (!drm_fbdev_emulation) | ||
| 110 | return 0; | ||
| 111 | |||
| 102 | mutex_lock(&dev->mode_config.mutex); | 112 | mutex_lock(&dev->mode_config.mutex); |
| 103 | drm_for_each_connector(connector, dev) { | 113 | drm_for_each_connector(connector, dev) { |
| 104 | struct drm_fb_helper_connector *fb_helper_connector; | 114 | struct drm_fb_helper_connector *fb_helper_connector; |
| @@ -129,6 +139,9 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_ | |||
| 129 | struct drm_fb_helper_connector **temp; | 139 | struct drm_fb_helper_connector **temp; |
| 130 | struct drm_fb_helper_connector *fb_helper_connector; | 140 | struct drm_fb_helper_connector *fb_helper_connector; |
| 131 | 141 | ||
| 142 | if (!drm_fbdev_emulation) | ||
| 143 | return 0; | ||
| 144 | |||
| 132 | WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); | 145 | WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); |
| 133 | if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { | 146 | if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { |
| 134 | temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL); | 147 | temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL); |
| @@ -184,6 +197,9 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, | |||
| 184 | struct drm_fb_helper_connector *fb_helper_connector; | 197 | struct drm_fb_helper_connector *fb_helper_connector; |
| 185 | int i, j; | 198 | int i, j; |
| 186 | 199 | ||
| 200 | if (!drm_fbdev_emulation) | ||
| 201 | return 0; | ||
| 202 | |||
| 187 | WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); | 203 | WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); |
| 188 | 204 | ||
| 189 | for (i = 0; i < fb_helper->connector_count; i++) { | 205 | for (i = 0; i < fb_helper->connector_count; i++) { |
| @@ -320,15 +336,96 @@ int drm_fb_helper_debug_leave(struct fb_info *info) | |||
| 320 | } | 336 | } |
| 321 | EXPORT_SYMBOL(drm_fb_helper_debug_leave); | 337 | EXPORT_SYMBOL(drm_fb_helper_debug_leave); |
| 322 | 338 | ||
| 323 | static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) | 339 | static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper) |
| 340 | { | ||
| 341 | struct drm_device *dev = fb_helper->dev; | ||
| 342 | struct drm_plane *plane; | ||
| 343 | struct drm_atomic_state *state; | ||
| 344 | int i, ret; | ||
| 345 | |||
| 346 | state = drm_atomic_state_alloc(dev); | ||
| 347 | if (!state) | ||
| 348 | return -ENOMEM; | ||
| 349 | |||
| 350 | state->acquire_ctx = dev->mode_config.acquire_ctx; | ||
| 351 | retry: | ||
| 352 | drm_for_each_plane(plane, dev) { | ||
| 353 | struct drm_plane_state *plane_state; | ||
| 354 | |||
| 355 | plane->old_fb = plane->fb; | ||
| 356 | |||
| 357 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
| 358 | if (IS_ERR(plane_state)) { | ||
| 359 | ret = PTR_ERR(plane_state); | ||
| 360 | goto fail; | ||
| 361 | } | ||
| 362 | |||
| 363 | ret = drm_atomic_plane_set_property(plane, plane_state, | ||
| 364 | dev->mode_config.rotation_property, | ||
| 365 | BIT(DRM_ROTATE_0)); | ||
| 366 | if (ret != 0) | ||
| 367 | goto fail; | ||
| 368 | |||
| 369 | /* disable non-primary: */ | ||
| 370 | if (plane->type == DRM_PLANE_TYPE_PRIMARY) | ||
| 371 | continue; | ||
| 372 | |||
| 373 | ret = __drm_atomic_helper_disable_plane(plane, plane_state); | ||
| 374 | if (ret != 0) | ||
| 375 | goto fail; | ||
| 376 | } | ||
| 377 | |||
| 378 | for(i = 0; i < fb_helper->crtc_count; i++) { | ||
| 379 | struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; | ||
| 380 | |||
| 381 | ret = __drm_atomic_helper_set_config(mode_set, state); | ||
| 382 | if (ret != 0) | ||
| 383 | goto fail; | ||
| 384 | } | ||
| 385 | |||
| 386 | ret = drm_atomic_commit(state); | ||
| 387 | |||
| 388 | fail: | ||
| 389 | drm_for_each_plane(plane, dev) { | ||
| 390 | if (ret == 0) { | ||
| 391 | struct drm_framebuffer *new_fb = plane->state->fb; | ||
| 392 | if (new_fb) | ||
| 393 | drm_framebuffer_reference(new_fb); | ||
| 394 | plane->fb = new_fb; | ||
| 395 | plane->crtc = plane->state->crtc; | ||
| 396 | |||
| 397 | if (plane->old_fb) | ||
| 398 | drm_framebuffer_unreference(plane->old_fb); | ||
| 399 | } | ||
| 400 | plane->old_fb = NULL; | ||
| 401 | } | ||
| 402 | |||
| 403 | if (ret == -EDEADLK) | ||
| 404 | goto backoff; | ||
| 405 | |||
| 406 | if (ret != 0) | ||
| 407 | drm_atomic_state_free(state); | ||
| 408 | |||
| 409 | return ret; | ||
| 410 | |||
| 411 | backoff: | ||
| 412 | drm_atomic_state_clear(state); | ||
| 413 | drm_atomic_legacy_backoff(state); | ||
| 414 | |||
| 415 | goto retry; | ||
| 416 | } | ||
| 417 | |||
| 418 | static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) | ||
| 324 | { | 419 | { |
| 325 | struct drm_device *dev = fb_helper->dev; | 420 | struct drm_device *dev = fb_helper->dev; |
| 326 | struct drm_plane *plane; | 421 | struct drm_plane *plane; |
| 327 | bool error = false; | ||
| 328 | int i; | 422 | int i; |
| 329 | 423 | ||
| 330 | drm_warn_on_modeset_not_all_locked(dev); | 424 | drm_warn_on_modeset_not_all_locked(dev); |
| 331 | 425 | ||
| 426 | if (fb_helper->atomic) | ||
| 427 | return restore_fbdev_mode_atomic(fb_helper); | ||
| 428 | |||
| 332 | drm_for_each_plane(plane, dev) { | 429 | drm_for_each_plane(plane, dev) { |
| 333 | if (plane->type != DRM_PLANE_TYPE_PRIMARY) | 430 | if (plane->type != DRM_PLANE_TYPE_PRIMARY) |
| 334 | drm_plane_force_disable(plane); | 431 | drm_plane_force_disable(plane); |
| @@ -348,14 +445,15 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) | |||
| 348 | if (crtc->funcs->cursor_set) { | 445 | if (crtc->funcs->cursor_set) { |
| 349 | ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0); | 446 | ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0); |
| 350 | if (ret) | 447 | if (ret) |
| 351 | error = true; | 448 | return ret; |
| 352 | } | 449 | } |
| 353 | 450 | ||
| 354 | ret = drm_mode_set_config_internal(mode_set); | 451 | ret = drm_mode_set_config_internal(mode_set); |
| 355 | if (ret) | 452 | if (ret) |
| 356 | error = true; | 453 | return ret; |
| 357 | } | 454 | } |
| 358 | return error; | 455 | |
| 456 | return 0; | ||
| 359 | } | 457 | } |
| 360 | 458 | ||
| 361 | /** | 459 | /** |
| @@ -365,12 +463,18 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) | |||
| 365 | * This should be called from driver's drm ->lastclose callback | 463 | * This should be called from driver's drm ->lastclose callback |
| 366 | * when implementing an fbcon on top of kms using this helper. This ensures that | 464 | * when implementing an fbcon on top of kms using this helper. This ensures that |
| 367 | * the user isn't greeted with a black screen when e.g. X dies. | 465 | * the user isn't greeted with a black screen when e.g. X dies. |
| 466 | * | ||
| 467 | * RETURNS: | ||
| 468 | * Zero if everything went ok, negative error code otherwise. | ||
| 368 | */ | 469 | */ |
| 369 | bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) | 470 | int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) |
| 370 | { | 471 | { |
| 371 | struct drm_device *dev = fb_helper->dev; | 472 | struct drm_device *dev = fb_helper->dev; |
| 372 | bool ret; | 473 | bool do_delayed; |
| 373 | bool do_delayed = false; | 474 | int ret; |
| 475 | |||
| 476 | if (!drm_fbdev_emulation) | ||
| 477 | return -ENODEV; | ||
| 374 | 478 | ||
| 375 | drm_modeset_lock_all(dev); | 479 | drm_modeset_lock_all(dev); |
| 376 | ret = restore_fbdev_mode(fb_helper); | 480 | ret = restore_fbdev_mode(fb_helper); |
| @@ -588,6 +692,9 @@ int drm_fb_helper_init(struct drm_device *dev, | |||
| 588 | struct drm_crtc *crtc; | 692 | struct drm_crtc *crtc; |
| 589 | int i; | 693 | int i; |
| 590 | 694 | ||
| 695 | if (!drm_fbdev_emulation) | ||
| 696 | return 0; | ||
| 697 | |||
| 591 | if (!max_conn_count) | 698 | if (!max_conn_count) |
| 592 | return -EINVAL; | 699 | return -EINVAL; |
| 593 | 700 | ||
| @@ -621,6 +728,8 @@ int drm_fb_helper_init(struct drm_device *dev, | |||
| 621 | i++; | 728 | i++; |
| 622 | } | 729 | } |
| 623 | 730 | ||
| 731 | fb_helper->atomic = !!drm_core_check_feature(dev, DRIVER_ATOMIC); | ||
| 732 | |||
| 624 | return 0; | 733 | return 0; |
| 625 | out_free: | 734 | out_free: |
| 626 | drm_fb_helper_crtc_free(fb_helper); | 735 | drm_fb_helper_crtc_free(fb_helper); |
| @@ -710,6 +819,9 @@ EXPORT_SYMBOL(drm_fb_helper_release_fbi); | |||
| 710 | 819 | ||
| 711 | void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) | 820 | void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) |
| 712 | { | 821 | { |
| 822 | if (!drm_fbdev_emulation) | ||
| 823 | return; | ||
| 824 | |||
| 713 | if (!list_empty(&fb_helper->kernel_fb_list)) { | 825 | if (!list_empty(&fb_helper->kernel_fb_list)) { |
| 714 | list_del(&fb_helper->kernel_fb_list); | 826 | list_del(&fb_helper->kernel_fb_list); |
| 715 | if (list_empty(&kernel_fb_helper_list)) { | 827 | if (list_empty(&kernel_fb_helper_list)) { |
| @@ -1118,6 +1230,57 @@ int drm_fb_helper_set_par(struct fb_info *info) | |||
| 1118 | } | 1230 | } |
| 1119 | EXPORT_SYMBOL(drm_fb_helper_set_par); | 1231 | EXPORT_SYMBOL(drm_fb_helper_set_par); |
| 1120 | 1232 | ||
| 1233 | static int pan_display_atomic(struct fb_var_screeninfo *var, | ||
| 1234 | struct fb_info *info) | ||
| 1235 | { | ||
| 1236 | struct drm_fb_helper *fb_helper = info->par; | ||
| 1237 | struct drm_device *dev = fb_helper->dev; | ||
| 1238 | struct drm_atomic_state *state; | ||
| 1239 | int i, ret; | ||
| 1240 | |||
| 1241 | state = drm_atomic_state_alloc(dev); | ||
| 1242 | if (!state) | ||
| 1243 | return -ENOMEM; | ||
| 1244 | |||
| 1245 | state->acquire_ctx = dev->mode_config.acquire_ctx; | ||
| 1246 | retry: | ||
| 1247 | for(i = 0; i < fb_helper->crtc_count; i++) { | ||
| 1248 | struct drm_mode_set *mode_set; | ||
| 1249 | |||
| 1250 | mode_set = &fb_helper->crtc_info[i].mode_set; | ||
| 1251 | |||
| 1252 | mode_set->x = var->xoffset; | ||
| 1253 | mode_set->y = var->yoffset; | ||
| 1254 | |||
| 1255 | ret = __drm_atomic_helper_set_config(mode_set, state); | ||
| 1256 | if (ret != 0) | ||
| 1257 | goto fail; | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | ret = drm_atomic_commit(state); | ||
| 1261 | if (ret != 0) | ||
| 1262 | goto fail; | ||
| 1263 | |||
| 1264 | info->var.xoffset = var->xoffset; | ||
| 1265 | info->var.yoffset = var->yoffset; | ||
| 1266 | |||
| 1267 | return 0; | ||
| 1268 | |||
| 1269 | fail: | ||
| 1270 | if (ret == -EDEADLK) | ||
| 1271 | goto backoff; | ||
| 1272 | |||
| 1273 | drm_atomic_state_free(state); | ||
| 1274 | |||
| 1275 | return ret; | ||
| 1276 | |||
| 1277 | backoff: | ||
| 1278 | drm_atomic_state_clear(state); | ||
| 1279 | drm_atomic_legacy_backoff(state); | ||
| 1280 | |||
| 1281 | goto retry; | ||
| 1282 | } | ||
| 1283 | |||
| 1121 | /** | 1284 | /** |
| 1122 | * drm_fb_helper_pan_display - implementation for ->fb_pan_display | 1285 | * drm_fb_helper_pan_display - implementation for ->fb_pan_display |
| 1123 | * @var: updated screen information | 1286 | * @var: updated screen information |
| @@ -1141,6 +1304,11 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | |||
| 1141 | return -EBUSY; | 1304 | return -EBUSY; |
| 1142 | } | 1305 | } |
| 1143 | 1306 | ||
| 1307 | if (fb_helper->atomic) { | ||
| 1308 | ret = pan_display_atomic(var, info); | ||
| 1309 | goto unlock; | ||
| 1310 | } | ||
| 1311 | |||
| 1144 | for (i = 0; i < fb_helper->crtc_count; i++) { | 1312 | for (i = 0; i < fb_helper->crtc_count; i++) { |
| 1145 | modeset = &fb_helper->crtc_info[i].mode_set; | 1313 | modeset = &fb_helper->crtc_info[i].mode_set; |
| 1146 | 1314 | ||
| @@ -1155,6 +1323,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | |||
| 1155 | } | 1323 | } |
| 1156 | } | 1324 | } |
| 1157 | } | 1325 | } |
| 1326 | unlock: | ||
| 1158 | drm_modeset_unlock_all(dev); | 1327 | drm_modeset_unlock_all(dev); |
| 1159 | return ret; | 1328 | return ret; |
| 1160 | } | 1329 | } |
| @@ -1930,6 +2099,9 @@ int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) | |||
| 1930 | struct drm_device *dev = fb_helper->dev; | 2099 | struct drm_device *dev = fb_helper->dev; |
| 1931 | int count = 0; | 2100 | int count = 0; |
| 1932 | 2101 | ||
| 2102 | if (!drm_fbdev_emulation) | ||
| 2103 | return 0; | ||
| 2104 | |||
| 1933 | mutex_lock(&dev->mode_config.mutex); | 2105 | mutex_lock(&dev->mode_config.mutex); |
| 1934 | count = drm_fb_helper_probe_connector_modes(fb_helper, | 2106 | count = drm_fb_helper_probe_connector_modes(fb_helper, |
| 1935 | dev->mode_config.max_width, | 2107 | dev->mode_config.max_width, |
| @@ -1973,6 +2145,9 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) | |||
| 1973 | struct drm_device *dev = fb_helper->dev; | 2145 | struct drm_device *dev = fb_helper->dev; |
| 1974 | u32 max_width, max_height; | 2146 | u32 max_width, max_height; |
| 1975 | 2147 | ||
| 2148 | if (!drm_fbdev_emulation) | ||
| 2149 | return 0; | ||
| 2150 | |||
| 1976 | mutex_lock(&fb_helper->dev->mode_config.mutex); | 2151 | mutex_lock(&fb_helper->dev->mode_config.mutex); |
| 1977 | if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) { | 2152 | if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) { |
| 1978 | fb_helper->delayed_hotplug = true; | 2153 | fb_helper->delayed_hotplug = true; |
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 059af01bd07a..43cbda3306ac 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h | |||
| @@ -73,7 +73,7 @@ int drm_authmagic(struct drm_device *dev, void *data, | |||
| 73 | /* drm_sysfs.c */ | 73 | /* drm_sysfs.c */ |
| 74 | extern struct class *drm_class; | 74 | extern struct class *drm_class; |
| 75 | 75 | ||
| 76 | struct class *drm_sysfs_create(struct module *owner, char *name); | 76 | int drm_sysfs_init(void); |
| 77 | void drm_sysfs_destroy(void); | 77 | void drm_sysfs_destroy(void); |
| 78 | struct device *drm_sysfs_minor_alloc(struct drm_minor *minor); | 78 | struct device *drm_sysfs_minor_alloc(struct drm_minor *minor); |
| 79 | int drm_sysfs_connector_add(struct drm_connector *connector); | 79 | int drm_sysfs_connector_add(struct drm_connector *connector); |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 22d207e211e7..ed2394e1720b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
| @@ -74,22 +74,22 @@ module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); | |||
| 74 | module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); | 74 | module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); |
| 75 | module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); | 75 | module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); |
| 76 | 76 | ||
| 77 | static void store_vblank(struct drm_device *dev, int crtc, | 77 | static void store_vblank(struct drm_device *dev, unsigned int pipe, |
| 78 | u32 vblank_count_inc, | 78 | u32 vblank_count_inc, |
| 79 | struct timeval *t_vblank) | 79 | struct timeval *t_vblank, u32 last) |
| 80 | { | 80 | { |
| 81 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | 81 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
| 82 | u32 tslot; | 82 | u32 tslot; |
| 83 | 83 | ||
| 84 | assert_spin_locked(&dev->vblank_time_lock); | 84 | assert_spin_locked(&dev->vblank_time_lock); |
| 85 | 85 | ||
| 86 | if (t_vblank) { | 86 | vblank->last = last; |
| 87 | /* All writers hold the spinlock, but readers are serialized by | 87 | |
| 88 | * the latching of vblank->count below. | 88 | /* All writers hold the spinlock, but readers are serialized by |
| 89 | */ | 89 | * the latching of vblank->count below. |
| 90 | tslot = vblank->count + vblank_count_inc; | 90 | */ |
| 91 | vblanktimestamp(dev, crtc, tslot) = *t_vblank; | 91 | tslot = vblank->count + vblank_count_inc; |
| 92 | } | 92 | vblanktimestamp(dev, pipe, tslot) = *t_vblank; |
| 93 | 93 | ||
| 94 | /* | 94 | /* |
| 95 | * vblank timestamp updates are protected on the write side with | 95 | * vblank timestamp updates are protected on the write side with |
| @@ -105,12 +105,60 @@ static void store_vblank(struct drm_device *dev, int crtc, | |||
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | /** | 107 | /** |
| 108 | * drm_reset_vblank_timestamp - reset the last timestamp to the last vblank | ||
| 109 | * @dev: DRM device | ||
| 110 | * @pipe: index of CRTC for which to reset the timestamp | ||
| 111 | * | ||
| 112 | * Reset the stored timestamp for the current vblank count to correspond | ||
| 113 | * to the last vblank occurred. | ||
| 114 | * | ||
| 115 | * Only to be called from drm_vblank_on(). | ||
| 116 | * | ||
| 117 | * Note: caller must hold dev->vbl_lock since this reads & writes | ||
| 118 | * device vblank fields. | ||
| 119 | */ | ||
| 120 | static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe) | ||
| 121 | { | ||
| 122 | u32 cur_vblank; | ||
| 123 | bool rc; | ||
| 124 | struct timeval t_vblank; | ||
| 125 | int count = DRM_TIMESTAMP_MAXRETRIES; | ||
| 126 | |||
| 127 | spin_lock(&dev->vblank_time_lock); | ||
| 128 | |||
| 129 | /* | ||
| 130 | * sample the current counter to avoid random jumps | ||
| 131 | * when drm_vblank_enable() applies the diff | ||
| 132 | */ | ||
| 133 | do { | ||
| 134 | cur_vblank = dev->driver->get_vblank_counter(dev, pipe); | ||
| 135 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0); | ||
| 136 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0); | ||
| 137 | |||
| 138 | /* | ||
| 139 | * Only reinitialize corresponding vblank timestamp if high-precision query | ||
| 140 | * available and didn't fail. Otherwise reinitialize delayed at next vblank | ||
| 141 | * interrupt and assign 0 for now, to mark the vblanktimestamp as invalid. | ||
| 142 | */ | ||
| 143 | if (!rc) | ||
| 144 | t_vblank = (struct timeval) {0, 0}; | ||
| 145 | |||
| 146 | /* | ||
| 147 | * +1 to make sure user will never see the same | ||
| 148 | * vblank counter value before and after a modeset | ||
| 149 | */ | ||
| 150 | store_vblank(dev, pipe, 1, &t_vblank, cur_vblank); | ||
| 151 | |||
| 152 | spin_unlock(&dev->vblank_time_lock); | ||
| 153 | } | ||
| 154 | |||
| 155 | /** | ||
| 108 | * drm_update_vblank_count - update the master vblank counter | 156 | * drm_update_vblank_count - update the master vblank counter |
| 109 | * @dev: DRM device | 157 | * @dev: DRM device |
| 110 | * @pipe: counter to update | 158 | * @pipe: counter to update |
| 111 | * | 159 | * |
| 112 | * Call back into the driver to update the appropriate vblank counter | 160 | * Call back into the driver to update the appropriate vblank counter |
| 113 | * (specified by @crtc). Deal with wraparound, if it occurred, and | 161 | * (specified by @pipe). Deal with wraparound, if it occurred, and |
| 114 | * update the last read value so we can deal with wraparound on the next | 162 | * update the last read value so we can deal with wraparound on the next |
| 115 | * call if necessary. | 163 | * call if necessary. |
| 116 | * | 164 | * |
| @@ -120,12 +168,15 @@ static void store_vblank(struct drm_device *dev, int crtc, | |||
| 120 | * Note: caller must hold dev->vbl_lock since this reads & writes | 168 | * Note: caller must hold dev->vbl_lock since this reads & writes |
| 121 | * device vblank fields. | 169 | * device vblank fields. |
| 122 | */ | 170 | */ |
| 123 | static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe) | 171 | static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, |
| 172 | unsigned long flags) | ||
| 124 | { | 173 | { |
| 125 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | 174 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
| 126 | u32 cur_vblank, diff; | 175 | u32 cur_vblank, diff; |
| 127 | bool rc; | 176 | bool rc; |
| 128 | struct timeval t_vblank; | 177 | struct timeval t_vblank; |
| 178 | int count = DRM_TIMESTAMP_MAXRETRIES; | ||
| 179 | int framedur_ns = vblank->framedur_ns; | ||
| 129 | 180 | ||
| 130 | /* | 181 | /* |
| 131 | * Interrupts were disabled prior to this call, so deal with counter | 182 | * Interrupts were disabled prior to this call, so deal with counter |
| @@ -141,23 +192,43 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe) | |||
| 141 | */ | 192 | */ |
| 142 | do { | 193 | do { |
| 143 | cur_vblank = dev->driver->get_vblank_counter(dev, pipe); | 194 | cur_vblank = dev->driver->get_vblank_counter(dev, pipe); |
| 144 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0); | 195 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, flags); |
| 145 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe)); | 196 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0); |
| 197 | |||
| 198 | if (dev->max_vblank_count != 0) { | ||
| 199 | /* trust the hw counter when it's around */ | ||
| 200 | diff = (cur_vblank - vblank->last) & dev->max_vblank_count; | ||
| 201 | } else if (rc && framedur_ns) { | ||
| 202 | const struct timeval *t_old; | ||
| 203 | u64 diff_ns; | ||
| 146 | 204 | ||
| 147 | /* Deal with counter wrap */ | 205 | t_old = &vblanktimestamp(dev, pipe, vblank->count); |
| 148 | diff = cur_vblank - vblank->last; | 206 | diff_ns = timeval_to_ns(&t_vblank) - timeval_to_ns(t_old); |
| 149 | if (cur_vblank < vblank->last) { | 207 | |
| 150 | diff += dev->max_vblank_count + 1; | 208 | /* |
| 209 | * Figure out how many vblanks we've missed based | ||
| 210 | * on the difference in the timestamps and the | ||
| 211 | * frame/field duration. | ||
| 212 | */ | ||
| 213 | diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); | ||
| 151 | 214 | ||
| 152 | DRM_DEBUG("last_vblank[%u]=0x%x, cur_vblank=0x%x => diff=0x%x\n", | 215 | if (diff == 0 && flags & DRM_CALLED_FROM_VBLIRQ) |
| 153 | pipe, vblank->last, cur_vblank, diff); | 216 | DRM_DEBUG("crtc %u: Redundant vblirq ignored." |
| 217 | " diff_ns = %lld, framedur_ns = %d)\n", | ||
| 218 | pipe, (long long) diff_ns, framedur_ns); | ||
| 219 | } else { | ||
| 220 | /* some kind of default for drivers w/o accurate vbl timestamping */ | ||
| 221 | diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; | ||
| 154 | } | 222 | } |
| 155 | 223 | ||
| 156 | DRM_DEBUG("updating vblank count on crtc %u, missed %d\n", | 224 | DRM_DEBUG("updating vblank count on crtc %u:" |
| 157 | pipe, diff); | 225 | " current=%u, diff=%u, hw=%u hw_last=%u\n", |
| 226 | pipe, vblank->count, diff, cur_vblank, vblank->last); | ||
| 158 | 227 | ||
| 159 | if (diff == 0) | 228 | if (diff == 0) { |
| 229 | WARN_ON_ONCE(cur_vblank != vblank->last); | ||
| 160 | return; | 230 | return; |
| 231 | } | ||
| 161 | 232 | ||
| 162 | /* | 233 | /* |
| 163 | * Only reinitialize corresponding vblank timestamp if high-precision query | 234 | * Only reinitialize corresponding vblank timestamp if high-precision query |
| @@ -167,7 +238,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe) | |||
| 167 | if (!rc) | 238 | if (!rc) |
| 168 | t_vblank = (struct timeval) {0, 0}; | 239 | t_vblank = (struct timeval) {0, 0}; |
| 169 | 240 | ||
| 170 | store_vblank(dev, pipe, diff, &t_vblank); | 241 | store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); |
| 171 | } | 242 | } |
| 172 | 243 | ||
| 173 | /* | 244 | /* |
| @@ -180,11 +251,6 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) | |||
| 180 | { | 251 | { |
| 181 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | 252 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
| 182 | unsigned long irqflags; | 253 | unsigned long irqflags; |
| 183 | u32 vblcount; | ||
| 184 | s64 diff_ns; | ||
| 185 | bool vblrc; | ||
| 186 | struct timeval tvblank; | ||
| 187 | int count = DRM_TIMESTAMP_MAXRETRIES; | ||
| 188 | 254 | ||
| 189 | /* Prevent vblank irq processing while disabling vblank irqs, | 255 | /* Prevent vblank irq processing while disabling vblank irqs, |
| 190 | * so no updates of timestamps or count can happen after we've | 256 | * so no updates of timestamps or count can happen after we've |
| @@ -193,26 +259,6 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) | |||
| 193 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); | 259 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); |
| 194 | 260 | ||
| 195 | /* | 261 | /* |
| 196 | * If the vblank interrupt was already disabled update the count | ||
| 197 | * and timestamp to maintain the appearance that the counter | ||
| 198 | * has been ticking all along until this time. This makes the | ||
| 199 | * count account for the entire time between drm_vblank_on() and | ||
| 200 | * drm_vblank_off(). | ||
| 201 | * | ||
| 202 | * But only do this if precise vblank timestamps are available. | ||
| 203 | * Otherwise we might read a totally bogus timestamp since drivers | ||
| 204 | * lacking precise timestamp support rely upon sampling the system clock | ||
| 205 | * at vblank interrupt time. Which obviously won't work out well if the | ||
| 206 | * vblank interrupt is disabled. | ||
| 207 | */ | ||
| 208 | if (!vblank->enabled && | ||
| 209 | drm_get_last_vbltimestamp(dev, pipe, &tvblank, 0)) { | ||
| 210 | drm_update_vblank_count(dev, pipe); | ||
| 211 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | ||
| 212 | return; | ||
| 213 | } | ||
| 214 | |||
| 215 | /* | ||
| 216 | * Only disable vblank interrupts if they're enabled. This avoids | 262 | * Only disable vblank interrupts if they're enabled. This avoids |
| 217 | * calling the ->disable_vblank() operation in atomic context with the | 263 | * calling the ->disable_vblank() operation in atomic context with the |
| 218 | * hardware potentially runtime suspended. | 264 | * hardware potentially runtime suspended. |
| @@ -222,47 +268,13 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) | |||
| 222 | vblank->enabled = false; | 268 | vblank->enabled = false; |
| 223 | } | 269 | } |
| 224 | 270 | ||
| 225 | /* No further vblank irq's will be processed after | 271 | /* |
| 226 | * this point. Get current hardware vblank count and | 272 | * Always update the count and timestamp to maintain the |
| 227 | * vblank timestamp, repeat until they are consistent. | 273 | * appearance that the counter has been ticking all along until |
| 228 | * | 274 | * this time. This makes the count account for the entire time |
| 229 | * FIXME: There is still a race condition here and in | 275 | * between drm_vblank_on() and drm_vblank_off(). |
| 230 | * drm_update_vblank_count() which can cause off-by-one | ||
| 231 | * reinitialization of software vblank counter. If gpu | ||
| 232 | * vblank counter doesn't increment exactly at the leading | ||
| 233 | * edge of a vblank interval, then we can lose 1 count if | ||
| 234 | * we happen to execute between start of vblank and the | ||
| 235 | * delayed gpu counter increment. | ||
| 236 | */ | ||
| 237 | do { | ||
| 238 | vblank->last = dev->driver->get_vblank_counter(dev, pipe); | ||
| 239 | vblrc = drm_get_last_vbltimestamp(dev, pipe, &tvblank, 0); | ||
| 240 | } while (vblank->last != dev->driver->get_vblank_counter(dev, pipe) && (--count) && vblrc); | ||
| 241 | |||
| 242 | if (!count) | ||
| 243 | vblrc = 0; | ||
| 244 | |||
| 245 | /* Compute time difference to stored timestamp of last vblank | ||
| 246 | * as updated by last invocation of drm_handle_vblank() in vblank irq. | ||
| 247 | */ | ||
| 248 | vblcount = vblank->count; | ||
| 249 | diff_ns = timeval_to_ns(&tvblank) - | ||
| 250 | timeval_to_ns(&vblanktimestamp(dev, pipe, vblcount)); | ||
| 251 | |||
| 252 | /* If there is at least 1 msec difference between the last stored | ||
| 253 | * timestamp and tvblank, then we are currently executing our | ||
| 254 | * disable inside a new vblank interval, the tvblank timestamp | ||
| 255 | * corresponds to this new vblank interval and the irq handler | ||
| 256 | * for this vblank didn't run yet and won't run due to our disable. | ||
| 257 | * Therefore we need to do the job of drm_handle_vblank() and | ||
| 258 | * increment the vblank counter by one to account for this vblank. | ||
| 259 | * | ||
| 260 | * Skip this step if there isn't any high precision timestamp | ||
| 261 | * available. In that case we can't account for this and just | ||
| 262 | * hope for the best. | ||
| 263 | */ | 276 | */ |
| 264 | if (vblrc && (abs64(diff_ns) > 1000000)) | 277 | drm_update_vblank_count(dev, pipe, 0); |
| 265 | store_vblank(dev, pipe, 1, &tvblank); | ||
| 266 | 278 | ||
| 267 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | 279 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); |
| 268 | } | 280 | } |
| @@ -603,7 +615,8 @@ int drm_control(struct drm_device *dev, void *data, | |||
| 603 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, | 615 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, |
| 604 | const struct drm_display_mode *mode) | 616 | const struct drm_display_mode *mode) |
| 605 | { | 617 | { |
| 606 | int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; | 618 | struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; |
| 619 | int linedur_ns = 0, framedur_ns = 0; | ||
| 607 | int dotclock = mode->crtc_clock; | 620 | int dotclock = mode->crtc_clock; |
| 608 | 621 | ||
| 609 | /* Valid dotclock? */ | 622 | /* Valid dotclock? */ |
| @@ -612,10 +625,9 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc, | |||
| 612 | 625 | ||
| 613 | /* | 626 | /* |
| 614 | * Convert scanline length in pixels and video | 627 | * Convert scanline length in pixels and video |
| 615 | * dot clock to line duration, frame duration | 628 | * dot clock to line duration and frame duration |
| 616 | * and pixel duration in nanoseconds: | 629 | * in nanoseconds: |
| 617 | */ | 630 | */ |
| 618 | pixeldur_ns = 1000000 / dotclock; | ||
| 619 | linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock); | 631 | linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock); |
| 620 | framedur_ns = div_u64((u64) frame_size * 1000000, dotclock); | 632 | framedur_ns = div_u64((u64) frame_size * 1000000, dotclock); |
| 621 | 633 | ||
| @@ -628,16 +640,14 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc, | |||
| 628 | DRM_ERROR("crtc %u: Can't calculate constants, dotclock = 0!\n", | 640 | DRM_ERROR("crtc %u: Can't calculate constants, dotclock = 0!\n", |
| 629 | crtc->base.id); | 641 | crtc->base.id); |
| 630 | 642 | ||
| 631 | crtc->pixeldur_ns = pixeldur_ns; | 643 | vblank->linedur_ns = linedur_ns; |
| 632 | crtc->linedur_ns = linedur_ns; | 644 | vblank->framedur_ns = framedur_ns; |
| 633 | crtc->framedur_ns = framedur_ns; | ||
| 634 | 645 | ||
| 635 | DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", | 646 | DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", |
| 636 | crtc->base.id, mode->crtc_htotal, | 647 | crtc->base.id, mode->crtc_htotal, |
| 637 | mode->crtc_vtotal, mode->crtc_vdisplay); | 648 | mode->crtc_vtotal, mode->crtc_vdisplay); |
| 638 | DRM_DEBUG("crtc %u: clock %d kHz framedur %d linedur %d, pixeldur %d\n", | 649 | DRM_DEBUG("crtc %u: clock %d kHz framedur %d linedur %d\n", |
| 639 | crtc->base.id, dotclock, framedur_ns, | 650 | crtc->base.id, dotclock, framedur_ns, linedur_ns); |
| 640 | linedur_ns, pixeldur_ns); | ||
| 641 | } | 651 | } |
| 642 | EXPORT_SYMBOL(drm_calc_timestamping_constants); | 652 | EXPORT_SYMBOL(drm_calc_timestamping_constants); |
| 643 | 653 | ||
| @@ -651,7 +661,6 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); | |||
| 651 | * @flags: Flags to pass to driver: | 661 | * @flags: Flags to pass to driver: |
| 652 | * 0 = Default, | 662 | * 0 = Default, |
| 653 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler | 663 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler |
| 654 | * @refcrtc: CRTC which defines scanout timing | ||
| 655 | * @mode: mode which defines the scanout timings | 664 | * @mode: mode which defines the scanout timings |
| 656 | * | 665 | * |
| 657 | * Implements calculation of exact vblank timestamps from given drm_display_mode | 666 | * Implements calculation of exact vblank timestamps from given drm_display_mode |
| @@ -692,15 +701,14 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
| 692 | int *max_error, | 701 | int *max_error, |
| 693 | struct timeval *vblank_time, | 702 | struct timeval *vblank_time, |
| 694 | unsigned flags, | 703 | unsigned flags, |
| 695 | const struct drm_crtc *refcrtc, | ||
| 696 | const struct drm_display_mode *mode) | 704 | const struct drm_display_mode *mode) |
| 697 | { | 705 | { |
| 698 | struct timeval tv_etime; | 706 | struct timeval tv_etime; |
| 699 | ktime_t stime, etime; | 707 | ktime_t stime, etime; |
| 700 | int vbl_status; | 708 | unsigned int vbl_status; |
| 709 | int ret = DRM_VBLANKTIME_SCANOUTPOS_METHOD; | ||
| 701 | int vpos, hpos, i; | 710 | int vpos, hpos, i; |
| 702 | int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; | 711 | int delta_ns, duration_ns; |
| 703 | bool invbl; | ||
| 704 | 712 | ||
| 705 | if (pipe >= dev->num_crtcs) { | 713 | if (pipe >= dev->num_crtcs) { |
| 706 | DRM_ERROR("Invalid crtc %u\n", pipe); | 714 | DRM_ERROR("Invalid crtc %u\n", pipe); |
| @@ -713,15 +721,10 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
| 713 | return -EIO; | 721 | return -EIO; |
| 714 | } | 722 | } |
| 715 | 723 | ||
| 716 | /* Durations of frames, lines, pixels in nanoseconds. */ | ||
| 717 | framedur_ns = refcrtc->framedur_ns; | ||
| 718 | linedur_ns = refcrtc->linedur_ns; | ||
| 719 | pixeldur_ns = refcrtc->pixeldur_ns; | ||
| 720 | |||
| 721 | /* If mode timing undefined, just return as no-op: | 724 | /* If mode timing undefined, just return as no-op: |
| 722 | * Happens during initial modesetting of a crtc. | 725 | * Happens during initial modesetting of a crtc. |
| 723 | */ | 726 | */ |
| 724 | if (framedur_ns == 0) { | 727 | if (mode->crtc_clock == 0) { |
| 725 | DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); | 728 | DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); |
| 726 | return -EAGAIN; | 729 | return -EAGAIN; |
| 727 | } | 730 | } |
| @@ -738,12 +741,14 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
| 738 | * Get vertical and horizontal scanout position vpos, hpos, | 741 | * Get vertical and horizontal scanout position vpos, hpos, |
| 739 | * and bounding timestamps stime, etime, pre/post query. | 742 | * and bounding timestamps stime, etime, pre/post query. |
| 740 | */ | 743 | */ |
| 741 | vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, &vpos, | 744 | vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, |
| 742 | &hpos, &stime, &etime); | 745 | &vpos, &hpos, |
| 746 | &stime, &etime, | ||
| 747 | mode); | ||
| 743 | 748 | ||
| 744 | /* Return as no-op if scanout query unsupported or failed. */ | 749 | /* Return as no-op if scanout query unsupported or failed. */ |
| 745 | if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { | 750 | if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { |
| 746 | DRM_DEBUG("crtc %u : scanoutpos query failed [%d].\n", | 751 | DRM_DEBUG("crtc %u : scanoutpos query failed [0x%x].\n", |
| 747 | pipe, vbl_status); | 752 | pipe, vbl_status); |
| 748 | return -EIO; | 753 | return -EIO; |
| 749 | } | 754 | } |
| @@ -770,13 +775,15 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
| 770 | * within vblank area, counting down the number of lines until | 775 | * within vblank area, counting down the number of lines until |
| 771 | * start of scanout. | 776 | * start of scanout. |
| 772 | */ | 777 | */ |
| 773 | invbl = vbl_status & DRM_SCANOUTPOS_IN_VBLANK; | 778 | if (vbl_status & DRM_SCANOUTPOS_IN_VBLANK) |
| 779 | ret |= DRM_VBLANKTIME_IN_VBLANK; | ||
| 774 | 780 | ||
| 775 | /* Convert scanout position into elapsed time at raw_time query | 781 | /* Convert scanout position into elapsed time at raw_time query |
| 776 | * since start of scanout at first display scanline. delta_ns | 782 | * since start of scanout at first display scanline. delta_ns |
| 777 | * can be negative if start of scanout hasn't happened yet. | 783 | * can be negative if start of scanout hasn't happened yet. |
| 778 | */ | 784 | */ |
| 779 | delta_ns = vpos * linedur_ns + hpos * pixeldur_ns; | 785 | delta_ns = div_s64(1000000LL * (vpos * mode->crtc_htotal + hpos), |
| 786 | mode->crtc_clock); | ||
| 780 | 787 | ||
| 781 | if (!drm_timestamp_monotonic) | 788 | if (!drm_timestamp_monotonic) |
| 782 | etime = ktime_mono_to_real(etime); | 789 | etime = ktime_mono_to_real(etime); |
| @@ -792,17 +799,13 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
| 792 | etime = ktime_sub_ns(etime, delta_ns); | 799 | etime = ktime_sub_ns(etime, delta_ns); |
| 793 | *vblank_time = ktime_to_timeval(etime); | 800 | *vblank_time = ktime_to_timeval(etime); |
| 794 | 801 | ||
| 795 | DRM_DEBUG("crtc %u : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", | 802 | DRM_DEBUG("crtc %u : v 0x%x p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", |
| 796 | pipe, (int)vbl_status, hpos, vpos, | 803 | pipe, vbl_status, hpos, vpos, |
| 797 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, | 804 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, |
| 798 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, | 805 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, |
| 799 | duration_ns/1000, i); | 806 | duration_ns/1000, i); |
| 800 | 807 | ||
| 801 | vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; | 808 | return ret; |
| 802 | if (invbl) | ||
| 803 | vbl_status |= DRM_VBLANKTIME_IN_VBLANK; | ||
| 804 | |||
| 805 | return vbl_status; | ||
| 806 | } | 809 | } |
| 807 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); | 810 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); |
| 808 | 811 | ||
| @@ -914,11 +917,14 @@ EXPORT_SYMBOL(drm_crtc_vblank_count); | |||
| 914 | * vblank events since the system was booted, including lost events due to | 917 | * vblank events since the system was booted, including lost events due to |
| 915 | * modesetting activity. Returns corresponding system timestamp of the time | 918 | * modesetting activity. Returns corresponding system timestamp of the time |
| 916 | * of the vblank interval that corresponds to the current vblank counter value. | 919 | * of the vblank interval that corresponds to the current vblank counter value. |
| 920 | * | ||
| 921 | * This is the legacy version of drm_crtc_vblank_count_and_time(). | ||
| 917 | */ | 922 | */ |
| 918 | u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, | 923 | u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, |
| 919 | struct timeval *vblanktime) | 924 | struct timeval *vblanktime) |
| 920 | { | 925 | { |
| 921 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | 926 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
| 927 | int count = DRM_TIMESTAMP_MAXRETRIES; | ||
| 922 | u32 cur_vblank; | 928 | u32 cur_vblank; |
| 923 | 929 | ||
| 924 | if (WARN_ON(pipe >= dev->num_crtcs)) | 930 | if (WARN_ON(pipe >= dev->num_crtcs)) |
| @@ -934,12 +940,33 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, | |||
| 934 | smp_rmb(); | 940 | smp_rmb(); |
| 935 | *vblanktime = vblanktimestamp(dev, pipe, cur_vblank); | 941 | *vblanktime = vblanktimestamp(dev, pipe, cur_vblank); |
| 936 | smp_rmb(); | 942 | smp_rmb(); |
| 937 | } while (cur_vblank != vblank->count); | 943 | } while (cur_vblank != vblank->count && --count > 0); |
| 938 | 944 | ||
| 939 | return cur_vblank; | 945 | return cur_vblank; |
| 940 | } | 946 | } |
| 941 | EXPORT_SYMBOL(drm_vblank_count_and_time); | 947 | EXPORT_SYMBOL(drm_vblank_count_and_time); |
| 942 | 948 | ||
| 949 | /** | ||
| 950 | * drm_crtc_vblank_count_and_time - retrieve "cooked" vblank counter value | ||
| 951 | * and the system timestamp corresponding to that vblank counter value | ||
| 952 | * @crtc: which counter to retrieve | ||
| 953 | * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. | ||
| 954 | * | ||
| 955 | * Fetches the "cooked" vblank count value that represents the number of | ||
| 956 | * vblank events since the system was booted, including lost events due to | ||
| 957 | * modesetting activity. Returns corresponding system timestamp of the time | ||
| 958 | * of the vblank interval that corresponds to the current vblank counter value. | ||
| 959 | * | ||
| 960 | * This is the native KMS version of drm_vblank_count_and_time(). | ||
| 961 | */ | ||
| 962 | u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, | ||
| 963 | struct timeval *vblanktime) | ||
| 964 | { | ||
| 965 | return drm_vblank_count_and_time(crtc->dev, drm_crtc_index(crtc), | ||
| 966 | vblanktime); | ||
| 967 | } | ||
| 968 | EXPORT_SYMBOL(drm_crtc_vblank_count_and_time); | ||
| 969 | |||
| 943 | static void send_vblank_event(struct drm_device *dev, | 970 | static void send_vblank_event(struct drm_device *dev, |
| 944 | struct drm_pending_vblank_event *e, | 971 | struct drm_pending_vblank_event *e, |
| 945 | unsigned long seq, struct timeval *now) | 972 | unsigned long seq, struct timeval *now) |
| @@ -1033,7 +1060,7 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) | |||
| 1033 | atomic_dec(&vblank->refcount); | 1060 | atomic_dec(&vblank->refcount); |
| 1034 | else { | 1061 | else { |
| 1035 | vblank->enabled = true; | 1062 | vblank->enabled = true; |
| 1036 | drm_update_vblank_count(dev, pipe); | 1063 | drm_update_vblank_count(dev, pipe, 0); |
| 1037 | } | 1064 | } |
| 1038 | } | 1065 | } |
| 1039 | 1066 | ||
| @@ -1154,8 +1181,8 @@ EXPORT_SYMBOL(drm_crtc_vblank_put); | |||
| 1154 | * @dev: DRM device | 1181 | * @dev: DRM device |
| 1155 | * @pipe: CRTC index | 1182 | * @pipe: CRTC index |
| 1156 | * | 1183 | * |
| 1157 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. | 1184 | * This waits for one vblank to pass on @pipe, using the irq driver interfaces. |
| 1158 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. | 1185 | * It is a failure to call this when the vblank irq for @pipe is disabled, e.g. |
| 1159 | * due to lack of driver support or because the crtc is off. | 1186 | * due to lack of driver support or because the crtc is off. |
| 1160 | */ | 1187 | */ |
| 1161 | void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) | 1188 | void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) |
| @@ -1276,7 +1303,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); | |||
| 1276 | 1303 | ||
| 1277 | /** | 1304 | /** |
| 1278 | * drm_crtc_vblank_reset - reset vblank state to off on a CRTC | 1305 | * drm_crtc_vblank_reset - reset vblank state to off on a CRTC |
| 1279 | * @drm_crtc: CRTC in question | 1306 | * @crtc: CRTC in question |
| 1280 | * | 1307 | * |
| 1281 | * Drivers can use this function to reset the vblank state to off at load time. | 1308 | * Drivers can use this function to reset the vblank state to off at load time. |
| 1282 | * Drivers should use this together with the drm_crtc_vblank_off() and | 1309 | * Drivers should use this together with the drm_crtc_vblank_off() and |
| @@ -1284,12 +1311,12 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); | |||
| 1284 | * drm_crtc_vblank_off() is that this function doesn't save the vblank counter | 1311 | * drm_crtc_vblank_off() is that this function doesn't save the vblank counter |
| 1285 | * and hence doesn't need to call any driver hooks. | 1312 | * and hence doesn't need to call any driver hooks. |
| 1286 | */ | 1313 | */ |
| 1287 | void drm_crtc_vblank_reset(struct drm_crtc *drm_crtc) | 1314 | void drm_crtc_vblank_reset(struct drm_crtc *crtc) |
| 1288 | { | 1315 | { |
| 1289 | struct drm_device *dev = drm_crtc->dev; | 1316 | struct drm_device *dev = crtc->dev; |
| 1290 | unsigned long irqflags; | 1317 | unsigned long irqflags; |
| 1291 | int crtc = drm_crtc_index(drm_crtc); | 1318 | unsigned int pipe = drm_crtc_index(crtc); |
| 1292 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | 1319 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
| 1293 | 1320 | ||
| 1294 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1321 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
| 1295 | /* | 1322 | /* |
| @@ -1333,16 +1360,8 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe) | |||
| 1333 | vblank->inmodeset = 0; | 1360 | vblank->inmodeset = 0; |
| 1334 | } | 1361 | } |
| 1335 | 1362 | ||
| 1336 | /* | 1363 | drm_reset_vblank_timestamp(dev, pipe); |
| 1337 | * sample the current counter to avoid random jumps | 1364 | |
| 1338 | * when drm_vblank_enable() applies the diff | ||
| 1339 | * | ||
| 1340 | * -1 to make sure user will never see the same | ||
| 1341 | * vblank counter value before and after a modeset | ||
| 1342 | */ | ||
| 1343 | vblank->last = | ||
| 1344 | (dev->driver->get_vblank_counter(dev, pipe) - 1) & | ||
| 1345 | dev->max_vblank_count; | ||
| 1346 | /* | 1365 | /* |
| 1347 | * re-enable interrupts if there are users left, or the | 1366 | * re-enable interrupts if there are users left, or the |
| 1348 | * user wishes vblank interrupts to be enabled all the time. | 1367 | * user wishes vblank interrupts to be enabled all the time. |
| @@ -1725,9 +1744,6 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) | |||
| 1725 | bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) | 1744 | bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) |
| 1726 | { | 1745 | { |
| 1727 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | 1746 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
| 1728 | u32 vblcount; | ||
| 1729 | s64 diff_ns; | ||
| 1730 | struct timeval tvblank; | ||
| 1731 | unsigned long irqflags; | 1747 | unsigned long irqflags; |
| 1732 | 1748 | ||
| 1733 | if (WARN_ON_ONCE(!dev->num_crtcs)) | 1749 | if (WARN_ON_ONCE(!dev->num_crtcs)) |
| @@ -1751,32 +1767,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) | |||
| 1751 | return false; | 1767 | return false; |
| 1752 | } | 1768 | } |
| 1753 | 1769 | ||
| 1754 | /* Fetch corresponding timestamp for this vblank interval from | 1770 | drm_update_vblank_count(dev, pipe, DRM_CALLED_FROM_VBLIRQ); |
| 1755 | * driver and store it in proper slot of timestamp ringbuffer. | ||
| 1756 | */ | ||
| 1757 | |||
| 1758 | /* Get current timestamp and count. */ | ||
| 1759 | vblcount = vblank->count; | ||
| 1760 | drm_get_last_vbltimestamp(dev, pipe, &tvblank, DRM_CALLED_FROM_VBLIRQ); | ||
| 1761 | |||
| 1762 | /* Compute time difference to timestamp of last vblank */ | ||
| 1763 | diff_ns = timeval_to_ns(&tvblank) - | ||
| 1764 | timeval_to_ns(&vblanktimestamp(dev, pipe, vblcount)); | ||
| 1765 | |||
| 1766 | /* Update vblank timestamp and count if at least | ||
| 1767 | * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds | ||
| 1768 | * difference between last stored timestamp and current | ||
| 1769 | * timestamp. A smaller difference means basically | ||
| 1770 | * identical timestamps. Happens if this vblank has | ||
| 1771 | * been already processed and this is a redundant call, | ||
| 1772 | * e.g., due to spurious vblank interrupts. We need to | ||
| 1773 | * ignore those for accounting. | ||
| 1774 | */ | ||
| 1775 | if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) | ||
| 1776 | store_vblank(dev, pipe, 1, &tvblank); | ||
| 1777 | else | ||
| 1778 | DRM_DEBUG("crtc %u: Redundant vblirq ignored. diff_ns = %d\n", | ||
| 1779 | pipe, (int) diff_ns); | ||
| 1780 | 1771 | ||
| 1781 | spin_unlock(&dev->vblank_time_lock); | 1772 | spin_unlock(&dev->vblank_time_lock); |
| 1782 | 1773 | ||
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 3427b115e2bb..04de6fd88f8c 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c | |||
| @@ -267,12 +267,12 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, | |||
| 267 | if (adj_end > end) | 267 | if (adj_end > end) |
| 268 | adj_end = end; | 268 | adj_end = end; |
| 269 | 269 | ||
| 270 | if (flags & DRM_MM_CREATE_TOP) | ||
| 271 | adj_start = adj_end - size; | ||
| 272 | |||
| 273 | if (mm->color_adjust) | 270 | if (mm->color_adjust) |
| 274 | mm->color_adjust(hole_node, color, &adj_start, &adj_end); | 271 | mm->color_adjust(hole_node, color, &adj_start, &adj_end); |
| 275 | 272 | ||
| 273 | if (flags & DRM_MM_CREATE_TOP) | ||
| 274 | adj_start = adj_end - size; | ||
| 275 | |||
| 276 | if (alignment) { | 276 | if (alignment) { |
| 277 | u64 tmp = adj_start; | 277 | u64 tmp = adj_start; |
| 278 | unsigned rem; | 278 | unsigned rem; |
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index fba321ca4344..6675b1428410 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c | |||
| @@ -307,6 +307,8 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, | |||
| 307 | WARN_ON(ctx->contended); | 307 | WARN_ON(ctx->contended); |
| 308 | 308 | ||
| 309 | if (ctx->trylock_only) { | 309 | if (ctx->trylock_only) { |
| 310 | lockdep_assert_held(&ctx->ww_ctx); | ||
| 311 | |||
| 310 | if (!ww_mutex_trylock(&lock->mutex)) | 312 | if (!ww_mutex_trylock(&lock->mutex)) |
| 311 | return -EBUSY; | 313 | return -EBUSY; |
| 312 | else | 314 | else |
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 5e5a07af02c8..d384ebcf0aaf 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c | |||
| @@ -426,7 +426,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, | |||
| 426 | 426 | ||
| 427 | if (plane_funcs->prepare_fb && plane_state->fb && | 427 | if (plane_funcs->prepare_fb && plane_state->fb && |
| 428 | plane_state->fb != old_fb) { | 428 | plane_state->fb != old_fb) { |
| 429 | ret = plane_funcs->prepare_fb(plane, plane_state->fb, | 429 | ret = plane_funcs->prepare_fb(plane, |
| 430 | plane_state); | 430 | plane_state); |
| 431 | if (ret) | 431 | if (ret) |
| 432 | goto out; | 432 | goto out; |
| @@ -479,8 +479,8 @@ int drm_plane_helper_commit(struct drm_plane *plane, | |||
| 479 | ret = 0; | 479 | ret = 0; |
| 480 | } | 480 | } |
| 481 | 481 | ||
| 482 | if (plane_funcs->cleanup_fb && old_fb) | 482 | if (plane_funcs->cleanup_fb) |
| 483 | plane_funcs->cleanup_fb(plane, old_fb, plane_state); | 483 | plane_funcs->cleanup_fb(plane, plane_state); |
| 484 | out: | 484 | out: |
| 485 | if (plane_state) { | 485 | if (plane_state) { |
| 486 | if (plane->funcs->atomic_destroy_state) | 486 | if (plane->funcs->atomic_destroy_state) |
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 0f6cd33b531f..f08873f6489c 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c | |||
| @@ -30,6 +30,8 @@ static struct device_type drm_sysfs_device_minor = { | |||
| 30 | .name = "drm_minor" | 30 | .name = "drm_minor" |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | struct class *drm_class; | ||
| 34 | |||
| 33 | /** | 35 | /** |
| 34 | * __drm_class_suspend - internal DRM class suspend routine | 36 | * __drm_class_suspend - internal DRM class suspend routine |
| 35 | * @dev: Linux device to suspend | 37 | * @dev: Linux device to suspend |
| @@ -112,41 +114,34 @@ static CLASS_ATTR_STRING(version, S_IRUGO, | |||
| 112 | CORE_DATE); | 114 | CORE_DATE); |
| 113 | 115 | ||
| 114 | /** | 116 | /** |
| 115 | * drm_sysfs_create - create a struct drm_sysfs_class structure | 117 | * drm_sysfs_init - initialize sysfs helpers |
| 116 | * @owner: pointer to the module that is to "own" this struct drm_sysfs_class | 118 | * |
| 117 | * @name: pointer to a string for the name of this class. | 119 | * This is used to create the DRM class, which is the implicit parent of any |
| 120 | * other top-level DRM sysfs objects. | ||
| 118 | * | 121 | * |
| 119 | * This is used to create DRM class pointer that can then be used | 122 | * You must call drm_sysfs_destroy() to release the allocated resources. |
| 120 | * in calls to drm_sysfs_device_add(). | ||
| 121 | * | 123 | * |
| 122 | * Note, the pointer created here is to be destroyed when finished by making a | 124 | * Return: 0 on success, negative error code on failure. |
| 123 | * call to drm_sysfs_destroy(). | ||
| 124 | */ | 125 | */ |
| 125 | struct class *drm_sysfs_create(struct module *owner, char *name) | 126 | int drm_sysfs_init(void) |
| 126 | { | 127 | { |
| 127 | struct class *class; | ||
| 128 | int err; | 128 | int err; |
| 129 | 129 | ||
| 130 | class = class_create(owner, name); | 130 | drm_class = class_create(THIS_MODULE, "drm"); |
| 131 | if (IS_ERR(class)) { | 131 | if (IS_ERR(drm_class)) |
| 132 | err = PTR_ERR(class); | 132 | return PTR_ERR(drm_class); |
| 133 | goto err_out; | ||
| 134 | } | ||
| 135 | |||
| 136 | class->pm = &drm_class_dev_pm_ops; | ||
| 137 | 133 | ||
| 138 | err = class_create_file(class, &class_attr_version.attr); | 134 | drm_class->pm = &drm_class_dev_pm_ops; |
| 139 | if (err) | ||
| 140 | goto err_out_class; | ||
| 141 | 135 | ||
| 142 | class->devnode = drm_devnode; | 136 | err = class_create_file(drm_class, &class_attr_version.attr); |
| 143 | 137 | if (err) { | |
| 144 | return class; | 138 | class_destroy(drm_class); |
| 139 | drm_class = NULL; | ||
| 140 | return err; | ||
| 141 | } | ||
| 145 | 142 | ||
| 146 | err_out_class: | 143 | drm_class->devnode = drm_devnode; |
| 147 | class_destroy(class); | 144 | return 0; |
| 148 | err_out: | ||
| 149 | return ERR_PTR(err); | ||
| 150 | } | 145 | } |
| 151 | 146 | ||
| 152 | /** | 147 | /** |
| @@ -156,7 +151,7 @@ err_out: | |||
| 156 | */ | 151 | */ |
| 157 | void drm_sysfs_destroy(void) | 152 | void drm_sysfs_destroy(void) |
| 158 | { | 153 | { |
| 159 | if ((drm_class == NULL) || (IS_ERR(drm_class))) | 154 | if (IS_ERR_OR_NULL(drm_class)) |
| 160 | return; | 155 | return; |
| 161 | class_remove_file(drm_class, &class_attr_version.attr); | 156 | class_remove_file(drm_class, &class_attr_version.attr); |
| 162 | class_destroy(drm_class); | 157 | class_destroy(drm_class); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 831d2e4cacf9..f0a5839bd226 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
| @@ -105,7 +105,7 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) | |||
| 105 | atomic_inc(&exynos_crtc->pending_update); | 105 | atomic_inc(&exynos_crtc->pending_update); |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | drm_atomic_helper_commit_planes(dev, state); | 108 | drm_atomic_helper_commit_planes(dev, state, false); |
| 109 | 109 | ||
| 110 | exynos_atomic_wait_for_commit(state); | 110 | exynos_atomic_wait_for_commit(state); |
| 111 | 111 | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c index d1e300dcd544..51daaea40b4d 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c | |||
| @@ -191,14 +191,12 @@ set_failed: | |||
| 191 | 191 | ||
| 192 | static void | 192 | static void |
| 193 | fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane, | 193 | fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane, |
| 194 | struct drm_framebuffer *fb, | ||
| 195 | const struct drm_plane_state *new_state) | 194 | const struct drm_plane_state *new_state) |
| 196 | { | 195 | { |
| 197 | } | 196 | } |
| 198 | 197 | ||
| 199 | static int | 198 | static int |
| 200 | fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane, | 199 | fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane, |
| 201 | struct drm_framebuffer *fb, | ||
| 202 | const struct drm_plane_state *new_state) | 200 | const struct drm_plane_state *new_state) |
| 203 | { | 201 | { |
| 204 | return 0; | 202 | return 0; |
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 0fafb8e2483a..17cea400ae32 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c | |||
| @@ -247,7 +247,6 @@ i2c_dp_aux_add_bus(struct i2c_adapter *adapter) | |||
| 247 | 247 | ||
| 248 | #define wait_for(COND, MS) _wait_for(COND, MS, 1) | 248 | #define wait_for(COND, MS) _wait_for(COND, MS, 1) |
| 249 | 249 | ||
| 250 | #define DP_LINK_STATUS_SIZE 6 | ||
| 251 | #define DP_LINK_CHECK_TIMEOUT (10 * 1000) | 250 | #define DP_LINK_CHECK_TIMEOUT (10 * 1000) |
| 252 | 251 | ||
| 253 | #define DP_LINK_CONFIGURATION_SIZE 9 | 252 | #define DP_LINK_CONFIGURATION_SIZE 9 |
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 51fa32392029..d9a72c96e56c 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c | |||
| @@ -119,8 +119,8 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder, | |||
| 119 | struct ch7006_encoder_params *params = &priv->params; | 119 | struct ch7006_encoder_params *params = &priv->params; |
| 120 | struct ch7006_state *state = &priv->state; | 120 | struct ch7006_state *state = &priv->state; |
| 121 | uint8_t *regs = state->regs; | 121 | uint8_t *regs = state->regs; |
| 122 | struct ch7006_mode *mode = priv->mode; | 122 | const struct ch7006_mode *mode = priv->mode; |
| 123 | struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; | 123 | const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; |
| 124 | int start_active; | 124 | int start_active; |
| 125 | 125 | ||
| 126 | ch7006_dbg(client, "\n"); | 126 | ch7006_dbg(client, "\n"); |
| @@ -226,7 +226,7 @@ static int ch7006_encoder_get_modes(struct drm_encoder *encoder, | |||
| 226 | struct drm_connector *connector) | 226 | struct drm_connector *connector) |
| 227 | { | 227 | { |
| 228 | struct ch7006_priv *priv = to_ch7006_priv(encoder); | 228 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 229 | struct ch7006_mode *mode; | 229 | const struct ch7006_mode *mode; |
| 230 | int n = 0; | 230 | int n = 0; |
| 231 | 231 | ||
| 232 | for (mode = ch7006_modes; mode->mode.clock; mode++) { | 232 | for (mode = ch7006_modes; mode->mode.clock; mode++) { |
diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c index 9b83574141a6..bb5f67f10edb 100644 --- a/drivers/gpu/drm/i2c/ch7006_mode.c +++ b/drivers/gpu/drm/i2c/ch7006_mode.c | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | #include "ch7006_priv.h" | 27 | #include "ch7006_priv.h" |
| 28 | 28 | ||
| 29 | char *ch7006_tv_norm_names[] = { | 29 | const char * const ch7006_tv_norm_names[] = { |
| 30 | [TV_NORM_PAL] = "PAL", | 30 | [TV_NORM_PAL] = "PAL", |
| 31 | [TV_NORM_PAL_M] = "PAL-M", | 31 | [TV_NORM_PAL_M] = "PAL-M", |
| 32 | [TV_NORM_PAL_N] = "PAL-N", | 32 | [TV_NORM_PAL_N] = "PAL-N", |
| @@ -46,7 +46,7 @@ char *ch7006_tv_norm_names[] = { | |||
| 46 | .vtotal = 625, \ | 46 | .vtotal = 625, \ |
| 47 | .hvirtual = 810 | 47 | .hvirtual = 810 |
| 48 | 48 | ||
| 49 | struct ch7006_tv_norm_info ch7006_tv_norms[] = { | 49 | const struct ch7006_tv_norm_info ch7006_tv_norms[] = { |
| 50 | [TV_NORM_NTSC_M] = { | 50 | [TV_NORM_NTSC_M] = { |
| 51 | NTSC_LIKE_TIMINGS, | 51 | NTSC_LIKE_TIMINGS, |
| 52 | .black_level = 0.339 * fixed1, | 52 | .black_level = 0.339 * fixed1, |
| @@ -142,7 +142,7 @@ struct ch7006_tv_norm_info ch7006_tv_norms[] = { | |||
| 142 | 142 | ||
| 143 | #define PAL_LIKE (1 << TV_NORM_PAL | 1 << TV_NORM_PAL_N | 1 << TV_NORM_PAL_NC) | 143 | #define PAL_LIKE (1 << TV_NORM_PAL | 1 << TV_NORM_PAL_N | 1 << TV_NORM_PAL_NC) |
| 144 | 144 | ||
| 145 | struct ch7006_mode ch7006_modes[] = { | 145 | const struct ch7006_mode ch7006_modes[] = { |
| 146 | MODE(21000, 512, 384, 840, 500, N, N, 181.797557582, 5_4, 0x6, PAL_LIKE), | 146 | MODE(21000, 512, 384, 840, 500, N, N, 181.797557582, 5_4, 0x6, PAL_LIKE), |
| 147 | MODE(26250, 512, 384, 840, 625, N, N, 145.438046066, 1_1, 0x1, PAL_LIKE), | 147 | MODE(26250, 512, 384, 840, 625, N, N, 145.438046066, 1_1, 0x1, PAL_LIKE), |
| 148 | MODE(20140, 512, 384, 800, 420, N, N, 213.257083791, 5_4, 0x4, NTSC_LIKE), | 148 | MODE(20140, 512, 384, 800, 420, N, N, 213.257083791, 5_4, 0x4, NTSC_LIKE), |
| @@ -171,11 +171,11 @@ struct ch7006_mode ch7006_modes[] = { | |||
| 171 | {} | 171 | {} |
| 172 | }; | 172 | }; |
| 173 | 173 | ||
| 174 | struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, | 174 | const struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, |
| 175 | const struct drm_display_mode *drm_mode) | 175 | const struct drm_display_mode *drm_mode) |
| 176 | { | 176 | { |
| 177 | struct ch7006_priv *priv = to_ch7006_priv(encoder); | 177 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 178 | struct ch7006_mode *mode; | 178 | const struct ch7006_mode *mode; |
| 179 | 179 | ||
| 180 | for (mode = ch7006_modes; mode->mode.clock; mode++) { | 180 | for (mode = ch7006_modes; mode->mode.clock; mode++) { |
| 181 | 181 | ||
| @@ -202,7 +202,7 @@ void ch7006_setup_levels(struct drm_encoder *encoder) | |||
| 202 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); | 202 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); |
| 203 | struct ch7006_priv *priv = to_ch7006_priv(encoder); | 203 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 204 | uint8_t *regs = priv->state.regs; | 204 | uint8_t *regs = priv->state.regs; |
| 205 | struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; | 205 | const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; |
| 206 | int gain; | 206 | int gain; |
| 207 | int black_level; | 207 | int black_level; |
| 208 | 208 | ||
| @@ -233,8 +233,8 @@ void ch7006_setup_subcarrier(struct drm_encoder *encoder) | |||
| 233 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); | 233 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); |
| 234 | struct ch7006_priv *priv = to_ch7006_priv(encoder); | 234 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 235 | struct ch7006_state *state = &priv->state; | 235 | struct ch7006_state *state = &priv->state; |
| 236 | struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; | 236 | const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; |
| 237 | struct ch7006_mode *mode = priv->mode; | 237 | const struct ch7006_mode *mode = priv->mode; |
| 238 | uint32_t subc_inc; | 238 | uint32_t subc_inc; |
| 239 | 239 | ||
| 240 | subc_inc = round_fixed((mode->subc_coeff >> 8) | 240 | subc_inc = round_fixed((mode->subc_coeff >> 8) |
| @@ -257,7 +257,7 @@ void ch7006_setup_pll(struct drm_encoder *encoder) | |||
| 257 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); | 257 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); |
| 258 | struct ch7006_priv *priv = to_ch7006_priv(encoder); | 258 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 259 | uint8_t *regs = priv->state.regs; | 259 | uint8_t *regs = priv->state.regs; |
| 260 | struct ch7006_mode *mode = priv->mode; | 260 | const struct ch7006_mode *mode = priv->mode; |
| 261 | int n, best_n = 0; | 261 | int n, best_n = 0; |
| 262 | int m, best_m = 0; | 262 | int m, best_m = 0; |
| 263 | int freq, best_freq = 0; | 263 | int freq, best_freq = 0; |
| @@ -328,9 +328,9 @@ void ch7006_setup_properties(struct drm_encoder *encoder) | |||
| 328 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); | 328 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); |
| 329 | struct ch7006_priv *priv = to_ch7006_priv(encoder); | 329 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 330 | struct ch7006_state *state = &priv->state; | 330 | struct ch7006_state *state = &priv->state; |
| 331 | struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; | 331 | const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; |
| 332 | struct ch7006_mode *ch_mode = priv->mode; | 332 | const struct ch7006_mode *ch_mode = priv->mode; |
| 333 | struct drm_display_mode *mode = &ch_mode->mode; | 333 | const struct drm_display_mode *mode = &ch_mode->mode; |
| 334 | uint8_t *regs = state->regs; | 334 | uint8_t *regs = state->regs; |
| 335 | int flicker, contrast, hpos, vpos; | 335 | int flicker, contrast, hpos, vpos; |
| 336 | uint64_t scale, aspect; | 336 | uint64_t scale, aspect; |
diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h index ce577841f931..dc6414af5d79 100644 --- a/drivers/gpu/drm/i2c/ch7006_priv.h +++ b/drivers/gpu/drm/i2c/ch7006_priv.h | |||
| @@ -78,7 +78,7 @@ struct ch7006_state { | |||
| 78 | 78 | ||
| 79 | struct ch7006_priv { | 79 | struct ch7006_priv { |
| 80 | struct ch7006_encoder_params params; | 80 | struct ch7006_encoder_params params; |
| 81 | struct ch7006_mode *mode; | 81 | const struct ch7006_mode *mode; |
| 82 | 82 | ||
| 83 | struct ch7006_state state; | 83 | struct ch7006_state state; |
| 84 | struct ch7006_state saved_state; | 84 | struct ch7006_state saved_state; |
| @@ -106,12 +106,12 @@ extern int ch7006_debug; | |||
| 106 | extern char *ch7006_tv_norm; | 106 | extern char *ch7006_tv_norm; |
| 107 | extern int ch7006_scale; | 107 | extern int ch7006_scale; |
| 108 | 108 | ||
| 109 | extern char *ch7006_tv_norm_names[]; | 109 | extern const char * const ch7006_tv_norm_names[]; |
| 110 | extern struct ch7006_tv_norm_info ch7006_tv_norms[]; | 110 | extern const struct ch7006_tv_norm_info ch7006_tv_norms[]; |
| 111 | extern struct ch7006_mode ch7006_modes[]; | 111 | extern const struct ch7006_mode ch7006_modes[]; |
| 112 | 112 | ||
| 113 | struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, | 113 | const struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, |
| 114 | const struct drm_display_mode *drm_mode); | 114 | const struct drm_display_mode *drm_mode); |
| 115 | 115 | ||
| 116 | void ch7006_setup_levels(struct drm_encoder *encoder); | 116 | void ch7006_setup_levels(struct drm_encoder *encoder); |
| 117 | void ch7006_setup_subcarrier(struct drm_encoder *encoder); | 117 | void ch7006_setup_subcarrier(struct drm_encoder *encoder); |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 39d73dbc1c47..88d064e80783 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
| @@ -674,12 +674,12 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) | |||
| 674 | 674 | ||
| 675 | static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, | 675 | static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, |
| 676 | unsigned int flags, int *vpos, int *hpos, | 676 | unsigned int flags, int *vpos, int *hpos, |
| 677 | ktime_t *stime, ktime_t *etime) | 677 | ktime_t *stime, ktime_t *etime, |
| 678 | const struct drm_display_mode *mode) | ||
| 678 | { | 679 | { |
| 679 | struct drm_i915_private *dev_priv = dev->dev_private; | 680 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 680 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | 681 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; |
| 681 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 682 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| 682 | const struct drm_display_mode *mode = &intel_crtc->base.hwmode; | ||
| 683 | int position; | 683 | int position; |
| 684 | int vbl_start, vbl_end, hsync_start, htotal, vtotal; | 684 | int vbl_start, vbl_end, hsync_start, htotal, vtotal; |
| 685 | bool in_vbl = true; | 685 | bool in_vbl = true; |
| @@ -836,7 +836,6 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, | |||
| 836 | /* Helper routine in DRM core does all the work: */ | 836 | /* Helper routine in DRM core does all the work: */ |
| 837 | return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, | 837 | return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, |
| 838 | vblank_time, flags, | 838 | vblank_time, flags, |
| 839 | crtc, | ||
| 840 | &crtc->hwmode); | 839 | &crtc->hwmode); |
| 841 | } | 840 | } |
| 842 | 841 | ||
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 2a5c76faf9f8..e35997ebb331 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c | |||
| @@ -404,7 +404,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) | |||
| 404 | struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); | 404 | struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); |
| 405 | enum port port = intel_dig_port->port; | 405 | enum port port = intel_dig_port->port; |
| 406 | 406 | ||
| 407 | connector = drm_select_eld(encoder, mode); | 407 | connector = drm_select_eld(encoder); |
| 408 | if (!connector) | 408 | if (!connector) |
| 409 | return; | 409 | return; |
| 410 | 410 | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cf418be7d30a..0379f14271de 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -13313,10 +13313,10 @@ static void intel_shared_dpll_init(struct drm_device *dev) | |||
| 13313 | */ | 13313 | */ |
| 13314 | int | 13314 | int |
| 13315 | intel_prepare_plane_fb(struct drm_plane *plane, | 13315 | intel_prepare_plane_fb(struct drm_plane *plane, |
| 13316 | struct drm_framebuffer *fb, | ||
| 13317 | const struct drm_plane_state *new_state) | 13316 | const struct drm_plane_state *new_state) |
| 13318 | { | 13317 | { |
| 13319 | struct drm_device *dev = plane->dev; | 13318 | struct drm_device *dev = plane->dev; |
| 13319 | struct drm_framebuffer *fb = new_state->fb; | ||
| 13320 | struct intel_plane *intel_plane = to_intel_plane(plane); | 13320 | struct intel_plane *intel_plane = to_intel_plane(plane); |
| 13321 | struct drm_i915_gem_object *obj = intel_fb_obj(fb); | 13321 | struct drm_i915_gem_object *obj = intel_fb_obj(fb); |
| 13322 | struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); | 13322 | struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); |
| @@ -13354,19 +13354,18 @@ intel_prepare_plane_fb(struct drm_plane *plane, | |||
| 13354 | */ | 13354 | */ |
| 13355 | void | 13355 | void |
| 13356 | intel_cleanup_plane_fb(struct drm_plane *plane, | 13356 | intel_cleanup_plane_fb(struct drm_plane *plane, |
| 13357 | struct drm_framebuffer *fb, | ||
| 13358 | const struct drm_plane_state *old_state) | 13357 | const struct drm_plane_state *old_state) |
| 13359 | { | 13358 | { |
| 13360 | struct drm_device *dev = plane->dev; | 13359 | struct drm_device *dev = plane->dev; |
| 13361 | struct drm_i915_gem_object *obj = intel_fb_obj(fb); | 13360 | struct drm_i915_gem_object *obj = intel_fb_obj(old_state->fb); |
| 13362 | 13361 | ||
| 13363 | if (WARN_ON(!obj)) | 13362 | if (!obj) |
| 13364 | return; | 13363 | return; |
| 13365 | 13364 | ||
| 13366 | if (plane->type != DRM_PLANE_TYPE_CURSOR || | 13365 | if (plane->type != DRM_PLANE_TYPE_CURSOR || |
| 13367 | !INTEL_INFO(dev)->cursor_needs_physical) { | 13366 | !INTEL_INFO(dev)->cursor_needs_physical) { |
| 13368 | mutex_lock(&dev->struct_mutex); | 13367 | mutex_lock(&dev->struct_mutex); |
| 13369 | intel_unpin_fb_obj(fb, old_state); | 13368 | intel_unpin_fb_obj(old_state->fb, old_state); |
| 13370 | mutex_unlock(&dev->struct_mutex); | 13369 | mutex_unlock(&dev->struct_mutex); |
| 13371 | } | 13370 | } |
| 13372 | } | 13371 | } |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0a2e33fbf20d..7bb96d5850de 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
| @@ -974,6 +974,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
| 974 | switch (msg->request & ~DP_AUX_I2C_MOT) { | 974 | switch (msg->request & ~DP_AUX_I2C_MOT) { |
| 975 | case DP_AUX_NATIVE_WRITE: | 975 | case DP_AUX_NATIVE_WRITE: |
| 976 | case DP_AUX_I2C_WRITE: | 976 | case DP_AUX_I2C_WRITE: |
| 977 | case DP_AUX_I2C_WRITE_STATUS_UPDATE: | ||
| 977 | txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE; | 978 | txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE; |
| 978 | rxsize = 2; /* 0 or 1 data bytes */ | 979 | rxsize = 2; /* 0 or 1 data bytes */ |
| 979 | 980 | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2b9e6f9775c5..354432fdfcf0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -834,8 +834,8 @@ struct intel_unpin_work { | |||
| 834 | u32 flip_count; | 834 | u32 flip_count; |
| 835 | u32 gtt_offset; | 835 | u32 gtt_offset; |
| 836 | struct drm_i915_gem_request *flip_queued_req; | 836 | struct drm_i915_gem_request *flip_queued_req; |
| 837 | int flip_queued_vblank; | 837 | u32 flip_queued_vblank; |
| 838 | int flip_ready_vblank; | 838 | u32 flip_ready_vblank; |
| 839 | bool enable_stall_check; | 839 | bool enable_stall_check; |
| 840 | }; | 840 | }; |
| 841 | 841 | ||
| @@ -1038,10 +1038,8 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe); | |||
| 1038 | void intel_finish_page_flip_plane(struct drm_device *dev, int plane); | 1038 | void intel_finish_page_flip_plane(struct drm_device *dev, int plane); |
| 1039 | void intel_check_page_flip(struct drm_device *dev, int pipe); | 1039 | void intel_check_page_flip(struct drm_device *dev, int pipe); |
| 1040 | int intel_prepare_plane_fb(struct drm_plane *plane, | 1040 | int intel_prepare_plane_fb(struct drm_plane *plane, |
| 1041 | struct drm_framebuffer *fb, | ||
| 1042 | const struct drm_plane_state *new_state); | 1041 | const struct drm_plane_state *new_state); |
| 1043 | void intel_cleanup_plane_fb(struct drm_plane *plane, | 1042 | void intel_cleanup_plane_fb(struct drm_plane *plane, |
| 1044 | struct drm_framebuffer *fb, | ||
| 1045 | const struct drm_plane_state *old_state); | 1043 | const struct drm_plane_state *old_state); |
| 1046 | int intel_plane_atomic_get_property(struct drm_plane *plane, | 1044 | int intel_plane_atomic_get_property(struct drm_plane *plane, |
| 1047 | const struct drm_plane_state *state, | 1045 | const struct drm_plane_state *state, |
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 8c6a6fa46005..ab2b856d91c3 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
| @@ -689,6 +689,8 @@ int intel_fbdev_init(struct drm_device *dev) | |||
| 689 | return ret; | 689 | return ret; |
| 690 | } | 690 | } |
| 691 | 691 | ||
| 692 | ifbdev->helper.atomic = true; | ||
| 693 | |||
| 692 | dev_priv->fbdev = ifbdev; | 694 | dev_priv->fbdev = ifbdev; |
| 693 | INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker); | 695 | INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker); |
| 694 | 696 | ||
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 0568ae6ec9dd..590ceabe2d5e 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c | |||
| @@ -1579,7 +1579,7 @@ intel_tv_init(struct drm_device *dev) | |||
| 1579 | struct intel_encoder *intel_encoder; | 1579 | struct intel_encoder *intel_encoder; |
| 1580 | struct intel_connector *intel_connector; | 1580 | struct intel_connector *intel_connector; |
| 1581 | u32 tv_dac_on, tv_dac_off, save_tv_dac; | 1581 | u32 tv_dac_on, tv_dac_off, save_tv_dac; |
| 1582 | char *tv_format_names[ARRAY_SIZE(tv_modes)]; | 1582 | const char *tv_format_names[ARRAY_SIZE(tv_modes)]; |
| 1583 | int i, initial_mode = 0; | 1583 | int i, initial_mode = 0; |
| 1584 | 1584 | ||
| 1585 | if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) | 1585 | if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) |
| @@ -1677,7 +1677,7 @@ intel_tv_init(struct drm_device *dev) | |||
| 1677 | 1677 | ||
| 1678 | /* Create TV properties then attach current values */ | 1678 | /* Create TV properties then attach current values */ |
| 1679 | for (i = 0; i < ARRAY_SIZE(tv_modes); i++) | 1679 | for (i = 0; i < ARRAY_SIZE(tv_modes); i++) |
| 1680 | tv_format_names[i] = (char *)tv_modes[i].name; | 1680 | tv_format_names[i] = tv_modes[i].name; |
| 1681 | drm_mode_create_tv_properties(dev, | 1681 | drm_mode_create_tv_properties(dev, |
| 1682 | ARRAY_SIZE(tv_modes), | 1682 | ARRAY_SIZE(tv_modes), |
| 1683 | tv_format_names); | 1683 | tv_format_names); |
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index e9dee367b597..30d57e74c42f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c | |||
| @@ -99,22 +99,28 @@ static const struct drm_plane_funcs mdp4_plane_funcs = { | |||
| 99 | }; | 99 | }; |
| 100 | 100 | ||
| 101 | static int mdp4_plane_prepare_fb(struct drm_plane *plane, | 101 | static int mdp4_plane_prepare_fb(struct drm_plane *plane, |
| 102 | struct drm_framebuffer *fb, | ||
| 103 | const struct drm_plane_state *new_state) | 102 | const struct drm_plane_state *new_state) |
| 104 | { | 103 | { |
| 105 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); | 104 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); |
| 106 | struct mdp4_kms *mdp4_kms = get_kms(plane); | 105 | struct mdp4_kms *mdp4_kms = get_kms(plane); |
| 106 | struct drm_framebuffer *fb = new_state->fb; | ||
| 107 | |||
| 108 | if (!fb) | ||
| 109 | return 0; | ||
| 107 | 110 | ||
| 108 | DBG("%s: prepare: FB[%u]", mdp4_plane->name, fb->base.id); | 111 | DBG("%s: prepare: FB[%u]", mdp4_plane->name, fb->base.id); |
| 109 | return msm_framebuffer_prepare(fb, mdp4_kms->id); | 112 | return msm_framebuffer_prepare(fb, mdp4_kms->id); |
| 110 | } | 113 | } |
| 111 | 114 | ||
| 112 | static void mdp4_plane_cleanup_fb(struct drm_plane *plane, | 115 | static void mdp4_plane_cleanup_fb(struct drm_plane *plane, |
| 113 | struct drm_framebuffer *fb, | ||
| 114 | const struct drm_plane_state *old_state) | 116 | const struct drm_plane_state *old_state) |
| 115 | { | 117 | { |
| 116 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); | 118 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); |
| 117 | struct mdp4_kms *mdp4_kms = get_kms(plane); | 119 | struct mdp4_kms *mdp4_kms = get_kms(plane); |
| 120 | struct drm_framebuffer *fb = old_state->fb; | ||
| 121 | |||
| 122 | if (!fb) | ||
| 123 | return; | ||
| 118 | 124 | ||
| 119 | DBG("%s: cleanup: FB[%u]", mdp4_plane->name, fb->base.id); | 125 | DBG("%s: cleanup: FB[%u]", mdp4_plane->name, fb->base.id); |
| 120 | msm_framebuffer_cleanup(fb, mdp4_kms->id); | 126 | msm_framebuffer_cleanup(fb, mdp4_kms->id); |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 07fb62fea6dc..a0f5ff0ce8dc 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | |||
| @@ -250,22 +250,28 @@ static const struct drm_plane_funcs mdp5_plane_funcs = { | |||
| 250 | }; | 250 | }; |
| 251 | 251 | ||
| 252 | static int mdp5_plane_prepare_fb(struct drm_plane *plane, | 252 | static int mdp5_plane_prepare_fb(struct drm_plane *plane, |
| 253 | struct drm_framebuffer *fb, | ||
| 254 | const struct drm_plane_state *new_state) | 253 | const struct drm_plane_state *new_state) |
| 255 | { | 254 | { |
| 256 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | 255 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); |
| 257 | struct mdp5_kms *mdp5_kms = get_kms(plane); | 256 | struct mdp5_kms *mdp5_kms = get_kms(plane); |
| 257 | struct drm_framebuffer *fb = new_state->fb; | ||
| 258 | |||
| 259 | if (!new_state->fb) | ||
| 260 | return 0; | ||
| 258 | 261 | ||
| 259 | DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id); | 262 | DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id); |
| 260 | return msm_framebuffer_prepare(fb, mdp5_kms->id); | 263 | return msm_framebuffer_prepare(fb, mdp5_kms->id); |
| 261 | } | 264 | } |
| 262 | 265 | ||
| 263 | static void mdp5_plane_cleanup_fb(struct drm_plane *plane, | 266 | static void mdp5_plane_cleanup_fb(struct drm_plane *plane, |
| 264 | struct drm_framebuffer *fb, | ||
| 265 | const struct drm_plane_state *old_state) | 267 | const struct drm_plane_state *old_state) |
| 266 | { | 268 | { |
| 267 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | 269 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); |
| 268 | struct mdp5_kms *mdp5_kms = get_kms(plane); | 270 | struct mdp5_kms *mdp5_kms = get_kms(plane); |
| 271 | struct drm_framebuffer *fb = old_state->fb; | ||
| 272 | |||
| 273 | if (!fb) | ||
| 274 | return; | ||
| 269 | 275 | ||
| 270 | DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id); | 276 | DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id); |
| 271 | msm_framebuffer_cleanup(fb, mdp5_kms->id); | 277 | msm_framebuffer_cleanup(fb, mdp5_kms->id); |
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 1ceb4f22dd89..7eb253bc24df 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c | |||
| @@ -125,7 +125,7 @@ static void complete_commit(struct msm_commit *c) | |||
| 125 | 125 | ||
| 126 | drm_atomic_helper_commit_modeset_disables(dev, state); | 126 | drm_atomic_helper_commit_modeset_disables(dev, state); |
| 127 | 127 | ||
| 128 | drm_atomic_helper_commit_planes(dev, state); | 128 | drm_atomic_helper_commit_planes(dev, state, false); |
| 129 | 129 | ||
| 130 | drm_atomic_helper_commit_modeset_enables(dev, state); | 130 | drm_atomic_helper_commit_modeset_enables(dev, state); |
| 131 | 131 | ||
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c index 08c6f5e50610..903c473d266f 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | #include "hw.h" | 32 | #include "hw.h" |
| 33 | #include "tvnv17.h" | 33 | #include "tvnv17.h" |
| 34 | 34 | ||
| 35 | char *nv17_tv_norm_names[NUM_TV_NORMS] = { | 35 | const char * const nv17_tv_norm_names[NUM_TV_NORMS] = { |
| 36 | [TV_NORM_PAL] = "PAL", | 36 | [TV_NORM_PAL] = "PAL", |
| 37 | [TV_NORM_PAL_M] = "PAL-M", | 37 | [TV_NORM_PAL_M] = "PAL-M", |
| 38 | [TV_NORM_PAL_N] = "PAL-N", | 38 | [TV_NORM_PAL_N] = "PAL-N", |
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h index 459910b6bb32..1b07521cde0d 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h | |||
| @@ -85,7 +85,7 @@ struct nv17_tv_encoder { | |||
| 85 | #define to_tv_enc(x) container_of(nouveau_encoder(x), \ | 85 | #define to_tv_enc(x) container_of(nouveau_encoder(x), \ |
| 86 | struct nv17_tv_encoder, base) | 86 | struct nv17_tv_encoder, base) |
| 87 | 87 | ||
| 88 | extern char *nv17_tv_norm_names[NUM_TV_NORMS]; | 88 | extern const char * const nv17_tv_norm_names[NUM_TV_NORMS]; |
| 89 | 89 | ||
| 90 | extern struct nv17_tv_norm_params { | 90 | extern struct nv17_tv_norm_params { |
| 91 | enum { | 91 | enum { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index cc6c228e11c8..a82c3cbe3127 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
| @@ -103,6 +103,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | |||
| 103 | .base.head = nouveau_crtc(crtc)->index, | 103 | .base.head = nouveau_crtc(crtc)->index, |
| 104 | }; | 104 | }; |
| 105 | struct nouveau_display *disp = nouveau_display(crtc->dev); | 105 | struct nouveau_display *disp = nouveau_display(crtc->dev); |
| 106 | struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; | ||
| 106 | int ret, retry = 1; | 107 | int ret, retry = 1; |
| 107 | 108 | ||
| 108 | do { | 109 | do { |
| @@ -116,7 +117,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | |||
| 116 | break; | 117 | break; |
| 117 | } | 118 | } |
| 118 | 119 | ||
| 119 | if (retry) ndelay(crtc->linedur_ns); | 120 | if (retry) ndelay(vblank->linedur_ns); |
| 120 | } while (retry--); | 121 | } while (retry--); |
| 121 | 122 | ||
| 122 | *hpos = args.scan.hline; | 123 | *hpos = args.scan.hline; |
| @@ -132,7 +133,8 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | |||
| 132 | 133 | ||
| 133 | int | 134 | int |
| 134 | nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags, | 135 | nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags, |
| 135 | int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) | 136 | int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, |
| 137 | const struct drm_display_mode *mode) | ||
| 136 | { | 138 | { |
| 137 | struct drm_crtc *crtc; | 139 | struct drm_crtc *crtc; |
| 138 | 140 | ||
| @@ -155,7 +157,7 @@ nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error, | |||
| 155 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 157 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
| 156 | if (nouveau_crtc(crtc)->index == head) { | 158 | if (nouveau_crtc(crtc)->index == head) { |
| 157 | return drm_calc_vbltimestamp_from_scanoutpos(dev, | 159 | return drm_calc_vbltimestamp_from_scanoutpos(dev, |
| 158 | head, max_error, time, flags, crtc, | 160 | head, max_error, time, flags, |
| 159 | &crtc->hwmode); | 161 | &crtc->hwmode); |
| 160 | } | 162 | } |
| 161 | } | 163 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index a6213e2425c5..4182d21538c5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h | |||
| @@ -68,7 +68,8 @@ void nouveau_display_resume(struct drm_device *dev, bool runtime); | |||
| 68 | int nouveau_display_vblank_enable(struct drm_device *, int); | 68 | int nouveau_display_vblank_enable(struct drm_device *, int); |
| 69 | void nouveau_display_vblank_disable(struct drm_device *, int); | 69 | void nouveau_display_vblank_disable(struct drm_device *, int); |
| 70 | int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, | 70 | int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, |
| 71 | int *, int *, ktime_t *, ktime_t *); | 71 | int *, int *, ktime_t *, ktime_t *, |
| 72 | const struct drm_display_mode *); | ||
| 72 | int nouveau_display_vblstamp(struct drm_device *, int, int *, | 73 | int nouveau_display_vblstamp(struct drm_device *, int, int *, |
| 73 | struct timeval *, unsigned); | 74 | struct timeval *, unsigned); |
| 74 | 75 | ||
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 419c2e49adf5..d685e23449ce 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c | |||
| @@ -96,7 +96,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit) | |||
| 96 | dispc_runtime_get(); | 96 | dispc_runtime_get(); |
| 97 | 97 | ||
| 98 | drm_atomic_helper_commit_modeset_disables(dev, old_state); | 98 | drm_atomic_helper_commit_modeset_disables(dev, old_state); |
| 99 | drm_atomic_helper_commit_planes(dev, old_state); | 99 | drm_atomic_helper_commit_planes(dev, old_state, false); |
| 100 | drm_atomic_helper_commit_modeset_enables(dev, old_state); | 100 | drm_atomic_helper_commit_modeset_enables(dev, old_state); |
| 101 | 101 | ||
| 102 | omap_atomic_wait_for_completion(dev, old_state); | 102 | omap_atomic_wait_for_completion(dev, old_state); |
| @@ -753,7 +753,7 @@ static void dev_lastclose(struct drm_device *dev) | |||
| 753 | { | 753 | { |
| 754 | int i; | 754 | int i; |
| 755 | 755 | ||
| 756 | /* we don't support vga-switcheroo.. so just make sure the fbdev | 756 | /* we don't support vga_switcheroo.. so just make sure the fbdev |
| 757 | * mode is active | 757 | * mode is active |
| 758 | */ | 758 | */ |
| 759 | struct omap_drm_private *priv = dev->dev_private; | 759 | struct omap_drm_private *priv = dev->dev_private; |
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 098904696a5c..09e363bb55f2 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c | |||
| @@ -60,17 +60,19 @@ to_omap_plane_state(struct drm_plane_state *state) | |||
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static int omap_plane_prepare_fb(struct drm_plane *plane, | 62 | static int omap_plane_prepare_fb(struct drm_plane *plane, |
| 63 | struct drm_framebuffer *fb, | ||
| 64 | const struct drm_plane_state *new_state) | 63 | const struct drm_plane_state *new_state) |
| 65 | { | 64 | { |
| 66 | return omap_framebuffer_pin(fb); | 65 | if (!new_state->fb) |
| 66 | return 0; | ||
| 67 | |||
| 68 | return omap_framebuffer_pin(new_state->fb); | ||
| 67 | } | 69 | } |
| 68 | 70 | ||
| 69 | static void omap_plane_cleanup_fb(struct drm_plane *plane, | 71 | static void omap_plane_cleanup_fb(struct drm_plane *plane, |
| 70 | struct drm_framebuffer *fb, | ||
| 71 | const struct drm_plane_state *old_state) | 72 | const struct drm_plane_state *old_state) |
| 72 | { | 73 | { |
| 73 | omap_framebuffer_unpin(fb); | 74 | if (old_state->fb) |
| 75 | omap_framebuffer_unpin(old_state->fb); | ||
| 74 | } | 76 | } |
| 75 | 77 | ||
| 76 | static void omap_plane_atomic_update(struct drm_plane *plane, | 78 | static void omap_plane_atomic_update(struct drm_plane *plane, |
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 9cd49c584263..bd73b4069069 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c | |||
| @@ -179,6 +179,7 @@ radeon_dp_aux_transfer_atom(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
| 179 | switch (msg->request & ~DP_AUX_I2C_MOT) { | 179 | switch (msg->request & ~DP_AUX_I2C_MOT) { |
| 180 | case DP_AUX_NATIVE_WRITE: | 180 | case DP_AUX_NATIVE_WRITE: |
| 181 | case DP_AUX_I2C_WRITE: | 181 | case DP_AUX_I2C_WRITE: |
| 182 | case DP_AUX_I2C_WRITE_STATUS_UPDATE: | ||
| 182 | /* The atom implementation only supports writes with a max payload of | 183 | /* The atom implementation only supports writes with a max payload of |
| 183 | * 12 bytes since it uses 4 bits for the total count (header + payload) | 184 | * 12 bytes since it uses 4 bits for the total count (header + payload) |
| 184 | * in the parameter space. The atom interface supports 16 byte | 185 | * in the parameter space. The atom interface supports 16 byte |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index d2e9e9efc159..0503af748d99 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
| @@ -323,7 +323,8 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) | |||
| 323 | */ | 323 | */ |
| 324 | if (update_pending && | 324 | if (update_pending && |
| 325 | (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0, | 325 | (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0, |
| 326 | &vpos, &hpos, NULL, NULL)) && | 326 | &vpos, &hpos, NULL, NULL, |
| 327 | &rdev->mode_info.crtcs[crtc_id]->base.hwmode)) && | ||
| 327 | ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || | 328 | ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || |
| 328 | (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) { | 329 | (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) { |
| 329 | /* crtc didn't flip in this target vblank interval, | 330 | /* crtc didn't flip in this target vblank interval, |
| @@ -1799,7 +1800,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, | |||
| 1799 | * | 1800 | * |
| 1800 | */ | 1801 | */ |
| 1801 | int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, | 1802 | int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, |
| 1802 | int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) | 1803 | int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, |
| 1804 | const struct drm_display_mode *mode) | ||
| 1803 | { | 1805 | { |
| 1804 | u32 stat_crtc = 0, vbl = 0, position = 0; | 1806 | u32 stat_crtc = 0, vbl = 0, position = 0; |
| 1805 | int vbl_start, vbl_end, vtotal, ret = 0; | 1807 | int vbl_start, vbl_end, vtotal, ret = 0; |
| @@ -1914,7 +1916,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl | |||
| 1914 | } | 1916 | } |
| 1915 | else { | 1917 | else { |
| 1916 | /* No: Fake something reasonable which gives at least ok results. */ | 1918 | /* No: Fake something reasonable which gives at least ok results. */ |
| 1917 | vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; | 1919 | vbl_start = mode->crtc_vdisplay; |
| 1918 | vbl_end = 0; | 1920 | vbl_end = 0; |
| 1919 | } | 1921 | } |
| 1920 | 1922 | ||
| @@ -1930,7 +1932,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl | |||
| 1930 | 1932 | ||
| 1931 | /* Inside "upper part" of vblank area? Apply corrective offset if so: */ | 1933 | /* Inside "upper part" of vblank area? Apply corrective offset if so: */ |
| 1932 | if (in_vbl && (*vpos >= vbl_start)) { | 1934 | if (in_vbl && (*vpos >= vbl_start)) { |
| 1933 | vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; | 1935 | vtotal = mode->crtc_vtotal; |
| 1934 | *vpos = *vpos - vtotal; | 1936 | *vpos = *vpos - vtotal; |
| 1935 | } | 1937 | } |
| 1936 | 1938 | ||
| @@ -1952,8 +1954,8 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl | |||
| 1952 | * We only do this if DRM_CALLED_FROM_VBLIRQ. | 1954 | * We only do this if DRM_CALLED_FROM_VBLIRQ. |
| 1953 | */ | 1955 | */ |
| 1954 | if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { | 1956 | if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { |
| 1955 | vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; | 1957 | vbl_start = mode->crtc_vdisplay; |
| 1956 | vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; | 1958 | vtotal = mode->crtc_vtotal; |
| 1957 | 1959 | ||
| 1958 | if (vbl_start - *vpos < vtotal / 100) { | 1960 | if (vbl_start - *vpos < vtotal / 100) { |
| 1959 | *vpos -= vtotal; | 1961 | *vpos -= vtotal; |
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 5751446677d3..e30c1d73b4ca 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
| @@ -126,8 +126,9 @@ struct dma_buf *radeon_gem_prime_export(struct drm_device *dev, | |||
| 126 | int flags); | 126 | int flags); |
| 127 | extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, | 127 | extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, |
| 128 | unsigned int flags, | 128 | unsigned int flags, |
| 129 | int *vpos, int *hpos, ktime_t *stime, | 129 | int *vpos, int *hpos, |
| 130 | ktime_t *etime); | 130 | ktime_t *stime, ktime_t *etime, |
| 131 | const struct drm_display_mode *mode); | ||
| 131 | extern bool radeon_is_px(struct drm_device *dev); | 132 | extern bool radeon_is_px(struct drm_device *dev); |
| 132 | extern const struct drm_ioctl_desc radeon_ioctls_kms[]; | 133 | extern const struct drm_ioctl_desc radeon_ioctls_kms[]; |
| 133 | extern int radeon_max_kms_ioctl; | 134 | extern int radeon_max_kms_ioctl; |
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 4a119c255ba9..fd9da282b29c 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c | |||
| @@ -841,7 +841,7 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, | |||
| 841 | /* Helper routine in DRM core does all the work: */ | 841 | /* Helper routine in DRM core does all the work: */ |
| 842 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, | 842 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, |
| 843 | vblank_time, flags, | 843 | vblank_time, flags, |
| 844 | drmcrtc, &drmcrtc->hwmode); | 844 | &drmcrtc->hwmode); |
| 845 | } | 845 | } |
| 846 | 846 | ||
| 847 | #define KMS_INVALID_IOCTL(name) \ | 847 | #define KMS_INVALID_IOCTL(name) \ |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index aecc3e3dec0c..2317d04f8a09 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
| @@ -876,8 +876,9 @@ extern void radeon_cursor_reset(struct drm_crtc *crtc); | |||
| 876 | 876 | ||
| 877 | extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, | 877 | extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, |
| 878 | unsigned int flags, | 878 | unsigned int flags, |
| 879 | int *vpos, int *hpos, ktime_t *stime, | 879 | int *vpos, int *hpos, |
| 880 | ktime_t *etime); | 880 | ktime_t *stime, ktime_t *etime, |
| 881 | const struct drm_display_mode *mode); | ||
| 881 | 882 | ||
| 882 | extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); | 883 | extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); |
| 883 | extern struct edid * | 884 | extern struct edid * |
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 05751f3f8444..10f4c12e439e 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
| @@ -1733,7 +1733,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) | |||
| 1733 | */ | 1733 | */ |
| 1734 | for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { | 1734 | for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { |
| 1735 | if (rdev->pm.active_crtcs & (1 << crtc)) { | 1735 | if (rdev->pm.active_crtcs & (1 << crtc)) { |
| 1736 | vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL); | 1736 | vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, |
| 1737 | &vpos, &hpos, NULL, NULL, | ||
| 1738 | &rdev->mode_info.crtcs[crtc]->base.hwmode); | ||
| 1737 | if ((vbl_status & DRM_SCANOUTPOS_VALID) && | 1739 | if ((vbl_status & DRM_SCANOUTPOS_VALID) && |
| 1738 | !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK)) | 1740 | !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK)) |
| 1739 | in_vbl = false; | 1741 | in_vbl = false; |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 56518eb1269a..ca12e8ca5552 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c | |||
| @@ -456,7 +456,7 @@ static void rcar_du_atomic_complete(struct rcar_du_commit *commit) | |||
| 456 | /* Apply the atomic update. */ | 456 | /* Apply the atomic update. */ |
| 457 | drm_atomic_helper_commit_modeset_disables(dev, old_state); | 457 | drm_atomic_helper_commit_modeset_disables(dev, old_state); |
| 458 | drm_atomic_helper_commit_modeset_enables(dev, old_state); | 458 | drm_atomic_helper_commit_modeset_enables(dev, old_state); |
| 459 | drm_atomic_helper_commit_planes(dev, old_state); | 459 | drm_atomic_helper_commit_planes(dev, old_state, false); |
| 460 | 460 | ||
| 461 | drm_atomic_helper_wait_for_vblanks(dev, old_state); | 461 | drm_atomic_helper_wait_for_vblanks(dev, old_state); |
| 462 | 462 | ||
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 6f4af6a8ba1b..9f85988a43ce 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c | |||
| @@ -59,7 +59,7 @@ static void sti_atomic_complete(struct sti_private *private, | |||
| 59 | */ | 59 | */ |
| 60 | 60 | ||
| 61 | drm_atomic_helper_commit_modeset_disables(drm, state); | 61 | drm_atomic_helper_commit_modeset_disables(drm, state); |
| 62 | drm_atomic_helper_commit_planes(drm, state); | 62 | drm_atomic_helper_commit_planes(drm, state, false); |
| 63 | drm_atomic_helper_commit_modeset_enables(drm, state); | 63 | drm_atomic_helper_commit_modeset_enables(drm, state); |
| 64 | 64 | ||
| 65 | drm_atomic_helper_wait_for_vblanks(drm, state); | 65 | drm_atomic_helper_wait_for_vblanks(drm, state); |
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index ddefb85dc4f7..b4af4ab9ce6b 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
| @@ -480,14 +480,12 @@ static const struct drm_plane_funcs tegra_primary_plane_funcs = { | |||
| 480 | }; | 480 | }; |
| 481 | 481 | ||
| 482 | static int tegra_plane_prepare_fb(struct drm_plane *plane, | 482 | static int tegra_plane_prepare_fb(struct drm_plane *plane, |
| 483 | struct drm_framebuffer *fb, | ||
| 484 | const struct drm_plane_state *new_state) | 483 | const struct drm_plane_state *new_state) |
| 485 | { | 484 | { |
| 486 | return 0; | 485 | return 0; |
| 487 | } | 486 | } |
| 488 | 487 | ||
| 489 | static void tegra_plane_cleanup_fb(struct drm_plane *plane, | 488 | static void tegra_plane_cleanup_fb(struct drm_plane *plane, |
| 490 | struct drm_framebuffer *fb, | ||
| 491 | const struct drm_plane_state *old_fb) | 489 | const struct drm_plane_state *old_fb) |
| 492 | { | 490 | { |
| 493 | } | 491 | } |
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 224a7dc8e4ed..6aecb6647313 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c | |||
| @@ -119,6 +119,7 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, | |||
| 119 | */ | 119 | */ |
| 120 | if (msg->size < 1) { | 120 | if (msg->size < 1) { |
| 121 | switch (msg->request & ~DP_AUX_I2C_MOT) { | 121 | switch (msg->request & ~DP_AUX_I2C_MOT) { |
| 122 | case DP_AUX_I2C_WRITE_STATUS_UPDATE: | ||
| 122 | case DP_AUX_I2C_WRITE: | 123 | case DP_AUX_I2C_WRITE: |
| 123 | case DP_AUX_I2C_READ: | 124 | case DP_AUX_I2C_READ: |
| 124 | value = DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY; | 125 | value = DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY; |
| @@ -149,7 +150,7 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, | |||
| 149 | 150 | ||
| 150 | break; | 151 | break; |
| 151 | 152 | ||
| 152 | case DP_AUX_I2C_STATUS: | 153 | case DP_AUX_I2C_WRITE_STATUS_UPDATE: |
| 153 | if (msg->request & DP_AUX_I2C_MOT) | 154 | if (msg->request & DP_AUX_I2C_MOT) |
| 154 | value |= DPAUX_DP_AUXCTL_CMD_MOT_RQ; | 155 | value |= DPAUX_DP_AUXCTL_CMD_MOT_RQ; |
| 155 | else | 156 | else |
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 6d88cf1fcd1c..2486bc24bff6 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
| @@ -56,7 +56,7 @@ static void tegra_atomic_complete(struct tegra_drm *tegra, | |||
| 56 | */ | 56 | */ |
| 57 | 57 | ||
| 58 | drm_atomic_helper_commit_modeset_disables(drm, state); | 58 | drm_atomic_helper_commit_modeset_disables(drm, state); |
| 59 | drm_atomic_helper_commit_planes(drm, state); | 59 | drm_atomic_helper_commit_planes(drm, state, false); |
| 60 | drm_atomic_helper_commit_modeset_enables(drm, state); | 60 | drm_atomic_helper_commit_modeset_enables(drm, state); |
| 61 | 61 | ||
| 62 | drm_atomic_helper_wait_for_vblanks(drm, state); | 62 | drm_atomic_helper_wait_for_vblanks(drm, state); |
