diff options
author | Dave Airlie <airlied@redhat.com> | 2015-09-29 18:35:45 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-09-29 18:35:45 -0400 |
commit | 2d4df13c0f9ef56452b1d9a9016cb3946e17bfe5 (patch) | |
tree | 9f5381966edbf51cafd23b7806ed754f4f3e8bd1 /drivers/gpu | |
parent | 9ffecb10283508260936b96022d4ee43a7798b4c (diff) | |
parent | cf6483050e9bf13979415d9fd388554d8c8f3477 (diff) |
Merge tag 'topic/drm-misc-2015-09-25' of git://anongit.freedesktop.org/drm-intel into drm-next
Another attempt at drm-misc for 4.4 ...
- better atomic helpers for runtime pm drivers
- atomic fbdev
- dp aux i2c STATUS_UPDATE handling (for short i2c replies from the sink)
- bunch of constify patches
- inital kerneldoc for vga switcheroo
- some vblank code cleanups from Ville and Thierry
- various polish all over
* tag 'topic/drm-misc-2015-09-25' of git://anongit.freedesktop.org/drm-intel: (57 commits)
drm/irq: Add drm_crtc_vblank_count_and_time()
drm/irq: Rename drm_crtc -> crtc
drm: drm_atomic_crtc_get_property should be static
drm/gma500: Remove DP_LINK_STATUS_SIZE redefinition
vga_switcheroo: Set active attribute to false for audio clients
drm/core: Preserve the fb id on close.
drm/core: Preserve the framebuffer after removing it.
drm: Use vblank timestamps to guesstimate how many vblanks were missed
drm: store_vblank() is never called with NULL timestamp
drm: Clean up drm_calc_vbltimestamp_from_scanoutpos() vbl_status
drm: Limit the number of .get_vblank_counter() retries
drm: Pass flags to drm_update_vblank_count()
drm/i915: Fix vblank count variable types
drm: Kill pixeldur_ns
drm: Stop using linedur_ns and pixeldur_ns for vblank timestamps
drm: Move timestamping constants into drm_vblank_crtc
drm/fbdev: Update legacy plane->fb refcounting for atomic restore
drm: fix kernel-doc warnings in drm_crtc.h
vga_switcheroo: Sort headers alphabetically
drm: Spell vga_switcheroo consistently
...
Diffstat (limited to 'drivers/gpu')
52 files changed, 1121 insertions, 442 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); |
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 21060668fd25..86c03b53e7bf 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c | |||
@@ -1,38 +1,102 @@ | |||
1 | /* | 1 | /* |
2 | * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs | ||
3 | * | ||
2 | * Copyright (c) 2010 Red Hat Inc. | 4 | * Copyright (c) 2010 Red Hat Inc. |
3 | * Author : Dave Airlie <airlied@redhat.com> | 5 | * Author : Dave Airlie <airlied@redhat.com> |
4 | * | 6 | * |
7 | * Copyright (c) 2015 Lukas Wunner <lukas@wunner.de> | ||
5 | * | 8 | * |
6 | * Licensed under GPLv2 | 9 | * Permission is hereby granted, free of charge, to any person obtaining a |
10 | * copy of this software and associated documentation files (the "Software"), | ||
11 | * to deal in the Software without restriction, including without limitation | ||
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
13 | * and/or sell copies of the Software, and to permit persons to whom the | ||
14 | * Software is furnished to do so, subject to the following conditions: | ||
7 | * | 15 | * |
8 | * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs | 16 | * The above copyright notice and this permission notice (including the next |
17 | * paragraph) shall be included in all copies or substantial portions of the | ||
18 | * Software. | ||
9 | * | 19 | * |
10 | * Switcher interface - methods require for ATPX and DCM | 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
11 | * - switchto - this throws the output MUX switch | 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
12 | * - discrete_set_power - sets the power state for the discrete card | 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
23 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
26 | * DEALINGS | ||
27 | * IN THE SOFTWARE. | ||
13 | * | 28 | * |
14 | * GPU driver interface | ||
15 | * - set_gpu_state - this should do the equiv of s/r for the card | ||
16 | * - this should *not* set the discrete power state | ||
17 | * - switch_check - check if the device is in a position to switch now | ||
18 | */ | 29 | */ |
19 | 30 | ||
20 | #define pr_fmt(fmt) "vga_switcheroo: " fmt | 31 | #define pr_fmt(fmt) "vga_switcheroo: " fmt |
21 | 32 | ||
22 | #include <linux/module.h> | 33 | #include <linux/console.h> |
23 | #include <linux/seq_file.h> | ||
24 | #include <linux/uaccess.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/debugfs.h> | 34 | #include <linux/debugfs.h> |
27 | #include <linux/fb.h> | 35 | #include <linux/fb.h> |
28 | 36 | #include <linux/fs.h> | |
37 | #include <linux/module.h> | ||
29 | #include <linux/pci.h> | 38 | #include <linux/pci.h> |
30 | #include <linux/console.h> | ||
31 | #include <linux/vga_switcheroo.h> | ||
32 | #include <linux/pm_runtime.h> | 39 | #include <linux/pm_runtime.h> |
33 | 40 | #include <linux/seq_file.h> | |
41 | #include <linux/uaccess.h> | ||
34 | #include <linux/vgaarb.h> | 42 | #include <linux/vgaarb.h> |
43 | #include <linux/vga_switcheroo.h> | ||
35 | 44 | ||
45 | /** | ||
46 | * DOC: Overview | ||
47 | * | ||
48 | * vga_switcheroo is the Linux subsystem for laptop hybrid graphics. | ||
49 | * These come in two flavors: | ||
50 | * | ||
51 | * * muxed: Dual GPUs with a multiplexer chip to switch outputs between GPUs. | ||
52 | * * muxless: Dual GPUs but only one of them is connected to outputs. | ||
53 | * The other one is merely used to offload rendering, its results | ||
54 | * are copied over PCIe into the framebuffer. On Linux this is | ||
55 | * supported with DRI PRIME. | ||
56 | * | ||
57 | * Hybrid graphics started to appear in the late Naughties and were initially | ||
58 | * all muxed. Newer laptops moved to a muxless architecture for cost reasons. | ||
59 | * A notable exception is the MacBook Pro which continues to use a mux. | ||
60 | * Muxes come with varying capabilities: Some switch only the panel, others | ||
61 | * can also switch external displays. Some switch all display pins at once | ||
62 | * while others can switch just the DDC lines. (To allow EDID probing | ||
63 | * for the inactive GPU.) Also, muxes are often used to cut power to the | ||
64 | * discrete GPU while it is not used. | ||
65 | * | ||
66 | * DRM drivers register GPUs with vga_switcheroo, these are heretoforth called | ||
67 | * clients. The mux is called the handler. Muxless machines also register a | ||
68 | * handler to control the power state of the discrete GPU, its ->switchto | ||
69 | * callback is a no-op for obvious reasons. The discrete GPU is often equipped | ||
70 | * with an HDA controller for the HDMI/DP audio signal, this will also | ||
71 | * register as a client so that vga_switcheroo can take care of the correct | ||
72 | * suspend/resume order when changing the discrete GPU's power state. In total | ||
73 | * there can thus be up to three clients: Two vga clients (GPUs) and one audio | ||
74 | * client (on the discrete GPU). The code is mostly prepared to support | ||
75 | * machines with more than two GPUs should they become available. | ||
76 | * The GPU to which the outputs are currently switched is called the | ||
77 | * active client in vga_switcheroo parlance. The GPU not in use is the | ||
78 | * inactive client. | ||
79 | */ | ||
80 | |||
81 | /** | ||
82 | * struct vga_switcheroo_client - registered client | ||
83 | * @pdev: client pci device | ||
84 | * @fb_info: framebuffer to which console is remapped on switching | ||
85 | * @pwr_state: current power state | ||
86 | * @ops: client callbacks | ||
87 | * @id: client identifier, see enum vga_switcheroo_client_id. | ||
88 | * Determining the id requires the handler, so GPUs are initially | ||
89 | * assigned -1 and later given their true id in vga_switcheroo_enable() | ||
90 | * @active: whether the outputs are currently switched to this client | ||
91 | * @driver_power_control: whether power state is controlled by the driver's | ||
92 | * runtime pm. If true, writing ON and OFF to the vga_switcheroo debugfs | ||
93 | * interface is a no-op so as not to interfere with runtime pm | ||
94 | * @list: client list | ||
95 | * | ||
96 | * Registered client. A client can be either a GPU or an audio device on a GPU. | ||
97 | * For audio clients, the @fb_info, @active and @driver_power_control members | ||
98 | * are bogus. | ||
99 | */ | ||
36 | struct vga_switcheroo_client { | 100 | struct vga_switcheroo_client { |
37 | struct pci_dev *pdev; | 101 | struct pci_dev *pdev; |
38 | struct fb_info *fb_info; | 102 | struct fb_info *fb_info; |
@@ -44,10 +108,28 @@ struct vga_switcheroo_client { | |||
44 | struct list_head list; | 108 | struct list_head list; |
45 | }; | 109 | }; |
46 | 110 | ||
111 | /* | ||
112 | * protects access to struct vgasr_priv | ||
113 | */ | ||
47 | static DEFINE_MUTEX(vgasr_mutex); | 114 | static DEFINE_MUTEX(vgasr_mutex); |
48 | 115 | ||
116 | /** | ||
117 | * struct vgasr_priv - vga_switcheroo private data | ||
118 | * @active: whether vga_switcheroo is enabled. | ||
119 | * Prerequisite is the registration of two GPUs and a handler | ||
120 | * @delayed_switch_active: whether a delayed switch is pending | ||
121 | * @delayed_client_id: client to which a delayed switch is pending | ||
122 | * @debugfs_root: directory for vga_switcheroo debugfs interface | ||
123 | * @switch_file: file for vga_switcheroo debugfs interface | ||
124 | * @registered_clients: number of registered GPUs | ||
125 | * (counting only vga clients, not audio clients) | ||
126 | * @clients: list of registered clients | ||
127 | * @handler: registered handler | ||
128 | * | ||
129 | * vga_switcheroo private data. Currently only one vga_switcheroo instance | ||
130 | * per system is supported. | ||
131 | */ | ||
49 | struct vgasr_priv { | 132 | struct vgasr_priv { |
50 | |||
51 | bool active; | 133 | bool active; |
52 | bool delayed_switch_active; | 134 | bool delayed_switch_active; |
53 | enum vga_switcheroo_client_id delayed_client_id; | 135 | enum vga_switcheroo_client_id delayed_client_id; |
@@ -103,6 +185,15 @@ static void vga_switcheroo_enable(void) | |||
103 | vgasr_priv.active = true; | 185 | vgasr_priv.active = true; |
104 | } | 186 | } |
105 | 187 | ||
188 | /** | ||
189 | * vga_switcheroo_register_handler() - register handler | ||
190 | * @handler: handler callbacks | ||
191 | * | ||
192 | * Register handler. Enable vga_switcheroo if two vga clients have already | ||
193 | * registered. | ||
194 | * | ||
195 | * Return: 0 on success, -EINVAL if a handler was already registered. | ||
196 | */ | ||
106 | int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) | 197 | int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) |
107 | { | 198 | { |
108 | mutex_lock(&vgasr_mutex); | 199 | mutex_lock(&vgasr_mutex); |
@@ -121,6 +212,11 @@ int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) | |||
121 | } | 212 | } |
122 | EXPORT_SYMBOL(vga_switcheroo_register_handler); | 213 | EXPORT_SYMBOL(vga_switcheroo_register_handler); |
123 | 214 | ||
215 | /** | ||
216 | * vga_switcheroo_unregister_handler() - unregister handler | ||
217 | * | ||
218 | * Unregister handler. Disable vga_switcheroo. | ||
219 | */ | ||
124 | void vga_switcheroo_unregister_handler(void) | 220 | void vga_switcheroo_unregister_handler(void) |
125 | { | 221 | { |
126 | mutex_lock(&vgasr_mutex); | 222 | mutex_lock(&vgasr_mutex); |
@@ -164,6 +260,19 @@ static int register_client(struct pci_dev *pdev, | |||
164 | return 0; | 260 | return 0; |
165 | } | 261 | } |
166 | 262 | ||
263 | /** | ||
264 | * vga_switcheroo_register_client - register vga client | ||
265 | * @pdev: client pci device | ||
266 | * @ops: client callbacks | ||
267 | * @driver_power_control: whether power state is controlled by the driver's | ||
268 | * runtime pm | ||
269 | * | ||
270 | * Register vga client (GPU). Enable vga_switcheroo if another GPU and a | ||
271 | * handler have already registered. The power state of the client is assumed | ||
272 | * to be ON. | ||
273 | * | ||
274 | * Return: 0 on success, -ENOMEM on memory allocation error. | ||
275 | */ | ||
167 | int vga_switcheroo_register_client(struct pci_dev *pdev, | 276 | int vga_switcheroo_register_client(struct pci_dev *pdev, |
168 | const struct vga_switcheroo_client_ops *ops, | 277 | const struct vga_switcheroo_client_ops *ops, |
169 | bool driver_power_control) | 278 | bool driver_power_control) |
@@ -174,11 +283,22 @@ int vga_switcheroo_register_client(struct pci_dev *pdev, | |||
174 | } | 283 | } |
175 | EXPORT_SYMBOL(vga_switcheroo_register_client); | 284 | EXPORT_SYMBOL(vga_switcheroo_register_client); |
176 | 285 | ||
286 | /** | ||
287 | * vga_switcheroo_register_audio_client - register audio client | ||
288 | * @pdev: client pci device | ||
289 | * @ops: client callbacks | ||
290 | * @id: client identifier, see enum vga_switcheroo_client_id | ||
291 | * | ||
292 | * Register audio client (audio device on a GPU). The power state of the | ||
293 | * client is assumed to be ON. | ||
294 | * | ||
295 | * Return: 0 on success, -ENOMEM on memory allocation error. | ||
296 | */ | ||
177 | int vga_switcheroo_register_audio_client(struct pci_dev *pdev, | 297 | int vga_switcheroo_register_audio_client(struct pci_dev *pdev, |
178 | const struct vga_switcheroo_client_ops *ops, | 298 | const struct vga_switcheroo_client_ops *ops, |
179 | int id, bool active) | 299 | int id) |
180 | { | 300 | { |
181 | return register_client(pdev, ops, id | ID_BIT_AUDIO, active, false); | 301 | return register_client(pdev, ops, id | ID_BIT_AUDIO, false, false); |
182 | } | 302 | } |
183 | EXPORT_SYMBOL(vga_switcheroo_register_audio_client); | 303 | EXPORT_SYMBOL(vga_switcheroo_register_audio_client); |
184 | 304 | ||
@@ -210,11 +330,20 @@ find_active_client(struct list_head *head) | |||
210 | struct vga_switcheroo_client *client; | 330 | struct vga_switcheroo_client *client; |
211 | 331 | ||
212 | list_for_each_entry(client, head, list) | 332 | list_for_each_entry(client, head, list) |
213 | if (client->active && client_is_vga(client)) | 333 | if (client->active) |
214 | return client; | 334 | return client; |
215 | return NULL; | 335 | return NULL; |
216 | } | 336 | } |
217 | 337 | ||
338 | /** | ||
339 | * vga_switcheroo_get_client_state() - obtain power state of a given client | ||
340 | * @pdev: client pci device | ||
341 | * | ||
342 | * Obtain power state of a given client as seen from vga_switcheroo. | ||
343 | * The function is only called from hda_intel.c. | ||
344 | * | ||
345 | * Return: Power state. | ||
346 | */ | ||
218 | int vga_switcheroo_get_client_state(struct pci_dev *pdev) | 347 | int vga_switcheroo_get_client_state(struct pci_dev *pdev) |
219 | { | 348 | { |
220 | struct vga_switcheroo_client *client; | 349 | struct vga_switcheroo_client *client; |
@@ -228,6 +357,12 @@ int vga_switcheroo_get_client_state(struct pci_dev *pdev) | |||
228 | } | 357 | } |
229 | EXPORT_SYMBOL(vga_switcheroo_get_client_state); | 358 | EXPORT_SYMBOL(vga_switcheroo_get_client_state); |
230 | 359 | ||
360 | /** | ||
361 | * vga_switcheroo_unregister_client() - unregister client | ||
362 | * @pdev: client pci device | ||
363 | * | ||
364 | * Unregister client. Disable vga_switcheroo if this is a vga client (GPU). | ||
365 | */ | ||
231 | void vga_switcheroo_unregister_client(struct pci_dev *pdev) | 366 | void vga_switcheroo_unregister_client(struct pci_dev *pdev) |
232 | { | 367 | { |
233 | struct vga_switcheroo_client *client; | 368 | struct vga_switcheroo_client *client; |
@@ -249,6 +384,14 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev) | |||
249 | } | 384 | } |
250 | EXPORT_SYMBOL(vga_switcheroo_unregister_client); | 385 | EXPORT_SYMBOL(vga_switcheroo_unregister_client); |
251 | 386 | ||
387 | /** | ||
388 | * vga_switcheroo_client_fb_set() - set framebuffer of a given client | ||
389 | * @pdev: client pci device | ||
390 | * @info: framebuffer | ||
391 | * | ||
392 | * Set framebuffer of a given client. The console will be remapped to this | ||
393 | * on switching. | ||
394 | */ | ||
252 | void vga_switcheroo_client_fb_set(struct pci_dev *pdev, | 395 | void vga_switcheroo_client_fb_set(struct pci_dev *pdev, |
253 | struct fb_info *info) | 396 | struct fb_info *info) |
254 | { | 397 | { |
@@ -262,6 +405,42 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev, | |||
262 | } | 405 | } |
263 | EXPORT_SYMBOL(vga_switcheroo_client_fb_set); | 406 | EXPORT_SYMBOL(vga_switcheroo_client_fb_set); |
264 | 407 | ||
408 | /** | ||
409 | * DOC: Manual switching and manual power control | ||
410 | * | ||
411 | * In this mode of use, the file /sys/kernel/debug/vgaswitcheroo/switch | ||
412 | * can be read to retrieve the current vga_switcheroo state and commands | ||
413 | * can be written to it to change the state. The file appears as soon as | ||
414 | * two GPU drivers and one handler have registered with vga_switcheroo. | ||
415 | * The following commands are understood: | ||
416 | * | ||
417 | * * OFF: Power off the device not in use. | ||
418 | * * ON: Power on the device not in use. | ||
419 | * * IGD: Switch to the integrated graphics device. | ||
420 | * Power on the integrated GPU if necessary, power off the discrete GPU. | ||
421 | * Prerequisite is that no user space processes (e.g. Xorg, alsactl) | ||
422 | * have opened device files of the GPUs or the audio client. If the | ||
423 | * switch fails, the user may invoke lsof(8) or fuser(1) on /dev/dri/ | ||
424 | * and /dev/snd/controlC1 to identify processes blocking the switch. | ||
425 | * * DIS: Switch to the discrete graphics device. | ||
426 | * * DIGD: Delayed switch to the integrated graphics device. | ||
427 | * This will perform the switch once the last user space process has | ||
428 | * closed the device files of the GPUs and the audio client. | ||
429 | * * DDIS: Delayed switch to the discrete graphics device. | ||
430 | * * MIGD: Mux-only switch to the integrated graphics device. | ||
431 | * Does not remap console or change the power state of either gpu. | ||
432 | * If the integrated GPU is currently off, the screen will turn black. | ||
433 | * If it is on, the screen will show whatever happens to be in VRAM. | ||
434 | * Either way, the user has to blindly enter the command to switch back. | ||
435 | * * MDIS: Mux-only switch to the discrete graphics device. | ||
436 | * | ||
437 | * For GPUs whose power state is controlled by the driver's runtime pm, | ||
438 | * the ON and OFF commands are a no-op (see next section). | ||
439 | * | ||
440 | * For muxless machines, the IGD/DIS, DIGD/DDIS and MIGD/MDIS commands | ||
441 | * should not be used. | ||
442 | */ | ||
443 | |||
265 | static int vga_switcheroo_show(struct seq_file *m, void *v) | 444 | static int vga_switcheroo_show(struct seq_file *m, void *v) |
266 | { | 445 | { |
267 | struct vga_switcheroo_client *client; | 446 | struct vga_switcheroo_client *client; |
@@ -559,6 +738,16 @@ fail: | |||
559 | return -1; | 738 | return -1; |
560 | } | 739 | } |
561 | 740 | ||
741 | /** | ||
742 | * vga_switcheroo_process_delayed_switch() - helper for delayed switching | ||
743 | * | ||
744 | * Process a delayed switch if one is pending. DRM drivers should call this | ||
745 | * from their ->lastclose callback. | ||
746 | * | ||
747 | * Return: 0 on success. -EINVAL if no delayed switch is pending, if the client | ||
748 | * has unregistered in the meantime or if there are other clients blocking the | ||
749 | * switch. If the actual switch fails, an error is reported and 0 is returned. | ||
750 | */ | ||
562 | int vga_switcheroo_process_delayed_switch(void) | 751 | int vga_switcheroo_process_delayed_switch(void) |
563 | { | 752 | { |
564 | struct vga_switcheroo_client *client; | 753 | struct vga_switcheroo_client *client; |
@@ -589,6 +778,39 @@ err: | |||
589 | } | 778 | } |
590 | EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch); | 779 | EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch); |
591 | 780 | ||
781 | /** | ||
782 | * DOC: Driver power control | ||
783 | * | ||
784 | * In this mode of use, the discrete GPU automatically powers up and down at | ||
785 | * the discretion of the driver's runtime pm. On muxed machines, the user may | ||
786 | * still influence the muxer state by way of the debugfs interface, however | ||
787 | * the ON and OFF commands become a no-op for the discrete GPU. | ||
788 | * | ||
789 | * This mode is the default on Nvidia HybridPower/Optimus and ATI PowerXpress. | ||
790 | * Specifying nouveau.runpm=0, radeon.runpm=0 or amdgpu.runpm=0 on the kernel | ||
791 | * command line disables it. | ||
792 | * | ||
793 | * When the driver decides to power up or down, it notifies vga_switcheroo | ||
794 | * thereof so that it can (a) power the audio device on the GPU up or down, | ||
795 | * and (b) update its internal power state representation for the device. | ||
796 | * This is achieved by vga_switcheroo_set_dynamic_switch(). | ||
797 | * | ||
798 | * After the GPU has been suspended, the handler needs to be called to cut | ||
799 | * power to the GPU. Likewise it needs to reinstate power before the GPU | ||
800 | * can resume. This is achieved by vga_switcheroo_init_domain_pm_ops(), | ||
801 | * which augments the GPU's suspend/resume functions by the requisite | ||
802 | * calls to the handler. | ||
803 | * | ||
804 | * When the audio device resumes, the GPU needs to be woken. This is achieved | ||
805 | * by vga_switcheroo_init_domain_pm_optimus_hdmi_audio(), which augments the | ||
806 | * audio device's resume function. | ||
807 | * | ||
808 | * On muxed machines, if the mux is initially switched to the discrete GPU, | ||
809 | * the user ends up with a black screen when the GPU powers down after boot. | ||
810 | * As a workaround, the mux is forced to the integrated GPU on runtime suspend, | ||
811 | * cf. https://bugs.freedesktop.org/show_bug.cgi?id=75917 | ||
812 | */ | ||
813 | |||
592 | static void vga_switcheroo_power_switch(struct pci_dev *pdev, | 814 | static void vga_switcheroo_power_switch(struct pci_dev *pdev, |
593 | enum vga_switcheroo_state state) | 815 | enum vga_switcheroo_state state) |
594 | { | 816 | { |
@@ -607,8 +829,17 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev, | |||
607 | vgasr_priv.handler->power_state(client->id, state); | 829 | vgasr_priv.handler->power_state(client->id, state); |
608 | } | 830 | } |
609 | 831 | ||
610 | /* force a PCI device to a certain state - mainly to turn off audio clients */ | 832 | /** |
611 | 833 | * vga_switcheroo_set_dynamic_switch() - helper for driver power control | |
834 | * @pdev: client pci device | ||
835 | * @dynamic: new power state | ||
836 | * | ||
837 | * Helper for GPUs whose power state is controlled by the driver's runtime pm. | ||
838 | * When the driver decides to power up or down, it notifies vga_switcheroo | ||
839 | * thereof using this helper so that it can (a) power the audio device on | ||
840 | * the GPU up or down, and (b) update its internal power state representation | ||
841 | * for the device. | ||
842 | */ | ||
612 | void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, | 843 | void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, |
613 | enum vga_switcheroo_state dynamic) | 844 | enum vga_switcheroo_state dynamic) |
614 | { | 845 | { |
@@ -654,8 +885,18 @@ static int vga_switcheroo_runtime_resume(struct device *dev) | |||
654 | return 0; | 885 | return 0; |
655 | } | 886 | } |
656 | 887 | ||
657 | /* this version is for the case where the power switch is separate | 888 | /** |
658 | to the device being powered down. */ | 889 | * vga_switcheroo_init_domain_pm_ops() - helper for driver power control |
890 | * @dev: vga client device | ||
891 | * @domain: power domain | ||
892 | * | ||
893 | * Helper for GPUs whose power state is controlled by the driver's runtime pm. | ||
894 | * After the GPU has been suspended, the handler needs to be called to cut | ||
895 | * power to the GPU. Likewise it needs to reinstate power before the GPU | ||
896 | * can resume. To this end, this helper augments the suspend/resume functions | ||
897 | * by the requisite calls to the handler. It needs only be called on platforms | ||
898 | * where the power switch is separate to the device being powered down. | ||
899 | */ | ||
659 | int vga_switcheroo_init_domain_pm_ops(struct device *dev, | 900 | int vga_switcheroo_init_domain_pm_ops(struct device *dev, |
660 | struct dev_pm_domain *domain) | 901 | struct dev_pm_domain *domain) |
661 | { | 902 | { |
@@ -709,6 +950,19 @@ static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev) | |||
709 | return ret; | 950 | return ret; |
710 | } | 951 | } |
711 | 952 | ||
953 | /** | ||
954 | * vga_switcheroo_init_domain_pm_optimus_hdmi_audio() - helper for driver | ||
955 | * power control | ||
956 | * @dev: audio client device | ||
957 | * @domain: power domain | ||
958 | * | ||
959 | * Helper for GPUs whose power state is controlled by the driver's runtime pm. | ||
960 | * When the audio device resumes, the GPU needs to be woken. This helper | ||
961 | * augments the audio device's resume function to do that. | ||
962 | * | ||
963 | * Return: 0 on success, -EINVAL if no power management operations are | ||
964 | * defined for this device. | ||
965 | */ | ||
712 | int | 966 | int |
713 | vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, | 967 | vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, |
714 | struct dev_pm_domain *domain) | 968 | struct dev_pm_domain *domain) |