0001
0002
0003
0004
0005
0006 #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
0007
0008 #include <linux/debugfs.h>
0009
0010 #include <drm/drm_framebuffer.h>
0011
0012 #include "dpu_encoder_phys.h"
0013 #include "dpu_formats.h"
0014 #include "dpu_hw_top.h"
0015 #include "dpu_hw_wb.h"
0016 #include "dpu_hw_lm.h"
0017 #include "dpu_hw_merge3d.h"
0018 #include "dpu_hw_interrupts.h"
0019 #include "dpu_core_irq.h"
0020 #include "dpu_vbif.h"
0021 #include "dpu_crtc.h"
0022 #include "disp/msm_disp_snapshot.h"
0023
0024 #define to_dpu_encoder_phys_wb(x) \
0025 container_of(x, struct dpu_encoder_phys_wb, base)
0026
0027
0028
0029
0030 static bool dpu_encoder_phys_wb_is_master(struct dpu_encoder_phys *phys_enc)
0031 {
0032
0033 return true;
0034 }
0035
0036
0037
0038
0039
0040 static void dpu_encoder_phys_wb_set_ot_limit(
0041 struct dpu_encoder_phys *phys_enc)
0042 {
0043 struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
0044 struct dpu_vbif_set_ot_params ot_params;
0045
0046 memset(&ot_params, 0, sizeof(ot_params));
0047 ot_params.xin_id = hw_wb->caps->xin_id;
0048 ot_params.num = hw_wb->idx - WB_0;
0049 ot_params.width = phys_enc->cached_mode.hdisplay;
0050 ot_params.height = phys_enc->cached_mode.vdisplay;
0051 ot_params.is_wfd = true;
0052 ot_params.frame_rate = drm_mode_vrefresh(&phys_enc->cached_mode);
0053 ot_params.vbif_idx = hw_wb->caps->vbif_idx;
0054 ot_params.clk_ctrl = hw_wb->caps->clk_ctrl;
0055 ot_params.rd = false;
0056
0057 dpu_vbif_set_ot_limit(phys_enc->dpu_kms, &ot_params);
0058 }
0059
0060
0061
0062
0063
0064 static void dpu_encoder_phys_wb_set_qos_remap(
0065 struct dpu_encoder_phys *phys_enc)
0066 {
0067 struct dpu_hw_wb *hw_wb;
0068 struct dpu_vbif_set_qos_params qos_params;
0069
0070 if (!phys_enc || !phys_enc->parent || !phys_enc->parent->crtc) {
0071 DPU_ERROR("invalid arguments\n");
0072 return;
0073 }
0074
0075 if (!phys_enc->hw_wb || !phys_enc->hw_wb->caps) {
0076 DPU_ERROR("invalid writeback hardware\n");
0077 return;
0078 }
0079
0080 hw_wb = phys_enc->hw_wb;
0081
0082 memset(&qos_params, 0, sizeof(qos_params));
0083 qos_params.vbif_idx = hw_wb->caps->vbif_idx;
0084 qos_params.xin_id = hw_wb->caps->xin_id;
0085 qos_params.clk_ctrl = hw_wb->caps->clk_ctrl;
0086 qos_params.num = hw_wb->idx - WB_0;
0087 qos_params.is_rt = false;
0088
0089 DPU_DEBUG("[qos_remap] wb:%d vbif:%d xin:%d is_rt:%d\n",
0090 qos_params.num,
0091 qos_params.vbif_idx,
0092 qos_params.xin_id, qos_params.is_rt);
0093
0094 dpu_vbif_set_qos_remap(phys_enc->dpu_kms, &qos_params);
0095 }
0096
0097
0098
0099
0100
0101 static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc)
0102 {
0103 struct dpu_hw_wb *hw_wb;
0104 struct dpu_hw_wb_qos_cfg qos_cfg;
0105 const struct dpu_mdss_cfg *catalog;
0106 const struct dpu_qos_lut_tbl *qos_lut_tb;
0107
0108 if (!phys_enc || !phys_enc->dpu_kms || !phys_enc->dpu_kms->catalog) {
0109 DPU_ERROR("invalid parameter(s)\n");
0110 return;
0111 }
0112
0113 catalog = phys_enc->dpu_kms->catalog;
0114
0115 hw_wb = phys_enc->hw_wb;
0116
0117 memset(&qos_cfg, 0, sizeof(struct dpu_hw_wb_qos_cfg));
0118 qos_cfg.danger_safe_en = true;
0119 qos_cfg.danger_lut =
0120 catalog->perf->danger_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
0121
0122 qos_cfg.safe_lut = catalog->perf->safe_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
0123
0124 qos_lut_tb = &catalog->perf->qos_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
0125 qos_cfg.creq_lut = _dpu_hw_get_qos_lut(qos_lut_tb, 0);
0126
0127 if (hw_wb->ops.setup_qos_lut)
0128 hw_wb->ops.setup_qos_lut(hw_wb, &qos_cfg);
0129 }
0130
0131
0132
0133
0134
0135
0136
0137 static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc,
0138 struct drm_framebuffer *fb)
0139 {
0140 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
0141 struct dpu_hw_wb *hw_wb;
0142 struct dpu_hw_wb_cfg *wb_cfg;
0143 struct dpu_hw_cdp_cfg cdp_cfg;
0144
0145 if (!phys_enc || !phys_enc->dpu_kms || !phys_enc->dpu_kms->catalog) {
0146 DPU_ERROR("invalid encoder\n");
0147 return;
0148 }
0149
0150 hw_wb = phys_enc->hw_wb;
0151 wb_cfg = &wb_enc->wb_cfg;
0152
0153 wb_cfg->intf_mode = phys_enc->intf_mode;
0154 wb_cfg->roi.x1 = 0;
0155 wb_cfg->roi.x2 = phys_enc->cached_mode.hdisplay;
0156 wb_cfg->roi.y1 = 0;
0157 wb_cfg->roi.y2 = phys_enc->cached_mode.vdisplay;
0158
0159 if (hw_wb->ops.setup_roi)
0160 hw_wb->ops.setup_roi(hw_wb, wb_cfg);
0161
0162 if (hw_wb->ops.setup_outformat)
0163 hw_wb->ops.setup_outformat(hw_wb, wb_cfg);
0164
0165 if (hw_wb->ops.setup_cdp) {
0166 memset(&cdp_cfg, 0, sizeof(struct dpu_hw_cdp_cfg));
0167
0168 cdp_cfg.enable = phys_enc->dpu_kms->catalog->perf->cdp_cfg
0169 [DPU_PERF_CDP_USAGE_NRT].wr_enable;
0170 cdp_cfg.ubwc_meta_enable =
0171 DPU_FORMAT_IS_UBWC(wb_cfg->dest.format);
0172 cdp_cfg.tile_amortize_enable =
0173 DPU_FORMAT_IS_UBWC(wb_cfg->dest.format) ||
0174 DPU_FORMAT_IS_TILE(wb_cfg->dest.format);
0175 cdp_cfg.preload_ahead = DPU_WB_CDP_PRELOAD_AHEAD_64;
0176
0177 hw_wb->ops.setup_cdp(hw_wb, &cdp_cfg);
0178 }
0179
0180 if (hw_wb->ops.setup_outaddress)
0181 hw_wb->ops.setup_outaddress(hw_wb, wb_cfg);
0182 }
0183
0184
0185
0186
0187
0188 static void dpu_encoder_phys_wb_setup_cdp(struct dpu_encoder_phys *phys_enc)
0189 {
0190 struct dpu_hw_wb *hw_wb;
0191 struct dpu_hw_ctl *ctl;
0192
0193 if (!phys_enc) {
0194 DPU_ERROR("invalid encoder\n");
0195 return;
0196 }
0197
0198 hw_wb = phys_enc->hw_wb;
0199 ctl = phys_enc->hw_ctl;
0200
0201 if (test_bit(DPU_CTL_ACTIVE_CFG, &ctl->caps->features) &&
0202 (phys_enc->hw_ctl &&
0203 phys_enc->hw_ctl->ops.setup_intf_cfg)) {
0204 struct dpu_hw_intf_cfg intf_cfg = {0};
0205 struct dpu_hw_pingpong *hw_pp = phys_enc->hw_pp;
0206 enum dpu_3d_blend_mode mode_3d;
0207
0208 mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
0209
0210 intf_cfg.intf = DPU_NONE;
0211 intf_cfg.wb = hw_wb->idx;
0212
0213 if (mode_3d && hw_pp && hw_pp->merge_3d)
0214 intf_cfg.merge_3d = hw_pp->merge_3d->idx;
0215
0216 if (phys_enc->hw_pp->merge_3d && phys_enc->hw_pp->merge_3d->ops.setup_3d_mode)
0217 phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d,
0218 mode_3d);
0219
0220
0221 if (hw_pp && phys_enc->hw_wb->ops.bind_pingpong_blk)
0222 phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, true,
0223 phys_enc->hw_pp->idx);
0224
0225 phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
0226 } else if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) {
0227 struct dpu_hw_intf_cfg intf_cfg = {0};
0228
0229 intf_cfg.intf = DPU_NONE;
0230 intf_cfg.wb = hw_wb->idx;
0231 intf_cfg.mode_3d =
0232 dpu_encoder_helper_get_3d_blend_mode(phys_enc);
0233 phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
0234 }
0235 }
0236
0237
0238
0239
0240
0241
0242
0243 static int dpu_encoder_phys_wb_atomic_check(
0244 struct dpu_encoder_phys *phys_enc,
0245 struct drm_crtc_state *crtc_state,
0246 struct drm_connector_state *conn_state)
0247 {
0248 struct drm_framebuffer *fb;
0249 const struct drm_display_mode *mode = &crtc_state->mode;
0250
0251 DPU_DEBUG("[atomic_check:%d, \"%s\",%d,%d]\n",
0252 phys_enc->wb_idx, mode->name, mode->hdisplay, mode->vdisplay);
0253
0254 if (!conn_state || !conn_state->connector) {
0255 DPU_ERROR("invalid connector state\n");
0256 return -EINVAL;
0257 } else if (conn_state->connector->status !=
0258 connector_status_connected) {
0259 DPU_ERROR("connector not connected %d\n",
0260 conn_state->connector->status);
0261 return -EINVAL;
0262 }
0263
0264 if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
0265 return 0;
0266
0267 fb = conn_state->writeback_job->fb;
0268
0269 DPU_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
0270 fb->width, fb->height);
0271
0272 if (fb->width != mode->hdisplay) {
0273 DPU_ERROR("invalid fb w=%d, mode w=%d\n", fb->width,
0274 mode->hdisplay);
0275 return -EINVAL;
0276 } else if (fb->height != mode->vdisplay) {
0277 DPU_ERROR("invalid fb h=%d, mode h=%d\n", fb->height,
0278 mode->vdisplay);
0279 return -EINVAL;
0280 } else if (fb->width > phys_enc->hw_wb->caps->maxlinewidth) {
0281 DPU_ERROR("invalid fb w=%d, maxlinewidth=%u\n",
0282 fb->width, phys_enc->hw_wb->caps->maxlinewidth);
0283 return -EINVAL;
0284 }
0285
0286 return 0;
0287 }
0288
0289
0290
0291
0292
0293
0294 static void _dpu_encoder_phys_wb_update_flush(struct dpu_encoder_phys *phys_enc)
0295 {
0296 struct dpu_hw_wb *hw_wb;
0297 struct dpu_hw_ctl *hw_ctl;
0298 struct dpu_hw_pingpong *hw_pp;
0299 u32 pending_flush = 0;
0300
0301 if (!phys_enc)
0302 return;
0303
0304 hw_wb = phys_enc->hw_wb;
0305 hw_pp = phys_enc->hw_pp;
0306 hw_ctl = phys_enc->hw_ctl;
0307
0308 DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
0309
0310 if (!hw_ctl) {
0311 DPU_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0);
0312 return;
0313 }
0314
0315 if (hw_ctl->ops.update_pending_flush_wb)
0316 hw_ctl->ops.update_pending_flush_wb(hw_ctl, hw_wb->idx);
0317
0318 if (hw_ctl->ops.update_pending_flush_merge_3d && hw_pp && hw_pp->merge_3d)
0319 hw_ctl->ops.update_pending_flush_merge_3d(hw_ctl,
0320 hw_pp->merge_3d->idx);
0321
0322 if (hw_ctl->ops.get_pending_flush)
0323 pending_flush = hw_ctl->ops.get_pending_flush(hw_ctl);
0324
0325 DPU_DEBUG("Pending flush mask for CTL_%d is 0x%x, WB %d\n",
0326 hw_ctl->idx - CTL_0, pending_flush,
0327 hw_wb->idx - WB_0);
0328 }
0329
0330
0331
0332
0333
0334 static void dpu_encoder_phys_wb_setup(
0335 struct dpu_encoder_phys *phys_enc)
0336 {
0337 struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
0338 struct drm_display_mode mode = phys_enc->cached_mode;
0339 struct drm_framebuffer *fb = NULL;
0340
0341 DPU_DEBUG("[mode_set:%d, \"%s\",%d,%d]\n",
0342 hw_wb->idx - WB_0, mode.name,
0343 mode.hdisplay, mode.vdisplay);
0344
0345 dpu_encoder_phys_wb_set_ot_limit(phys_enc);
0346
0347 dpu_encoder_phys_wb_set_qos_remap(phys_enc);
0348
0349 dpu_encoder_phys_wb_set_qos(phys_enc);
0350
0351 dpu_encoder_phys_wb_setup_fb(phys_enc, fb);
0352
0353 dpu_encoder_phys_wb_setup_cdp(phys_enc);
0354
0355 }
0356
0357 static void _dpu_encoder_phys_wb_frame_done_helper(void *arg)
0358 {
0359 struct dpu_encoder_phys *phys_enc = arg;
0360 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
0361
0362 struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
0363 unsigned long lock_flags;
0364 u32 event = DPU_ENCODER_FRAME_EVENT_DONE;
0365
0366 DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
0367
0368 if (phys_enc->parent_ops->handle_frame_done)
0369 phys_enc->parent_ops->handle_frame_done(phys_enc->parent,
0370 phys_enc, event);
0371
0372 if (phys_enc->parent_ops->handle_vblank_virt)
0373 phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent,
0374 phys_enc);
0375
0376 spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
0377 atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
0378 spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
0379
0380 if (wb_enc->wb_conn)
0381 drm_writeback_signal_completion(wb_enc->wb_conn, 0);
0382
0383
0384 wake_up_all(&phys_enc->pending_kickoff_wq);
0385 }
0386
0387
0388
0389
0390
0391
0392 static void dpu_encoder_phys_wb_done_irq(void *arg, int irq_idx)
0393 {
0394 _dpu_encoder_phys_wb_frame_done_helper(arg);
0395 }
0396
0397
0398
0399
0400
0401
0402 static void dpu_encoder_phys_wb_irq_ctrl(
0403 struct dpu_encoder_phys *phys, bool enable)
0404 {
0405
0406 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys);
0407
0408 if (enable && atomic_inc_return(&wb_enc->wbirq_refcount) == 1)
0409 dpu_core_irq_register_callback(phys->dpu_kms,
0410 phys->irq[INTR_IDX_WB_DONE], dpu_encoder_phys_wb_done_irq, phys);
0411 else if (!enable &&
0412 atomic_dec_return(&wb_enc->wbirq_refcount) == 0)
0413 dpu_core_irq_unregister_callback(phys->dpu_kms, phys->irq[INTR_IDX_WB_DONE]);
0414 }
0415
0416 static void dpu_encoder_phys_wb_atomic_mode_set(
0417 struct dpu_encoder_phys *phys_enc,
0418 struct drm_crtc_state *crtc_state,
0419 struct drm_connector_state *conn_state)
0420 {
0421
0422 phys_enc->irq[INTR_IDX_WB_DONE] = phys_enc->hw_wb->caps->intr_wb_done;
0423 }
0424
0425 static void _dpu_encoder_phys_wb_handle_wbdone_timeout(
0426 struct dpu_encoder_phys *phys_enc)
0427 {
0428 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
0429 u32 frame_event = DPU_ENCODER_FRAME_EVENT_ERROR;
0430
0431 wb_enc->wb_done_timeout_cnt++;
0432
0433 if (wb_enc->wb_done_timeout_cnt == 1)
0434 msm_disp_snapshot_state(phys_enc->parent->dev);
0435
0436 atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
0437
0438
0439 phys_enc->enable_state = DPU_ENC_ERR_NEEDS_HW_RESET;
0440
0441 if (wb_enc->wb_conn)
0442 drm_writeback_signal_completion(wb_enc->wb_conn, 0);
0443
0444 if (phys_enc->parent_ops->handle_frame_done)
0445 phys_enc->parent_ops->handle_frame_done(
0446 phys_enc->parent, phys_enc, frame_event);
0447 }
0448
0449
0450
0451
0452
0453 static int dpu_encoder_phys_wb_wait_for_commit_done(
0454 struct dpu_encoder_phys *phys_enc)
0455 {
0456 unsigned long ret;
0457 struct dpu_encoder_wait_info wait_info;
0458 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
0459
0460 wait_info.wq = &phys_enc->pending_kickoff_wq;
0461 wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
0462 wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
0463
0464 ret = dpu_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE,
0465 dpu_encoder_phys_wb_done_irq, &wait_info);
0466 if (ret == -ETIMEDOUT)
0467 _dpu_encoder_phys_wb_handle_wbdone_timeout(phys_enc);
0468 else if (!ret)
0469 wb_enc->wb_done_timeout_cnt = 0;
0470
0471 return ret;
0472 }
0473
0474
0475
0476
0477
0478
0479 static void dpu_encoder_phys_wb_prepare_for_kickoff(
0480 struct dpu_encoder_phys *phys_enc)
0481 {
0482 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
0483 struct drm_connector *drm_conn;
0484 struct drm_connector_state *state;
0485
0486 DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
0487
0488 if (!wb_enc->wb_conn || !wb_enc->wb_job) {
0489 DPU_ERROR("invalid wb_conn or wb_job\n");
0490 return;
0491 }
0492
0493 drm_conn = &wb_enc->wb_conn->base;
0494 state = drm_conn->state;
0495
0496 if (wb_enc->wb_conn && wb_enc->wb_job)
0497 drm_writeback_queue_job(wb_enc->wb_conn, state);
0498
0499 dpu_encoder_phys_wb_setup(phys_enc);
0500
0501 _dpu_encoder_phys_wb_update_flush(phys_enc);
0502 }
0503
0504
0505
0506
0507
0508 static bool dpu_encoder_phys_wb_needs_single_flush(struct dpu_encoder_phys *phys_enc)
0509 {
0510 DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
0511 return false;
0512 }
0513
0514
0515
0516
0517
0518 static void dpu_encoder_phys_wb_handle_post_kickoff(
0519 struct dpu_encoder_phys *phys_enc)
0520 {
0521 DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
0522
0523 }
0524
0525
0526
0527
0528
0529 static void dpu_encoder_phys_wb_enable(struct dpu_encoder_phys *phys_enc)
0530 {
0531 DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
0532 phys_enc->enable_state = DPU_ENC_ENABLED;
0533 }
0534
0535
0536
0537
0538 static void dpu_encoder_phys_wb_disable(struct dpu_encoder_phys *phys_enc)
0539 {
0540 struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
0541 struct dpu_hw_ctl *hw_ctl = phys_enc->hw_ctl;
0542
0543 DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
0544
0545 if (phys_enc->enable_state == DPU_ENC_DISABLED) {
0546 DPU_ERROR("encoder is already disabled\n");
0547 return;
0548 }
0549
0550
0551 if (phys_enc->hw_ctl->ops.clear_pending_flush)
0552 phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl);
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564 if (hw_ctl->caps->features & BIT(DPU_CTL_ACTIVE_CFG))
0565 dpu_encoder_helper_phys_cleanup(phys_enc);
0566
0567 phys_enc->enable_state = DPU_ENC_DISABLED;
0568 }
0569
0570
0571
0572
0573
0574 static void dpu_encoder_phys_wb_destroy(struct dpu_encoder_phys *phys_enc)
0575 {
0576 if (!phys_enc)
0577 return;
0578
0579 DPU_DEBUG("[wb:%d]\n", phys_enc->wb_idx - WB_0);
0580
0581 kfree(phys_enc);
0582 }
0583
0584 static void dpu_encoder_phys_wb_prepare_wb_job(struct dpu_encoder_phys *phys_enc,
0585 struct drm_writeback_job *job)
0586 {
0587 const struct msm_format *format;
0588 struct msm_gem_address_space *aspace;
0589 struct dpu_hw_wb_cfg *wb_cfg;
0590 int ret;
0591 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
0592
0593 if (!job->fb)
0594 return;
0595
0596 wb_enc->wb_job = job;
0597 wb_enc->wb_conn = job->connector;
0598 aspace = phys_enc->dpu_kms->base.aspace;
0599
0600 wb_cfg = &wb_enc->wb_cfg;
0601
0602 memset(wb_cfg, 0, sizeof(struct dpu_hw_wb_cfg));
0603
0604 ret = msm_framebuffer_prepare(job->fb, aspace, false);
0605 if (ret) {
0606 DPU_ERROR("prep fb failed, %d\n", ret);
0607 return;
0608 }
0609
0610 format = msm_framebuffer_format(job->fb);
0611
0612 wb_cfg->dest.format = dpu_get_dpu_format_ext(
0613 format->pixel_format, job->fb->modifier);
0614 if (!wb_cfg->dest.format) {
0615
0616 DPU_ERROR("failed to get format %x\n", format->pixel_format);
0617 return;
0618 }
0619
0620 ret = dpu_format_populate_layout(aspace, job->fb, &wb_cfg->dest);
0621 if (ret) {
0622 DPU_DEBUG("failed to populate layout %d\n", ret);
0623 return;
0624 }
0625
0626 wb_cfg->dest.width = job->fb->width;
0627 wb_cfg->dest.height = job->fb->height;
0628 wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes;
0629
0630 if ((wb_cfg->dest.format->fetch_planes == DPU_PLANE_PLANAR) &&
0631 (wb_cfg->dest.format->element[0] == C1_B_Cb))
0632 swap(wb_cfg->dest.plane_addr[1], wb_cfg->dest.plane_addr[2]);
0633
0634 DPU_DEBUG("[fb_offset:%8.8x,%8.8x,%8.8x,%8.8x]\n",
0635 wb_cfg->dest.plane_addr[0], wb_cfg->dest.plane_addr[1],
0636 wb_cfg->dest.plane_addr[2], wb_cfg->dest.plane_addr[3]);
0637
0638 DPU_DEBUG("[fb_stride:%8.8x,%8.8x,%8.8x,%8.8x]\n",
0639 wb_cfg->dest.plane_pitch[0], wb_cfg->dest.plane_pitch[1],
0640 wb_cfg->dest.plane_pitch[2], wb_cfg->dest.plane_pitch[3]);
0641 }
0642
0643 static void dpu_encoder_phys_wb_cleanup_wb_job(struct dpu_encoder_phys *phys_enc,
0644 struct drm_writeback_job *job)
0645 {
0646 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
0647 struct msm_gem_address_space *aspace;
0648
0649 if (!job->fb)
0650 return;
0651
0652 aspace = phys_enc->dpu_kms->base.aspace;
0653
0654 msm_framebuffer_cleanup(job->fb, aspace, false);
0655 wb_enc->wb_job = NULL;
0656 wb_enc->wb_conn = NULL;
0657 }
0658
0659 static bool dpu_encoder_phys_wb_is_valid_for_commit(struct dpu_encoder_phys *phys_enc)
0660 {
0661 struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
0662
0663 if (wb_enc->wb_job)
0664 return true;
0665 else
0666 return false;
0667 }
0668
0669
0670
0671
0672
0673 static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops)
0674 {
0675 ops->is_master = dpu_encoder_phys_wb_is_master;
0676 ops->atomic_mode_set = dpu_encoder_phys_wb_atomic_mode_set;
0677 ops->enable = dpu_encoder_phys_wb_enable;
0678 ops->disable = dpu_encoder_phys_wb_disable;
0679 ops->destroy = dpu_encoder_phys_wb_destroy;
0680 ops->atomic_check = dpu_encoder_phys_wb_atomic_check;
0681 ops->wait_for_commit_done = dpu_encoder_phys_wb_wait_for_commit_done;
0682 ops->prepare_for_kickoff = dpu_encoder_phys_wb_prepare_for_kickoff;
0683 ops->handle_post_kickoff = dpu_encoder_phys_wb_handle_post_kickoff;
0684 ops->needs_single_flush = dpu_encoder_phys_wb_needs_single_flush;
0685 ops->trigger_start = dpu_encoder_helper_trigger_start;
0686 ops->prepare_wb_job = dpu_encoder_phys_wb_prepare_wb_job;
0687 ops->cleanup_wb_job = dpu_encoder_phys_wb_cleanup_wb_job;
0688 ops->irq_control = dpu_encoder_phys_wb_irq_ctrl;
0689 ops->is_valid_for_commit = dpu_encoder_phys_wb_is_valid_for_commit;
0690
0691 }
0692
0693
0694
0695
0696
0697 struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
0698 struct dpu_enc_phys_init_params *p)
0699 {
0700 struct dpu_encoder_phys *phys_enc = NULL;
0701 struct dpu_encoder_phys_wb *wb_enc = NULL;
0702 int ret = 0;
0703 int i;
0704
0705 DPU_DEBUG("\n");
0706
0707 if (!p || !p->parent) {
0708 DPU_ERROR("invalid params\n");
0709 ret = -EINVAL;
0710 goto fail_alloc;
0711 }
0712
0713 wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL);
0714 if (!wb_enc) {
0715 DPU_ERROR("failed to allocate wb phys_enc enc\n");
0716 ret = -ENOMEM;
0717 goto fail_alloc;
0718 }
0719
0720 phys_enc = &wb_enc->base;
0721 phys_enc->hw_mdptop = p->dpu_kms->hw_mdp;
0722 phys_enc->wb_idx = p->wb_idx;
0723
0724 dpu_encoder_phys_wb_init_ops(&phys_enc->ops);
0725 phys_enc->parent = p->parent;
0726 phys_enc->parent_ops = p->parent_ops;
0727 phys_enc->dpu_kms = p->dpu_kms;
0728 phys_enc->split_role = p->split_role;
0729 phys_enc->intf_mode = INTF_MODE_WB_LINE;
0730 phys_enc->wb_idx = p->wb_idx;
0731 phys_enc->enc_spinlock = p->enc_spinlock;
0732
0733 atomic_set(&wb_enc->wbirq_refcount, 0);
0734
0735 for (i = 0; i < ARRAY_SIZE(phys_enc->irq); i++)
0736 phys_enc->irq[i] = -EINVAL;
0737
0738 atomic_set(&phys_enc->pending_kickoff_cnt, 0);
0739 atomic_set(&phys_enc->vblank_refcount, 0);
0740 wb_enc->wb_done_timeout_cnt = 0;
0741
0742 init_waitqueue_head(&phys_enc->pending_kickoff_wq);
0743 phys_enc->enable_state = DPU_ENC_DISABLED;
0744
0745 DPU_DEBUG("Created dpu_encoder_phys for wb %d\n",
0746 phys_enc->wb_idx);
0747
0748 return phys_enc;
0749
0750 fail_alloc:
0751 return ERR_PTR(ret);
0752 }