Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
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  * dpu_encoder_phys_wb_is_master - report wb always as master encoder
0029  */
0030 static bool dpu_encoder_phys_wb_is_master(struct dpu_encoder_phys *phys_enc)
0031 {
0032     /* there is only one physical enc for dpu_writeback */
0033     return true;
0034 }
0035 
0036 /**
0037  * dpu_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface
0038  * @phys_enc:   Pointer to physical encoder
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  * dpu_encoder_phys_wb_set_qos_remap - set QoS remapper for writeback
0062  * @phys_enc:   Pointer to physical encoder
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  * dpu_encoder_phys_wb_set_qos - set QoS/danger/safe LUTs for writeback
0099  * @phys_enc:   Pointer to physical encoder
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  * dpu_encoder_phys_wb_setup_fb - setup output framebuffer
0133  * @phys_enc:   Pointer to physical encoder
0134  * @fb:     Pointer to output framebuffer
0135  * @wb_roi: Pointer to output region of interest
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  * dpu_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
0186  * @phys_enc:Pointer to physical encoder
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         /* setup which pp blk will connect to this wb */
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  * dpu_encoder_phys_wb_atomic_check - verify and fixup given atomic states
0239  * @phys_enc:   Pointer to physical encoder
0240  * @crtc_state: Pointer to CRTC atomic state
0241  * @conn_state: Pointer to connector atomic state
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  * _dpu_encoder_phys_wb_update_flush - flush hardware update
0292  * @phys_enc:   Pointer to physical encoder
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  * dpu_encoder_phys_wb_setup - setup writeback encoder
0332  * @phys_enc:   Pointer to physical encoder
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     /* Signal any waiting atomic commit thread */
0384     wake_up_all(&phys_enc->pending_kickoff_wq);
0385 }
0386 
0387 /**
0388  * dpu_encoder_phys_wb_done_irq - writeback interrupt handler
0389  * @arg:    Pointer to writeback encoder
0390  * @irq_idx:    interrupt index
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  * dpu_encoder_phys_wb_irq_ctrl - irq control of WB
0399  * @phys:   Pointer to physical encoder
0400  * @enable: indicates enable or disable interrupts
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     /* request a ctl reset before the next kickoff */
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  * dpu_encoder_phys_wb_wait_for_commit_done - wait until request is committed
0451  * @phys_enc:   Pointer to physical encoder
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  * dpu_encoder_phys_wb_prepare_for_kickoff - pre-kickoff processing
0476  * @phys_enc:   Pointer to physical encoder
0477  * Returns: Zero on success
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  * dpu_encoder_phys_wb_needs_single_flush - trigger flush processing
0506  * @phys_enc:   Pointer to physical encoder
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  * dpu_encoder_phys_wb_handle_post_kickoff - post-kickoff processing
0516  * @phys_enc:   Pointer to physical encoder
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  * dpu_encoder_phys_wb_enable - enable writeback encoder
0527  * @phys_enc:   Pointer to physical encoder
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  * dpu_encoder_phys_wb_disable - disable writeback encoder
0536  * @phys_enc:   Pointer to physical encoder
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     /* reset h/w before final flush */
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      * New CTL reset sequence from 5.0 MDP onwards.
0556      * If has_3d_merge_reset is not set, legacy reset
0557      * sequence is executed.
0558      *
0559      * Legacy reset sequence has not been implemented yet.
0560      * Any target earlier than SM8150 will need it and when
0561      * WB support is added to those targets will need to add
0562      * the legacy teardown sequence as well.
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  * dpu_encoder_phys_wb_destroy - destroy writeback encoder
0572  * @phys_enc:   Pointer to physical encoder
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         /* this error should be detected during atomic_check */
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  * dpu_encoder_phys_wb_init_ops - initialize writeback operations
0671  * @ops:    Pointer to encoder operation table
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  * dpu_encoder_phys_wb_init - initialize writeback encoder
0695  * @init:   Pointer to init info structure with initialization params
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 }