1 /* 2 * Copyright (C) 2014-2018 The Linux Foundation. All rights reserved. 3 * Copyright (C) 2013 Red Hat 4 * 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 */ 18 19 #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ 20 21 #include <linux/debugfs.h> 22 #include <linux/dma-buf.h> 23 24 #include <drm/drm_atomic_uapi.h> 25 26 #include "msm_drv.h" 27 #include "dpu_kms.h" 28 #include "dpu_formats.h" 29 #include "dpu_hw_sspp.h" 30 #include "dpu_hw_catalog_format.h" 31 #include "dpu_trace.h" 32 #include "dpu_crtc.h" 33 #include "dpu_vbif.h" 34 #include "dpu_plane.h" 35 36 #define DPU_DEBUG_PLANE(pl, fmt, ...) DPU_DEBUG("plane%d " fmt,\ 37 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__) 38 39 #define DPU_ERROR_PLANE(pl, fmt, ...) DPU_ERROR("plane%d " fmt,\ 40 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__) 41 42 #define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci)) 43 #define PHASE_STEP_SHIFT 21 44 #define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT)) 45 #define PHASE_RESIDUAL 15 46 47 #define SHARP_STRENGTH_DEFAULT 32 48 #define SHARP_EDGE_THR_DEFAULT 112 49 #define SHARP_SMOOTH_THR_DEFAULT 8 50 #define SHARP_NOISE_THR_DEFAULT 2 51 52 #define DPU_NAME_SIZE 12 53 54 #define DPU_PLANE_COLOR_FILL_FLAG BIT(31) 55 #define DPU_ZPOS_MAX 255 56 57 /* multirect rect index */ 58 enum { 59 R0, 60 R1, 61 R_MAX 62 }; 63 64 #define DPU_QSEED3_DEFAULT_PRELOAD_H 0x4 65 #define DPU_QSEED3_DEFAULT_PRELOAD_V 0x3 66 67 #define DEFAULT_REFRESH_RATE 60 68 69 /** 70 * enum dpu_plane_qos - Different qos configurations for each pipe 71 * 72 * @DPU_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe. 73 * @DPU_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe. 74 * this configuration is mutually exclusive from VBLANK_CTRL. 75 * @DPU_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe. 76 */ 77 enum dpu_plane_qos { 78 DPU_PLANE_QOS_VBLANK_CTRL = BIT(0), 79 DPU_PLANE_QOS_VBLANK_AMORTIZE = BIT(1), 80 DPU_PLANE_QOS_PANIC_CTRL = BIT(2), 81 }; 82 83 /* 84 * struct dpu_plane - local dpu plane structure 85 * @aspace: address space pointer 86 * @csc_ptr: Points to dpu_csc_cfg structure to use for current 87 * @mplane_list: List of multirect planes of the same pipe 88 * @catalog: Points to dpu catalog structure 89 * @revalidate: force revalidation of all the plane properties 90 */ 91 struct dpu_plane { 92 struct drm_plane base; 93 94 struct mutex lock; 95 96 enum dpu_sspp pipe; 97 uint32_t features; /* capabilities from catalog */ 98 uint32_t nformats; 99 uint32_t formats[64]; 100 101 struct dpu_hw_pipe *pipe_hw; 102 struct dpu_hw_pipe_cfg pipe_cfg; 103 struct dpu_hw_pipe_qos_cfg pipe_qos_cfg; 104 uint32_t color_fill; 105 bool is_error; 106 bool is_rt_pipe; 107 bool is_virtual; 108 struct list_head mplane_list; 109 struct dpu_mdss_cfg *catalog; 110 111 struct dpu_csc_cfg *csc_ptr; 112 113 const struct dpu_sspp_sub_blks *pipe_sblk; 114 char pipe_name[DPU_NAME_SIZE]; 115 116 /* debugfs related stuff */ 117 struct dentry *debugfs_root; 118 struct dpu_debugfs_regset32 debugfs_src; 119 struct dpu_debugfs_regset32 debugfs_scaler; 120 struct dpu_debugfs_regset32 debugfs_csc; 121 bool debugfs_default_scale; 122 }; 123 124 #define to_dpu_plane(x) container_of(x, struct dpu_plane, base) 125 126 static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane) 127 { 128 struct msm_drm_private *priv = plane->dev->dev_private; 129 130 return to_dpu_kms(priv->kms); 131 } 132 133 /** 134 * _dpu_plane_calc_fill_level - calculate fill level of the given source format 135 * @plane: Pointer to drm plane 136 * @fmt: Pointer to source buffer format 137 * @src_wdith: width of source buffer 138 * Return: fill level corresponding to the source buffer/format or 0 if error 139 */ 140 static inline int _dpu_plane_calc_fill_level(struct drm_plane *plane, 141 const struct dpu_format *fmt, u32 src_width) 142 { 143 struct dpu_plane *pdpu, *tmp; 144 struct dpu_plane_state *pstate; 145 u32 fixed_buff_size; 146 u32 total_fl; 147 148 if (!fmt || !plane->state || !src_width || !fmt->bpp) { 149 DPU_ERROR("invalid arguments\n"); 150 return 0; 151 } 152 153 pdpu = to_dpu_plane(plane); 154 pstate = to_dpu_plane_state(plane->state); 155 fixed_buff_size = pdpu->pipe_sblk->common->pixel_ram_size; 156 157 list_for_each_entry(tmp, &pdpu->mplane_list, mplane_list) { 158 if (!tmp->base.state->visible) 159 continue; 160 DPU_DEBUG("plane%d/%d src_width:%d/%d\n", 161 pdpu->base.base.id, tmp->base.base.id, 162 src_width, 163 drm_rect_width(&tmp->pipe_cfg.src_rect)); 164 src_width = max_t(u32, src_width, 165 drm_rect_width(&tmp->pipe_cfg.src_rect)); 166 } 167 168 if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) { 169 if (fmt->chroma_sample == DPU_CHROMA_420) { 170 /* NV12 */ 171 total_fl = (fixed_buff_size / 2) / 172 ((src_width + 32) * fmt->bpp); 173 } else { 174 /* non NV12 */ 175 total_fl = (fixed_buff_size / 2) * 2 / 176 ((src_width + 32) * fmt->bpp); 177 } 178 } else { 179 if (pstate->multirect_mode == DPU_SSPP_MULTIRECT_PARALLEL) { 180 total_fl = (fixed_buff_size / 2) * 2 / 181 ((src_width + 32) * fmt->bpp); 182 } else { 183 total_fl = (fixed_buff_size) * 2 / 184 ((src_width + 32) * fmt->bpp); 185 } 186 } 187 188 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s w:%u fl:%u\n", 189 plane->base.id, pdpu->pipe - SSPP_VIG0, 190 (char *)&fmt->base.pixel_format, 191 src_width, total_fl); 192 193 return total_fl; 194 } 195 196 /** 197 * _dpu_plane_get_qos_lut - get LUT mapping based on fill level 198 * @tbl: Pointer to LUT table 199 * @total_fl: fill level 200 * Return: LUT setting corresponding to the fill level 201 */ 202 static u64 _dpu_plane_get_qos_lut(const struct dpu_qos_lut_tbl *tbl, 203 u32 total_fl) 204 { 205 int i; 206 207 if (!tbl || !tbl->nentry || !tbl->entries) 208 return 0; 209 210 for (i = 0; i < tbl->nentry; i++) 211 if (total_fl <= tbl->entries[i].fl) 212 return tbl->entries[i].lut; 213 214 /* if last fl is zero, use as default */ 215 if (!tbl->entries[i-1].fl) 216 return tbl->entries[i-1].lut; 217 218 return 0; 219 } 220 221 /** 222 * _dpu_plane_set_qos_lut - set QoS LUT of the given plane 223 * @plane: Pointer to drm plane 224 * @fb: Pointer to framebuffer associated with the given plane 225 */ 226 static void _dpu_plane_set_qos_lut(struct drm_plane *plane, 227 struct drm_framebuffer *fb) 228 { 229 struct dpu_plane *pdpu = to_dpu_plane(plane); 230 const struct dpu_format *fmt = NULL; 231 u64 qos_lut; 232 u32 total_fl = 0, lut_usage; 233 234 if (!pdpu->is_rt_pipe) { 235 lut_usage = DPU_QOS_LUT_USAGE_NRT; 236 } else { 237 fmt = dpu_get_dpu_format_ext( 238 fb->format->format, 239 fb->modifier); 240 total_fl = _dpu_plane_calc_fill_level(plane, fmt, 241 drm_rect_width(&pdpu->pipe_cfg.src_rect)); 242 243 if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) 244 lut_usage = DPU_QOS_LUT_USAGE_LINEAR; 245 else 246 lut_usage = DPU_QOS_LUT_USAGE_MACROTILE; 247 } 248 249 qos_lut = _dpu_plane_get_qos_lut( 250 &pdpu->catalog->perf.qos_lut_tbl[lut_usage], total_fl); 251 252 pdpu->pipe_qos_cfg.creq_lut = qos_lut; 253 254 trace_dpu_perf_set_qos_luts(pdpu->pipe - SSPP_VIG0, 255 (fmt) ? fmt->base.pixel_format : 0, 256 pdpu->is_rt_pipe, total_fl, qos_lut, lut_usage); 257 258 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%llx\n", 259 plane->base.id, 260 pdpu->pipe - SSPP_VIG0, 261 fmt ? (char *)&fmt->base.pixel_format : NULL, 262 pdpu->is_rt_pipe, total_fl, qos_lut); 263 264 pdpu->pipe_hw->ops.setup_creq_lut(pdpu->pipe_hw, &pdpu->pipe_qos_cfg); 265 } 266 267 /** 268 * _dpu_plane_set_panic_lut - set danger/safe LUT of the given plane 269 * @plane: Pointer to drm plane 270 * @fb: Pointer to framebuffer associated with the given plane 271 */ 272 static void _dpu_plane_set_danger_lut(struct drm_plane *plane, 273 struct drm_framebuffer *fb) 274 { 275 struct dpu_plane *pdpu = to_dpu_plane(plane); 276 const struct dpu_format *fmt = NULL; 277 u32 danger_lut, safe_lut; 278 279 if (!pdpu->is_rt_pipe) { 280 danger_lut = pdpu->catalog->perf.danger_lut_tbl 281 [DPU_QOS_LUT_USAGE_NRT]; 282 safe_lut = pdpu->catalog->perf.safe_lut_tbl 283 [DPU_QOS_LUT_USAGE_NRT]; 284 } else { 285 fmt = dpu_get_dpu_format_ext( 286 fb->format->format, 287 fb->modifier); 288 289 if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) { 290 danger_lut = pdpu->catalog->perf.danger_lut_tbl 291 [DPU_QOS_LUT_USAGE_LINEAR]; 292 safe_lut = pdpu->catalog->perf.safe_lut_tbl 293 [DPU_QOS_LUT_USAGE_LINEAR]; 294 } else { 295 danger_lut = pdpu->catalog->perf.danger_lut_tbl 296 [DPU_QOS_LUT_USAGE_MACROTILE]; 297 safe_lut = pdpu->catalog->perf.safe_lut_tbl 298 [DPU_QOS_LUT_USAGE_MACROTILE]; 299 } 300 } 301 302 pdpu->pipe_qos_cfg.danger_lut = danger_lut; 303 pdpu->pipe_qos_cfg.safe_lut = safe_lut; 304 305 trace_dpu_perf_set_danger_luts(pdpu->pipe - SSPP_VIG0, 306 (fmt) ? fmt->base.pixel_format : 0, 307 (fmt) ? fmt->fetch_mode : 0, 308 pdpu->pipe_qos_cfg.danger_lut, 309 pdpu->pipe_qos_cfg.safe_lut); 310 311 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n", 312 plane->base.id, 313 pdpu->pipe - SSPP_VIG0, 314 fmt ? (char *)&fmt->base.pixel_format : NULL, 315 fmt ? fmt->fetch_mode : -1, 316 pdpu->pipe_qos_cfg.danger_lut, 317 pdpu->pipe_qos_cfg.safe_lut); 318 319 pdpu->pipe_hw->ops.setup_danger_safe_lut(pdpu->pipe_hw, 320 &pdpu->pipe_qos_cfg); 321 } 322 323 /** 324 * _dpu_plane_set_qos_ctrl - set QoS control of the given plane 325 * @plane: Pointer to drm plane 326 * @enable: true to enable QoS control 327 * @flags: QoS control mode (enum dpu_plane_qos) 328 */ 329 static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane, 330 bool enable, u32 flags) 331 { 332 struct dpu_plane *pdpu = to_dpu_plane(plane); 333 334 if (flags & DPU_PLANE_QOS_VBLANK_CTRL) { 335 pdpu->pipe_qos_cfg.creq_vblank = pdpu->pipe_sblk->creq_vblank; 336 pdpu->pipe_qos_cfg.danger_vblank = 337 pdpu->pipe_sblk->danger_vblank; 338 pdpu->pipe_qos_cfg.vblank_en = enable; 339 } 340 341 if (flags & DPU_PLANE_QOS_VBLANK_AMORTIZE) { 342 /* this feature overrules previous VBLANK_CTRL */ 343 pdpu->pipe_qos_cfg.vblank_en = false; 344 pdpu->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */ 345 } 346 347 if (flags & DPU_PLANE_QOS_PANIC_CTRL) 348 pdpu->pipe_qos_cfg.danger_safe_en = enable; 349 350 if (!pdpu->is_rt_pipe) { 351 pdpu->pipe_qos_cfg.vblank_en = false; 352 pdpu->pipe_qos_cfg.danger_safe_en = false; 353 } 354 355 DPU_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n", 356 plane->base.id, 357 pdpu->pipe - SSPP_VIG0, 358 pdpu->pipe_qos_cfg.danger_safe_en, 359 pdpu->pipe_qos_cfg.vblank_en, 360 pdpu->pipe_qos_cfg.creq_vblank, 361 pdpu->pipe_qos_cfg.danger_vblank, 362 pdpu->is_rt_pipe); 363 364 pdpu->pipe_hw->ops.setup_qos_ctrl(pdpu->pipe_hw, 365 &pdpu->pipe_qos_cfg); 366 } 367 368 static void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) 369 { 370 struct dpu_plane *pdpu = to_dpu_plane(plane); 371 struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); 372 373 if (!pdpu->is_rt_pipe) 374 return; 375 376 pm_runtime_get_sync(&dpu_kms->pdev->dev); 377 _dpu_plane_set_qos_ctrl(plane, enable, DPU_PLANE_QOS_PANIC_CTRL); 378 pm_runtime_put_sync(&dpu_kms->pdev->dev); 379 } 380 381 /** 382 * _dpu_plane_set_ot_limit - set OT limit for the given plane 383 * @plane: Pointer to drm plane 384 * @crtc: Pointer to drm crtc 385 */ 386 static void _dpu_plane_set_ot_limit(struct drm_plane *plane, 387 struct drm_crtc *crtc) 388 { 389 struct dpu_plane *pdpu = to_dpu_plane(plane); 390 struct dpu_vbif_set_ot_params ot_params; 391 struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); 392 393 memset(&ot_params, 0, sizeof(ot_params)); 394 ot_params.xin_id = pdpu->pipe_hw->cap->xin_id; 395 ot_params.num = pdpu->pipe_hw->idx - SSPP_NONE; 396 ot_params.width = drm_rect_width(&pdpu->pipe_cfg.src_rect); 397 ot_params.height = drm_rect_height(&pdpu->pipe_cfg.src_rect); 398 ot_params.is_wfd = !pdpu->is_rt_pipe; 399 ot_params.frame_rate = crtc->mode.vrefresh; 400 ot_params.vbif_idx = VBIF_RT; 401 ot_params.clk_ctrl = pdpu->pipe_hw->cap->clk_ctrl; 402 ot_params.rd = true; 403 404 dpu_vbif_set_ot_limit(dpu_kms, &ot_params); 405 } 406 407 /** 408 * _dpu_plane_set_vbif_qos - set vbif QoS for the given plane 409 * @plane: Pointer to drm plane 410 */ 411 static void _dpu_plane_set_qos_remap(struct drm_plane *plane) 412 { 413 struct dpu_plane *pdpu = to_dpu_plane(plane); 414 struct dpu_vbif_set_qos_params qos_params; 415 struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); 416 417 memset(&qos_params, 0, sizeof(qos_params)); 418 qos_params.vbif_idx = VBIF_RT; 419 qos_params.clk_ctrl = pdpu->pipe_hw->cap->clk_ctrl; 420 qos_params.xin_id = pdpu->pipe_hw->cap->xin_id; 421 qos_params.num = pdpu->pipe_hw->idx - SSPP_VIG0; 422 qos_params.is_rt = pdpu->is_rt_pipe; 423 424 DPU_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n", 425 plane->base.id, qos_params.num, 426 qos_params.vbif_idx, 427 qos_params.xin_id, qos_params.is_rt, 428 qos_params.clk_ctrl); 429 430 dpu_vbif_set_qos_remap(dpu_kms, &qos_params); 431 } 432 433 /** 434 * _dpu_plane_get_aspace: gets the address space 435 */ 436 static inline struct msm_gem_address_space *_dpu_plane_get_aspace( 437 struct dpu_plane *pdpu) 438 { 439 struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); 440 441 return kms->base.aspace; 442 } 443 444 static inline void _dpu_plane_set_scanout(struct drm_plane *plane, 445 struct dpu_plane_state *pstate, 446 struct dpu_hw_pipe_cfg *pipe_cfg, 447 struct drm_framebuffer *fb) 448 { 449 struct dpu_plane *pdpu = to_dpu_plane(plane); 450 struct msm_gem_address_space *aspace = _dpu_plane_get_aspace(pdpu); 451 int ret; 452 453 ret = dpu_format_populate_layout(aspace, fb, &pipe_cfg->layout); 454 if (ret == -EAGAIN) 455 DPU_DEBUG_PLANE(pdpu, "not updating same src addrs\n"); 456 else if (ret) 457 DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret); 458 else if (pdpu->pipe_hw->ops.setup_sourceaddress) { 459 trace_dpu_plane_set_scanout(pdpu->pipe_hw->idx, 460 &pipe_cfg->layout, 461 pstate->multirect_index); 462 pdpu->pipe_hw->ops.setup_sourceaddress(pdpu->pipe_hw, pipe_cfg, 463 pstate->multirect_index); 464 } 465 } 466 467 static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu, 468 struct dpu_plane_state *pstate, 469 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h, 470 struct dpu_hw_scaler3_cfg *scale_cfg, 471 const struct dpu_format *fmt, 472 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v) 473 { 474 uint32_t i; 475 476 memset(scale_cfg, 0, sizeof(*scale_cfg)); 477 memset(&pstate->pixel_ext, 0, sizeof(struct dpu_hw_pixel_ext)); 478 479 scale_cfg->phase_step_x[DPU_SSPP_COMP_0] = 480 mult_frac((1 << PHASE_STEP_SHIFT), src_w, dst_w); 481 scale_cfg->phase_step_y[DPU_SSPP_COMP_0] = 482 mult_frac((1 << PHASE_STEP_SHIFT), src_h, dst_h); 483 484 485 scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2] = 486 scale_cfg->phase_step_y[DPU_SSPP_COMP_0] / chroma_subsmpl_v; 487 scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2] = 488 scale_cfg->phase_step_x[DPU_SSPP_COMP_0] / chroma_subsmpl_h; 489 490 scale_cfg->phase_step_x[DPU_SSPP_COMP_2] = 491 scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2]; 492 scale_cfg->phase_step_y[DPU_SSPP_COMP_2] = 493 scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2]; 494 495 scale_cfg->phase_step_x[DPU_SSPP_COMP_3] = 496 scale_cfg->phase_step_x[DPU_SSPP_COMP_0]; 497 scale_cfg->phase_step_y[DPU_SSPP_COMP_3] = 498 scale_cfg->phase_step_y[DPU_SSPP_COMP_0]; 499 500 for (i = 0; i < DPU_MAX_PLANES; i++) { 501 scale_cfg->src_width[i] = src_w; 502 scale_cfg->src_height[i] = src_h; 503 if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) { 504 scale_cfg->src_width[i] /= chroma_subsmpl_h; 505 scale_cfg->src_height[i] /= chroma_subsmpl_v; 506 } 507 scale_cfg->preload_x[i] = DPU_QSEED3_DEFAULT_PRELOAD_H; 508 scale_cfg->preload_y[i] = DPU_QSEED3_DEFAULT_PRELOAD_V; 509 pstate->pixel_ext.num_ext_pxls_top[i] = 510 scale_cfg->src_height[i]; 511 pstate->pixel_ext.num_ext_pxls_left[i] = 512 scale_cfg->src_width[i]; 513 } 514 if (!(DPU_FORMAT_IS_YUV(fmt)) && (src_h == dst_h) 515 && (src_w == dst_w)) 516 return; 517 518 scale_cfg->dst_width = dst_w; 519 scale_cfg->dst_height = dst_h; 520 scale_cfg->y_rgb_filter_cfg = DPU_SCALE_BIL; 521 scale_cfg->uv_filter_cfg = DPU_SCALE_BIL; 522 scale_cfg->alpha_filter_cfg = DPU_SCALE_ALPHA_BIL; 523 scale_cfg->lut_flag = 0; 524 scale_cfg->blend_cfg = 1; 525 scale_cfg->enable = 1; 526 } 527 528 static inline void _dpu_plane_setup_csc(struct dpu_plane *pdpu) 529 { 530 static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = { 531 { 532 /* S15.16 format */ 533 0x00012A00, 0x00000000, 0x00019880, 534 0x00012A00, 0xFFFF9B80, 0xFFFF3000, 535 0x00012A00, 0x00020480, 0x00000000, 536 }, 537 /* signed bias */ 538 { 0xfff0, 0xff80, 0xff80,}, 539 { 0x0, 0x0, 0x0,}, 540 /* unsigned clamp */ 541 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, 542 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,}, 543 }; 544 static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = { 545 { 546 /* S15.16 format */ 547 0x00012A00, 0x00000000, 0x00019880, 548 0x00012A00, 0xFFFF9B80, 0xFFFF3000, 549 0x00012A00, 0x00020480, 0x00000000, 550 }, 551 /* signed bias */ 552 { 0xffc0, 0xfe00, 0xfe00,}, 553 { 0x0, 0x0, 0x0,}, 554 /* unsigned clamp */ 555 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, 556 { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, 557 }; 558 559 if (!pdpu) { 560 DPU_ERROR("invalid plane\n"); 561 return; 562 } 563 564 if (BIT(DPU_SSPP_CSC_10BIT) & pdpu->features) 565 pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc10_YUV2RGB_601L; 566 else 567 pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc_YUV2RGB_601L; 568 569 DPU_DEBUG_PLANE(pdpu, "using 0x%X 0x%X 0x%X...\n", 570 pdpu->csc_ptr->csc_mv[0], 571 pdpu->csc_ptr->csc_mv[1], 572 pdpu->csc_ptr->csc_mv[2]); 573 } 574 575 static void _dpu_plane_setup_scaler(struct dpu_plane *pdpu, 576 struct dpu_plane_state *pstate, 577 const struct dpu_format *fmt, bool color_fill) 578 { 579 uint32_t chroma_subsmpl_h, chroma_subsmpl_v; 580 581 /* don't chroma subsample if decimating */ 582 chroma_subsmpl_h = 583 drm_format_horz_chroma_subsampling(fmt->base.pixel_format); 584 chroma_subsmpl_v = 585 drm_format_vert_chroma_subsampling(fmt->base.pixel_format); 586 587 /* update scaler. calculate default config for QSEED3 */ 588 _dpu_plane_setup_scaler3(pdpu, pstate, 589 drm_rect_width(&pdpu->pipe_cfg.src_rect), 590 drm_rect_height(&pdpu->pipe_cfg.src_rect), 591 drm_rect_width(&pdpu->pipe_cfg.dst_rect), 592 drm_rect_height(&pdpu->pipe_cfg.dst_rect), 593 &pstate->scaler3_cfg, fmt, 594 chroma_subsmpl_h, chroma_subsmpl_v); 595 } 596 597 /** 598 * _dpu_plane_color_fill - enables color fill on plane 599 * @pdpu: Pointer to DPU plane object 600 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red 601 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha 602 * Returns: 0 on success 603 */ 604 static int _dpu_plane_color_fill(struct dpu_plane *pdpu, 605 uint32_t color, uint32_t alpha) 606 { 607 const struct dpu_format *fmt; 608 const struct drm_plane *plane = &pdpu->base; 609 struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state); 610 611 DPU_DEBUG_PLANE(pdpu, "\n"); 612 613 /* 614 * select fill format to match user property expectation, 615 * h/w only supports RGB variants 616 */ 617 fmt = dpu_get_dpu_format(DRM_FORMAT_ABGR8888); 618 619 /* update sspp */ 620 if (fmt && pdpu->pipe_hw->ops.setup_solidfill) { 621 pdpu->pipe_hw->ops.setup_solidfill(pdpu->pipe_hw, 622 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24), 623 pstate->multirect_index); 624 625 /* override scaler/decimation if solid fill */ 626 pdpu->pipe_cfg.src_rect.x1 = 0; 627 pdpu->pipe_cfg.src_rect.y1 = 0; 628 pdpu->pipe_cfg.src_rect.x2 = 629 drm_rect_width(&pdpu->pipe_cfg.dst_rect); 630 pdpu->pipe_cfg.src_rect.y2 = 631 drm_rect_height(&pdpu->pipe_cfg.dst_rect); 632 _dpu_plane_setup_scaler(pdpu, pstate, fmt, true); 633 634 if (pdpu->pipe_hw->ops.setup_format) 635 pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, 636 fmt, DPU_SSPP_SOLID_FILL, 637 pstate->multirect_index); 638 639 if (pdpu->pipe_hw->ops.setup_rects) 640 pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw, 641 &pdpu->pipe_cfg, 642 pstate->multirect_index); 643 644 if (pdpu->pipe_hw->ops.setup_pe) 645 pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw, 646 &pstate->pixel_ext); 647 648 if (pdpu->pipe_hw->ops.setup_scaler && 649 pstate->multirect_index != DPU_SSPP_RECT_1) 650 pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw, 651 &pdpu->pipe_cfg, &pstate->pixel_ext, 652 &pstate->scaler3_cfg); 653 } 654 655 return 0; 656 } 657 658 void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state) 659 { 660 struct dpu_plane_state *pstate = to_dpu_plane_state(drm_state); 661 662 pstate->multirect_index = DPU_SSPP_RECT_SOLO; 663 pstate->multirect_mode = DPU_SSPP_MULTIRECT_NONE; 664 } 665 666 int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane) 667 { 668 struct dpu_plane_state *pstate[R_MAX]; 669 const struct drm_plane_state *drm_state[R_MAX]; 670 struct drm_rect src[R_MAX], dst[R_MAX]; 671 struct dpu_plane *dpu_plane[R_MAX]; 672 const struct dpu_format *fmt[R_MAX]; 673 int i, buffer_lines; 674 unsigned int max_tile_height = 1; 675 bool parallel_fetch_qualified = true; 676 bool has_tiled_rect = false; 677 678 for (i = 0; i < R_MAX; i++) { 679 const struct msm_format *msm_fmt; 680 681 drm_state[i] = i ? plane->r1 : plane->r0; 682 msm_fmt = msm_framebuffer_format(drm_state[i]->fb); 683 fmt[i] = to_dpu_format(msm_fmt); 684 685 if (DPU_FORMAT_IS_UBWC(fmt[i])) { 686 has_tiled_rect = true; 687 if (fmt[i]->tile_height > max_tile_height) 688 max_tile_height = fmt[i]->tile_height; 689 } 690 } 691 692 for (i = 0; i < R_MAX; i++) { 693 int width_threshold; 694 695 pstate[i] = to_dpu_plane_state(drm_state[i]); 696 dpu_plane[i] = to_dpu_plane(drm_state[i]->plane); 697 698 if (pstate[i] == NULL) { 699 DPU_ERROR("DPU plane state of plane id %d is NULL\n", 700 drm_state[i]->plane->base.id); 701 return -EINVAL; 702 } 703 704 src[i].x1 = drm_state[i]->src_x >> 16; 705 src[i].y1 = drm_state[i]->src_y >> 16; 706 src[i].x2 = src[i].x1 + (drm_state[i]->src_w >> 16); 707 src[i].y2 = src[i].y1 + (drm_state[i]->src_h >> 16); 708 709 dst[i] = drm_plane_state_dest(drm_state[i]); 710 711 if (drm_rect_calc_hscale(&src[i], &dst[i], 1, 1) != 1 || 712 drm_rect_calc_vscale(&src[i], &dst[i], 1, 1) != 1) { 713 DPU_ERROR_PLANE(dpu_plane[i], 714 "scaling is not supported in multirect mode\n"); 715 return -EINVAL; 716 } 717 718 if (DPU_FORMAT_IS_YUV(fmt[i])) { 719 DPU_ERROR_PLANE(dpu_plane[i], 720 "Unsupported format for multirect mode\n"); 721 return -EINVAL; 722 } 723 724 /** 725 * SSPP PD_MEM is split half - one for each RECT. 726 * Tiled formats need 5 lines of buffering while fetching 727 * whereas linear formats need only 2 lines. 728 * So we cannot support more than half of the supported SSPP 729 * width for tiled formats. 730 */ 731 width_threshold = dpu_plane[i]->pipe_sblk->common->maxlinewidth; 732 if (has_tiled_rect) 733 width_threshold /= 2; 734 735 if (parallel_fetch_qualified && 736 drm_rect_width(&src[i]) > width_threshold) 737 parallel_fetch_qualified = false; 738 739 } 740 741 /* Validate RECT's and set the mode */ 742 743 /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */ 744 if (parallel_fetch_qualified) { 745 pstate[R0]->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL; 746 pstate[R1]->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL; 747 748 goto done; 749 } 750 751 /* TIME_MX Mode */ 752 buffer_lines = 2 * max_tile_height; 753 754 if (dst[R1].y1 >= dst[R0].y2 + buffer_lines || 755 dst[R0].y1 >= dst[R1].y2 + buffer_lines) { 756 pstate[R0]->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX; 757 pstate[R1]->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX; 758 } else { 759 DPU_ERROR( 760 "No multirect mode possible for the planes (%d - %d)\n", 761 drm_state[R0]->plane->base.id, 762 drm_state[R1]->plane->base.id); 763 return -EINVAL; 764 } 765 766 done: 767 if (dpu_plane[R0]->is_virtual) { 768 pstate[R0]->multirect_index = DPU_SSPP_RECT_1; 769 pstate[R1]->multirect_index = DPU_SSPP_RECT_0; 770 } else { 771 pstate[R0]->multirect_index = DPU_SSPP_RECT_0; 772 pstate[R1]->multirect_index = DPU_SSPP_RECT_1; 773 }; 774 775 DPU_DEBUG_PLANE(dpu_plane[R0], "R0: %d - %d\n", 776 pstate[R0]->multirect_mode, pstate[R0]->multirect_index); 777 DPU_DEBUG_PLANE(dpu_plane[R1], "R1: %d - %d\n", 778 pstate[R1]->multirect_mode, pstate[R1]->multirect_index); 779 return 0; 780 } 781 782 /** 783 * dpu_plane_get_ctl_flush - get control flush for the given plane 784 * @plane: Pointer to drm plane structure 785 * @ctl: Pointer to hardware control driver 786 * @flush_sspp: Pointer to sspp flush control word 787 */ 788 void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl, 789 u32 *flush_sspp) 790 { 791 *flush_sspp = ctl->ops.get_bitmask_sspp(ctl, dpu_plane_pipe(plane)); 792 } 793 794 static int dpu_plane_prepare_fb(struct drm_plane *plane, 795 struct drm_plane_state *new_state) 796 { 797 struct drm_framebuffer *fb = new_state->fb; 798 struct dpu_plane *pdpu = to_dpu_plane(plane); 799 struct dpu_plane_state *pstate = to_dpu_plane_state(new_state); 800 struct dpu_hw_fmt_layout layout; 801 struct drm_gem_object *obj; 802 struct msm_gem_object *msm_obj; 803 struct dma_fence *fence; 804 struct msm_gem_address_space *aspace = _dpu_plane_get_aspace(pdpu); 805 int ret; 806 807 if (!new_state->fb) 808 return 0; 809 810 DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", fb->base.id); 811 812 /* cache aspace */ 813 pstate->aspace = aspace; 814 815 /* 816 * TODO: Need to sort out the msm_framebuffer_prepare() call below so 817 * we can use msm_atomic_prepare_fb() instead of doing the 818 * implicit fence and fb prepare by hand here. 819 */ 820 obj = msm_framebuffer_bo(new_state->fb, 0); 821 msm_obj = to_msm_bo(obj); 822 fence = reservation_object_get_excl_rcu(msm_obj->resv); 823 if (fence) 824 drm_atomic_set_fence_for_plane(new_state, fence); 825 826 if (pstate->aspace) { 827 ret = msm_framebuffer_prepare(new_state->fb, 828 pstate->aspace); 829 if (ret) { 830 DPU_ERROR("failed to prepare framebuffer\n"); 831 return ret; 832 } 833 } 834 835 /* validate framebuffer layout before commit */ 836 ret = dpu_format_populate_layout(pstate->aspace, 837 new_state->fb, &layout); 838 if (ret) { 839 DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret); 840 return ret; 841 } 842 843 return 0; 844 } 845 846 static void dpu_plane_cleanup_fb(struct drm_plane *plane, 847 struct drm_plane_state *old_state) 848 { 849 struct dpu_plane *pdpu = to_dpu_plane(plane); 850 struct dpu_plane_state *old_pstate; 851 852 if (!old_state || !old_state->fb) 853 return; 854 855 old_pstate = to_dpu_plane_state(old_state); 856 857 DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", old_state->fb->base.id); 858 859 msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace); 860 } 861 862 static bool dpu_plane_validate_src(struct drm_rect *src, 863 struct drm_rect *fb_rect, 864 uint32_t min_src_size) 865 { 866 /* Ensure fb size is supported */ 867 if (drm_rect_width(fb_rect) > MAX_IMG_WIDTH || 868 drm_rect_height(fb_rect) > MAX_IMG_HEIGHT) 869 return false; 870 871 /* Ensure src rect is above the minimum size */ 872 if (drm_rect_width(src) < min_src_size || 873 drm_rect_height(src) < min_src_size) 874 return false; 875 876 /* Ensure src is fully encapsulated in fb */ 877 return drm_rect_intersect(fb_rect, src) && 878 drm_rect_equals(fb_rect, src); 879 } 880 881 static int dpu_plane_atomic_check(struct drm_plane *plane, 882 struct drm_plane_state *state) 883 { 884 int ret = 0, min_scale; 885 struct dpu_plane *pdpu = to_dpu_plane(plane); 886 const struct drm_crtc_state *crtc_state = NULL; 887 const struct dpu_format *fmt; 888 struct drm_rect src, dst, fb_rect = { 0 }; 889 uint32_t min_src_size, max_linewidth; 890 891 if (state->crtc) 892 crtc_state = drm_atomic_get_new_crtc_state(state->state, 893 state->crtc); 894 895 min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxdwnscale); 896 ret = drm_atomic_helper_check_plane_state(state, crtc_state, min_scale, 897 pdpu->pipe_sblk->maxupscale << 16, 898 true, true); 899 if (ret) { 900 DPU_ERROR_PLANE(pdpu, "Check plane state failed (%d)\n", ret); 901 return ret; 902 } 903 if (!state->visible) 904 return 0; 905 906 src.x1 = state->src_x >> 16; 907 src.y1 = state->src_y >> 16; 908 src.x2 = src.x1 + (state->src_w >> 16); 909 src.y2 = src.y1 + (state->src_h >> 16); 910 911 dst = drm_plane_state_dest(state); 912 913 fb_rect.x2 = state->fb->width; 914 fb_rect.y2 = state->fb->height; 915 916 max_linewidth = pdpu->pipe_sblk->common->maxlinewidth; 917 918 fmt = to_dpu_format(msm_framebuffer_format(state->fb)); 919 920 min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1; 921 922 if (DPU_FORMAT_IS_YUV(fmt) && 923 (!(pdpu->features & DPU_SSPP_SCALER) || 924 !(pdpu->features & (BIT(DPU_SSPP_CSC) 925 | BIT(DPU_SSPP_CSC_10BIT))))) { 926 DPU_ERROR_PLANE(pdpu, 927 "plane doesn't have scaler/csc for yuv\n"); 928 return -EINVAL; 929 930 /* check src bounds */ 931 } else if (!dpu_plane_validate_src(&src, &fb_rect, min_src_size)) { 932 DPU_ERROR_PLANE(pdpu, "invalid source " DRM_RECT_FMT "\n", 933 DRM_RECT_ARG(&src)); 934 return -E2BIG; 935 936 /* valid yuv image */ 937 } else if (DPU_FORMAT_IS_YUV(fmt) && 938 (src.x1 & 0x1 || src.y1 & 0x1 || 939 drm_rect_width(&src) & 0x1 || 940 drm_rect_height(&src) & 0x1)) { 941 DPU_ERROR_PLANE(pdpu, "invalid yuv source " DRM_RECT_FMT "\n", 942 DRM_RECT_ARG(&src)); 943 return -EINVAL; 944 945 /* min dst support */ 946 } else if (drm_rect_width(&dst) < 0x1 || drm_rect_height(&dst) < 0x1) { 947 DPU_ERROR_PLANE(pdpu, "invalid dest rect " DRM_RECT_FMT "\n", 948 DRM_RECT_ARG(&dst)); 949 return -EINVAL; 950 951 /* check decimated source width */ 952 } else if (drm_rect_width(&src) > max_linewidth) { 953 DPU_ERROR_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", 954 DRM_RECT_ARG(&src), max_linewidth); 955 return -E2BIG; 956 } 957 958 return 0; 959 } 960 961 void dpu_plane_flush(struct drm_plane *plane) 962 { 963 struct dpu_plane *pdpu; 964 struct dpu_plane_state *pstate; 965 966 if (!plane || !plane->state) { 967 DPU_ERROR("invalid plane\n"); 968 return; 969 } 970 971 pdpu = to_dpu_plane(plane); 972 pstate = to_dpu_plane_state(plane->state); 973 974 /* 975 * These updates have to be done immediately before the plane flush 976 * timing, and may not be moved to the atomic_update/mode_set functions. 977 */ 978 if (pdpu->is_error) 979 /* force white frame with 100% alpha pipe output on error */ 980 _dpu_plane_color_fill(pdpu, 0xFFFFFF, 0xFF); 981 else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) 982 /* force 100% alpha */ 983 _dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF); 984 else if (pdpu->pipe_hw && pdpu->csc_ptr && pdpu->pipe_hw->ops.setup_csc) 985 pdpu->pipe_hw->ops.setup_csc(pdpu->pipe_hw, pdpu->csc_ptr); 986 987 /* flag h/w flush complete */ 988 if (plane->state) 989 pstate->pending = false; 990 } 991 992 /** 993 * dpu_plane_set_error: enable/disable error condition 994 * @plane: pointer to drm_plane structure 995 */ 996 void dpu_plane_set_error(struct drm_plane *plane, bool error) 997 { 998 struct dpu_plane *pdpu; 999 1000 if (!plane) 1001 return; 1002 1003 pdpu = to_dpu_plane(plane); 1004 pdpu->is_error = error; 1005 } 1006 1007 static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) 1008 { 1009 uint32_t src_flags; 1010 struct dpu_plane *pdpu = to_dpu_plane(plane); 1011 struct drm_plane_state *state = plane->state; 1012 struct dpu_plane_state *pstate = to_dpu_plane_state(state); 1013 struct drm_crtc *crtc = state->crtc; 1014 struct drm_framebuffer *fb = state->fb; 1015 const struct dpu_format *fmt = 1016 to_dpu_format(msm_framebuffer_format(fb)); 1017 1018 memset(&(pdpu->pipe_cfg), 0, sizeof(struct dpu_hw_pipe_cfg)); 1019 1020 _dpu_plane_set_scanout(plane, pstate, &pdpu->pipe_cfg, fb); 1021 1022 pstate->pending = true; 1023 1024 pdpu->is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT); 1025 _dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL); 1026 1027 DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FP_FMT "->crtc%u " DRM_RECT_FMT 1028 ", %4.4s ubwc %d\n", fb->base.id, DRM_RECT_FP_ARG(&state->src), 1029 crtc->base.id, DRM_RECT_ARG(&state->dst), 1030 (char *)&fmt->base.pixel_format, DPU_FORMAT_IS_UBWC(fmt)); 1031 1032 pdpu->pipe_cfg.src_rect = state->src; 1033 1034 /* state->src is 16.16, src_rect is not */ 1035 pdpu->pipe_cfg.src_rect.x1 >>= 16; 1036 pdpu->pipe_cfg.src_rect.x2 >>= 16; 1037 pdpu->pipe_cfg.src_rect.y1 >>= 16; 1038 pdpu->pipe_cfg.src_rect.y2 >>= 16; 1039 1040 pdpu->pipe_cfg.dst_rect = state->dst; 1041 1042 _dpu_plane_setup_scaler(pdpu, pstate, fmt, false); 1043 1044 /* override for color fill */ 1045 if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) { 1046 /* skip remaining processing on color fill */ 1047 return; 1048 } 1049 1050 if (pdpu->pipe_hw->ops.setup_rects) { 1051 pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw, 1052 &pdpu->pipe_cfg, 1053 pstate->multirect_index); 1054 } 1055 1056 if (pdpu->pipe_hw->ops.setup_pe && 1057 (pstate->multirect_index != DPU_SSPP_RECT_1)) 1058 pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw, 1059 &pstate->pixel_ext); 1060 1061 /** 1062 * when programmed in multirect mode, scalar block will be 1063 * bypassed. Still we need to update alpha and bitwidth 1064 * ONLY for RECT0 1065 */ 1066 if (pdpu->pipe_hw->ops.setup_scaler && 1067 pstate->multirect_index != DPU_SSPP_RECT_1) 1068 pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw, 1069 &pdpu->pipe_cfg, &pstate->pixel_ext, 1070 &pstate->scaler3_cfg); 1071 1072 if (pdpu->pipe_hw->ops.setup_multirect) 1073 pdpu->pipe_hw->ops.setup_multirect( 1074 pdpu->pipe_hw, 1075 pstate->multirect_index, 1076 pstate->multirect_mode); 1077 1078 if (pdpu->pipe_hw->ops.setup_format) { 1079 src_flags = 0x0; 1080 1081 /* update format */ 1082 pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, fmt, src_flags, 1083 pstate->multirect_index); 1084 1085 if (pdpu->pipe_hw->ops.setup_cdp) { 1086 struct dpu_hw_pipe_cdp_cfg *cdp_cfg = &pstate->cdp_cfg; 1087 1088 memset(cdp_cfg, 0, sizeof(struct dpu_hw_pipe_cdp_cfg)); 1089 1090 cdp_cfg->enable = pdpu->catalog->perf.cdp_cfg 1091 [DPU_PERF_CDP_USAGE_RT].rd_enable; 1092 cdp_cfg->ubwc_meta_enable = 1093 DPU_FORMAT_IS_UBWC(fmt); 1094 cdp_cfg->tile_amortize_enable = 1095 DPU_FORMAT_IS_UBWC(fmt) || 1096 DPU_FORMAT_IS_TILE(fmt); 1097 cdp_cfg->preload_ahead = DPU_SSPP_CDP_PRELOAD_AHEAD_64; 1098 1099 pdpu->pipe_hw->ops.setup_cdp(pdpu->pipe_hw, cdp_cfg); 1100 } 1101 1102 /* update csc */ 1103 if (DPU_FORMAT_IS_YUV(fmt)) 1104 _dpu_plane_setup_csc(pdpu); 1105 else 1106 pdpu->csc_ptr = 0; 1107 } 1108 1109 _dpu_plane_set_qos_lut(plane, fb); 1110 _dpu_plane_set_danger_lut(plane, fb); 1111 1112 if (plane->type != DRM_PLANE_TYPE_CURSOR) { 1113 _dpu_plane_set_qos_ctrl(plane, true, DPU_PLANE_QOS_PANIC_CTRL); 1114 _dpu_plane_set_ot_limit(plane, crtc); 1115 } 1116 1117 _dpu_plane_set_qos_remap(plane); 1118 } 1119 1120 static void _dpu_plane_atomic_disable(struct drm_plane *plane) 1121 { 1122 struct dpu_plane *pdpu = to_dpu_plane(plane); 1123 struct drm_plane_state *state = plane->state; 1124 struct dpu_plane_state *pstate = to_dpu_plane_state(state); 1125 1126 trace_dpu_plane_disable(DRMID(plane), is_dpu_plane_virtual(plane), 1127 pstate->multirect_mode); 1128 1129 pstate->pending = true; 1130 1131 if (is_dpu_plane_virtual(plane) && 1132 pdpu->pipe_hw && pdpu->pipe_hw->ops.setup_multirect) 1133 pdpu->pipe_hw->ops.setup_multirect(pdpu->pipe_hw, 1134 DPU_SSPP_RECT_SOLO, DPU_SSPP_MULTIRECT_NONE); 1135 } 1136 1137 static void dpu_plane_atomic_update(struct drm_plane *plane, 1138 struct drm_plane_state *old_state) 1139 { 1140 struct dpu_plane *pdpu = to_dpu_plane(plane); 1141 struct drm_plane_state *state = plane->state; 1142 1143 pdpu->is_error = false; 1144 1145 DPU_DEBUG_PLANE(pdpu, "\n"); 1146 1147 if (!state->visible) { 1148 _dpu_plane_atomic_disable(plane); 1149 } else { 1150 dpu_plane_sspp_atomic_update(plane); 1151 } 1152 } 1153 1154 void dpu_plane_restore(struct drm_plane *plane) 1155 { 1156 struct dpu_plane *pdpu; 1157 1158 if (!plane || !plane->state) { 1159 DPU_ERROR("invalid plane\n"); 1160 return; 1161 } 1162 1163 pdpu = to_dpu_plane(plane); 1164 1165 DPU_DEBUG_PLANE(pdpu, "\n"); 1166 1167 /* last plane state is same as current state */ 1168 dpu_plane_atomic_update(plane, plane->state); 1169 } 1170 1171 static void dpu_plane_destroy(struct drm_plane *plane) 1172 { 1173 struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL; 1174 1175 DPU_DEBUG_PLANE(pdpu, "\n"); 1176 1177 if (pdpu) { 1178 _dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL); 1179 1180 mutex_destroy(&pdpu->lock); 1181 1182 drm_plane_helper_disable(plane, NULL); 1183 1184 /* this will destroy the states as well */ 1185 drm_plane_cleanup(plane); 1186 1187 dpu_hw_sspp_destroy(pdpu->pipe_hw); 1188 1189 kfree(pdpu); 1190 } 1191 } 1192 1193 static void dpu_plane_destroy_state(struct drm_plane *plane, 1194 struct drm_plane_state *state) 1195 { 1196 struct dpu_plane_state *pstate; 1197 1198 if (!plane || !state) { 1199 DPU_ERROR("invalid arg(s), plane %d state %d\n", 1200 plane != 0, state != 0); 1201 return; 1202 } 1203 1204 pstate = to_dpu_plane_state(state); 1205 1206 __drm_atomic_helper_plane_destroy_state(state); 1207 1208 kfree(pstate); 1209 } 1210 1211 static struct drm_plane_state * 1212 dpu_plane_duplicate_state(struct drm_plane *plane) 1213 { 1214 struct dpu_plane *pdpu; 1215 struct dpu_plane_state *pstate; 1216 struct dpu_plane_state *old_state; 1217 1218 if (!plane) { 1219 DPU_ERROR("invalid plane\n"); 1220 return NULL; 1221 } else if (!plane->state) { 1222 DPU_ERROR("invalid plane state\n"); 1223 return NULL; 1224 } 1225 1226 old_state = to_dpu_plane_state(plane->state); 1227 pdpu = to_dpu_plane(plane); 1228 pstate = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL); 1229 if (!pstate) { 1230 DPU_ERROR_PLANE(pdpu, "failed to allocate state\n"); 1231 return NULL; 1232 } 1233 1234 DPU_DEBUG_PLANE(pdpu, "\n"); 1235 1236 pstate->pending = false; 1237 1238 __drm_atomic_helper_plane_duplicate_state(plane, &pstate->base); 1239 1240 return &pstate->base; 1241 } 1242 1243 static void dpu_plane_reset(struct drm_plane *plane) 1244 { 1245 struct dpu_plane *pdpu; 1246 struct dpu_plane_state *pstate; 1247 1248 if (!plane) { 1249 DPU_ERROR("invalid plane\n"); 1250 return; 1251 } 1252 1253 pdpu = to_dpu_plane(plane); 1254 DPU_DEBUG_PLANE(pdpu, "\n"); 1255 1256 /* remove previous state, if present */ 1257 if (plane->state) { 1258 dpu_plane_destroy_state(plane, plane->state); 1259 plane->state = 0; 1260 } 1261 1262 pstate = kzalloc(sizeof(*pstate), GFP_KERNEL); 1263 if (!pstate) { 1264 DPU_ERROR_PLANE(pdpu, "failed to allocate state\n"); 1265 return; 1266 } 1267 1268 pstate->base.plane = plane; 1269 1270 plane->state = &pstate->base; 1271 } 1272 1273 #ifdef CONFIG_DEBUG_FS 1274 static ssize_t _dpu_plane_danger_read(struct file *file, 1275 char __user *buff, size_t count, loff_t *ppos) 1276 { 1277 struct dpu_kms *kms = file->private_data; 1278 struct dpu_mdss_cfg *cfg = kms->catalog; 1279 int len = 0; 1280 char buf[40] = {'\0'}; 1281 1282 if (!cfg) 1283 return -ENODEV; 1284 1285 if (*ppos) 1286 return 0; /* the end */ 1287 1288 len = snprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl); 1289 if (len < 0 || len >= sizeof(buf)) 1290 return 0; 1291 1292 if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) 1293 return -EFAULT; 1294 1295 *ppos += len; /* increase offset */ 1296 1297 return len; 1298 } 1299 1300 static void _dpu_plane_set_danger_state(struct dpu_kms *kms, bool enable) 1301 { 1302 struct drm_plane *plane; 1303 1304 drm_for_each_plane(plane, kms->dev) { 1305 if (plane->fb && plane->state) { 1306 dpu_plane_danger_signal_ctrl(plane, enable); 1307 DPU_DEBUG("plane:%d img:%dx%d ", 1308 plane->base.id, plane->fb->width, 1309 plane->fb->height); 1310 DPU_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n", 1311 plane->state->src_x >> 16, 1312 plane->state->src_y >> 16, 1313 plane->state->src_w >> 16, 1314 plane->state->src_h >> 16, 1315 plane->state->crtc_x, plane->state->crtc_y, 1316 plane->state->crtc_w, plane->state->crtc_h); 1317 } else { 1318 DPU_DEBUG("Inactive plane:%d\n", plane->base.id); 1319 } 1320 } 1321 } 1322 1323 static ssize_t _dpu_plane_danger_write(struct file *file, 1324 const char __user *user_buf, size_t count, loff_t *ppos) 1325 { 1326 struct dpu_kms *kms = file->private_data; 1327 struct dpu_mdss_cfg *cfg = kms->catalog; 1328 int disable_panic; 1329 char buf[10]; 1330 1331 if (!cfg) 1332 return -EFAULT; 1333 1334 if (count >= sizeof(buf)) 1335 return -EFAULT; 1336 1337 if (copy_from_user(buf, user_buf, count)) 1338 return -EFAULT; 1339 1340 buf[count] = 0; /* end of string */ 1341 1342 if (kstrtoint(buf, 0, &disable_panic)) 1343 return -EFAULT; 1344 1345 if (disable_panic) { 1346 /* Disable panic signal for all active pipes */ 1347 DPU_DEBUG("Disabling danger:\n"); 1348 _dpu_plane_set_danger_state(kms, false); 1349 kms->has_danger_ctrl = false; 1350 } else { 1351 /* Enable panic signal for all active pipes */ 1352 DPU_DEBUG("Enabling danger:\n"); 1353 kms->has_danger_ctrl = true; 1354 _dpu_plane_set_danger_state(kms, true); 1355 } 1356 1357 return count; 1358 } 1359 1360 static const struct file_operations dpu_plane_danger_enable = { 1361 .open = simple_open, 1362 .read = _dpu_plane_danger_read, 1363 .write = _dpu_plane_danger_write, 1364 }; 1365 1366 static int _dpu_plane_init_debugfs(struct drm_plane *plane) 1367 { 1368 struct dpu_plane *pdpu; 1369 struct dpu_kms *kms; 1370 struct msm_drm_private *priv; 1371 const struct dpu_sspp_sub_blks *sblk = 0; 1372 const struct dpu_sspp_cfg *cfg = 0; 1373 1374 if (!plane || !plane->dev) { 1375 DPU_ERROR("invalid arguments\n"); 1376 return -EINVAL; 1377 } 1378 1379 priv = plane->dev->dev_private; 1380 if (!priv || !priv->kms) { 1381 DPU_ERROR("invalid KMS reference\n"); 1382 return -EINVAL; 1383 } 1384 1385 kms = to_dpu_kms(priv->kms); 1386 pdpu = to_dpu_plane(plane); 1387 1388 if (pdpu && pdpu->pipe_hw) 1389 cfg = pdpu->pipe_hw->cap; 1390 if (cfg) 1391 sblk = cfg->sblk; 1392 1393 if (!sblk) 1394 return 0; 1395 1396 /* create overall sub-directory for the pipe */ 1397 pdpu->debugfs_root = 1398 debugfs_create_dir(pdpu->pipe_name, 1399 plane->dev->primary->debugfs_root); 1400 1401 if (!pdpu->debugfs_root) 1402 return -ENOMEM; 1403 1404 /* don't error check these */ 1405 debugfs_create_x32("features", 0600, 1406 pdpu->debugfs_root, &pdpu->features); 1407 1408 /* add register dump support */ 1409 dpu_debugfs_setup_regset32(&pdpu->debugfs_src, 1410 sblk->src_blk.base + cfg->base, 1411 sblk->src_blk.len, 1412 kms); 1413 dpu_debugfs_create_regset32("src_blk", 0400, 1414 pdpu->debugfs_root, &pdpu->debugfs_src); 1415 1416 if (cfg->features & BIT(DPU_SSPP_SCALER_QSEED3) || 1417 cfg->features & BIT(DPU_SSPP_SCALER_QSEED2)) { 1418 dpu_debugfs_setup_regset32(&pdpu->debugfs_scaler, 1419 sblk->scaler_blk.base + cfg->base, 1420 sblk->scaler_blk.len, 1421 kms); 1422 dpu_debugfs_create_regset32("scaler_blk", 0400, 1423 pdpu->debugfs_root, 1424 &pdpu->debugfs_scaler); 1425 debugfs_create_bool("default_scaling", 1426 0600, 1427 pdpu->debugfs_root, 1428 &pdpu->debugfs_default_scale); 1429 } 1430 1431 if (cfg->features & BIT(DPU_SSPP_CSC) || 1432 cfg->features & BIT(DPU_SSPP_CSC_10BIT)) { 1433 dpu_debugfs_setup_regset32(&pdpu->debugfs_csc, 1434 sblk->csc_blk.base + cfg->base, 1435 sblk->csc_blk.len, 1436 kms); 1437 dpu_debugfs_create_regset32("csc_blk", 0400, 1438 pdpu->debugfs_root, &pdpu->debugfs_csc); 1439 } 1440 1441 debugfs_create_u32("xin_id", 1442 0400, 1443 pdpu->debugfs_root, 1444 (u32 *) &cfg->xin_id); 1445 debugfs_create_u32("clk_ctrl", 1446 0400, 1447 pdpu->debugfs_root, 1448 (u32 *) &cfg->clk_ctrl); 1449 debugfs_create_x32("creq_vblank", 1450 0600, 1451 pdpu->debugfs_root, 1452 (u32 *) &sblk->creq_vblank); 1453 debugfs_create_x32("danger_vblank", 1454 0600, 1455 pdpu->debugfs_root, 1456 (u32 *) &sblk->danger_vblank); 1457 1458 debugfs_create_file("disable_danger", 1459 0600, 1460 pdpu->debugfs_root, 1461 kms, &dpu_plane_danger_enable); 1462 1463 return 0; 1464 } 1465 1466 static void _dpu_plane_destroy_debugfs(struct drm_plane *plane) 1467 { 1468 struct dpu_plane *pdpu; 1469 1470 if (!plane) 1471 return; 1472 pdpu = to_dpu_plane(plane); 1473 1474 debugfs_remove_recursive(pdpu->debugfs_root); 1475 } 1476 #else 1477 static int _dpu_plane_init_debugfs(struct drm_plane *plane) 1478 { 1479 return 0; 1480 } 1481 static void _dpu_plane_destroy_debugfs(struct drm_plane *plane) 1482 { 1483 } 1484 #endif 1485 1486 static int dpu_plane_late_register(struct drm_plane *plane) 1487 { 1488 return _dpu_plane_init_debugfs(plane); 1489 } 1490 1491 static void dpu_plane_early_unregister(struct drm_plane *plane) 1492 { 1493 _dpu_plane_destroy_debugfs(plane); 1494 } 1495 1496 static const struct drm_plane_funcs dpu_plane_funcs = { 1497 .update_plane = drm_atomic_helper_update_plane, 1498 .disable_plane = drm_atomic_helper_disable_plane, 1499 .destroy = dpu_plane_destroy, 1500 .reset = dpu_plane_reset, 1501 .atomic_duplicate_state = dpu_plane_duplicate_state, 1502 .atomic_destroy_state = dpu_plane_destroy_state, 1503 .late_register = dpu_plane_late_register, 1504 .early_unregister = dpu_plane_early_unregister, 1505 }; 1506 1507 static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = { 1508 .prepare_fb = dpu_plane_prepare_fb, 1509 .cleanup_fb = dpu_plane_cleanup_fb, 1510 .atomic_check = dpu_plane_atomic_check, 1511 .atomic_update = dpu_plane_atomic_update, 1512 }; 1513 1514 enum dpu_sspp dpu_plane_pipe(struct drm_plane *plane) 1515 { 1516 return plane ? to_dpu_plane(plane)->pipe : SSPP_NONE; 1517 } 1518 1519 bool is_dpu_plane_virtual(struct drm_plane *plane) 1520 { 1521 return plane ? to_dpu_plane(plane)->is_virtual : false; 1522 } 1523 1524 /* initialize plane */ 1525 struct drm_plane *dpu_plane_init(struct drm_device *dev, 1526 uint32_t pipe, enum drm_plane_type type, 1527 unsigned long possible_crtcs, u32 master_plane_id) 1528 { 1529 struct drm_plane *plane = NULL, *master_plane = NULL; 1530 const struct dpu_format_extended *format_list; 1531 struct dpu_plane *pdpu; 1532 struct msm_drm_private *priv = dev->dev_private; 1533 struct dpu_kms *kms = to_dpu_kms(priv->kms); 1534 int zpos_max = DPU_ZPOS_MAX; 1535 int ret = -EINVAL; 1536 1537 /* create and zero local structure */ 1538 pdpu = kzalloc(sizeof(*pdpu), GFP_KERNEL); 1539 if (!pdpu) { 1540 DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe); 1541 ret = -ENOMEM; 1542 goto exit; 1543 } 1544 1545 /* cache local stuff for later */ 1546 plane = &pdpu->base; 1547 pdpu->pipe = pipe; 1548 pdpu->is_virtual = (master_plane_id != 0); 1549 INIT_LIST_HEAD(&pdpu->mplane_list); 1550 master_plane = drm_plane_find(dev, NULL, master_plane_id); 1551 if (master_plane) { 1552 struct dpu_plane *mpdpu = to_dpu_plane(master_plane); 1553 1554 list_add_tail(&pdpu->mplane_list, &mpdpu->mplane_list); 1555 } 1556 1557 /* initialize underlying h/w driver */ 1558 pdpu->pipe_hw = dpu_hw_sspp_init(pipe, kms->mmio, kms->catalog, 1559 master_plane_id != 0); 1560 if (IS_ERR(pdpu->pipe_hw)) { 1561 DPU_ERROR("[%u]SSPP init failed\n", pipe); 1562 ret = PTR_ERR(pdpu->pipe_hw); 1563 goto clean_plane; 1564 } else if (!pdpu->pipe_hw->cap || !pdpu->pipe_hw->cap->sblk) { 1565 DPU_ERROR("[%u]SSPP init returned invalid cfg\n", pipe); 1566 goto clean_sspp; 1567 } 1568 1569 /* cache features mask for later */ 1570 pdpu->features = pdpu->pipe_hw->cap->features; 1571 pdpu->pipe_sblk = pdpu->pipe_hw->cap->sblk; 1572 if (!pdpu->pipe_sblk) { 1573 DPU_ERROR("[%u]invalid sblk\n", pipe); 1574 goto clean_sspp; 1575 } 1576 1577 if (!master_plane_id) 1578 format_list = pdpu->pipe_sblk->format_list; 1579 else 1580 format_list = pdpu->pipe_sblk->virt_format_list; 1581 1582 pdpu->nformats = dpu_populate_formats(format_list, 1583 pdpu->formats, 1584 0, 1585 ARRAY_SIZE(pdpu->formats)); 1586 1587 if (!pdpu->nformats) { 1588 DPU_ERROR("[%u]no valid formats for plane\n", pipe); 1589 goto clean_sspp; 1590 } 1591 1592 ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs, 1593 pdpu->formats, pdpu->nformats, 1594 NULL, type, NULL); 1595 if (ret) 1596 goto clean_sspp; 1597 1598 pdpu->catalog = kms->catalog; 1599 1600 if (kms->catalog->mixer_count && 1601 kms->catalog->mixer[0].sblk->maxblendstages) { 1602 zpos_max = kms->catalog->mixer[0].sblk->maxblendstages - 1; 1603 if (zpos_max > DPU_STAGE_MAX - DPU_STAGE_0 - 1) 1604 zpos_max = DPU_STAGE_MAX - DPU_STAGE_0 - 1; 1605 } 1606 1607 ret = drm_plane_create_zpos_property(plane, 0, 0, zpos_max); 1608 if (ret) 1609 DPU_ERROR("failed to install zpos property, rc = %d\n", ret); 1610 1611 /* success! finalize initialization */ 1612 drm_plane_helper_add(plane, &dpu_plane_helper_funcs); 1613 1614 /* save user friendly pipe name for later */ 1615 snprintf(pdpu->pipe_name, DPU_NAME_SIZE, "plane%u", plane->base.id); 1616 1617 mutex_init(&pdpu->lock); 1618 1619 DPU_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", pdpu->pipe_name, 1620 pipe, plane->base.id, master_plane_id); 1621 return plane; 1622 1623 clean_sspp: 1624 if (pdpu && pdpu->pipe_hw) 1625 dpu_hw_sspp_destroy(pdpu->pipe_hw); 1626 clean_plane: 1627 kfree(pdpu); 1628 exit: 1629 return ERR_PTR(ret); 1630 } 1631