| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. |
|---|
| 3 | 4 | * Copyright (C) 2013 Red Hat |
|---|
| 4 | 5 | * Author: Rob Clark <robdclark@gmail.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 7 | | - * under the terms of the GNU General Public License version 2 as published by |
|---|
| 8 | | - * the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 13 | | - * more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License along with |
|---|
| 16 | | - * this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | 6 | */ |
|---|
| 18 | 7 | |
|---|
| 19 | 8 | #ifndef __MSM_KMS_H__ |
|---|
| .. | .. |
|---|
| 41 | 30 | irqreturn_t (*irq)(struct msm_kms *kms); |
|---|
| 42 | 31 | int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); |
|---|
| 43 | 32 | void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); |
|---|
| 44 | | - /* modeset, bracketing atomic_commit(): */ |
|---|
| 33 | + |
|---|
| 34 | + /* |
|---|
| 35 | + * Atomic commit handling: |
|---|
| 36 | + * |
|---|
| 37 | + * Note that in the case of async commits, the funcs which take |
|---|
| 38 | + * a crtc_mask (ie. ->flush_commit(), and ->complete_commit()) |
|---|
| 39 | + * might not be evenly balanced with ->prepare_commit(), however |
|---|
| 40 | + * each crtc that effected by a ->prepare_commit() (potentially |
|---|
| 41 | + * multiple times) will eventually (at end of vsync period) be |
|---|
| 42 | + * flushed and completed. |
|---|
| 43 | + * |
|---|
| 44 | + * This has some implications about tracking of cleanup state, |
|---|
| 45 | + * for example SMP blocks to release after commit completes. Ie. |
|---|
| 46 | + * cleanup state should be also duplicated in the various |
|---|
| 47 | + * duplicate_state() methods, as the current cleanup state at |
|---|
| 48 | + * ->complete_commit() time may have accumulated cleanup work |
|---|
| 49 | + * from multiple commits. |
|---|
| 50 | + */ |
|---|
| 51 | + |
|---|
| 52 | + /** |
|---|
| 53 | + * Enable/disable power/clks needed for hw access done in other |
|---|
| 54 | + * commit related methods. |
|---|
| 55 | + * |
|---|
| 56 | + * If mdp4 is migrated to runpm, we could probably drop these |
|---|
| 57 | + * and use runpm directly. |
|---|
| 58 | + */ |
|---|
| 59 | + void (*enable_commit)(struct msm_kms *kms); |
|---|
| 60 | + void (*disable_commit)(struct msm_kms *kms); |
|---|
| 61 | + |
|---|
| 62 | + /** |
|---|
| 63 | + * If the kms backend supports async commit, it should implement |
|---|
| 64 | + * this method to return the time of the next vsync. This is |
|---|
| 65 | + * used to determine a time slightly before vsync, for the async |
|---|
| 66 | + * commit timer to run and complete an async commit. |
|---|
| 67 | + */ |
|---|
| 68 | + ktime_t (*vsync_time)(struct msm_kms *kms, struct drm_crtc *crtc); |
|---|
| 69 | + |
|---|
| 70 | + /** |
|---|
| 71 | + * Prepare for atomic commit. This is called after any previous |
|---|
| 72 | + * (async or otherwise) commit has completed. |
|---|
| 73 | + */ |
|---|
| 45 | 74 | void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state); |
|---|
| 46 | | - void (*commit)(struct msm_kms *kms, struct drm_atomic_state *state); |
|---|
| 47 | | - void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state); |
|---|
| 48 | | - /* functions to wait for atomic commit completed on each CRTC */ |
|---|
| 49 | | - void (*wait_for_crtc_commit_done)(struct msm_kms *kms, |
|---|
| 50 | | - struct drm_crtc *crtc); |
|---|
| 75 | + |
|---|
| 76 | + /** |
|---|
| 77 | + * Flush an atomic commit. This is called after the hardware |
|---|
| 78 | + * updates have already been pushed down to effected planes/ |
|---|
| 79 | + * crtcs/encoders/connectors. |
|---|
| 80 | + */ |
|---|
| 81 | + void (*flush_commit)(struct msm_kms *kms, unsigned crtc_mask); |
|---|
| 82 | + |
|---|
| 83 | + /** |
|---|
| 84 | + * Wait for any in-progress flush to complete on the specified |
|---|
| 85 | + * crtcs. This should not block if there is no in-progress |
|---|
| 86 | + * commit (ie. don't just wait for a vblank), as it will also |
|---|
| 87 | + * be called before ->prepare_commit() to ensure any potential |
|---|
| 88 | + * "async" commit has completed. |
|---|
| 89 | + */ |
|---|
| 90 | + void (*wait_flush)(struct msm_kms *kms, unsigned crtc_mask); |
|---|
| 91 | + |
|---|
| 92 | + /** |
|---|
| 93 | + * Clean up after commit is completed. This is called after |
|---|
| 94 | + * ->wait_flush(), to give the backend a chance to do any |
|---|
| 95 | + * post-commit cleanup. |
|---|
| 96 | + */ |
|---|
| 97 | + void (*complete_commit)(struct msm_kms *kms, unsigned crtc_mask); |
|---|
| 98 | + |
|---|
| 99 | + /* |
|---|
| 100 | + * Format handling: |
|---|
| 101 | + */ |
|---|
| 102 | + |
|---|
| 51 | 103 | /* get msm_format w/ optional format modifiers from drm_mode_fb_cmd2 */ |
|---|
| 52 | 104 | const struct msm_format *(*get_format)(struct msm_kms *kms, |
|---|
| 53 | 105 | const uint32_t format, |
|---|
| .. | .. |
|---|
| 57 | 109 | const struct msm_format *msm_fmt, |
|---|
| 58 | 110 | const struct drm_mode_fb_cmd2 *cmd, |
|---|
| 59 | 111 | struct drm_gem_object **bos); |
|---|
| 112 | + |
|---|
| 60 | 113 | /* misc: */ |
|---|
| 61 | 114 | long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, |
|---|
| 62 | 115 | struct drm_encoder *encoder); |
|---|
| .. | .. |
|---|
| 67 | 120 | void (*set_encoder_mode)(struct msm_kms *kms, |
|---|
| 68 | 121 | struct drm_encoder *encoder, |
|---|
| 69 | 122 | bool cmd_mode); |
|---|
| 70 | | - /* pm suspend/resume hooks */ |
|---|
| 71 | | - int (*pm_suspend)(struct device *dev); |
|---|
| 72 | | - int (*pm_resume)(struct device *dev); |
|---|
| 73 | 123 | /* cleanup: */ |
|---|
| 74 | 124 | void (*destroy)(struct msm_kms *kms); |
|---|
| 75 | 125 | #ifdef CONFIG_DEBUG_FS |
|---|
| .. | .. |
|---|
| 78 | 128 | #endif |
|---|
| 79 | 129 | }; |
|---|
| 80 | 130 | |
|---|
| 131 | +struct msm_kms; |
|---|
| 132 | + |
|---|
| 133 | +/* |
|---|
| 134 | + * A per-crtc timer for pending async atomic flushes. Scheduled to expire |
|---|
| 135 | + * shortly before vblank to flush pending async updates. |
|---|
| 136 | + */ |
|---|
| 137 | +struct msm_pending_timer { |
|---|
| 138 | + struct hrtimer timer; |
|---|
| 139 | + struct work_struct work; |
|---|
| 140 | + struct msm_kms *kms; |
|---|
| 141 | + unsigned crtc_idx; |
|---|
| 142 | +}; |
|---|
| 143 | + |
|---|
| 81 | 144 | struct msm_kms { |
|---|
| 82 | 145 | const struct msm_kms_funcs *funcs; |
|---|
| 146 | + struct drm_device *dev; |
|---|
| 83 | 147 | |
|---|
| 84 | 148 | /* irq number to be passed on to drm_irq_install */ |
|---|
| 85 | 149 | int irq; |
|---|
| 86 | 150 | |
|---|
| 87 | 151 | /* mapper-id used to request GEM buffer mapped for scanout: */ |
|---|
| 88 | 152 | struct msm_gem_address_space *aspace; |
|---|
| 153 | + |
|---|
| 154 | + /* |
|---|
| 155 | + * For async commit, where ->flush_commit() and later happens |
|---|
| 156 | + * from the crtc's pending_timer close to end of the frame: |
|---|
| 157 | + */ |
|---|
| 158 | + struct mutex commit_lock; |
|---|
| 159 | + unsigned pending_crtc_mask; |
|---|
| 160 | + struct msm_pending_timer pending_timers[MAX_CRTCS]; |
|---|
| 89 | 161 | }; |
|---|
| 90 | 162 | |
|---|
| 91 | 163 | static inline void msm_kms_init(struct msm_kms *kms, |
|---|
| 92 | 164 | const struct msm_kms_funcs *funcs) |
|---|
| 93 | 165 | { |
|---|
| 166 | + unsigned i; |
|---|
| 167 | + |
|---|
| 168 | + mutex_init(&kms->commit_lock); |
|---|
| 94 | 169 | kms->funcs = funcs; |
|---|
| 170 | + |
|---|
| 171 | + for (i = 0; i < ARRAY_SIZE(kms->pending_timers); i++) |
|---|
| 172 | + msm_atomic_init_pending_timer(&kms->pending_timers[i], kms, i); |
|---|
| 95 | 173 | } |
|---|
| 96 | 174 | |
|---|
| 97 | 175 | struct msm_kms *mdp4_kms_init(struct drm_device *dev); |
|---|
| .. | .. |
|---|
| 112 | 190 | int mdp5_mdss_init(struct drm_device *dev); |
|---|
| 113 | 191 | int dpu_mdss_init(struct drm_device *dev); |
|---|
| 114 | 192 | |
|---|
| 193 | +#define for_each_crtc_mask(dev, crtc, crtc_mask) \ |
|---|
| 194 | + drm_for_each_crtc(crtc, dev) \ |
|---|
| 195 | + for_each_if (drm_crtc_mask(crtc) & (crtc_mask)) |
|---|
| 196 | + |
|---|
| 115 | 197 | #endif /* __MSM_KMS_H__ */ |
|---|