| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2014-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 | #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ |
|---|
| 20 | 9 | #include <linux/sort.h> |
|---|
| 21 | 10 | #include <linux/debugfs.h> |
|---|
| 22 | 11 | #include <linux/ktime.h> |
|---|
| 23 | | -#include <drm/drm_mode.h> |
|---|
| 12 | +#include <linux/bits.h> |
|---|
| 13 | + |
|---|
| 24 | 14 | #include <drm/drm_crtc.h> |
|---|
| 25 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 26 | 15 | #include <drm/drm_flip_work.h> |
|---|
| 16 | +#include <drm/drm_mode.h> |
|---|
| 17 | +#include <drm/drm_probe_helper.h> |
|---|
| 27 | 18 | #include <drm/drm_rect.h> |
|---|
| 19 | +#include <drm/drm_vblank.h> |
|---|
| 28 | 20 | |
|---|
| 29 | 21 | #include "dpu_kms.h" |
|---|
| 30 | 22 | #include "dpu_hw_lm.h" |
|---|
| 31 | 23 | #include "dpu_hw_ctl.h" |
|---|
| 24 | +#include "dpu_hw_dspp.h" |
|---|
| 32 | 25 | #include "dpu_crtc.h" |
|---|
| 33 | 26 | #include "dpu_plane.h" |
|---|
| 34 | 27 | #include "dpu_encoder.h" |
|---|
| 35 | 28 | #include "dpu_vbif.h" |
|---|
| 36 | | -#include "dpu_power_handle.h" |
|---|
| 37 | 29 | #include "dpu_core_perf.h" |
|---|
| 38 | 30 | #include "dpu_trace.h" |
|---|
| 39 | 31 | |
|---|
| .. | .. |
|---|
| 47 | 39 | #define LEFT_MIXER 0 |
|---|
| 48 | 40 | #define RIGHT_MIXER 1 |
|---|
| 49 | 41 | |
|---|
| 50 | | -#define MISR_BUFF_SIZE 256 |
|---|
| 42 | +/* timeout in ms waiting for frame done */ |
|---|
| 43 | +#define DPU_CRTC_FRAME_DONE_TIMEOUT_MS 60 |
|---|
| 51 | 44 | |
|---|
| 52 | | -static inline struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) |
|---|
| 45 | +#define CONVERT_S3_15(val) \ |
|---|
| 46 | + (((((u64)val) & ~BIT_ULL(63)) >> 17) & GENMASK_ULL(17, 0)) |
|---|
| 47 | + |
|---|
| 48 | +static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) |
|---|
| 53 | 49 | { |
|---|
| 54 | | - struct msm_drm_private *priv; |
|---|
| 55 | | - |
|---|
| 56 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
|---|
| 57 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 58 | | - return NULL; |
|---|
| 59 | | - } |
|---|
| 60 | | - priv = crtc->dev->dev_private; |
|---|
| 61 | | - if (!priv || !priv->kms) { |
|---|
| 62 | | - DPU_ERROR("invalid kms\n"); |
|---|
| 63 | | - return NULL; |
|---|
| 64 | | - } |
|---|
| 50 | + struct msm_drm_private *priv = crtc->dev->dev_private; |
|---|
| 65 | 51 | |
|---|
| 66 | 52 | return to_dpu_kms(priv->kms); |
|---|
| 67 | | -} |
|---|
| 68 | | - |
|---|
| 69 | | -static inline int _dpu_crtc_power_enable(struct dpu_crtc *dpu_crtc, bool enable) |
|---|
| 70 | | -{ |
|---|
| 71 | | - struct drm_crtc *crtc; |
|---|
| 72 | | - struct msm_drm_private *priv; |
|---|
| 73 | | - struct dpu_kms *dpu_kms; |
|---|
| 74 | | - |
|---|
| 75 | | - if (!dpu_crtc) { |
|---|
| 76 | | - DPU_ERROR("invalid dpu crtc\n"); |
|---|
| 77 | | - return -EINVAL; |
|---|
| 78 | | - } |
|---|
| 79 | | - |
|---|
| 80 | | - crtc = &dpu_crtc->base; |
|---|
| 81 | | - if (!crtc->dev || !crtc->dev->dev_private) { |
|---|
| 82 | | - DPU_ERROR("invalid drm device\n"); |
|---|
| 83 | | - return -EINVAL; |
|---|
| 84 | | - } |
|---|
| 85 | | - |
|---|
| 86 | | - priv = crtc->dev->dev_private; |
|---|
| 87 | | - if (!priv->kms) { |
|---|
| 88 | | - DPU_ERROR("invalid kms\n"); |
|---|
| 89 | | - return -EINVAL; |
|---|
| 90 | | - } |
|---|
| 91 | | - |
|---|
| 92 | | - dpu_kms = to_dpu_kms(priv->kms); |
|---|
| 93 | | - |
|---|
| 94 | | - if (enable) |
|---|
| 95 | | - pm_runtime_get_sync(&dpu_kms->pdev->dev); |
|---|
| 96 | | - else |
|---|
| 97 | | - pm_runtime_put_sync(&dpu_kms->pdev->dev); |
|---|
| 98 | | - |
|---|
| 99 | | - return 0; |
|---|
| 100 | | -} |
|---|
| 101 | | - |
|---|
| 102 | | -/** |
|---|
| 103 | | - * _dpu_crtc_rp_to_crtc - get crtc from resource pool object |
|---|
| 104 | | - * @rp: Pointer to resource pool |
|---|
| 105 | | - * return: Pointer to drm crtc if success; null otherwise |
|---|
| 106 | | - */ |
|---|
| 107 | | -static struct drm_crtc *_dpu_crtc_rp_to_crtc(struct dpu_crtc_respool *rp) |
|---|
| 108 | | -{ |
|---|
| 109 | | - if (!rp) |
|---|
| 110 | | - return NULL; |
|---|
| 111 | | - |
|---|
| 112 | | - return container_of(rp, struct dpu_crtc_state, rp)->base.crtc; |
|---|
| 113 | | -} |
|---|
| 114 | | - |
|---|
| 115 | | -/** |
|---|
| 116 | | - * _dpu_crtc_rp_reclaim - reclaim unused, or all if forced, resources in pool |
|---|
| 117 | | - * @rp: Pointer to resource pool |
|---|
| 118 | | - * @force: True to reclaim all resources; otherwise, reclaim only unused ones |
|---|
| 119 | | - * return: None |
|---|
| 120 | | - */ |
|---|
| 121 | | -static void _dpu_crtc_rp_reclaim(struct dpu_crtc_respool *rp, bool force) |
|---|
| 122 | | -{ |
|---|
| 123 | | - struct dpu_crtc_res *res, *next; |
|---|
| 124 | | - struct drm_crtc *crtc; |
|---|
| 125 | | - |
|---|
| 126 | | - crtc = _dpu_crtc_rp_to_crtc(rp); |
|---|
| 127 | | - if (!crtc) { |
|---|
| 128 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 129 | | - return; |
|---|
| 130 | | - } |
|---|
| 131 | | - |
|---|
| 132 | | - DPU_DEBUG("crtc%d.%u %s\n", crtc->base.id, rp->sequence_id, |
|---|
| 133 | | - force ? "destroy" : "free_unused"); |
|---|
| 134 | | - |
|---|
| 135 | | - list_for_each_entry_safe(res, next, &rp->res_list, list) { |
|---|
| 136 | | - if (!force && !(res->flags & DPU_CRTC_RES_FLAG_FREE)) |
|---|
| 137 | | - continue; |
|---|
| 138 | | - DPU_DEBUG("crtc%d.%u reclaim res:0x%x/0x%llx/%pK/%d\n", |
|---|
| 139 | | - crtc->base.id, rp->sequence_id, |
|---|
| 140 | | - res->type, res->tag, res->val, |
|---|
| 141 | | - atomic_read(&res->refcount)); |
|---|
| 142 | | - list_del(&res->list); |
|---|
| 143 | | - if (res->ops.put) |
|---|
| 144 | | - res->ops.put(res->val); |
|---|
| 145 | | - kfree(res); |
|---|
| 146 | | - } |
|---|
| 147 | | -} |
|---|
| 148 | | - |
|---|
| 149 | | -/** |
|---|
| 150 | | - * _dpu_crtc_rp_free_unused - free unused resource in pool |
|---|
| 151 | | - * @rp: Pointer to resource pool |
|---|
| 152 | | - * return: none |
|---|
| 153 | | - */ |
|---|
| 154 | | -static void _dpu_crtc_rp_free_unused(struct dpu_crtc_respool *rp) |
|---|
| 155 | | -{ |
|---|
| 156 | | - mutex_lock(rp->rp_lock); |
|---|
| 157 | | - _dpu_crtc_rp_reclaim(rp, false); |
|---|
| 158 | | - mutex_unlock(rp->rp_lock); |
|---|
| 159 | | -} |
|---|
| 160 | | - |
|---|
| 161 | | -/** |
|---|
| 162 | | - * _dpu_crtc_rp_destroy - destroy resource pool |
|---|
| 163 | | - * @rp: Pointer to resource pool |
|---|
| 164 | | - * return: None |
|---|
| 165 | | - */ |
|---|
| 166 | | -static void _dpu_crtc_rp_destroy(struct dpu_crtc_respool *rp) |
|---|
| 167 | | -{ |
|---|
| 168 | | - mutex_lock(rp->rp_lock); |
|---|
| 169 | | - list_del_init(&rp->rp_list); |
|---|
| 170 | | - _dpu_crtc_rp_reclaim(rp, true); |
|---|
| 171 | | - mutex_unlock(rp->rp_lock); |
|---|
| 172 | | -} |
|---|
| 173 | | - |
|---|
| 174 | | -/** |
|---|
| 175 | | - * _dpu_crtc_hw_blk_get - get callback for hardware block |
|---|
| 176 | | - * @val: Resource handle |
|---|
| 177 | | - * @type: Resource type |
|---|
| 178 | | - * @tag: Search tag for given resource |
|---|
| 179 | | - * return: Resource handle |
|---|
| 180 | | - */ |
|---|
| 181 | | -static void *_dpu_crtc_hw_blk_get(void *val, u32 type, u64 tag) |
|---|
| 182 | | -{ |
|---|
| 183 | | - DPU_DEBUG("res:%d/0x%llx/%pK\n", type, tag, val); |
|---|
| 184 | | - return dpu_hw_blk_get(val, type, tag); |
|---|
| 185 | | -} |
|---|
| 186 | | - |
|---|
| 187 | | -/** |
|---|
| 188 | | - * _dpu_crtc_hw_blk_put - put callback for hardware block |
|---|
| 189 | | - * @val: Resource handle |
|---|
| 190 | | - * return: None |
|---|
| 191 | | - */ |
|---|
| 192 | | -static void _dpu_crtc_hw_blk_put(void *val) |
|---|
| 193 | | -{ |
|---|
| 194 | | - DPU_DEBUG("res://%pK\n", val); |
|---|
| 195 | | - dpu_hw_blk_put(val); |
|---|
| 196 | | -} |
|---|
| 197 | | - |
|---|
| 198 | | -/** |
|---|
| 199 | | - * _dpu_crtc_rp_duplicate - duplicate resource pool and reset reference count |
|---|
| 200 | | - * @rp: Pointer to original resource pool |
|---|
| 201 | | - * @dup_rp: Pointer to duplicated resource pool |
|---|
| 202 | | - * return: None |
|---|
| 203 | | - */ |
|---|
| 204 | | -static void _dpu_crtc_rp_duplicate(struct dpu_crtc_respool *rp, |
|---|
| 205 | | - struct dpu_crtc_respool *dup_rp) |
|---|
| 206 | | -{ |
|---|
| 207 | | - struct dpu_crtc_res *res, *dup_res; |
|---|
| 208 | | - struct drm_crtc *crtc; |
|---|
| 209 | | - |
|---|
| 210 | | - if (!rp || !dup_rp || !rp->rp_head) { |
|---|
| 211 | | - DPU_ERROR("invalid resource pool\n"); |
|---|
| 212 | | - return; |
|---|
| 213 | | - } |
|---|
| 214 | | - |
|---|
| 215 | | - crtc = _dpu_crtc_rp_to_crtc(rp); |
|---|
| 216 | | - if (!crtc) { |
|---|
| 217 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 218 | | - return; |
|---|
| 219 | | - } |
|---|
| 220 | | - |
|---|
| 221 | | - DPU_DEBUG("crtc%d.%u duplicate\n", crtc->base.id, rp->sequence_id); |
|---|
| 222 | | - |
|---|
| 223 | | - mutex_lock(rp->rp_lock); |
|---|
| 224 | | - dup_rp->sequence_id = rp->sequence_id + 1; |
|---|
| 225 | | - INIT_LIST_HEAD(&dup_rp->res_list); |
|---|
| 226 | | - dup_rp->ops = rp->ops; |
|---|
| 227 | | - list_for_each_entry(res, &rp->res_list, list) { |
|---|
| 228 | | - dup_res = kzalloc(sizeof(struct dpu_crtc_res), GFP_KERNEL); |
|---|
| 229 | | - if (!dup_res) { |
|---|
| 230 | | - mutex_unlock(rp->rp_lock); |
|---|
| 231 | | - return; |
|---|
| 232 | | - } |
|---|
| 233 | | - INIT_LIST_HEAD(&dup_res->list); |
|---|
| 234 | | - atomic_set(&dup_res->refcount, 0); |
|---|
| 235 | | - dup_res->type = res->type; |
|---|
| 236 | | - dup_res->tag = res->tag; |
|---|
| 237 | | - dup_res->val = res->val; |
|---|
| 238 | | - dup_res->ops = res->ops; |
|---|
| 239 | | - dup_res->flags = DPU_CRTC_RES_FLAG_FREE; |
|---|
| 240 | | - DPU_DEBUG("crtc%d.%u dup res:0x%x/0x%llx/%pK/%d\n", |
|---|
| 241 | | - crtc->base.id, dup_rp->sequence_id, |
|---|
| 242 | | - dup_res->type, dup_res->tag, dup_res->val, |
|---|
| 243 | | - atomic_read(&dup_res->refcount)); |
|---|
| 244 | | - list_add_tail(&dup_res->list, &dup_rp->res_list); |
|---|
| 245 | | - if (dup_res->ops.get) |
|---|
| 246 | | - dup_res->ops.get(dup_res->val, 0, -1); |
|---|
| 247 | | - } |
|---|
| 248 | | - |
|---|
| 249 | | - dup_rp->rp_lock = rp->rp_lock; |
|---|
| 250 | | - dup_rp->rp_head = rp->rp_head; |
|---|
| 251 | | - INIT_LIST_HEAD(&dup_rp->rp_list); |
|---|
| 252 | | - list_add_tail(&dup_rp->rp_list, rp->rp_head); |
|---|
| 253 | | - mutex_unlock(rp->rp_lock); |
|---|
| 254 | | -} |
|---|
| 255 | | - |
|---|
| 256 | | -/** |
|---|
| 257 | | - * _dpu_crtc_rp_reset - reset resource pool after allocation |
|---|
| 258 | | - * @rp: Pointer to original resource pool |
|---|
| 259 | | - * @rp_lock: Pointer to serialization resource pool lock |
|---|
| 260 | | - * @rp_head: Pointer to crtc resource pool head |
|---|
| 261 | | - * return: None |
|---|
| 262 | | - */ |
|---|
| 263 | | -static void _dpu_crtc_rp_reset(struct dpu_crtc_respool *rp, |
|---|
| 264 | | - struct mutex *rp_lock, struct list_head *rp_head) |
|---|
| 265 | | -{ |
|---|
| 266 | | - if (!rp || !rp_lock || !rp_head) { |
|---|
| 267 | | - DPU_ERROR("invalid resource pool\n"); |
|---|
| 268 | | - return; |
|---|
| 269 | | - } |
|---|
| 270 | | - |
|---|
| 271 | | - mutex_lock(rp_lock); |
|---|
| 272 | | - rp->rp_lock = rp_lock; |
|---|
| 273 | | - rp->rp_head = rp_head; |
|---|
| 274 | | - INIT_LIST_HEAD(&rp->rp_list); |
|---|
| 275 | | - rp->sequence_id = 0; |
|---|
| 276 | | - INIT_LIST_HEAD(&rp->res_list); |
|---|
| 277 | | - rp->ops.get = _dpu_crtc_hw_blk_get; |
|---|
| 278 | | - rp->ops.put = _dpu_crtc_hw_blk_put; |
|---|
| 279 | | - list_add_tail(&rp->rp_list, rp->rp_head); |
|---|
| 280 | | - mutex_unlock(rp_lock); |
|---|
| 281 | 53 | } |
|---|
| 282 | 54 | |
|---|
| 283 | 55 | static void dpu_crtc_destroy(struct drm_crtc *crtc) |
|---|
| .. | .. |
|---|
| 289 | 61 | if (!crtc) |
|---|
| 290 | 62 | return; |
|---|
| 291 | 63 | |
|---|
| 292 | | - dpu_crtc->phandle = NULL; |
|---|
| 293 | | - |
|---|
| 294 | 64 | drm_crtc_cleanup(crtc); |
|---|
| 295 | | - mutex_destroy(&dpu_crtc->crtc_lock); |
|---|
| 296 | 65 | kfree(dpu_crtc); |
|---|
| 297 | 66 | } |
|---|
| 298 | 67 | |
|---|
| 299 | 68 | static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer, |
|---|
| 300 | | - struct dpu_plane_state *pstate) |
|---|
| 69 | + struct dpu_plane_state *pstate, struct dpu_format *format) |
|---|
| 301 | 70 | { |
|---|
| 302 | 71 | struct dpu_hw_mixer *lm = mixer->hw_lm; |
|---|
| 72 | + uint32_t blend_op; |
|---|
| 73 | + struct drm_format_name_buf format_name; |
|---|
| 303 | 74 | |
|---|
| 304 | 75 | /* default to opaque blending */ |
|---|
| 305 | | - lm->ops.setup_blend_config(lm, pstate->stage, 0XFF, 0, |
|---|
| 306 | | - DPU_BLEND_FG_ALPHA_FG_CONST | |
|---|
| 307 | | - DPU_BLEND_BG_ALPHA_BG_CONST); |
|---|
| 76 | + blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | |
|---|
| 77 | + DPU_BLEND_BG_ALPHA_BG_CONST; |
|---|
| 78 | + |
|---|
| 79 | + if (format->alpha_enable) { |
|---|
| 80 | + /* coverage blending */ |
|---|
| 81 | + blend_op = DPU_BLEND_FG_ALPHA_FG_PIXEL | |
|---|
| 82 | + DPU_BLEND_BG_ALPHA_FG_PIXEL | |
|---|
| 83 | + DPU_BLEND_BG_INV_ALPHA; |
|---|
| 84 | + } |
|---|
| 85 | + |
|---|
| 86 | + lm->ops.setup_blend_config(lm, pstate->stage, |
|---|
| 87 | + 0xFF, 0, blend_op); |
|---|
| 88 | + |
|---|
| 89 | + DPU_DEBUG("format:%s, alpha_en:%u blend_op:0x%x\n", |
|---|
| 90 | + drm_get_format_name(format->base.pixel_format, &format_name), |
|---|
| 91 | + format->alpha_enable, blend_op); |
|---|
| 308 | 92 | } |
|---|
| 309 | 93 | |
|---|
| 310 | 94 | static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) |
|---|
| 311 | 95 | { |
|---|
| 312 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 313 | 96 | struct dpu_crtc_state *crtc_state; |
|---|
| 314 | 97 | int lm_idx, lm_horiz_position; |
|---|
| 315 | 98 | |
|---|
| 316 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 317 | 99 | crtc_state = to_dpu_crtc_state(crtc->state); |
|---|
| 318 | 100 | |
|---|
| 319 | 101 | lm_horiz_position = 0; |
|---|
| 320 | | - for (lm_idx = 0; lm_idx < dpu_crtc->num_mixers; lm_idx++) { |
|---|
| 102 | + for (lm_idx = 0; lm_idx < crtc_state->num_mixers; lm_idx++) { |
|---|
| 321 | 103 | const struct drm_rect *lm_roi = &crtc_state->lm_bounds[lm_idx]; |
|---|
| 322 | | - struct dpu_hw_mixer *hw_lm = dpu_crtc->mixers[lm_idx].hw_lm; |
|---|
| 104 | + struct dpu_hw_mixer *hw_lm = crtc_state->mixers[lm_idx].hw_lm; |
|---|
| 323 | 105 | struct dpu_hw_mixer_cfg cfg; |
|---|
| 324 | 106 | |
|---|
| 325 | 107 | if (!lm_roi || !drm_rect_visible(lm_roi)) |
|---|
| .. | .. |
|---|
| 339 | 121 | struct drm_plane *plane; |
|---|
| 340 | 122 | struct drm_framebuffer *fb; |
|---|
| 341 | 123 | struct drm_plane_state *state; |
|---|
| 342 | | - struct dpu_crtc_state *cstate; |
|---|
| 124 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 343 | 125 | struct dpu_plane_state *pstate = NULL; |
|---|
| 344 | 126 | struct dpu_format *format; |
|---|
| 345 | | - struct dpu_hw_ctl *ctl; |
|---|
| 346 | | - struct dpu_hw_mixer *lm; |
|---|
| 347 | | - struct dpu_hw_stage_cfg *stage_cfg; |
|---|
| 127 | + struct dpu_hw_ctl *ctl = mixer->lm_ctl; |
|---|
| 128 | + struct dpu_hw_stage_cfg *stage_cfg = &dpu_crtc->stage_cfg; |
|---|
| 348 | 129 | |
|---|
| 349 | 130 | u32 flush_mask; |
|---|
| 350 | 131 | uint32_t stage_idx, lm_idx; |
|---|
| 351 | 132 | int zpos_cnt[DPU_STAGE_MAX + 1] = { 0 }; |
|---|
| 352 | 133 | bool bg_alpha_enable = false; |
|---|
| 353 | | - |
|---|
| 354 | | - if (!dpu_crtc || !mixer) { |
|---|
| 355 | | - DPU_ERROR("invalid dpu_crtc or mixer\n"); |
|---|
| 356 | | - return; |
|---|
| 357 | | - } |
|---|
| 358 | | - |
|---|
| 359 | | - ctl = mixer->hw_ctl; |
|---|
| 360 | | - lm = mixer->hw_lm; |
|---|
| 361 | | - stage_cfg = &dpu_crtc->stage_cfg; |
|---|
| 362 | | - cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 363 | 134 | |
|---|
| 364 | 135 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
|---|
| 365 | 136 | state = plane->state; |
|---|
| .. | .. |
|---|
| 379 | 150 | state->fb ? state->fb->base.id : -1); |
|---|
| 380 | 151 | |
|---|
| 381 | 152 | format = to_dpu_format(msm_framebuffer_format(pstate->base.fb)); |
|---|
| 382 | | - if (!format) { |
|---|
| 383 | | - DPU_ERROR("invalid format\n"); |
|---|
| 384 | | - return; |
|---|
| 385 | | - } |
|---|
| 386 | 153 | |
|---|
| 387 | 154 | if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable) |
|---|
| 388 | 155 | bg_alpha_enable = true; |
|---|
| .. | .. |
|---|
| 400 | 167 | fb ? fb->modifier : 0); |
|---|
| 401 | 168 | |
|---|
| 402 | 169 | /* blend config update */ |
|---|
| 403 | | - for (lm_idx = 0; lm_idx < dpu_crtc->num_mixers; lm_idx++) { |
|---|
| 404 | | - _dpu_crtc_setup_blend_cfg(mixer + lm_idx, pstate); |
|---|
| 170 | + for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) { |
|---|
| 171 | + _dpu_crtc_setup_blend_cfg(mixer + lm_idx, |
|---|
| 172 | + pstate, format); |
|---|
| 405 | 173 | |
|---|
| 406 | 174 | mixer[lm_idx].flush_mask |= flush_mask; |
|---|
| 407 | 175 | |
|---|
| .. | .. |
|---|
| 422 | 190 | */ |
|---|
| 423 | 191 | static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) |
|---|
| 424 | 192 | { |
|---|
| 425 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 426 | | - struct dpu_crtc_state *dpu_crtc_state; |
|---|
| 427 | | - struct dpu_crtc_mixer *mixer; |
|---|
| 193 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 194 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 195 | + struct dpu_crtc_mixer *mixer = cstate->mixers; |
|---|
| 428 | 196 | struct dpu_hw_ctl *ctl; |
|---|
| 429 | 197 | struct dpu_hw_mixer *lm; |
|---|
| 430 | | - |
|---|
| 431 | 198 | int i; |
|---|
| 432 | | - |
|---|
| 433 | | - if (!crtc) |
|---|
| 434 | | - return; |
|---|
| 435 | | - |
|---|
| 436 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 437 | | - dpu_crtc_state = to_dpu_crtc_state(crtc->state); |
|---|
| 438 | | - mixer = dpu_crtc->mixers; |
|---|
| 439 | 199 | |
|---|
| 440 | 200 | DPU_DEBUG("%s\n", dpu_crtc->name); |
|---|
| 441 | 201 | |
|---|
| 442 | | - if (dpu_crtc->num_mixers > CRTC_DUAL_MIXERS) { |
|---|
| 443 | | - DPU_ERROR("invalid number mixers: %d\n", dpu_crtc->num_mixers); |
|---|
| 444 | | - return; |
|---|
| 445 | | - } |
|---|
| 446 | | - |
|---|
| 447 | | - for (i = 0; i < dpu_crtc->num_mixers; i++) { |
|---|
| 448 | | - if (!mixer[i].hw_lm || !mixer[i].hw_ctl) { |
|---|
| 449 | | - DPU_ERROR("invalid lm or ctl assigned to mixer\n"); |
|---|
| 450 | | - return; |
|---|
| 451 | | - } |
|---|
| 202 | + for (i = 0; i < cstate->num_mixers; i++) { |
|---|
| 452 | 203 | mixer[i].mixer_op_mode = 0; |
|---|
| 453 | 204 | mixer[i].flush_mask = 0; |
|---|
| 454 | | - if (mixer[i].hw_ctl->ops.clear_all_blendstages) |
|---|
| 455 | | - mixer[i].hw_ctl->ops.clear_all_blendstages( |
|---|
| 456 | | - mixer[i].hw_ctl); |
|---|
| 205 | + if (mixer[i].lm_ctl->ops.clear_all_blendstages) |
|---|
| 206 | + mixer[i].lm_ctl->ops.clear_all_blendstages( |
|---|
| 207 | + mixer[i].lm_ctl); |
|---|
| 457 | 208 | } |
|---|
| 458 | 209 | |
|---|
| 459 | 210 | /* initialize stage cfg */ |
|---|
| .. | .. |
|---|
| 461 | 212 | |
|---|
| 462 | 213 | _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer); |
|---|
| 463 | 214 | |
|---|
| 464 | | - for (i = 0; i < dpu_crtc->num_mixers; i++) { |
|---|
| 465 | | - ctl = mixer[i].hw_ctl; |
|---|
| 215 | + for (i = 0; i < cstate->num_mixers; i++) { |
|---|
| 216 | + ctl = mixer[i].lm_ctl; |
|---|
| 466 | 217 | lm = mixer[i].hw_lm; |
|---|
| 467 | 218 | |
|---|
| 468 | 219 | lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); |
|---|
| .. | .. |
|---|
| 514 | 265 | { |
|---|
| 515 | 266 | struct drm_encoder *encoder; |
|---|
| 516 | 267 | |
|---|
| 517 | | - if (!crtc || !crtc->dev) { |
|---|
| 518 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 519 | | - return INTF_MODE_NONE; |
|---|
| 520 | | - } |
|---|
| 268 | + /* |
|---|
| 269 | + * TODO: This function is called from dpu debugfs and as part of atomic |
|---|
| 270 | + * check. When called from debugfs, the crtc->mutex must be held to |
|---|
| 271 | + * read crtc->state. However reading crtc->state from atomic check isn't |
|---|
| 272 | + * allowed (unless you have a good reason, a big comment, and a deep |
|---|
| 273 | + * understanding of how the atomic/modeset locks work (<- and this is |
|---|
| 274 | + * probably not possible)). So we'll keep the WARN_ON here for now, but |
|---|
| 275 | + * really we need to figure out a better way to track our operating mode |
|---|
| 276 | + */ |
|---|
| 277 | + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); |
|---|
| 521 | 278 | |
|---|
| 522 | | - drm_for_each_encoder(encoder, crtc->dev) |
|---|
| 523 | | - if (encoder->crtc == crtc) |
|---|
| 524 | | - return dpu_encoder_get_intf_mode(encoder); |
|---|
| 279 | + /* TODO: Returns the first INTF_MODE, could there be multiple values? */ |
|---|
| 280 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
|---|
| 281 | + return dpu_encoder_get_intf_mode(encoder); |
|---|
| 525 | 282 | |
|---|
| 526 | 283 | return INTF_MODE_NONE; |
|---|
| 527 | 284 | } |
|---|
| 528 | 285 | |
|---|
| 529 | | -static void dpu_crtc_vblank_cb(void *data) |
|---|
| 286 | +void dpu_crtc_vblank_callback(struct drm_crtc *crtc) |
|---|
| 530 | 287 | { |
|---|
| 531 | | - struct drm_crtc *crtc = (struct drm_crtc *)data; |
|---|
| 532 | 288 | struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 533 | 289 | |
|---|
| 534 | 290 | /* keep statistics on vblank callback - with auto reset via debugfs */ |
|---|
| .. | .. |
|---|
| 536 | 292 | dpu_crtc->vblank_cb_time = ktime_get(); |
|---|
| 537 | 293 | else |
|---|
| 538 | 294 | dpu_crtc->vblank_cb_count++; |
|---|
| 539 | | - _dpu_crtc_complete_flip(crtc); |
|---|
| 540 | 295 | drm_crtc_handle_vblank(crtc); |
|---|
| 541 | 296 | trace_dpu_crtc_vblank_cb(DRMID(crtc)); |
|---|
| 542 | 297 | } |
|---|
| 543 | 298 | |
|---|
| 544 | 299 | static void dpu_crtc_frame_event_work(struct kthread_work *work) |
|---|
| 545 | 300 | { |
|---|
| 546 | | - struct msm_drm_private *priv; |
|---|
| 547 | | - struct dpu_crtc_frame_event *fevent; |
|---|
| 548 | | - struct drm_crtc *crtc; |
|---|
| 549 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 550 | | - struct dpu_kms *dpu_kms; |
|---|
| 301 | + struct dpu_crtc_frame_event *fevent = container_of(work, |
|---|
| 302 | + struct dpu_crtc_frame_event, work); |
|---|
| 303 | + struct drm_crtc *crtc = fevent->crtc; |
|---|
| 304 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 551 | 305 | unsigned long flags; |
|---|
| 552 | 306 | bool frame_done = false; |
|---|
| 553 | 307 | |
|---|
| 554 | | - if (!work) { |
|---|
| 555 | | - DPU_ERROR("invalid work handle\n"); |
|---|
| 556 | | - return; |
|---|
| 557 | | - } |
|---|
| 558 | | - |
|---|
| 559 | | - fevent = container_of(work, struct dpu_crtc_frame_event, work); |
|---|
| 560 | | - if (!fevent->crtc || !fevent->crtc->state) { |
|---|
| 561 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 562 | | - return; |
|---|
| 563 | | - } |
|---|
| 564 | | - |
|---|
| 565 | | - crtc = fevent->crtc; |
|---|
| 566 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 567 | | - |
|---|
| 568 | | - dpu_kms = _dpu_crtc_get_kms(crtc); |
|---|
| 569 | | - if (!dpu_kms) { |
|---|
| 570 | | - DPU_ERROR("invalid kms handle\n"); |
|---|
| 571 | | - return; |
|---|
| 572 | | - } |
|---|
| 573 | | - priv = dpu_kms->dev->dev_private; |
|---|
| 574 | 308 | DPU_ATRACE_BEGIN("crtc_frame_event"); |
|---|
| 575 | 309 | |
|---|
| 576 | 310 | DRM_DEBUG_KMS("crtc%d event:%u ts:%lld\n", crtc->base.id, fevent->event, |
|---|
| .. | .. |
|---|
| 581 | 315 | | DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) { |
|---|
| 582 | 316 | |
|---|
| 583 | 317 | if (atomic_read(&dpu_crtc->frame_pending) < 1) { |
|---|
| 584 | | - /* this should not happen */ |
|---|
| 585 | | - DRM_ERROR("crtc%d ev:%u ts:%lld frame_pending:%d\n", |
|---|
| 586 | | - crtc->base.id, |
|---|
| 587 | | - fevent->event, |
|---|
| 588 | | - ktime_to_ns(fevent->ts), |
|---|
| 589 | | - atomic_read(&dpu_crtc->frame_pending)); |
|---|
| 318 | + /* ignore vblank when not pending */ |
|---|
| 590 | 319 | } else if (atomic_dec_return(&dpu_crtc->frame_pending) == 0) { |
|---|
| 591 | 320 | /* release bandwidth and other resources */ |
|---|
| 592 | 321 | trace_dpu_crtc_frame_event_done(DRMID(crtc), |
|---|
| .. | .. |
|---|
| 636 | 365 | unsigned long flags; |
|---|
| 637 | 366 | u32 crtc_id; |
|---|
| 638 | 367 | |
|---|
| 639 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
|---|
| 640 | | - DPU_ERROR("invalid parameters\n"); |
|---|
| 641 | | - return; |
|---|
| 642 | | - } |
|---|
| 643 | | - |
|---|
| 644 | 368 | /* Nothing to do on idle event */ |
|---|
| 645 | 369 | if (event & DPU_ENCODER_FRAME_EVENT_IDLE) |
|---|
| 646 | 370 | return; |
|---|
| .. | .. |
|---|
| 666 | 390 | fevent->event = event; |
|---|
| 667 | 391 | fevent->crtc = crtc; |
|---|
| 668 | 392 | fevent->ts = ktime_get(); |
|---|
| 669 | | - kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); |
|---|
| 393 | + kthread_queue_work(priv->event_thread[crtc_id].worker, &fevent->work); |
|---|
| 670 | 394 | } |
|---|
| 671 | 395 | |
|---|
| 672 | | -void dpu_crtc_complete_commit(struct drm_crtc *crtc, |
|---|
| 673 | | - struct drm_crtc_state *old_state) |
|---|
| 396 | +void dpu_crtc_complete_commit(struct drm_crtc *crtc) |
|---|
| 674 | 397 | { |
|---|
| 675 | | - if (!crtc || !crtc->state) { |
|---|
| 676 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 677 | | - return; |
|---|
| 678 | | - } |
|---|
| 679 | 398 | trace_dpu_crtc_complete_commit(DRMID(crtc)); |
|---|
| 680 | | -} |
|---|
| 681 | | - |
|---|
| 682 | | -static void _dpu_crtc_setup_mixer_for_encoder( |
|---|
| 683 | | - struct drm_crtc *crtc, |
|---|
| 684 | | - struct drm_encoder *enc) |
|---|
| 685 | | -{ |
|---|
| 686 | | - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 687 | | - struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); |
|---|
| 688 | | - struct dpu_rm *rm = &dpu_kms->rm; |
|---|
| 689 | | - struct dpu_crtc_mixer *mixer; |
|---|
| 690 | | - struct dpu_hw_ctl *last_valid_ctl = NULL; |
|---|
| 691 | | - int i; |
|---|
| 692 | | - struct dpu_rm_hw_iter lm_iter, ctl_iter; |
|---|
| 693 | | - |
|---|
| 694 | | - dpu_rm_init_hw_iter(&lm_iter, enc->base.id, DPU_HW_BLK_LM); |
|---|
| 695 | | - dpu_rm_init_hw_iter(&ctl_iter, enc->base.id, DPU_HW_BLK_CTL); |
|---|
| 696 | | - |
|---|
| 697 | | - /* Set up all the mixers and ctls reserved by this encoder */ |
|---|
| 698 | | - for (i = dpu_crtc->num_mixers; i < ARRAY_SIZE(dpu_crtc->mixers); i++) { |
|---|
| 699 | | - mixer = &dpu_crtc->mixers[i]; |
|---|
| 700 | | - |
|---|
| 701 | | - if (!dpu_rm_get_hw(rm, &lm_iter)) |
|---|
| 702 | | - break; |
|---|
| 703 | | - mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw; |
|---|
| 704 | | - |
|---|
| 705 | | - /* CTL may be <= LMs, if <, multiple LMs controlled by 1 CTL */ |
|---|
| 706 | | - if (!dpu_rm_get_hw(rm, &ctl_iter)) { |
|---|
| 707 | | - DPU_DEBUG("no ctl assigned to lm %d, using previous\n", |
|---|
| 708 | | - mixer->hw_lm->idx - LM_0); |
|---|
| 709 | | - mixer->hw_ctl = last_valid_ctl; |
|---|
| 710 | | - } else { |
|---|
| 711 | | - mixer->hw_ctl = (struct dpu_hw_ctl *)ctl_iter.hw; |
|---|
| 712 | | - last_valid_ctl = mixer->hw_ctl; |
|---|
| 713 | | - } |
|---|
| 714 | | - |
|---|
| 715 | | - /* Shouldn't happen, mixers are always >= ctls */ |
|---|
| 716 | | - if (!mixer->hw_ctl) { |
|---|
| 717 | | - DPU_ERROR("no valid ctls found for lm %d\n", |
|---|
| 718 | | - mixer->hw_lm->idx - LM_0); |
|---|
| 719 | | - return; |
|---|
| 720 | | - } |
|---|
| 721 | | - |
|---|
| 722 | | - mixer->encoder = enc; |
|---|
| 723 | | - |
|---|
| 724 | | - dpu_crtc->num_mixers++; |
|---|
| 725 | | - DPU_DEBUG("setup mixer %d: lm %d\n", |
|---|
| 726 | | - i, mixer->hw_lm->idx - LM_0); |
|---|
| 727 | | - DPU_DEBUG("setup mixer %d: ctl %d\n", |
|---|
| 728 | | - i, mixer->hw_ctl->idx - CTL_0); |
|---|
| 729 | | - } |
|---|
| 730 | | -} |
|---|
| 731 | | - |
|---|
| 732 | | -static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc) |
|---|
| 733 | | -{ |
|---|
| 734 | | - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 735 | | - struct drm_encoder *enc; |
|---|
| 736 | | - |
|---|
| 737 | | - dpu_crtc->num_mixers = 0; |
|---|
| 738 | | - dpu_crtc->mixers_swapped = false; |
|---|
| 739 | | - memset(dpu_crtc->mixers, 0, sizeof(dpu_crtc->mixers)); |
|---|
| 740 | | - |
|---|
| 741 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 742 | | - /* Check for mixers on all encoders attached to this crtc */ |
|---|
| 743 | | - list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { |
|---|
| 744 | | - if (enc->crtc != crtc) |
|---|
| 745 | | - continue; |
|---|
| 746 | | - |
|---|
| 747 | | - _dpu_crtc_setup_mixer_for_encoder(crtc, enc); |
|---|
| 748 | | - } |
|---|
| 749 | | - |
|---|
| 750 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 399 | + _dpu_crtc_complete_flip(crtc); |
|---|
| 751 | 400 | } |
|---|
| 752 | 401 | |
|---|
| 753 | 402 | static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, |
|---|
| 754 | 403 | struct drm_crtc_state *state) |
|---|
| 755 | 404 | { |
|---|
| 756 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 757 | | - struct dpu_crtc_state *cstate; |
|---|
| 758 | | - struct drm_display_mode *adj_mode; |
|---|
| 759 | | - u32 crtc_split_width; |
|---|
| 405 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); |
|---|
| 406 | + struct drm_display_mode *adj_mode = &state->adjusted_mode; |
|---|
| 407 | + u32 crtc_split_width = adj_mode->hdisplay / cstate->num_mixers; |
|---|
| 760 | 408 | int i; |
|---|
| 761 | 409 | |
|---|
| 762 | | - if (!crtc || !state) { |
|---|
| 763 | | - DPU_ERROR("invalid args\n"); |
|---|
| 764 | | - return; |
|---|
| 765 | | - } |
|---|
| 766 | | - |
|---|
| 767 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 768 | | - cstate = to_dpu_crtc_state(state); |
|---|
| 769 | | - |
|---|
| 770 | | - adj_mode = &state->adjusted_mode; |
|---|
| 771 | | - crtc_split_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, adj_mode); |
|---|
| 772 | | - |
|---|
| 773 | | - for (i = 0; i < dpu_crtc->num_mixers; i++) { |
|---|
| 410 | + for (i = 0; i < cstate->num_mixers; i++) { |
|---|
| 774 | 411 | struct drm_rect *r = &cstate->lm_bounds[i]; |
|---|
| 775 | 412 | r->x1 = crtc_split_width * i; |
|---|
| 776 | 413 | r->y1 = 0; |
|---|
| 777 | 414 | r->x2 = r->x1 + crtc_split_width; |
|---|
| 778 | | - r->y2 = dpu_crtc_get_mixer_height(dpu_crtc, cstate, adj_mode); |
|---|
| 415 | + r->y2 = adj_mode->vdisplay; |
|---|
| 779 | 416 | |
|---|
| 780 | 417 | trace_dpu_crtc_setup_lm_bounds(DRMID(crtc), i, r); |
|---|
| 781 | 418 | } |
|---|
| 419 | +} |
|---|
| 782 | 420 | |
|---|
| 783 | | - drm_mode_debug_printmodeline(adj_mode); |
|---|
| 421 | +static void _dpu_crtc_get_pcc_coeff(struct drm_crtc_state *state, |
|---|
| 422 | + struct dpu_hw_pcc_cfg *cfg) |
|---|
| 423 | +{ |
|---|
| 424 | + struct drm_color_ctm *ctm; |
|---|
| 425 | + |
|---|
| 426 | + memset(cfg, 0, sizeof(struct dpu_hw_pcc_cfg)); |
|---|
| 427 | + |
|---|
| 428 | + ctm = (struct drm_color_ctm *)state->ctm->data; |
|---|
| 429 | + |
|---|
| 430 | + if (!ctm) |
|---|
| 431 | + return; |
|---|
| 432 | + |
|---|
| 433 | + cfg->r.r = CONVERT_S3_15(ctm->matrix[0]); |
|---|
| 434 | + cfg->g.r = CONVERT_S3_15(ctm->matrix[1]); |
|---|
| 435 | + cfg->b.r = CONVERT_S3_15(ctm->matrix[2]); |
|---|
| 436 | + |
|---|
| 437 | + cfg->r.g = CONVERT_S3_15(ctm->matrix[3]); |
|---|
| 438 | + cfg->g.g = CONVERT_S3_15(ctm->matrix[4]); |
|---|
| 439 | + cfg->b.g = CONVERT_S3_15(ctm->matrix[5]); |
|---|
| 440 | + |
|---|
| 441 | + cfg->r.b = CONVERT_S3_15(ctm->matrix[6]); |
|---|
| 442 | + cfg->g.b = CONVERT_S3_15(ctm->matrix[7]); |
|---|
| 443 | + cfg->b.b = CONVERT_S3_15(ctm->matrix[8]); |
|---|
| 444 | +} |
|---|
| 445 | + |
|---|
| 446 | +static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) |
|---|
| 447 | +{ |
|---|
| 448 | + struct drm_crtc_state *state = crtc->state; |
|---|
| 449 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 450 | + struct dpu_crtc_mixer *mixer = cstate->mixers; |
|---|
| 451 | + struct dpu_hw_pcc_cfg cfg; |
|---|
| 452 | + struct dpu_hw_ctl *ctl; |
|---|
| 453 | + struct dpu_hw_dspp *dspp; |
|---|
| 454 | + int i; |
|---|
| 455 | + |
|---|
| 456 | + |
|---|
| 457 | + if (!state->color_mgmt_changed) |
|---|
| 458 | + return; |
|---|
| 459 | + |
|---|
| 460 | + for (i = 0; i < cstate->num_mixers; i++) { |
|---|
| 461 | + ctl = mixer[i].lm_ctl; |
|---|
| 462 | + dspp = mixer[i].hw_dspp; |
|---|
| 463 | + |
|---|
| 464 | + if (!dspp || !dspp->ops.setup_pcc) |
|---|
| 465 | + continue; |
|---|
| 466 | + |
|---|
| 467 | + if (!state->ctm) { |
|---|
| 468 | + dspp->ops.setup_pcc(dspp, NULL); |
|---|
| 469 | + } else { |
|---|
| 470 | + _dpu_crtc_get_pcc_coeff(state, &cfg); |
|---|
| 471 | + dspp->ops.setup_pcc(dspp, &cfg); |
|---|
| 472 | + } |
|---|
| 473 | + |
|---|
| 474 | + mixer[i].flush_mask |= ctl->ops.get_bitmask_dspp(ctl, |
|---|
| 475 | + mixer[i].hw_dspp->idx); |
|---|
| 476 | + |
|---|
| 477 | + /* stage config flush mask */ |
|---|
| 478 | + ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); |
|---|
| 479 | + |
|---|
| 480 | + DPU_DEBUG("lm %d, ctl %d, flush mask 0x%x\n", |
|---|
| 481 | + mixer[i].hw_lm->idx - DSPP_0, |
|---|
| 482 | + ctl->idx - CTL_0, |
|---|
| 483 | + mixer[i].flush_mask); |
|---|
| 484 | + } |
|---|
| 784 | 485 | } |
|---|
| 785 | 486 | |
|---|
| 786 | 487 | static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, |
|---|
| 787 | 488 | struct drm_crtc_state *old_state) |
|---|
| 788 | 489 | { |
|---|
| 789 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 490 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 790 | 491 | struct drm_encoder *encoder; |
|---|
| 791 | | - struct drm_device *dev; |
|---|
| 792 | | - unsigned long flags; |
|---|
| 793 | | - struct dpu_crtc_smmu_state_data *smmu_state; |
|---|
| 794 | | - |
|---|
| 795 | | - if (!crtc) { |
|---|
| 796 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 797 | | - return; |
|---|
| 798 | | - } |
|---|
| 799 | 492 | |
|---|
| 800 | 493 | if (!crtc->state->enable) { |
|---|
| 801 | 494 | DPU_DEBUG("crtc%d -> enable %d, skip atomic_begin\n", |
|---|
| .. | .. |
|---|
| 805 | 498 | |
|---|
| 806 | 499 | DPU_DEBUG("crtc%d\n", crtc->base.id); |
|---|
| 807 | 500 | |
|---|
| 808 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 809 | | - dev = crtc->dev; |
|---|
| 810 | | - smmu_state = &dpu_crtc->smmu_state; |
|---|
| 501 | + _dpu_crtc_setup_lm_bounds(crtc, crtc->state); |
|---|
| 811 | 502 | |
|---|
| 812 | | - if (!dpu_crtc->num_mixers) { |
|---|
| 813 | | - _dpu_crtc_setup_mixers(crtc); |
|---|
| 814 | | - _dpu_crtc_setup_lm_bounds(crtc, crtc->state); |
|---|
| 815 | | - } |
|---|
| 816 | | - |
|---|
| 817 | | - if (dpu_crtc->event) { |
|---|
| 818 | | - WARN_ON(dpu_crtc->event); |
|---|
| 819 | | - } else { |
|---|
| 820 | | - spin_lock_irqsave(&dev->event_lock, flags); |
|---|
| 821 | | - dpu_crtc->event = crtc->state->event; |
|---|
| 822 | | - crtc->state->event = NULL; |
|---|
| 823 | | - spin_unlock_irqrestore(&dev->event_lock, flags); |
|---|
| 824 | | - } |
|---|
| 825 | | - |
|---|
| 826 | | - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
|---|
| 827 | | - if (encoder->crtc != crtc) |
|---|
| 828 | | - continue; |
|---|
| 829 | | - |
|---|
| 830 | | - /* encoder will trigger pending mask now */ |
|---|
| 503 | + /* encoder will trigger pending mask now */ |
|---|
| 504 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
|---|
| 831 | 505 | dpu_encoder_trigger_kickoff_pending(encoder); |
|---|
| 832 | | - } |
|---|
| 833 | 506 | |
|---|
| 834 | 507 | /* |
|---|
| 835 | 508 | * If no mixers have been allocated in dpu_crtc_atomic_check(), |
|---|
| 836 | 509 | * it means we are trying to flush a CRTC whose state is disabled: |
|---|
| 837 | 510 | * nothing else needs to be done. |
|---|
| 838 | 511 | */ |
|---|
| 839 | | - if (unlikely(!dpu_crtc->num_mixers)) |
|---|
| 512 | + if (unlikely(!cstate->num_mixers)) |
|---|
| 840 | 513 | return; |
|---|
| 841 | 514 | |
|---|
| 842 | 515 | _dpu_crtc_blend_setup(crtc); |
|---|
| 516 | + |
|---|
| 517 | + _dpu_crtc_setup_cp_blocks(crtc); |
|---|
| 843 | 518 | |
|---|
| 844 | 519 | /* |
|---|
| 845 | 520 | * PP_DONE irq is only used by command mode for now. |
|---|
| .. | .. |
|---|
| 857 | 532 | struct drm_device *dev; |
|---|
| 858 | 533 | struct drm_plane *plane; |
|---|
| 859 | 534 | struct msm_drm_private *priv; |
|---|
| 860 | | - struct msm_drm_thread *event_thread; |
|---|
| 861 | 535 | unsigned long flags; |
|---|
| 862 | 536 | struct dpu_crtc_state *cstate; |
|---|
| 863 | | - |
|---|
| 864 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
|---|
| 865 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 866 | | - return; |
|---|
| 867 | | - } |
|---|
| 868 | 537 | |
|---|
| 869 | 538 | if (!crtc->state->enable) { |
|---|
| 870 | 539 | DPU_DEBUG("crtc%d -> enable %d, skip atomic_flush\n", |
|---|
| .. | .. |
|---|
| 884 | 553 | return; |
|---|
| 885 | 554 | } |
|---|
| 886 | 555 | |
|---|
| 887 | | - event_thread = &priv->event_thread[crtc->index]; |
|---|
| 888 | | - |
|---|
| 889 | | - if (dpu_crtc->event) { |
|---|
| 890 | | - DPU_DEBUG("already received dpu_crtc->event\n"); |
|---|
| 891 | | - } else { |
|---|
| 892 | | - spin_lock_irqsave(&dev->event_lock, flags); |
|---|
| 893 | | - dpu_crtc->event = crtc->state->event; |
|---|
| 894 | | - crtc->state->event = NULL; |
|---|
| 895 | | - spin_unlock_irqrestore(&dev->event_lock, flags); |
|---|
| 896 | | - } |
|---|
| 556 | + WARN_ON(dpu_crtc->event); |
|---|
| 557 | + spin_lock_irqsave(&dev->event_lock, flags); |
|---|
| 558 | + dpu_crtc->event = crtc->state->event; |
|---|
| 559 | + crtc->state->event = NULL; |
|---|
| 560 | + spin_unlock_irqrestore(&dev->event_lock, flags); |
|---|
| 897 | 561 | |
|---|
| 898 | 562 | /* |
|---|
| 899 | 563 | * If no mixers has been allocated in dpu_crtc_atomic_check(), |
|---|
| 900 | 564 | * it means we are trying to flush a CRTC whose state is disabled: |
|---|
| 901 | 565 | * nothing else needs to be done. |
|---|
| 902 | 566 | */ |
|---|
| 903 | | - if (unlikely(!dpu_crtc->num_mixers)) |
|---|
| 567 | + if (unlikely(!cstate->num_mixers)) |
|---|
| 904 | 568 | return; |
|---|
| 905 | 569 | |
|---|
| 906 | 570 | /* |
|---|
| .. | .. |
|---|
| 938 | 602 | static void dpu_crtc_destroy_state(struct drm_crtc *crtc, |
|---|
| 939 | 603 | struct drm_crtc_state *state) |
|---|
| 940 | 604 | { |
|---|
| 941 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 942 | | - struct dpu_crtc_state *cstate; |
|---|
| 943 | | - |
|---|
| 944 | | - if (!crtc || !state) { |
|---|
| 945 | | - DPU_ERROR("invalid argument(s)\n"); |
|---|
| 946 | | - return; |
|---|
| 947 | | - } |
|---|
| 948 | | - |
|---|
| 949 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 950 | | - cstate = to_dpu_crtc_state(state); |
|---|
| 605 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); |
|---|
| 951 | 606 | |
|---|
| 952 | 607 | DPU_DEBUG("crtc%d\n", crtc->base.id); |
|---|
| 953 | | - |
|---|
| 954 | | - _dpu_crtc_rp_destroy(&cstate->rp); |
|---|
| 955 | 608 | |
|---|
| 956 | 609 | __drm_atomic_helper_crtc_destroy_state(state); |
|---|
| 957 | 610 | |
|---|
| .. | .. |
|---|
| 960 | 613 | |
|---|
| 961 | 614 | static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) |
|---|
| 962 | 615 | { |
|---|
| 963 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 616 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 964 | 617 | int ret, rc = 0; |
|---|
| 965 | | - |
|---|
| 966 | | - if (!crtc) { |
|---|
| 967 | | - DPU_ERROR("invalid argument\n"); |
|---|
| 968 | | - return -EINVAL; |
|---|
| 969 | | - } |
|---|
| 970 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 971 | 618 | |
|---|
| 972 | 619 | if (!atomic_read(&dpu_crtc->frame_pending)) { |
|---|
| 973 | 620 | DPU_DEBUG("no frames pending\n"); |
|---|
| .. | .. |
|---|
| 976 | 623 | |
|---|
| 977 | 624 | DPU_ATRACE_BEGIN("frame done completion wait"); |
|---|
| 978 | 625 | ret = wait_for_completion_timeout(&dpu_crtc->frame_done_comp, |
|---|
| 979 | | - msecs_to_jiffies(DPU_FRAME_DONE_TIMEOUT)); |
|---|
| 626 | + msecs_to_jiffies(DPU_CRTC_FRAME_DONE_TIMEOUT_MS)); |
|---|
| 980 | 627 | if (!ret) { |
|---|
| 981 | 628 | DRM_ERROR("frame done wait timed out, ret:%d\n", ret); |
|---|
| 982 | 629 | rc = -ETIMEDOUT; |
|---|
| .. | .. |
|---|
| 989 | 636 | void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) |
|---|
| 990 | 637 | { |
|---|
| 991 | 638 | struct drm_encoder *encoder; |
|---|
| 992 | | - struct drm_device *dev; |
|---|
| 993 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 994 | | - struct msm_drm_private *priv; |
|---|
| 995 | | - struct dpu_kms *dpu_kms; |
|---|
| 996 | | - struct dpu_crtc_state *cstate; |
|---|
| 997 | | - int ret; |
|---|
| 998 | | - |
|---|
| 999 | | - if (!crtc) { |
|---|
| 1000 | | - DPU_ERROR("invalid argument\n"); |
|---|
| 1001 | | - return; |
|---|
| 1002 | | - } |
|---|
| 1003 | | - dev = crtc->dev; |
|---|
| 1004 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1005 | | - dpu_kms = _dpu_crtc_get_kms(crtc); |
|---|
| 1006 | | - |
|---|
| 1007 | | - if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev_private) { |
|---|
| 1008 | | - DPU_ERROR("invalid argument\n"); |
|---|
| 1009 | | - return; |
|---|
| 1010 | | - } |
|---|
| 1011 | | - |
|---|
| 1012 | | - priv = dpu_kms->dev->dev_private; |
|---|
| 1013 | | - cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 639 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 640 | + struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); |
|---|
| 641 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 1014 | 642 | |
|---|
| 1015 | 643 | /* |
|---|
| 1016 | 644 | * If no mixers has been allocated in dpu_crtc_atomic_check(), |
|---|
| 1017 | 645 | * it means we are trying to start a CRTC whose state is disabled: |
|---|
| 1018 | 646 | * nothing else needs to be done. |
|---|
| 1019 | 647 | */ |
|---|
| 1020 | | - if (unlikely(!dpu_crtc->num_mixers)) |
|---|
| 648 | + if (unlikely(!cstate->num_mixers)) |
|---|
| 1021 | 649 | return; |
|---|
| 1022 | 650 | |
|---|
| 1023 | 651 | DPU_ATRACE_BEGIN("crtc_commit"); |
|---|
| 1024 | 652 | |
|---|
| 1025 | | - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
|---|
| 1026 | | - struct dpu_encoder_kickoff_params params = { 0 }; |
|---|
| 1027 | | - |
|---|
| 1028 | | - if (encoder->crtc != crtc) |
|---|
| 1029 | | - continue; |
|---|
| 1030 | | - |
|---|
| 1031 | | - /* |
|---|
| 1032 | | - * Encoder will flush/start now, unless it has a tx pending. |
|---|
| 1033 | | - * If so, it may delay and flush at an irq event (e.g. ppdone) |
|---|
| 1034 | | - */ |
|---|
| 1035 | | - dpu_encoder_prepare_for_kickoff(encoder, ¶ms); |
|---|
| 1036 | | - } |
|---|
| 1037 | | - |
|---|
| 1038 | | - /* wait for frame_event_done completion */ |
|---|
| 1039 | | - DPU_ATRACE_BEGIN("wait_for_frame_done_event"); |
|---|
| 1040 | | - ret = _dpu_crtc_wait_for_frame_done(crtc); |
|---|
| 1041 | | - DPU_ATRACE_END("wait_for_frame_done_event"); |
|---|
| 1042 | | - if (ret) { |
|---|
| 1043 | | - DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", |
|---|
| 1044 | | - crtc->base.id, |
|---|
| 1045 | | - atomic_read(&dpu_crtc->frame_pending)); |
|---|
| 1046 | | - goto end; |
|---|
| 1047 | | - } |
|---|
| 653 | + /* |
|---|
| 654 | + * Encoder will flush/start now, unless it has a tx pending. If so, it |
|---|
| 655 | + * may delay and flush at an irq event (e.g. ppdone) |
|---|
| 656 | + */ |
|---|
| 657 | + drm_for_each_encoder_mask(encoder, crtc->dev, |
|---|
| 658 | + crtc->state->encoder_mask) |
|---|
| 659 | + dpu_encoder_prepare_for_kickoff(encoder); |
|---|
| 1048 | 660 | |
|---|
| 1049 | 661 | if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { |
|---|
| 1050 | 662 | /* acquire bandwidth and other resources */ |
|---|
| .. | .. |
|---|
| 1056 | 668 | |
|---|
| 1057 | 669 | dpu_vbif_clear_errors(dpu_kms); |
|---|
| 1058 | 670 | |
|---|
| 1059 | | - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
|---|
| 1060 | | - if (encoder->crtc != crtc) |
|---|
| 1061 | | - continue; |
|---|
| 1062 | | - |
|---|
| 671 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
|---|
| 1063 | 672 | dpu_encoder_kickoff(encoder); |
|---|
| 1064 | | - } |
|---|
| 1065 | 673 | |
|---|
| 1066 | | -end: |
|---|
| 1067 | 674 | reinit_completion(&dpu_crtc->frame_done_comp); |
|---|
| 1068 | 675 | DPU_ATRACE_END("crtc_commit"); |
|---|
| 1069 | 676 | } |
|---|
| 1070 | 677 | |
|---|
| 1071 | | -/** |
|---|
| 1072 | | - * _dpu_crtc_vblank_enable_no_lock - update power resource and vblank request |
|---|
| 1073 | | - * @dpu_crtc: Pointer to dpu crtc structure |
|---|
| 1074 | | - * @enable: Whether to enable/disable vblanks |
|---|
| 1075 | | - * |
|---|
| 1076 | | - * @Return: error code |
|---|
| 1077 | | - */ |
|---|
| 1078 | | -static int _dpu_crtc_vblank_enable_no_lock( |
|---|
| 1079 | | - struct dpu_crtc *dpu_crtc, bool enable) |
|---|
| 678 | +static void dpu_crtc_reset(struct drm_crtc *crtc) |
|---|
| 1080 | 679 | { |
|---|
| 1081 | | - struct drm_device *dev; |
|---|
| 1082 | | - struct drm_crtc *crtc; |
|---|
| 1083 | | - struct drm_encoder *enc; |
|---|
| 680 | + struct dpu_crtc_state *cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); |
|---|
| 1084 | 681 | |
|---|
| 1085 | | - if (!dpu_crtc) { |
|---|
| 1086 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 1087 | | - return -EINVAL; |
|---|
| 1088 | | - } |
|---|
| 682 | + if (crtc->state) |
|---|
| 683 | + dpu_crtc_destroy_state(crtc, crtc->state); |
|---|
| 1089 | 684 | |
|---|
| 1090 | | - crtc = &dpu_crtc->base; |
|---|
| 1091 | | - dev = crtc->dev; |
|---|
| 1092 | | - |
|---|
| 1093 | | - if (enable) { |
|---|
| 1094 | | - int ret; |
|---|
| 1095 | | - |
|---|
| 1096 | | - /* drop lock since power crtc cb may try to re-acquire lock */ |
|---|
| 1097 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 1098 | | - ret = _dpu_crtc_power_enable(dpu_crtc, true); |
|---|
| 1099 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 1100 | | - if (ret) |
|---|
| 1101 | | - return ret; |
|---|
| 1102 | | - |
|---|
| 1103 | | - list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { |
|---|
| 1104 | | - if (enc->crtc != crtc) |
|---|
| 1105 | | - continue; |
|---|
| 1106 | | - |
|---|
| 1107 | | - trace_dpu_crtc_vblank_enable(DRMID(&dpu_crtc->base), |
|---|
| 1108 | | - DRMID(enc), enable, |
|---|
| 1109 | | - dpu_crtc); |
|---|
| 1110 | | - |
|---|
| 1111 | | - dpu_encoder_register_vblank_callback(enc, |
|---|
| 1112 | | - dpu_crtc_vblank_cb, (void *)crtc); |
|---|
| 1113 | | - } |
|---|
| 1114 | | - } else { |
|---|
| 1115 | | - list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { |
|---|
| 1116 | | - if (enc->crtc != crtc) |
|---|
| 1117 | | - continue; |
|---|
| 1118 | | - |
|---|
| 1119 | | - trace_dpu_crtc_vblank_enable(DRMID(&dpu_crtc->base), |
|---|
| 1120 | | - DRMID(enc), enable, |
|---|
| 1121 | | - dpu_crtc); |
|---|
| 1122 | | - |
|---|
| 1123 | | - dpu_encoder_register_vblank_callback(enc, NULL, NULL); |
|---|
| 1124 | | - } |
|---|
| 1125 | | - |
|---|
| 1126 | | - /* drop lock since power crtc cb may try to re-acquire lock */ |
|---|
| 1127 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 1128 | | - _dpu_crtc_power_enable(dpu_crtc, false); |
|---|
| 1129 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 1130 | | - } |
|---|
| 1131 | | - |
|---|
| 1132 | | - return 0; |
|---|
| 1133 | | -} |
|---|
| 1134 | | - |
|---|
| 1135 | | -/** |
|---|
| 1136 | | - * _dpu_crtc_set_suspend - notify crtc of suspend enable/disable |
|---|
| 1137 | | - * @crtc: Pointer to drm crtc object |
|---|
| 1138 | | - * @enable: true to enable suspend, false to indicate resume |
|---|
| 1139 | | - */ |
|---|
| 1140 | | -static void _dpu_crtc_set_suspend(struct drm_crtc *crtc, bool enable) |
|---|
| 1141 | | -{ |
|---|
| 1142 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 1143 | | - struct msm_drm_private *priv; |
|---|
| 1144 | | - struct dpu_kms *dpu_kms; |
|---|
| 1145 | | - int ret = 0; |
|---|
| 1146 | | - |
|---|
| 1147 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
|---|
| 1148 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 1149 | | - return; |
|---|
| 1150 | | - } |
|---|
| 1151 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1152 | | - priv = crtc->dev->dev_private; |
|---|
| 1153 | | - |
|---|
| 1154 | | - if (!priv->kms) { |
|---|
| 1155 | | - DPU_ERROR("invalid crtc kms\n"); |
|---|
| 1156 | | - return; |
|---|
| 1157 | | - } |
|---|
| 1158 | | - dpu_kms = to_dpu_kms(priv->kms); |
|---|
| 1159 | | - |
|---|
| 1160 | | - DRM_DEBUG_KMS("crtc%d suspend = %d\n", crtc->base.id, enable); |
|---|
| 1161 | | - |
|---|
| 1162 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 1163 | | - |
|---|
| 1164 | | - /* |
|---|
| 1165 | | - * If the vblank is enabled, release a power reference on suspend |
|---|
| 1166 | | - * and take it back during resume (if it is still enabled). |
|---|
| 1167 | | - */ |
|---|
| 1168 | | - trace_dpu_crtc_set_suspend(DRMID(&dpu_crtc->base), enable, dpu_crtc); |
|---|
| 1169 | | - if (dpu_crtc->suspend == enable) |
|---|
| 1170 | | - DPU_DEBUG("crtc%d suspend already set to %d, ignoring update\n", |
|---|
| 1171 | | - crtc->base.id, enable); |
|---|
| 1172 | | - else if (dpu_crtc->enabled && dpu_crtc->vblank_requested) { |
|---|
| 1173 | | - ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, !enable); |
|---|
| 1174 | | - if (ret) |
|---|
| 1175 | | - DPU_ERROR("%s vblank enable failed: %d\n", |
|---|
| 1176 | | - dpu_crtc->name, ret); |
|---|
| 1177 | | - } |
|---|
| 1178 | | - |
|---|
| 1179 | | - dpu_crtc->suspend = enable; |
|---|
| 1180 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 685 | + if (cstate) |
|---|
| 686 | + __drm_atomic_helper_crtc_reset(crtc, &cstate->base); |
|---|
| 687 | + else |
|---|
| 688 | + __drm_atomic_helper_crtc_reset(crtc, NULL); |
|---|
| 1181 | 689 | } |
|---|
| 1182 | 690 | |
|---|
| 1183 | 691 | /** |
|---|
| 1184 | 692 | * dpu_crtc_duplicate_state - state duplicate hook |
|---|
| 1185 | 693 | * @crtc: Pointer to drm crtc structure |
|---|
| 1186 | | - * @Returns: Pointer to new drm_crtc_state structure |
|---|
| 1187 | 694 | */ |
|---|
| 1188 | 695 | static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) |
|---|
| 1189 | 696 | { |
|---|
| 1190 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 1191 | | - struct dpu_crtc_state *cstate, *old_cstate; |
|---|
| 697 | + struct dpu_crtc_state *cstate, *old_cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 1192 | 698 | |
|---|
| 1193 | | - if (!crtc || !crtc->state) { |
|---|
| 1194 | | - DPU_ERROR("invalid argument(s)\n"); |
|---|
| 1195 | | - return NULL; |
|---|
| 1196 | | - } |
|---|
| 1197 | | - |
|---|
| 1198 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1199 | | - old_cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 1200 | 699 | cstate = kmemdup(old_cstate, sizeof(*old_cstate), GFP_KERNEL); |
|---|
| 1201 | 700 | if (!cstate) { |
|---|
| 1202 | 701 | DPU_ERROR("failed to allocate state\n"); |
|---|
| .. | .. |
|---|
| 1206 | 705 | /* duplicate base helper */ |
|---|
| 1207 | 706 | __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); |
|---|
| 1208 | 707 | |
|---|
| 1209 | | - _dpu_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp); |
|---|
| 1210 | | - |
|---|
| 1211 | 708 | return &cstate->base; |
|---|
| 1212 | 709 | } |
|---|
| 1213 | 710 | |
|---|
| 1214 | | -/** |
|---|
| 1215 | | - * dpu_crtc_reset - reset hook for CRTCs |
|---|
| 1216 | | - * Resets the atomic state for @crtc by freeing the state pointer (which might |
|---|
| 1217 | | - * be NULL, e.g. at driver load time) and allocating a new empty state object. |
|---|
| 1218 | | - * @crtc: Pointer to drm crtc structure |
|---|
| 1219 | | - */ |
|---|
| 1220 | | -static void dpu_crtc_reset(struct drm_crtc *crtc) |
|---|
| 711 | +static void dpu_crtc_disable(struct drm_crtc *crtc, |
|---|
| 712 | + struct drm_crtc_state *old_crtc_state) |
|---|
| 1221 | 713 | { |
|---|
| 1222 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 1223 | | - struct dpu_crtc_state *cstate; |
|---|
| 1224 | | - |
|---|
| 1225 | | - if (!crtc) { |
|---|
| 1226 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 1227 | | - return; |
|---|
| 1228 | | - } |
|---|
| 1229 | | - |
|---|
| 1230 | | - /* revert suspend actions, if necessary */ |
|---|
| 1231 | | - if (dpu_kms_is_suspend_state(crtc->dev)) |
|---|
| 1232 | | - _dpu_crtc_set_suspend(crtc, false); |
|---|
| 1233 | | - |
|---|
| 1234 | | - /* remove previous state, if present */ |
|---|
| 1235 | | - if (crtc->state) { |
|---|
| 1236 | | - dpu_crtc_destroy_state(crtc, crtc->state); |
|---|
| 1237 | | - crtc->state = 0; |
|---|
| 1238 | | - } |
|---|
| 1239 | | - |
|---|
| 1240 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1241 | | - cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); |
|---|
| 1242 | | - if (!cstate) { |
|---|
| 1243 | | - DPU_ERROR("failed to allocate state\n"); |
|---|
| 1244 | | - return; |
|---|
| 1245 | | - } |
|---|
| 1246 | | - |
|---|
| 1247 | | - _dpu_crtc_rp_reset(&cstate->rp, &dpu_crtc->rp_lock, |
|---|
| 1248 | | - &dpu_crtc->rp_head); |
|---|
| 1249 | | - |
|---|
| 1250 | | - cstate->base.crtc = crtc; |
|---|
| 1251 | | - crtc->state = &cstate->base; |
|---|
| 1252 | | -} |
|---|
| 1253 | | - |
|---|
| 1254 | | -static void dpu_crtc_handle_power_event(u32 event_type, void *arg) |
|---|
| 1255 | | -{ |
|---|
| 1256 | | - struct drm_crtc *crtc = arg; |
|---|
| 1257 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 714 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 715 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 1258 | 716 | struct drm_encoder *encoder; |
|---|
| 1259 | | - struct dpu_crtc_mixer *m; |
|---|
| 1260 | | - u32 i, misr_status; |
|---|
| 1261 | | - |
|---|
| 1262 | | - if (!crtc) { |
|---|
| 1263 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 1264 | | - return; |
|---|
| 1265 | | - } |
|---|
| 1266 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1267 | | - |
|---|
| 1268 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 1269 | | - |
|---|
| 1270 | | - trace_dpu_crtc_handle_power_event(DRMID(crtc), event_type); |
|---|
| 1271 | | - |
|---|
| 1272 | | - switch (event_type) { |
|---|
| 1273 | | - case DPU_POWER_EVENT_POST_ENABLE: |
|---|
| 1274 | | - /* restore encoder; crtc will be programmed during commit */ |
|---|
| 1275 | | - drm_for_each_encoder(encoder, crtc->dev) { |
|---|
| 1276 | | - if (encoder->crtc != crtc) |
|---|
| 1277 | | - continue; |
|---|
| 1278 | | - |
|---|
| 1279 | | - dpu_encoder_virt_restore(encoder); |
|---|
| 1280 | | - } |
|---|
| 1281 | | - |
|---|
| 1282 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
|---|
| 1283 | | - m = &dpu_crtc->mixers[i]; |
|---|
| 1284 | | - if (!m->hw_lm || !m->hw_lm->ops.setup_misr || |
|---|
| 1285 | | - !dpu_crtc->misr_enable) |
|---|
| 1286 | | - continue; |
|---|
| 1287 | | - |
|---|
| 1288 | | - m->hw_lm->ops.setup_misr(m->hw_lm, true, |
|---|
| 1289 | | - dpu_crtc->misr_frame_count); |
|---|
| 1290 | | - } |
|---|
| 1291 | | - break; |
|---|
| 1292 | | - case DPU_POWER_EVENT_PRE_DISABLE: |
|---|
| 1293 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
|---|
| 1294 | | - m = &dpu_crtc->mixers[i]; |
|---|
| 1295 | | - if (!m->hw_lm || !m->hw_lm->ops.collect_misr || |
|---|
| 1296 | | - !dpu_crtc->misr_enable) |
|---|
| 1297 | | - continue; |
|---|
| 1298 | | - |
|---|
| 1299 | | - misr_status = m->hw_lm->ops.collect_misr(m->hw_lm); |
|---|
| 1300 | | - dpu_crtc->misr_data[i] = misr_status ? misr_status : |
|---|
| 1301 | | - dpu_crtc->misr_data[i]; |
|---|
| 1302 | | - } |
|---|
| 1303 | | - break; |
|---|
| 1304 | | - case DPU_POWER_EVENT_POST_DISABLE: |
|---|
| 1305 | | - /** |
|---|
| 1306 | | - * Nothing to do. All the planes on the CRTC will be |
|---|
| 1307 | | - * programmed for every frame |
|---|
| 1308 | | - */ |
|---|
| 1309 | | - break; |
|---|
| 1310 | | - default: |
|---|
| 1311 | | - DPU_DEBUG("event:%d not handled\n", event_type); |
|---|
| 1312 | | - break; |
|---|
| 1313 | | - } |
|---|
| 1314 | | - |
|---|
| 1315 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 1316 | | -} |
|---|
| 1317 | | - |
|---|
| 1318 | | -static void dpu_crtc_disable(struct drm_crtc *crtc) |
|---|
| 1319 | | -{ |
|---|
| 1320 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 1321 | | - struct dpu_crtc_state *cstate; |
|---|
| 1322 | | - struct drm_display_mode *mode; |
|---|
| 1323 | | - struct drm_encoder *encoder; |
|---|
| 1324 | | - struct msm_drm_private *priv; |
|---|
| 1325 | | - int ret; |
|---|
| 1326 | 717 | unsigned long flags; |
|---|
| 1327 | | - |
|---|
| 1328 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { |
|---|
| 1329 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 1330 | | - return; |
|---|
| 1331 | | - } |
|---|
| 1332 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1333 | | - cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 1334 | | - mode = &cstate->base.adjusted_mode; |
|---|
| 1335 | | - priv = crtc->dev->dev_private; |
|---|
| 718 | + bool release_bandwidth = false; |
|---|
| 1336 | 719 | |
|---|
| 1337 | 720 | DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); |
|---|
| 1338 | | - |
|---|
| 1339 | | - if (dpu_kms_is_suspend_state(crtc->dev)) |
|---|
| 1340 | | - _dpu_crtc_set_suspend(crtc, true); |
|---|
| 1341 | 721 | |
|---|
| 1342 | 722 | /* Disable/save vblank irq handling */ |
|---|
| 1343 | 723 | drm_crtc_vblank_off(crtc); |
|---|
| 1344 | 724 | |
|---|
| 1345 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 725 | + drm_for_each_encoder_mask(encoder, crtc->dev, |
|---|
| 726 | + old_crtc_state->encoder_mask) { |
|---|
| 727 | + /* in video mode, we hold an extra bandwidth reference |
|---|
| 728 | + * as we cannot drop bandwidth at frame-done if any |
|---|
| 729 | + * crtc is being used in video mode. |
|---|
| 730 | + */ |
|---|
| 731 | + if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) |
|---|
| 732 | + release_bandwidth = true; |
|---|
| 733 | + dpu_encoder_assign_crtc(encoder, NULL); |
|---|
| 734 | + } |
|---|
| 1346 | 735 | |
|---|
| 1347 | 736 | /* wait for frame_event_done completion */ |
|---|
| 1348 | 737 | if (_dpu_crtc_wait_for_frame_done(crtc)) |
|---|
| .. | .. |
|---|
| 1351 | 740 | atomic_read(&dpu_crtc->frame_pending)); |
|---|
| 1352 | 741 | |
|---|
| 1353 | 742 | trace_dpu_crtc_disable(DRMID(crtc), false, dpu_crtc); |
|---|
| 1354 | | - if (dpu_crtc->enabled && !dpu_crtc->suspend && |
|---|
| 1355 | | - dpu_crtc->vblank_requested) { |
|---|
| 1356 | | - ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, false); |
|---|
| 1357 | | - if (ret) |
|---|
| 1358 | | - DPU_ERROR("%s vblank enable failed: %d\n", |
|---|
| 1359 | | - dpu_crtc->name, ret); |
|---|
| 1360 | | - } |
|---|
| 1361 | 743 | dpu_crtc->enabled = false; |
|---|
| 1362 | 744 | |
|---|
| 1363 | 745 | if (atomic_read(&dpu_crtc->frame_pending)) { |
|---|
| 1364 | 746 | trace_dpu_crtc_disable_frame_pending(DRMID(crtc), |
|---|
| 1365 | 747 | atomic_read(&dpu_crtc->frame_pending)); |
|---|
| 1366 | | - dpu_core_perf_crtc_release_bw(crtc); |
|---|
| 748 | + if (release_bandwidth) |
|---|
| 749 | + dpu_core_perf_crtc_release_bw(crtc); |
|---|
| 1367 | 750 | atomic_set(&dpu_crtc->frame_pending, 0); |
|---|
| 1368 | 751 | } |
|---|
| 1369 | 752 | |
|---|
| 1370 | 753 | dpu_core_perf_crtc_update(crtc, 0, true); |
|---|
| 1371 | 754 | |
|---|
| 1372 | | - drm_for_each_encoder(encoder, crtc->dev) { |
|---|
| 1373 | | - if (encoder->crtc != crtc) |
|---|
| 1374 | | - continue; |
|---|
| 755 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
|---|
| 1375 | 756 | dpu_encoder_register_frame_event_callback(encoder, NULL, NULL); |
|---|
| 1376 | | - } |
|---|
| 1377 | 757 | |
|---|
| 1378 | | - if (dpu_crtc->power_event) |
|---|
| 1379 | | - dpu_power_handle_unregister_event(dpu_crtc->phandle, |
|---|
| 1380 | | - dpu_crtc->power_event); |
|---|
| 1381 | | - |
|---|
| 1382 | | - memset(dpu_crtc->mixers, 0, sizeof(dpu_crtc->mixers)); |
|---|
| 1383 | | - dpu_crtc->num_mixers = 0; |
|---|
| 1384 | | - dpu_crtc->mixers_swapped = false; |
|---|
| 758 | + memset(cstate->mixers, 0, sizeof(cstate->mixers)); |
|---|
| 759 | + cstate->num_mixers = 0; |
|---|
| 1385 | 760 | |
|---|
| 1386 | 761 | /* disable clk & bw control until clk & bw properties are set */ |
|---|
| 1387 | 762 | cstate->bw_control = false; |
|---|
| 1388 | 763 | cstate->bw_split_vote = false; |
|---|
| 1389 | | - |
|---|
| 1390 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 1391 | 764 | |
|---|
| 1392 | 765 | if (crtc->state->event && !crtc->state->active) { |
|---|
| 1393 | 766 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
|---|
| .. | .. |
|---|
| 1395 | 768 | crtc->state->event = NULL; |
|---|
| 1396 | 769 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); |
|---|
| 1397 | 770 | } |
|---|
| 771 | + |
|---|
| 772 | + pm_runtime_put_sync(crtc->dev->dev); |
|---|
| 1398 | 773 | } |
|---|
| 1399 | 774 | |
|---|
| 1400 | 775 | static void dpu_crtc_enable(struct drm_crtc *crtc, |
|---|
| 1401 | 776 | struct drm_crtc_state *old_crtc_state) |
|---|
| 1402 | 777 | { |
|---|
| 1403 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 778 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1404 | 779 | struct drm_encoder *encoder; |
|---|
| 1405 | | - struct msm_drm_private *priv; |
|---|
| 1406 | | - int ret; |
|---|
| 780 | + bool request_bandwidth = false; |
|---|
| 1407 | 781 | |
|---|
| 1408 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
|---|
| 1409 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 1410 | | - return; |
|---|
| 1411 | | - } |
|---|
| 1412 | | - priv = crtc->dev->dev_private; |
|---|
| 782 | + pm_runtime_get_sync(crtc->dev->dev); |
|---|
| 1413 | 783 | |
|---|
| 1414 | 784 | DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); |
|---|
| 1415 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1416 | 785 | |
|---|
| 1417 | | - drm_for_each_encoder(encoder, crtc->dev) { |
|---|
| 1418 | | - if (encoder->crtc != crtc) |
|---|
| 1419 | | - continue; |
|---|
| 786 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { |
|---|
| 787 | + /* in video mode, we hold an extra bandwidth reference |
|---|
| 788 | + * as we cannot drop bandwidth at frame-done if any |
|---|
| 789 | + * crtc is being used in video mode. |
|---|
| 790 | + */ |
|---|
| 791 | + if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) |
|---|
| 792 | + request_bandwidth = true; |
|---|
| 1420 | 793 | dpu_encoder_register_frame_event_callback(encoder, |
|---|
| 1421 | 794 | dpu_crtc_frame_event_cb, (void *)crtc); |
|---|
| 1422 | 795 | } |
|---|
| 1423 | 796 | |
|---|
| 1424 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 797 | + if (request_bandwidth) |
|---|
| 798 | + atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); |
|---|
| 799 | + |
|---|
| 1425 | 800 | trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); |
|---|
| 1426 | | - if (!dpu_crtc->enabled && !dpu_crtc->suspend && |
|---|
| 1427 | | - dpu_crtc->vblank_requested) { |
|---|
| 1428 | | - ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, true); |
|---|
| 1429 | | - if (ret) |
|---|
| 1430 | | - DPU_ERROR("%s vblank enable failed: %d\n", |
|---|
| 1431 | | - dpu_crtc->name, ret); |
|---|
| 1432 | | - } |
|---|
| 1433 | 801 | dpu_crtc->enabled = true; |
|---|
| 1434 | 802 | |
|---|
| 1435 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 803 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
|---|
| 804 | + dpu_encoder_assign_crtc(encoder, crtc); |
|---|
| 1436 | 805 | |
|---|
| 1437 | 806 | /* Enable/restore vblank irq handling */ |
|---|
| 1438 | 807 | drm_crtc_vblank_on(crtc); |
|---|
| 1439 | | - |
|---|
| 1440 | | - dpu_crtc->power_event = dpu_power_handle_register_event( |
|---|
| 1441 | | - dpu_crtc->phandle, |
|---|
| 1442 | | - DPU_POWER_EVENT_POST_ENABLE | DPU_POWER_EVENT_POST_DISABLE | |
|---|
| 1443 | | - DPU_POWER_EVENT_PRE_DISABLE, |
|---|
| 1444 | | - dpu_crtc_handle_power_event, crtc, dpu_crtc->name); |
|---|
| 1445 | | - |
|---|
| 1446 | 808 | } |
|---|
| 1447 | 809 | |
|---|
| 1448 | 810 | struct plane_state { |
|---|
| .. | .. |
|---|
| 1455 | 817 | static int dpu_crtc_atomic_check(struct drm_crtc *crtc, |
|---|
| 1456 | 818 | struct drm_crtc_state *state) |
|---|
| 1457 | 819 | { |
|---|
| 1458 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 820 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 821 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); |
|---|
| 1459 | 822 | struct plane_state *pstates; |
|---|
| 1460 | | - struct dpu_crtc_state *cstate; |
|---|
| 1461 | 823 | |
|---|
| 1462 | 824 | const struct drm_plane_state *pstate; |
|---|
| 1463 | 825 | struct drm_plane *plane; |
|---|
| 1464 | 826 | struct drm_display_mode *mode; |
|---|
| 1465 | 827 | |
|---|
| 1466 | | - int cnt = 0, rc = 0, mixer_width, i, z_pos; |
|---|
| 828 | + int cnt = 0, rc = 0, mixer_width = 0, i, z_pos; |
|---|
| 1467 | 829 | |
|---|
| 1468 | 830 | struct dpu_multirect_plane_states multirect_plane[DPU_STAGE_MAX * 2]; |
|---|
| 1469 | 831 | int multirect_count = 0; |
|---|
| .. | .. |
|---|
| 1471 | 833 | int left_zpos_cnt = 0, right_zpos_cnt = 0; |
|---|
| 1472 | 834 | struct drm_rect crtc_rect = { 0 }; |
|---|
| 1473 | 835 | |
|---|
| 1474 | | - if (!crtc) { |
|---|
| 1475 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 1476 | | - return -EINVAL; |
|---|
| 1477 | | - } |
|---|
| 1478 | | - |
|---|
| 1479 | 836 | pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL); |
|---|
| 1480 | | - |
|---|
| 1481 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1482 | | - cstate = to_dpu_crtc_state(state); |
|---|
| 837 | + if (!pstates) |
|---|
| 838 | + return -ENOMEM; |
|---|
| 1483 | 839 | |
|---|
| 1484 | 840 | if (!state->enable || !state->active) { |
|---|
| 1485 | 841 | DPU_DEBUG("crtc%d -> enable %d, active %d, skip atomic_check\n", |
|---|
| .. | .. |
|---|
| 1496 | 852 | |
|---|
| 1497 | 853 | memset(pipe_staged, 0, sizeof(pipe_staged)); |
|---|
| 1498 | 854 | |
|---|
| 1499 | | - mixer_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, mode); |
|---|
| 855 | + if (cstate->num_mixers) { |
|---|
| 856 | + mixer_width = mode->hdisplay / cstate->num_mixers; |
|---|
| 1500 | 857 | |
|---|
| 1501 | | - _dpu_crtc_setup_lm_bounds(crtc, state); |
|---|
| 858 | + _dpu_crtc_setup_lm_bounds(crtc, state); |
|---|
| 859 | + } |
|---|
| 1502 | 860 | |
|---|
| 1503 | 861 | crtc_rect.x2 = mode->hdisplay; |
|---|
| 1504 | 862 | crtc_rect.y2 = mode->vdisplay; |
|---|
| .. | .. |
|---|
| 1608 | 966 | } |
|---|
| 1609 | 967 | } |
|---|
| 1610 | 968 | |
|---|
| 969 | + atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); |
|---|
| 970 | + |
|---|
| 1611 | 971 | rc = dpu_core_perf_crtc_check(crtc, state); |
|---|
| 1612 | 972 | if (rc) { |
|---|
| 1613 | 973 | DPU_ERROR("crtc%d failed performance check %d\n", |
|---|
| .. | .. |
|---|
| 1678 | 1038 | } |
|---|
| 1679 | 1039 | |
|---|
| 1680 | 1040 | end: |
|---|
| 1681 | | - _dpu_crtc_rp_free_unused(&cstate->rp); |
|---|
| 1682 | 1041 | kfree(pstates); |
|---|
| 1683 | 1042 | return rc; |
|---|
| 1684 | 1043 | } |
|---|
| 1685 | 1044 | |
|---|
| 1686 | 1045 | int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) |
|---|
| 1687 | 1046 | { |
|---|
| 1688 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 1689 | | - int ret; |
|---|
| 1047 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1048 | + struct drm_encoder *enc; |
|---|
| 1690 | 1049 | |
|---|
| 1691 | | - if (!crtc) { |
|---|
| 1692 | | - DPU_ERROR("invalid crtc\n"); |
|---|
| 1693 | | - return -EINVAL; |
|---|
| 1694 | | - } |
|---|
| 1695 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1696 | | - |
|---|
| 1697 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 1698 | 1050 | trace_dpu_crtc_vblank(DRMID(&dpu_crtc->base), en, dpu_crtc); |
|---|
| 1699 | | - if (dpu_crtc->enabled && !dpu_crtc->suspend) { |
|---|
| 1700 | | - ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, en); |
|---|
| 1701 | | - if (ret) |
|---|
| 1702 | | - DPU_ERROR("%s vblank enable failed: %d\n", |
|---|
| 1703 | | - dpu_crtc->name, ret); |
|---|
| 1051 | + |
|---|
| 1052 | + /* |
|---|
| 1053 | + * Normally we would iterate through encoder_mask in crtc state to find |
|---|
| 1054 | + * attached encoders. In this case, we might be disabling vblank _after_ |
|---|
| 1055 | + * encoder_mask has been cleared. |
|---|
| 1056 | + * |
|---|
| 1057 | + * Instead, we "assign" a crtc to the encoder in enable and clear it in |
|---|
| 1058 | + * disable (which is also after encoder_mask is cleared). So instead of |
|---|
| 1059 | + * using encoder mask, we'll ask the encoder to toggle itself iff it's |
|---|
| 1060 | + * currently assigned to our crtc. |
|---|
| 1061 | + * |
|---|
| 1062 | + * Note also that this function cannot be called while crtc is disabled |
|---|
| 1063 | + * since we use drm_crtc_vblank_on/off. So we don't need to worry |
|---|
| 1064 | + * about the assigned crtcs being inconsistent with the current state |
|---|
| 1065 | + * (which means no need to worry about modeset locks). |
|---|
| 1066 | + */ |
|---|
| 1067 | + list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { |
|---|
| 1068 | + trace_dpu_crtc_vblank_enable(DRMID(crtc), DRMID(enc), en, |
|---|
| 1069 | + dpu_crtc); |
|---|
| 1070 | + |
|---|
| 1071 | + dpu_encoder_toggle_vblank_for_crtc(enc, crtc, en); |
|---|
| 1704 | 1072 | } |
|---|
| 1705 | | - dpu_crtc->vblank_requested = en; |
|---|
| 1706 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 1707 | 1073 | |
|---|
| 1708 | 1074 | return 0; |
|---|
| 1709 | 1075 | } |
|---|
| .. | .. |
|---|
| 1724 | 1090 | |
|---|
| 1725 | 1091 | int i, out_width; |
|---|
| 1726 | 1092 | |
|---|
| 1727 | | - if (!s || !s->private) |
|---|
| 1728 | | - return -EINVAL; |
|---|
| 1729 | | - |
|---|
| 1730 | 1093 | dpu_crtc = s->private; |
|---|
| 1731 | 1094 | crtc = &dpu_crtc->base; |
|---|
| 1095 | + |
|---|
| 1096 | + drm_modeset_lock_all(crtc->dev); |
|---|
| 1732 | 1097 | cstate = to_dpu_crtc_state(crtc->state); |
|---|
| 1733 | 1098 | |
|---|
| 1734 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 1735 | 1099 | mode = &crtc->state->adjusted_mode; |
|---|
| 1736 | | - out_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, mode); |
|---|
| 1100 | + out_width = mode->hdisplay / cstate->num_mixers; |
|---|
| 1737 | 1101 | |
|---|
| 1738 | 1102 | seq_printf(s, "crtc:%d width:%d height:%d\n", crtc->base.id, |
|---|
| 1739 | 1103 | mode->hdisplay, mode->vdisplay); |
|---|
| 1740 | 1104 | |
|---|
| 1741 | 1105 | seq_puts(s, "\n"); |
|---|
| 1742 | 1106 | |
|---|
| 1743 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
|---|
| 1744 | | - m = &dpu_crtc->mixers[i]; |
|---|
| 1745 | | - if (!m->hw_lm) |
|---|
| 1746 | | - seq_printf(s, "\tmixer[%d] has no lm\n", i); |
|---|
| 1747 | | - else if (!m->hw_ctl) |
|---|
| 1748 | | - seq_printf(s, "\tmixer[%d] has no ctl\n", i); |
|---|
| 1749 | | - else |
|---|
| 1750 | | - seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", |
|---|
| 1751 | | - m->hw_lm->idx - LM_0, m->hw_ctl->idx - CTL_0, |
|---|
| 1752 | | - out_width, mode->vdisplay); |
|---|
| 1107 | + for (i = 0; i < cstate->num_mixers; ++i) { |
|---|
| 1108 | + m = &cstate->mixers[i]; |
|---|
| 1109 | + seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", |
|---|
| 1110 | + m->hw_lm->idx - LM_0, m->lm_ctl->idx - CTL_0, |
|---|
| 1111 | + out_width, mode->vdisplay); |
|---|
| 1753 | 1112 | } |
|---|
| 1754 | 1113 | |
|---|
| 1755 | 1114 | seq_puts(s, "\n"); |
|---|
| .. | .. |
|---|
| 1818 | 1177 | dpu_crtc->vblank_cb_time = ktime_set(0, 0); |
|---|
| 1819 | 1178 | } |
|---|
| 1820 | 1179 | |
|---|
| 1821 | | - seq_printf(s, "vblank_enable:%d\n", dpu_crtc->vblank_requested); |
|---|
| 1822 | | - |
|---|
| 1823 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 1180 | + drm_modeset_unlock_all(crtc->dev); |
|---|
| 1824 | 1181 | |
|---|
| 1825 | 1182 | return 0; |
|---|
| 1826 | 1183 | } |
|---|
| 1827 | 1184 | |
|---|
| 1828 | | -static int _dpu_debugfs_status_open(struct inode *inode, struct file *file) |
|---|
| 1829 | | -{ |
|---|
| 1830 | | - return single_open(file, _dpu_debugfs_status_show, inode->i_private); |
|---|
| 1831 | | -} |
|---|
| 1832 | | - |
|---|
| 1833 | | -static ssize_t _dpu_crtc_misr_setup(struct file *file, |
|---|
| 1834 | | - const char __user *user_buf, size_t count, loff_t *ppos) |
|---|
| 1835 | | -{ |
|---|
| 1836 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 1837 | | - struct dpu_crtc_mixer *m; |
|---|
| 1838 | | - int i = 0, rc; |
|---|
| 1839 | | - char buf[MISR_BUFF_SIZE + 1]; |
|---|
| 1840 | | - u32 frame_count, enable; |
|---|
| 1841 | | - size_t buff_copy; |
|---|
| 1842 | | - |
|---|
| 1843 | | - if (!file || !file->private_data) |
|---|
| 1844 | | - return -EINVAL; |
|---|
| 1845 | | - |
|---|
| 1846 | | - dpu_crtc = file->private_data; |
|---|
| 1847 | | - buff_copy = min_t(size_t, count, MISR_BUFF_SIZE); |
|---|
| 1848 | | - if (copy_from_user(buf, user_buf, buff_copy)) { |
|---|
| 1849 | | - DPU_ERROR("buffer copy failed\n"); |
|---|
| 1850 | | - return -EINVAL; |
|---|
| 1851 | | - } |
|---|
| 1852 | | - |
|---|
| 1853 | | - buf[buff_copy] = 0; /* end of string */ |
|---|
| 1854 | | - |
|---|
| 1855 | | - if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) |
|---|
| 1856 | | - return -EINVAL; |
|---|
| 1857 | | - |
|---|
| 1858 | | - rc = _dpu_crtc_power_enable(dpu_crtc, true); |
|---|
| 1859 | | - if (rc) |
|---|
| 1860 | | - return rc; |
|---|
| 1861 | | - |
|---|
| 1862 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 1863 | | - dpu_crtc->misr_enable = enable; |
|---|
| 1864 | | - dpu_crtc->misr_frame_count = frame_count; |
|---|
| 1865 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
|---|
| 1866 | | - dpu_crtc->misr_data[i] = 0; |
|---|
| 1867 | | - m = &dpu_crtc->mixers[i]; |
|---|
| 1868 | | - if (!m->hw_lm || !m->hw_lm->ops.setup_misr) |
|---|
| 1869 | | - continue; |
|---|
| 1870 | | - |
|---|
| 1871 | | - m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count); |
|---|
| 1872 | | - } |
|---|
| 1873 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 1874 | | - _dpu_crtc_power_enable(dpu_crtc, false); |
|---|
| 1875 | | - |
|---|
| 1876 | | - return count; |
|---|
| 1877 | | -} |
|---|
| 1878 | | - |
|---|
| 1879 | | -static ssize_t _dpu_crtc_misr_read(struct file *file, |
|---|
| 1880 | | - char __user *user_buff, size_t count, loff_t *ppos) |
|---|
| 1881 | | -{ |
|---|
| 1882 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 1883 | | - struct dpu_crtc_mixer *m; |
|---|
| 1884 | | - int i = 0, rc; |
|---|
| 1885 | | - u32 misr_status; |
|---|
| 1886 | | - ssize_t len = 0; |
|---|
| 1887 | | - char buf[MISR_BUFF_SIZE + 1] = {'\0'}; |
|---|
| 1888 | | - |
|---|
| 1889 | | - if (*ppos) |
|---|
| 1890 | | - return 0; |
|---|
| 1891 | | - |
|---|
| 1892 | | - if (!file || !file->private_data) |
|---|
| 1893 | | - return -EINVAL; |
|---|
| 1894 | | - |
|---|
| 1895 | | - dpu_crtc = file->private_data; |
|---|
| 1896 | | - rc = _dpu_crtc_power_enable(dpu_crtc, true); |
|---|
| 1897 | | - if (rc) |
|---|
| 1898 | | - return rc; |
|---|
| 1899 | | - |
|---|
| 1900 | | - mutex_lock(&dpu_crtc->crtc_lock); |
|---|
| 1901 | | - if (!dpu_crtc->misr_enable) { |
|---|
| 1902 | | - len += snprintf(buf + len, MISR_BUFF_SIZE - len, |
|---|
| 1903 | | - "disabled\n"); |
|---|
| 1904 | | - goto buff_check; |
|---|
| 1905 | | - } |
|---|
| 1906 | | - |
|---|
| 1907 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
|---|
| 1908 | | - m = &dpu_crtc->mixers[i]; |
|---|
| 1909 | | - if (!m->hw_lm || !m->hw_lm->ops.collect_misr) |
|---|
| 1910 | | - continue; |
|---|
| 1911 | | - |
|---|
| 1912 | | - misr_status = m->hw_lm->ops.collect_misr(m->hw_lm); |
|---|
| 1913 | | - dpu_crtc->misr_data[i] = misr_status ? misr_status : |
|---|
| 1914 | | - dpu_crtc->misr_data[i]; |
|---|
| 1915 | | - len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n", |
|---|
| 1916 | | - m->hw_lm->idx - LM_0); |
|---|
| 1917 | | - len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n", |
|---|
| 1918 | | - dpu_crtc->misr_data[i]); |
|---|
| 1919 | | - } |
|---|
| 1920 | | - |
|---|
| 1921 | | -buff_check: |
|---|
| 1922 | | - if (count <= len) { |
|---|
| 1923 | | - len = 0; |
|---|
| 1924 | | - goto end; |
|---|
| 1925 | | - } |
|---|
| 1926 | | - |
|---|
| 1927 | | - if (copy_to_user(user_buff, buf, len)) { |
|---|
| 1928 | | - len = -EFAULT; |
|---|
| 1929 | | - goto end; |
|---|
| 1930 | | - } |
|---|
| 1931 | | - |
|---|
| 1932 | | - *ppos += len; /* increase offset */ |
|---|
| 1933 | | - |
|---|
| 1934 | | -end: |
|---|
| 1935 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
|---|
| 1936 | | - _dpu_crtc_power_enable(dpu_crtc, false); |
|---|
| 1937 | | - return len; |
|---|
| 1938 | | -} |
|---|
| 1939 | | - |
|---|
| 1940 | | -#define DEFINE_DPU_DEBUGFS_SEQ_FOPS(__prefix) \ |
|---|
| 1941 | | -static int __prefix ## _open(struct inode *inode, struct file *file) \ |
|---|
| 1942 | | -{ \ |
|---|
| 1943 | | - return single_open(file, __prefix ## _show, inode->i_private); \ |
|---|
| 1944 | | -} \ |
|---|
| 1945 | | -static const struct file_operations __prefix ## _fops = { \ |
|---|
| 1946 | | - .owner = THIS_MODULE, \ |
|---|
| 1947 | | - .open = __prefix ## _open, \ |
|---|
| 1948 | | - .release = single_release, \ |
|---|
| 1949 | | - .read = seq_read, \ |
|---|
| 1950 | | - .llseek = seq_lseek, \ |
|---|
| 1951 | | -} |
|---|
| 1185 | +DEFINE_SHOW_ATTRIBUTE(_dpu_debugfs_status); |
|---|
| 1952 | 1186 | |
|---|
| 1953 | 1187 | static int dpu_crtc_debugfs_state_show(struct seq_file *s, void *v) |
|---|
| 1954 | 1188 | { |
|---|
| 1955 | 1189 | struct drm_crtc *crtc = (struct drm_crtc *) s->private; |
|---|
| 1956 | 1190 | struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1957 | | - struct dpu_crtc_res *res; |
|---|
| 1958 | | - struct dpu_crtc_respool *rp; |
|---|
| 1959 | | - int i; |
|---|
| 1960 | 1191 | |
|---|
| 1961 | 1192 | seq_printf(s, "client type: %d\n", dpu_crtc_get_client_type(crtc)); |
|---|
| 1962 | 1193 | seq_printf(s, "intf_mode: %d\n", dpu_crtc_get_intf_mode(crtc)); |
|---|
| 1963 | 1194 | seq_printf(s, "core_clk_rate: %llu\n", |
|---|
| 1964 | 1195 | dpu_crtc->cur_perf.core_clk_rate); |
|---|
| 1965 | | - for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; |
|---|
| 1966 | | - i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { |
|---|
| 1967 | | - seq_printf(s, "bw_ctl[%s]: %llu\n", |
|---|
| 1968 | | - dpu_power_handle_get_dbus_name(i), |
|---|
| 1969 | | - dpu_crtc->cur_perf.bw_ctl[i]); |
|---|
| 1970 | | - seq_printf(s, "max_per_pipe_ib[%s]: %llu\n", |
|---|
| 1971 | | - dpu_power_handle_get_dbus_name(i), |
|---|
| 1972 | | - dpu_crtc->cur_perf.max_per_pipe_ib[i]); |
|---|
| 1973 | | - } |
|---|
| 1974 | | - |
|---|
| 1975 | | - mutex_lock(&dpu_crtc->rp_lock); |
|---|
| 1976 | | - list_for_each_entry(rp, &dpu_crtc->rp_head, rp_list) { |
|---|
| 1977 | | - seq_printf(s, "rp.%d: ", rp->sequence_id); |
|---|
| 1978 | | - list_for_each_entry(res, &rp->res_list, list) |
|---|
| 1979 | | - seq_printf(s, "0x%x/0x%llx/%pK/%d ", |
|---|
| 1980 | | - res->type, res->tag, res->val, |
|---|
| 1981 | | - atomic_read(&res->refcount)); |
|---|
| 1982 | | - seq_puts(s, "\n"); |
|---|
| 1983 | | - } |
|---|
| 1984 | | - mutex_unlock(&dpu_crtc->rp_lock); |
|---|
| 1196 | + seq_printf(s, "bw_ctl: %llu\n", dpu_crtc->cur_perf.bw_ctl); |
|---|
| 1197 | + seq_printf(s, "max_per_pipe_ib: %llu\n", |
|---|
| 1198 | + dpu_crtc->cur_perf.max_per_pipe_ib); |
|---|
| 1985 | 1199 | |
|---|
| 1986 | 1200 | return 0; |
|---|
| 1987 | 1201 | } |
|---|
| 1988 | | -DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_crtc_debugfs_state); |
|---|
| 1202 | +DEFINE_SHOW_ATTRIBUTE(dpu_crtc_debugfs_state); |
|---|
| 1989 | 1203 | |
|---|
| 1990 | 1204 | static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) |
|---|
| 1991 | 1205 | { |
|---|
| 1992 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 1993 | | - struct dpu_kms *dpu_kms; |
|---|
| 1994 | | - |
|---|
| 1995 | | - static const struct file_operations debugfs_status_fops = { |
|---|
| 1996 | | - .open = _dpu_debugfs_status_open, |
|---|
| 1997 | | - .read = seq_read, |
|---|
| 1998 | | - .llseek = seq_lseek, |
|---|
| 1999 | | - .release = single_release, |
|---|
| 2000 | | - }; |
|---|
| 2001 | | - static const struct file_operations debugfs_misr_fops = { |
|---|
| 2002 | | - .open = simple_open, |
|---|
| 2003 | | - .read = _dpu_crtc_misr_read, |
|---|
| 2004 | | - .write = _dpu_crtc_misr_setup, |
|---|
| 2005 | | - }; |
|---|
| 2006 | | - |
|---|
| 2007 | | - if (!crtc) |
|---|
| 2008 | | - return -EINVAL; |
|---|
| 2009 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 2010 | | - |
|---|
| 2011 | | - dpu_kms = _dpu_crtc_get_kms(crtc); |
|---|
| 2012 | | - if (!dpu_kms) |
|---|
| 2013 | | - return -EINVAL; |
|---|
| 1206 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 2014 | 1207 | |
|---|
| 2015 | 1208 | dpu_crtc->debugfs_root = debugfs_create_dir(dpu_crtc->name, |
|---|
| 2016 | 1209 | crtc->dev->primary->debugfs_root); |
|---|
| 2017 | | - if (!dpu_crtc->debugfs_root) |
|---|
| 2018 | | - return -ENOMEM; |
|---|
| 2019 | 1210 | |
|---|
| 2020 | | - /* don't error check these */ |
|---|
| 2021 | 1211 | debugfs_create_file("status", 0400, |
|---|
| 2022 | 1212 | dpu_crtc->debugfs_root, |
|---|
| 2023 | | - dpu_crtc, &debugfs_status_fops); |
|---|
| 1213 | + dpu_crtc, &_dpu_debugfs_status_fops); |
|---|
| 2024 | 1214 | debugfs_create_file("state", 0600, |
|---|
| 2025 | 1215 | dpu_crtc->debugfs_root, |
|---|
| 2026 | 1216 | &dpu_crtc->base, |
|---|
| 2027 | 1217 | &dpu_crtc_debugfs_state_fops); |
|---|
| 2028 | | - debugfs_create_file("misr_data", 0600, dpu_crtc->debugfs_root, |
|---|
| 2029 | | - dpu_crtc, &debugfs_misr_fops); |
|---|
| 2030 | 1218 | |
|---|
| 2031 | 1219 | return 0; |
|---|
| 2032 | | -} |
|---|
| 2033 | | - |
|---|
| 2034 | | -static void _dpu_crtc_destroy_debugfs(struct drm_crtc *crtc) |
|---|
| 2035 | | -{ |
|---|
| 2036 | | - struct dpu_crtc *dpu_crtc; |
|---|
| 2037 | | - |
|---|
| 2038 | | - if (!crtc) |
|---|
| 2039 | | - return; |
|---|
| 2040 | | - dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 2041 | | - debugfs_remove_recursive(dpu_crtc->debugfs_root); |
|---|
| 2042 | 1220 | } |
|---|
| 2043 | 1221 | #else |
|---|
| 2044 | 1222 | static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) |
|---|
| 2045 | 1223 | { |
|---|
| 2046 | 1224 | return 0; |
|---|
| 2047 | | -} |
|---|
| 2048 | | - |
|---|
| 2049 | | -static void _dpu_crtc_destroy_debugfs(struct drm_crtc *crtc) |
|---|
| 2050 | | -{ |
|---|
| 2051 | 1225 | } |
|---|
| 2052 | 1226 | #endif /* CONFIG_DEBUG_FS */ |
|---|
| 2053 | 1227 | |
|---|
| .. | .. |
|---|
| 2058 | 1232 | |
|---|
| 2059 | 1233 | static void dpu_crtc_early_unregister(struct drm_crtc *crtc) |
|---|
| 2060 | 1234 | { |
|---|
| 2061 | | - _dpu_crtc_destroy_debugfs(crtc); |
|---|
| 1235 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
|---|
| 1236 | + |
|---|
| 1237 | + debugfs_remove_recursive(dpu_crtc->debugfs_root); |
|---|
| 2062 | 1238 | } |
|---|
| 2063 | 1239 | |
|---|
| 2064 | 1240 | static const struct drm_crtc_funcs dpu_crtc_funcs = { |
|---|
| .. | .. |
|---|
| 2070 | 1246 | .atomic_destroy_state = dpu_crtc_destroy_state, |
|---|
| 2071 | 1247 | .late_register = dpu_crtc_late_register, |
|---|
| 2072 | 1248 | .early_unregister = dpu_crtc_early_unregister, |
|---|
| 1249 | + .enable_vblank = msm_crtc_enable_vblank, |
|---|
| 1250 | + .disable_vblank = msm_crtc_disable_vblank, |
|---|
| 2073 | 1251 | }; |
|---|
| 2074 | 1252 | |
|---|
| 2075 | 1253 | static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { |
|---|
| 2076 | | - .disable = dpu_crtc_disable, |
|---|
| 1254 | + .atomic_disable = dpu_crtc_disable, |
|---|
| 2077 | 1255 | .atomic_enable = dpu_crtc_enable, |
|---|
| 2078 | 1256 | .atomic_check = dpu_crtc_atomic_check, |
|---|
| 2079 | 1257 | .atomic_begin = dpu_crtc_atomic_begin, |
|---|
| .. | .. |
|---|
| 2081 | 1259 | }; |
|---|
| 2082 | 1260 | |
|---|
| 2083 | 1261 | /* initialize crtc */ |
|---|
| 2084 | | -struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane) |
|---|
| 1262 | +struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, |
|---|
| 1263 | + struct drm_plane *cursor) |
|---|
| 2085 | 1264 | { |
|---|
| 1265 | + struct msm_drm_private *priv = dev->dev_private; |
|---|
| 1266 | + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); |
|---|
| 2086 | 1267 | struct drm_crtc *crtc = NULL; |
|---|
| 2087 | 1268 | struct dpu_crtc *dpu_crtc = NULL; |
|---|
| 2088 | | - struct msm_drm_private *priv = NULL; |
|---|
| 2089 | | - struct dpu_kms *kms = NULL; |
|---|
| 2090 | 1269 | int i; |
|---|
| 2091 | | - |
|---|
| 2092 | | - priv = dev->dev_private; |
|---|
| 2093 | | - kms = to_dpu_kms(priv->kms); |
|---|
| 2094 | 1270 | |
|---|
| 2095 | 1271 | dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL); |
|---|
| 2096 | 1272 | if (!dpu_crtc) |
|---|
| .. | .. |
|---|
| 2099 | 1275 | crtc = &dpu_crtc->base; |
|---|
| 2100 | 1276 | crtc->dev = dev; |
|---|
| 2101 | 1277 | |
|---|
| 2102 | | - mutex_init(&dpu_crtc->crtc_lock); |
|---|
| 2103 | 1278 | spin_lock_init(&dpu_crtc->spin_lock); |
|---|
| 2104 | 1279 | atomic_set(&dpu_crtc->frame_pending, 0); |
|---|
| 2105 | | - |
|---|
| 2106 | | - mutex_init(&dpu_crtc->rp_lock); |
|---|
| 2107 | | - INIT_LIST_HEAD(&dpu_crtc->rp_head); |
|---|
| 2108 | 1280 | |
|---|
| 2109 | 1281 | init_completion(&dpu_crtc->frame_done_comp); |
|---|
| 2110 | 1282 | |
|---|
| .. | .. |
|---|
| 2118 | 1290 | dpu_crtc_frame_event_work); |
|---|
| 2119 | 1291 | } |
|---|
| 2120 | 1292 | |
|---|
| 2121 | | - drm_crtc_init_with_planes(dev, crtc, plane, NULL, &dpu_crtc_funcs, |
|---|
| 1293 | + drm_crtc_init_with_planes(dev, crtc, plane, cursor, &dpu_crtc_funcs, |
|---|
| 2122 | 1294 | NULL); |
|---|
| 2123 | 1295 | |
|---|
| 2124 | 1296 | drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); |
|---|
| 1297 | + |
|---|
| 1298 | + if (dpu_kms->catalog->dspp_count) |
|---|
| 1299 | + drm_crtc_enable_color_mgmt(crtc, 0, true, 0); |
|---|
| 2125 | 1300 | |
|---|
| 2126 | 1301 | /* save user friendly CRTC name for later */ |
|---|
| 2127 | 1302 | snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); |
|---|
| 2128 | 1303 | |
|---|
| 2129 | 1304 | /* initialize event handling */ |
|---|
| 2130 | 1305 | spin_lock_init(&dpu_crtc->event_lock); |
|---|
| 2131 | | - |
|---|
| 2132 | | - dpu_crtc->phandle = &kms->phandle; |
|---|
| 2133 | 1306 | |
|---|
| 2134 | 1307 | DPU_DEBUG("%s: successfully initialized crtc\n", dpu_crtc->name); |
|---|
| 2135 | 1308 | return crtc; |
|---|