Merge tag 'soc-fixes-5.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[sfrench/cifs-2.6.git] / drivers / gpu / drm / msm / disp / dpu1 / dpu_encoder_phys_wb.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  */
5
6 #define pr_fmt(fmt)     "[drm:%s:%d] " fmt, __func__, __LINE__
7
8 #include <linux/debugfs.h>
9
10 #include "dpu_encoder_phys.h"
11 #include "dpu_formats.h"
12 #include "dpu_hw_top.h"
13 #include "dpu_hw_wb.h"
14 #include "dpu_hw_lm.h"
15 #include "dpu_hw_blk.h"
16 #include "dpu_hw_merge3d.h"
17 #include "dpu_hw_interrupts.h"
18 #include "dpu_core_irq.h"
19 #include "dpu_vbif.h"
20 #include "dpu_crtc.h"
21 #include "disp/msm_disp_snapshot.h"
22
23 #define DEFAULT_MAX_WRITEBACK_WIDTH 2048
24
25 #define to_dpu_encoder_phys_wb(x) \
26         container_of(x, struct dpu_encoder_phys_wb, base)
27
28 /**
29  * dpu_encoder_phys_wb_is_master - report wb always as master encoder
30  */
31 static bool dpu_encoder_phys_wb_is_master(struct dpu_encoder_phys *phys_enc)
32 {
33         /* there is only one physical enc for dpu_writeback */
34         return true;
35 }
36
37 /**
38  * dpu_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface
39  * @phys_enc:   Pointer to physical encoder
40  */
41 static void dpu_encoder_phys_wb_set_ot_limit(
42                 struct dpu_encoder_phys *phys_enc)
43 {
44         struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
45         struct dpu_vbif_set_ot_params ot_params;
46
47         memset(&ot_params, 0, sizeof(ot_params));
48         ot_params.xin_id = hw_wb->caps->xin_id;
49         ot_params.num = hw_wb->idx - WB_0;
50         ot_params.width = phys_enc->cached_mode.hdisplay;
51         ot_params.height = phys_enc->cached_mode.vdisplay;
52         ot_params.is_wfd = true;
53         ot_params.frame_rate = drm_mode_vrefresh(&phys_enc->cached_mode);
54         ot_params.vbif_idx = hw_wb->caps->vbif_idx;
55         ot_params.clk_ctrl = hw_wb->caps->clk_ctrl;
56         ot_params.rd = false;
57
58         dpu_vbif_set_ot_limit(phys_enc->dpu_kms, &ot_params);
59 }
60
61 /**
62  * dpu_encoder_phys_wb_set_qos_remap - set QoS remapper for writeback
63  * @phys_enc:   Pointer to physical encoder
64  */
65 static void dpu_encoder_phys_wb_set_qos_remap(
66                 struct dpu_encoder_phys *phys_enc)
67 {
68         struct dpu_hw_wb *hw_wb;
69         struct dpu_vbif_set_qos_params qos_params;
70
71         if (!phys_enc || !phys_enc->parent || !phys_enc->parent->crtc) {
72                 DPU_ERROR("invalid arguments\n");
73                 return;
74         }
75
76         if (!phys_enc->hw_wb || !phys_enc->hw_wb->caps) {
77                 DPU_ERROR("invalid writeback hardware\n");
78                 return;
79         }
80
81         hw_wb = phys_enc->hw_wb;
82
83         memset(&qos_params, 0, sizeof(qos_params));
84         qos_params.vbif_idx = hw_wb->caps->vbif_idx;
85         qos_params.xin_id = hw_wb->caps->xin_id;
86         qos_params.clk_ctrl = hw_wb->caps->clk_ctrl;
87         qos_params.num = hw_wb->idx - WB_0;
88         qos_params.is_rt = false;
89
90         DPU_DEBUG("[qos_remap] wb:%d vbif:%d xin:%d is_rt:%d\n",
91                         qos_params.num,
92                         qos_params.vbif_idx,
93                         qos_params.xin_id, qos_params.is_rt);
94
95         dpu_vbif_set_qos_remap(phys_enc->dpu_kms, &qos_params);
96 }
97
98 /**
99  * dpu_encoder_phys_wb_set_qos - set QoS/danger/safe LUTs for writeback
100  * @phys_enc:   Pointer to physical encoder
101  */
102 static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc)
103 {
104         struct dpu_hw_wb *hw_wb;
105         struct dpu_hw_wb_qos_cfg qos_cfg;
106         struct dpu_mdss_cfg *catalog;
107         struct dpu_qos_lut_tbl *qos_lut_tb;
108
109         if (!phys_enc || !phys_enc->dpu_kms || !phys_enc->dpu_kms->catalog) {
110                 DPU_ERROR("invalid parameter(s)\n");
111                 return;
112         }
113
114         catalog = phys_enc->dpu_kms->catalog;
115
116         hw_wb = phys_enc->hw_wb;
117
118         memset(&qos_cfg, 0, sizeof(struct dpu_hw_wb_qos_cfg));
119         qos_cfg.danger_safe_en = true;
120         qos_cfg.danger_lut =
121                 catalog->perf.danger_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
122
123         qos_cfg.safe_lut = catalog->perf.safe_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
124
125         qos_lut_tb = &catalog->perf.qos_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
126         qos_cfg.creq_lut = _dpu_hw_get_qos_lut(qos_lut_tb, 0);
127
128         if (hw_wb->ops.setup_qos_lut)
129                 hw_wb->ops.setup_qos_lut(hw_wb, &qos_cfg);
130 }
131
132 /**
133  * dpu_encoder_phys_wb_setup_fb - setup output framebuffer
134  * @phys_enc:   Pointer to physical encoder
135  * @fb:         Pointer to output framebuffer
136  * @wb_roi:     Pointer to output region of interest
137  */
138 static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc,
139                 struct drm_framebuffer *fb)
140 {
141         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
142         struct dpu_hw_wb *hw_wb;
143         struct dpu_hw_wb_cfg *wb_cfg;
144         struct dpu_hw_cdp_cfg cdp_cfg;
145
146         if (!phys_enc || !phys_enc->dpu_kms || !phys_enc->dpu_kms->catalog) {
147                 DPU_ERROR("invalid encoder\n");
148                 return;
149         }
150
151         hw_wb = phys_enc->hw_wb;
152         wb_cfg = &wb_enc->wb_cfg;
153
154         wb_cfg->intf_mode = phys_enc->intf_mode;
155         wb_cfg->roi.x1 = 0;
156         wb_cfg->roi.x2 = phys_enc->cached_mode.hdisplay;
157         wb_cfg->roi.y1 = 0;
158         wb_cfg->roi.y2 = phys_enc->cached_mode.vdisplay;
159
160         if (hw_wb->ops.setup_roi)
161                 hw_wb->ops.setup_roi(hw_wb, wb_cfg);
162
163         if (hw_wb->ops.setup_outformat)
164                 hw_wb->ops.setup_outformat(hw_wb, wb_cfg);
165
166         if (hw_wb->ops.setup_cdp) {
167                 memset(&cdp_cfg, 0, sizeof(struct dpu_hw_cdp_cfg));
168
169                 cdp_cfg.enable = phys_enc->dpu_kms->catalog->perf.cdp_cfg
170                                 [DPU_PERF_CDP_USAGE_NRT].wr_enable;
171                 cdp_cfg.ubwc_meta_enable =
172                                 DPU_FORMAT_IS_UBWC(wb_cfg->dest.format);
173                 cdp_cfg.tile_amortize_enable =
174                                 DPU_FORMAT_IS_UBWC(wb_cfg->dest.format) ||
175                                 DPU_FORMAT_IS_TILE(wb_cfg->dest.format);
176                 cdp_cfg.preload_ahead = DPU_WB_CDP_PRELOAD_AHEAD_64;
177
178                 hw_wb->ops.setup_cdp(hw_wb, &cdp_cfg);
179         }
180
181         if (hw_wb->ops.setup_outaddress)
182                 hw_wb->ops.setup_outaddress(hw_wb, wb_cfg);
183 }
184
185 /**
186  * dpu_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
187  * @phys_enc:Pointer to physical encoder
188  */
189 static void dpu_encoder_phys_wb_setup_cdp(struct dpu_encoder_phys *phys_enc)
190 {
191         struct dpu_hw_wb *hw_wb;
192         struct dpu_hw_ctl *ctl;
193
194         if (!phys_enc) {
195                 DPU_ERROR("invalid encoder\n");
196                 return;
197         }
198
199         hw_wb = phys_enc->hw_wb;
200         ctl = phys_enc->hw_ctl;
201
202         if (test_bit(DPU_CTL_ACTIVE_CFG, &ctl->caps->features) &&
203                 (phys_enc->hw_ctl &&
204                  phys_enc->hw_ctl->ops.setup_intf_cfg)) {
205                 struct dpu_hw_intf_cfg intf_cfg = {0};
206                 struct dpu_hw_pingpong *hw_pp = phys_enc->hw_pp;
207                 enum dpu_3d_blend_mode mode_3d;
208
209                 mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
210
211                 intf_cfg.intf = DPU_NONE;
212                 intf_cfg.wb = hw_wb->idx;
213
214                 if (mode_3d && hw_pp && hw_pp->merge_3d)
215                         intf_cfg.merge_3d = hw_pp->merge_3d->idx;
216
217                 if (phys_enc->hw_pp->merge_3d && phys_enc->hw_pp->merge_3d->ops.setup_3d_mode)
218                         phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d,
219                                         mode_3d);
220
221                 /* setup which pp blk will connect to this wb */
222                 if (hw_pp && phys_enc->hw_wb->ops.bind_pingpong_blk)
223                         phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, true,
224                                         phys_enc->hw_pp->idx);
225
226                 phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
227         } else if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) {
228                 struct dpu_hw_intf_cfg intf_cfg = {0};
229
230                 intf_cfg.intf = DPU_NONE;
231                 intf_cfg.wb = hw_wb->idx;
232                 intf_cfg.mode_3d =
233                         dpu_encoder_helper_get_3d_blend_mode(phys_enc);
234                 phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
235         }
236 }
237
238 /**
239  * dpu_encoder_phys_wb_atomic_check - verify and fixup given atomic states
240  * @phys_enc:   Pointer to physical encoder
241  * @crtc_state: Pointer to CRTC atomic state
242  * @conn_state: Pointer to connector atomic state
243  */
244 static int dpu_encoder_phys_wb_atomic_check(
245                 struct dpu_encoder_phys *phys_enc,
246                 struct drm_crtc_state *crtc_state,
247                 struct drm_connector_state *conn_state)
248 {
249         struct drm_framebuffer *fb;
250         const struct drm_display_mode *mode = &crtc_state->mode;
251
252         DPU_DEBUG("[atomic_check:%d, \"%s\",%d,%d]\n",
253                         phys_enc->wb_idx, mode->name, mode->hdisplay, mode->vdisplay);
254
255         if (!conn_state || !conn_state->connector) {
256                 DPU_ERROR("invalid connector state\n");
257                 return -EINVAL;
258         } else if (conn_state->connector->status !=
259                         connector_status_connected) {
260                 DPU_ERROR("connector not connected %d\n",
261                                 conn_state->connector->status);
262                 return -EINVAL;
263         }
264
265         if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
266                 return 0;
267
268         fb = conn_state->writeback_job->fb;
269
270         DPU_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
271                         fb->width, fb->height);
272
273         if (fb->width != mode->hdisplay) {
274                 DPU_ERROR("invalid fb w=%d, mode w=%d\n", fb->width,
275                                 mode->hdisplay);
276                 return -EINVAL;
277         } else if (fb->height != mode->vdisplay) {
278                 DPU_ERROR("invalid fb h=%d, mode h=%d\n", fb->height,
279                                   mode->vdisplay);
280                 return -EINVAL;
281         } else if (fb->width > DEFAULT_MAX_WRITEBACK_WIDTH) {
282                 DPU_ERROR("invalid fb w=%d, maxlinewidth=%u\n",
283                                   fb->width, DEFAULT_MAX_WRITEBACK_WIDTH);
284                 return -EINVAL;
285         }
286
287         return 0;
288 }
289
290
291 /**
292  * _dpu_encoder_phys_wb_update_flush - flush hardware update
293  * @phys_enc:   Pointer to physical encoder
294  */
295 static void _dpu_encoder_phys_wb_update_flush(struct dpu_encoder_phys *phys_enc)
296 {
297         struct dpu_hw_wb *hw_wb;
298         struct dpu_hw_ctl *hw_ctl;
299         struct dpu_hw_pingpong *hw_pp;
300         u32 pending_flush = 0;
301
302         if (!phys_enc)
303                 return;
304
305         hw_wb = phys_enc->hw_wb;
306         hw_pp = phys_enc->hw_pp;
307         hw_ctl = phys_enc->hw_ctl;
308
309         DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
310
311         if (!hw_ctl) {
312                 DPU_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0);
313                 return;
314         }
315
316         if (hw_ctl->ops.update_pending_flush_wb)
317                 hw_ctl->ops.update_pending_flush_wb(hw_ctl, hw_wb->idx);
318
319         if (hw_ctl->ops.update_pending_flush_merge_3d && hw_pp && hw_pp->merge_3d)
320                 hw_ctl->ops.update_pending_flush_merge_3d(hw_ctl,
321                                 hw_pp->merge_3d->idx);
322
323         if (hw_ctl->ops.get_pending_flush)
324                 pending_flush = hw_ctl->ops.get_pending_flush(hw_ctl);
325
326         DPU_DEBUG("Pending flush mask for CTL_%d is 0x%x, WB %d\n",
327                         hw_ctl->idx - CTL_0, pending_flush,
328                         hw_wb->idx - WB_0);
329 }
330
331 /**
332  * dpu_encoder_phys_wb_setup - setup writeback encoder
333  * @phys_enc:   Pointer to physical encoder
334  */
335 static void dpu_encoder_phys_wb_setup(
336                 struct dpu_encoder_phys *phys_enc)
337 {
338         struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
339         struct drm_display_mode mode = phys_enc->cached_mode;
340         struct drm_framebuffer *fb = NULL;
341
342         DPU_DEBUG("[mode_set:%d, \"%s\",%d,%d]\n",
343                         hw_wb->idx - WB_0, mode.name,
344                         mode.hdisplay, mode.vdisplay);
345
346         dpu_encoder_phys_wb_set_ot_limit(phys_enc);
347
348         dpu_encoder_phys_wb_set_qos_remap(phys_enc);
349
350         dpu_encoder_phys_wb_set_qos(phys_enc);
351
352         dpu_encoder_phys_wb_setup_fb(phys_enc, fb);
353
354         dpu_encoder_phys_wb_setup_cdp(phys_enc);
355
356 }
357
358 static void _dpu_encoder_phys_wb_frame_done_helper(void *arg)
359 {
360         struct dpu_encoder_phys *phys_enc = arg;
361         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
362
363         struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
364         unsigned long lock_flags;
365         u32 event = DPU_ENCODER_FRAME_EVENT_DONE;
366
367         DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
368
369         if (phys_enc->parent_ops->handle_frame_done)
370                 phys_enc->parent_ops->handle_frame_done(phys_enc->parent,
371                                 phys_enc, event);
372
373         if (phys_enc->parent_ops->handle_vblank_virt)
374                 phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent,
375                                 phys_enc);
376
377         spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
378         atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
379         spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
380
381         if (wb_enc->wb_conn)
382                 drm_writeback_signal_completion(wb_enc->wb_conn, 0);
383
384         /* Signal any waiting atomic commit thread */
385         wake_up_all(&phys_enc->pending_kickoff_wq);
386 }
387
388 /**
389  * dpu_encoder_phys_wb_done_irq - writeback interrupt handler
390  * @arg:        Pointer to writeback encoder
391  * @irq_idx:    interrupt index
392  */
393 static void dpu_encoder_phys_wb_done_irq(void *arg, int irq_idx)
394 {
395         _dpu_encoder_phys_wb_frame_done_helper(arg);
396 }
397
398 /**
399  * dpu_encoder_phys_wb_irq_ctrl - irq control of WB
400  * @phys:       Pointer to physical encoder
401  * @enable:     indicates enable or disable interrupts
402  */
403 static void dpu_encoder_phys_wb_irq_ctrl(
404                 struct dpu_encoder_phys *phys, bool enable)
405 {
406
407         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys);
408
409         if (enable && atomic_inc_return(&wb_enc->wbirq_refcount) == 1)
410                 dpu_core_irq_register_callback(phys->dpu_kms,
411                                 phys->irq[INTR_IDX_WB_DONE], dpu_encoder_phys_wb_done_irq, phys);
412         else if (!enable &&
413                         atomic_dec_return(&wb_enc->wbirq_refcount) == 0)
414                 dpu_core_irq_unregister_callback(phys->dpu_kms, phys->irq[INTR_IDX_WB_DONE]);
415 }
416
417 static void dpu_encoder_phys_wb_atomic_mode_set(
418                 struct dpu_encoder_phys *phys_enc,
419                 struct drm_crtc_state *crtc_state,
420                 struct drm_connector_state *conn_state)
421 {
422
423         phys_enc->irq[INTR_IDX_WB_DONE] = phys_enc->hw_wb->caps->intr_wb_done;
424 }
425
426 static void _dpu_encoder_phys_wb_handle_wbdone_timeout(
427                 struct dpu_encoder_phys *phys_enc)
428 {
429         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
430         u32 frame_event = DPU_ENCODER_FRAME_EVENT_ERROR;
431
432         wb_enc->wb_done_timeout_cnt++;
433
434         if (wb_enc->wb_done_timeout_cnt == 1)
435                 msm_disp_snapshot_state(phys_enc->parent->dev);
436
437         atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
438
439         /* request a ctl reset before the next kickoff */
440         phys_enc->enable_state = DPU_ENC_ERR_NEEDS_HW_RESET;
441
442         if (wb_enc->wb_conn)
443                 drm_writeback_signal_completion(wb_enc->wb_conn, 0);
444
445         if (phys_enc->parent_ops->handle_frame_done)
446                 phys_enc->parent_ops->handle_frame_done(
447                                 phys_enc->parent, phys_enc, frame_event);
448 }
449
450 /**
451  * dpu_encoder_phys_wb_wait_for_commit_done - wait until request is committed
452  * @phys_enc:   Pointer to physical encoder
453  */
454 static int dpu_encoder_phys_wb_wait_for_commit_done(
455                 struct dpu_encoder_phys *phys_enc)
456 {
457         unsigned long ret;
458         struct dpu_encoder_wait_info wait_info;
459         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
460
461         wait_info.wq = &phys_enc->pending_kickoff_wq;
462         wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
463         wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
464
465         ret = dpu_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE,
466                         dpu_encoder_phys_wb_done_irq, &wait_info);
467         if (ret == -ETIMEDOUT)
468                 _dpu_encoder_phys_wb_handle_wbdone_timeout(phys_enc);
469         else if (!ret)
470                 wb_enc->wb_done_timeout_cnt = 0;
471
472         return ret;
473 }
474
475 /**
476  * dpu_encoder_phys_wb_prepare_for_kickoff - pre-kickoff processing
477  * @phys_enc:   Pointer to physical encoder
478  * Returns:     Zero on success
479  */
480 static void dpu_encoder_phys_wb_prepare_for_kickoff(
481                 struct dpu_encoder_phys *phys_enc)
482 {
483         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
484         struct drm_connector *drm_conn;
485         struct drm_connector_state *state;
486
487         DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
488
489         if (!wb_enc->wb_conn || !wb_enc->wb_job) {
490                 DPU_ERROR("invalid wb_conn or wb_job\n");
491                 return;
492         }
493
494         drm_conn = &wb_enc->wb_conn->base;
495         state = drm_conn->state;
496
497         if (wb_enc->wb_conn && wb_enc->wb_job)
498                 drm_writeback_queue_job(wb_enc->wb_conn, state);
499
500         dpu_encoder_phys_wb_setup(phys_enc);
501
502         _dpu_encoder_phys_wb_update_flush(phys_enc);
503 }
504
505 /**
506  * dpu_encoder_phys_wb_needs_single_flush - trigger flush processing
507  * @phys_enc:   Pointer to physical encoder
508  */
509 static bool dpu_encoder_phys_wb_needs_single_flush(struct dpu_encoder_phys *phys_enc)
510 {
511         DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
512         return false;
513 }
514
515 /**
516  * dpu_encoder_phys_wb_handle_post_kickoff - post-kickoff processing
517  * @phys_enc:   Pointer to physical encoder
518  */
519 static void dpu_encoder_phys_wb_handle_post_kickoff(
520                 struct dpu_encoder_phys *phys_enc)
521 {
522         DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
523
524 }
525
526 /**
527  * dpu_encoder_phys_wb_enable - enable writeback encoder
528  * @phys_enc:   Pointer to physical encoder
529  */
530 static void dpu_encoder_phys_wb_enable(struct dpu_encoder_phys *phys_enc)
531 {
532         DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
533         phys_enc->enable_state = DPU_ENC_ENABLED;
534 }
535 /**
536  * dpu_encoder_phys_wb_disable - disable writeback encoder
537  * @phys_enc:   Pointer to physical encoder
538  */
539 static void dpu_encoder_phys_wb_disable(struct dpu_encoder_phys *phys_enc)
540 {
541         struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
542         struct dpu_hw_ctl *hw_ctl = phys_enc->hw_ctl;
543
544         DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
545
546         if (phys_enc->enable_state == DPU_ENC_DISABLED) {
547                 DPU_ERROR("encoder is already disabled\n");
548                 return;
549         }
550
551         /* reset h/w before final flush */
552         if (phys_enc->hw_ctl->ops.clear_pending_flush)
553                 phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl);
554
555         /*
556          * New CTL reset sequence from 5.0 MDP onwards.
557          * If has_3d_merge_reset is not set, legacy reset
558          * sequence is executed.
559          *
560          * Legacy reset sequence has not been implemented yet.
561          * Any target earlier than SM8150 will need it and when
562          * WB support is added to those targets will need to add
563          * the legacy teardown sequence as well.
564          */
565         if (hw_ctl->caps->features & BIT(DPU_CTL_ACTIVE_CFG))
566                 dpu_encoder_helper_phys_cleanup(phys_enc);
567
568         phys_enc->enable_state = DPU_ENC_DISABLED;
569 }
570
571 /**
572  * dpu_encoder_phys_wb_destroy - destroy writeback encoder
573  * @phys_enc:   Pointer to physical encoder
574  */
575 static void dpu_encoder_phys_wb_destroy(struct dpu_encoder_phys *phys_enc)
576 {
577         if (!phys_enc)
578                 return;
579
580         DPU_DEBUG("[wb:%d]\n", phys_enc->wb_idx - WB_0);
581
582         kfree(phys_enc);
583 }
584
585 static void dpu_encoder_phys_wb_prepare_wb_job(struct dpu_encoder_phys *phys_enc,
586                 struct drm_writeback_job *job)
587 {
588         const struct msm_format *format;
589         struct msm_gem_address_space *aspace;
590         struct dpu_hw_wb_cfg *wb_cfg;
591         int ret;
592         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
593
594         if (!job->fb)
595                 return;
596
597         wb_enc->wb_job = job;
598         wb_enc->wb_conn = job->connector;
599         aspace = phys_enc->dpu_kms->base.aspace;
600
601         wb_cfg = &wb_enc->wb_cfg;
602
603         memset(wb_cfg, 0, sizeof(struct dpu_hw_wb_cfg));
604
605         ret = msm_framebuffer_prepare(job->fb, aspace, false);
606         if (ret) {
607                 DPU_ERROR("prep fb failed, %d\n", ret);
608                 return;
609         }
610
611         format = msm_framebuffer_format(job->fb);
612
613         wb_cfg->dest.format = dpu_get_dpu_format_ext(
614                         format->pixel_format, job->fb->modifier);
615         if (!wb_cfg->dest.format) {
616                 /* this error should be detected during atomic_check */
617                 DPU_ERROR("failed to get format %x\n", format->pixel_format);
618                 return;
619         }
620
621         ret = dpu_format_populate_layout(aspace, job->fb, &wb_cfg->dest);
622         if (ret) {
623                 DPU_DEBUG("failed to populate layout %d\n", ret);
624                 return;
625         }
626
627         wb_cfg->dest.width = job->fb->width;
628         wb_cfg->dest.height = job->fb->height;
629         wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes;
630
631         if ((wb_cfg->dest.format->fetch_planes == DPU_PLANE_PLANAR) &&
632                         (wb_cfg->dest.format->element[0] == C1_B_Cb))
633                 swap(wb_cfg->dest.plane_addr[1], wb_cfg->dest.plane_addr[2]);
634
635         DPU_DEBUG("[fb_offset:%8.8x,%8.8x,%8.8x,%8.8x]\n",
636                         wb_cfg->dest.plane_addr[0], wb_cfg->dest.plane_addr[1],
637                         wb_cfg->dest.plane_addr[2], wb_cfg->dest.plane_addr[3]);
638
639         DPU_DEBUG("[fb_stride:%8.8x,%8.8x,%8.8x,%8.8x]\n",
640                         wb_cfg->dest.plane_pitch[0], wb_cfg->dest.plane_pitch[1],
641                         wb_cfg->dest.plane_pitch[2], wb_cfg->dest.plane_pitch[3]);
642 }
643
644 static void dpu_encoder_phys_wb_cleanup_wb_job(struct dpu_encoder_phys *phys_enc,
645                 struct drm_writeback_job *job)
646 {
647         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
648         struct msm_gem_address_space *aspace;
649
650         if (!job->fb)
651                 return;
652
653         aspace = phys_enc->dpu_kms->base.aspace;
654
655         msm_framebuffer_cleanup(job->fb, aspace, false);
656         wb_enc->wb_job = NULL;
657         wb_enc->wb_conn = NULL;
658 }
659
660 static bool dpu_encoder_phys_wb_is_valid_for_commit(struct dpu_encoder_phys *phys_enc)
661 {
662         struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
663
664         if (wb_enc->wb_job)
665                 return true;
666         else
667                 return false;
668 }
669
670 /**
671  * dpu_encoder_phys_wb_init_ops - initialize writeback operations
672  * @ops:        Pointer to encoder operation table
673  */
674 static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops)
675 {
676         ops->is_master = dpu_encoder_phys_wb_is_master;
677         ops->atomic_mode_set = dpu_encoder_phys_wb_atomic_mode_set;
678         ops->enable = dpu_encoder_phys_wb_enable;
679         ops->disable = dpu_encoder_phys_wb_disable;
680         ops->destroy = dpu_encoder_phys_wb_destroy;
681         ops->atomic_check = dpu_encoder_phys_wb_atomic_check;
682         ops->wait_for_commit_done = dpu_encoder_phys_wb_wait_for_commit_done;
683         ops->prepare_for_kickoff = dpu_encoder_phys_wb_prepare_for_kickoff;
684         ops->handle_post_kickoff = dpu_encoder_phys_wb_handle_post_kickoff;
685         ops->needs_single_flush = dpu_encoder_phys_wb_needs_single_flush;
686         ops->trigger_start = dpu_encoder_helper_trigger_start;
687         ops->prepare_wb_job = dpu_encoder_phys_wb_prepare_wb_job;
688         ops->cleanup_wb_job = dpu_encoder_phys_wb_cleanup_wb_job;
689         ops->irq_control = dpu_encoder_phys_wb_irq_ctrl;
690         ops->is_valid_for_commit = dpu_encoder_phys_wb_is_valid_for_commit;
691
692 }
693
694 /**
695  * dpu_encoder_phys_wb_init - initialize writeback encoder
696  * @init:       Pointer to init info structure with initialization params
697  */
698 struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
699                 struct dpu_enc_phys_init_params *p)
700 {
701         struct dpu_encoder_phys *phys_enc = NULL;
702         struct dpu_encoder_phys_wb *wb_enc = NULL;
703         int ret = 0;
704         int i;
705
706         DPU_DEBUG("\n");
707
708         if (!p || !p->parent) {
709                 DPU_ERROR("invalid params\n");
710                 ret = -EINVAL;
711                 goto fail_alloc;
712         }
713
714         wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL);
715         if (!wb_enc) {
716                 DPU_ERROR("failed to allocate wb phys_enc enc\n");
717                 ret = -ENOMEM;
718                 goto fail_alloc;
719         }
720
721         phys_enc = &wb_enc->base;
722         phys_enc->hw_mdptop = p->dpu_kms->hw_mdp;
723         phys_enc->wb_idx = p->wb_idx;
724
725         dpu_encoder_phys_wb_init_ops(&phys_enc->ops);
726         phys_enc->parent = p->parent;
727         phys_enc->parent_ops = p->parent_ops;
728         phys_enc->dpu_kms = p->dpu_kms;
729         phys_enc->split_role = p->split_role;
730         phys_enc->intf_mode = INTF_MODE_WB_LINE;
731         phys_enc->wb_idx = p->wb_idx;
732         phys_enc->enc_spinlock = p->enc_spinlock;
733
734         atomic_set(&wb_enc->wbirq_refcount, 0);
735
736         for (i = 0; i < ARRAY_SIZE(phys_enc->irq); i++)
737                 phys_enc->irq[i] = -EINVAL;
738
739         atomic_set(&phys_enc->pending_kickoff_cnt, 0);
740         atomic_set(&phys_enc->vblank_refcount, 0);
741         wb_enc->wb_done_timeout_cnt = 0;
742
743         init_waitqueue_head(&phys_enc->pending_kickoff_wq);
744         phys_enc->enable_state = DPU_ENC_DISABLED;
745
746         DPU_DEBUG("Created dpu_encoder_phys for wb %d\n",
747                         phys_enc->wb_idx);
748
749         return phys_enc;
750
751 fail_alloc:
752         return ERR_PTR(ret);
753 }