blob: a30199048080e2c26e80d9ca824eda0d73b85177 [file] [log] [blame]
Alan Kwongbb27c092016-07-20 16:41:25 -04001/*
Raviteja Tamatamd94b2652019-02-11 17:02:39 +05302 * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
Alan Kwongbb27c092016-07-20 16:41:25 -04003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
Alan Kwongbb27c092016-07-20 16:41:25 -040012 */
13
Alan Kwong4c3cf4c2016-09-25 20:08:09 -040014#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
Alan Kwongbb27c092016-07-20 16:41:25 -040015#include <linux/debugfs.h>
Alan Kwong03b89842017-08-17 16:32:45 -040016#include <uapi/drm/sde_drm.h>
Alan Kwongbb27c092016-07-20 16:41:25 -040017
18#include "sde_encoder_phys.h"
19#include "sde_formats.h"
20#include "sde_hw_top.h"
21#include "sde_hw_interrupts.h"
Alan Kwongf5dd86c2016-08-09 18:08:17 -040022#include "sde_core_irq.h"
Alan Kwongbb27c092016-07-20 16:41:25 -040023#include "sde_wb.h"
Lloyd Atkinson8772e202016-09-26 17:52:16 -040024#include "sde_vbif.h"
Alan Kwonga62eeb82017-04-19 08:57:55 -070025#include "sde_crtc.h"
Alan Kwongbb27c092016-07-20 16:41:25 -040026
Alan Kwongbb27c092016-07-20 16:41:25 -040027#define to_sde_encoder_phys_wb(x) \
28 container_of(x, struct sde_encoder_phys_wb, base)
29
Alan Kwong1124f1f2017-11-10 18:14:39 -050030#define WBID(wb_enc) \
31 ((wb_enc && wb_enc->wb_dev) ? wb_enc->wb_dev->wb_idx - WB_0 : -1)
Alan Kwongbb27c092016-07-20 16:41:25 -040032
33/**
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -040034 * sde_encoder_phys_wb_is_master - report wb always as master encoder
35 */
36static bool sde_encoder_phys_wb_is_master(struct sde_encoder_phys *phys_enc)
37{
38 return true;
39}
40
41/**
Alan Kwongbb27c092016-07-20 16:41:25 -040042 * sde_encoder_phys_wb_get_intr_type - get interrupt type based on block mode
43 * @hw_wb: Pointer to h/w writeback driver
44 */
45static enum sde_intr_type sde_encoder_phys_wb_get_intr_type(
46 struct sde_hw_wb *hw_wb)
47{
48 return (hw_wb->caps->features & BIT(SDE_WB_BLOCK_MODE)) ?
49 SDE_IRQ_TYPE_WB_ROT_COMP : SDE_IRQ_TYPE_WB_WFD_COMP;
50}
51
52/**
Alan Kwong5d324e42016-07-28 22:56:18 -040053 * sde_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface
54 * @phys_enc: Pointer to physical encoder
55 */
56static void sde_encoder_phys_wb_set_ot_limit(
57 struct sde_encoder_phys *phys_enc)
58{
59 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
60 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
61 struct sde_vbif_set_ot_params ot_params;
62
63 memset(&ot_params, 0, sizeof(ot_params));
64 ot_params.xin_id = hw_wb->caps->xin_id;
65 ot_params.num = hw_wb->idx - WB_0;
66 ot_params.width = wb_enc->wb_roi.w;
67 ot_params.height = wb_enc->wb_roi.h;
68 ot_params.is_wfd = true;
69 ot_params.frame_rate = phys_enc->cached_mode.vrefresh;
70 ot_params.vbif_idx = hw_wb->caps->vbif_idx;
71 ot_params.clk_ctrl = hw_wb->caps->clk_ctrl;
72 ot_params.rd = false;
73
74 sde_vbif_set_ot_limit(phys_enc->sde_kms, &ot_params);
75}
76
77/**
Alan Kwongbb27c092016-07-20 16:41:25 -040078 * sde_encoder_phys_wb_set_traffic_shaper - set traffic shaper for writeback
79 * @phys_enc: Pointer to physical encoder
80 */
81static void sde_encoder_phys_wb_set_traffic_shaper(
82 struct sde_encoder_phys *phys_enc)
83{
84 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
85 struct sde_hw_wb_cfg *wb_cfg = &wb_enc->wb_cfg;
86
87 /* traffic shaper is only enabled for rotator */
88 wb_cfg->ts_cfg.en = false;
89}
90
91/**
Alan Kwonga62eeb82017-04-19 08:57:55 -070092 * sde_encoder_phys_wb_set_qos_remap - set QoS remapper for writeback
93 * @phys_enc: Pointer to physical encoder
94 */
95static void sde_encoder_phys_wb_set_qos_remap(
96 struct sde_encoder_phys *phys_enc)
97{
98 struct sde_encoder_phys_wb *wb_enc;
99 struct sde_hw_wb *hw_wb;
100 struct drm_crtc *crtc;
101 struct sde_vbif_set_qos_params qos_params;
102
103 if (!phys_enc || !phys_enc->parent || !phys_enc->parent->crtc) {
104 SDE_ERROR("invalid arguments\n");
105 return;
106 }
107
108 wb_enc = to_sde_encoder_phys_wb(phys_enc);
Harsh Sahufae4d812017-11-29 15:08:59 -0800109 if (!wb_enc->crtc) {
110 SDE_ERROR("invalid crtc");
111 return;
112 }
113
114 crtc = wb_enc->crtc;
Alan Kwonga62eeb82017-04-19 08:57:55 -0700115
116 if (!wb_enc->hw_wb || !wb_enc->hw_wb->caps) {
117 SDE_ERROR("invalid writeback hardware\n");
118 return;
119 }
120
121 hw_wb = wb_enc->hw_wb;
122
123 memset(&qos_params, 0, sizeof(qos_params));
124 qos_params.vbif_idx = hw_wb->caps->vbif_idx;
125 qos_params.xin_id = hw_wb->caps->xin_id;
126 qos_params.clk_ctrl = hw_wb->caps->clk_ctrl;
127 qos_params.num = hw_wb->idx - WB_0;
128 qos_params.is_rt = sde_crtc_get_client_type(crtc) != NRT_CLIENT;
129
130 SDE_DEBUG("[qos_remap] wb:%d vbif:%d xin:%d rt:%d\n",
131 qos_params.num,
132 qos_params.vbif_idx,
133 qos_params.xin_id, qos_params.is_rt);
134
135 sde_vbif_set_qos_remap(phys_enc->sde_kms, &qos_params);
136}
137
138/**
Alan Kwongbb27c092016-07-20 16:41:25 -0400139 * sde_encoder_phys_wb_setup_fb - setup output framebuffer
140 * @phys_enc: Pointer to physical encoder
141 * @fb: Pointer to output framebuffer
142 * @wb_roi: Pointer to output region of interest
143 */
144static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc,
145 struct drm_framebuffer *fb, struct sde_rect *wb_roi)
146{
147 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Clarence Ip03521982016-08-26 10:49:47 -0400148 struct sde_hw_wb *hw_wb;
149 struct sde_hw_wb_cfg *wb_cfg;
Alan Kwong143f50c2017-04-28 07:34:28 -0700150 struct sde_hw_wb_cdp_cfg *cdp_cfg;
Alan Kwongbb27c092016-07-20 16:41:25 -0400151 const struct msm_format *format;
Jordan Croused8e96522017-02-13 10:14:16 -0700152 int ret;
153 struct msm_gem_address_space *aspace;
Alan Kwong03b89842017-08-17 16:32:45 -0400154 u32 fb_mode;
Alan Kwongbb27c092016-07-20 16:41:25 -0400155
Alan Kwong03b89842017-08-17 16:32:45 -0400156 if (!phys_enc || !phys_enc->sde_kms || !phys_enc->sde_kms->catalog ||
157 !phys_enc->connector) {
Clarence Ip03521982016-08-26 10:49:47 -0400158 SDE_ERROR("invalid encoder\n");
159 return;
160 }
161
162 hw_wb = wb_enc->hw_wb;
163 wb_cfg = &wb_enc->wb_cfg;
Alan Kwong143f50c2017-04-28 07:34:28 -0700164 cdp_cfg = &wb_enc->cdp_cfg;
Alan Kwongbb27c092016-07-20 16:41:25 -0400165 memset(wb_cfg, 0, sizeof(struct sde_hw_wb_cfg));
166
Clarence Ip03521982016-08-26 10:49:47 -0400167 wb_cfg->intf_mode = phys_enc->intf_mode;
Alan Kwong03b89842017-08-17 16:32:45 -0400168
169 fb_mode = sde_connector_get_property(phys_enc->connector->state,
170 CONNECTOR_PROP_FB_TRANSLATION_MODE);
171 if (phys_enc->enable_state == SDE_ENC_DISABLING)
172 wb_cfg->is_secure = false;
173 else if (fb_mode == SDE_DRM_FB_SEC)
174 wb_cfg->is_secure = true;
175 else
176 wb_cfg->is_secure = false;
177
Jordan Croused8e96522017-02-13 10:14:16 -0700178 aspace = (wb_cfg->is_secure) ?
179 wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] :
180 wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -0400181
182 SDE_DEBUG("[fb_secure:%d]\n", wb_cfg->is_secure);
183
Alan Kwong03b89842017-08-17 16:32:45 -0400184 ret = msm_framebuffer_prepare(fb, aspace);
185 if (ret) {
186 SDE_ERROR("prep fb failed, %d\n", ret);
187 return;
188 }
189
190 /* cache framebuffer for cleanup in writeback done */
191 wb_enc->wb_fb = fb;
192 wb_enc->wb_aspace = aspace;
193
Alan Kwongbb27c092016-07-20 16:41:25 -0400194 format = msm_framebuffer_format(fb);
Dhaval Patelccbcb3d2016-08-22 11:58:14 -0700195 if (!format) {
196 SDE_DEBUG("invalid format for fb\n");
197 return;
198 }
199
Alan Kwongbb27c092016-07-20 16:41:25 -0400200 wb_cfg->dest.format = sde_get_sde_format_ext(
201 format->pixel_format,
202 fb->modifier,
203 drm_format_num_planes(fb->pixel_format));
204 if (!wb_cfg->dest.format) {
205 /* this error should be detected during atomic_check */
206 SDE_ERROR("failed to get format %x\n", format->pixel_format);
207 return;
208 }
abeykunf1539f72016-08-24 16:08:03 -0400209 wb_cfg->roi = *wb_roi;
Alan Kwongbb27c092016-07-20 16:41:25 -0400210
abeykunf1539f72016-08-24 16:08:03 -0400211 if (hw_wb->caps->features & BIT(SDE_WB_XY_ROI_OFFSET)) {
Jordan Croused8e96522017-02-13 10:14:16 -0700212 ret = sde_format_populate_layout(aspace, fb, &wb_cfg->dest);
abeykunf1539f72016-08-24 16:08:03 -0400213 if (ret) {
214 SDE_DEBUG("failed to populate layout %d\n", ret);
215 return;
216 }
217 wb_cfg->dest.width = fb->width;
218 wb_cfg->dest.height = fb->height;
219 wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes;
220 } else {
Jordan Croused8e96522017-02-13 10:14:16 -0700221 ret = sde_format_populate_layout_with_roi(aspace, fb, wb_roi,
Alan Kwongbb27c092016-07-20 16:41:25 -0400222 &wb_cfg->dest);
abeykunf1539f72016-08-24 16:08:03 -0400223 if (ret) {
224 /* this error should be detected during atomic_check */
225 SDE_DEBUG("failed to populate layout %d\n", ret);
226 return;
227 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400228 }
229
230 if ((wb_cfg->dest.format->fetch_planes == SDE_PLANE_PLANAR) &&
231 (wb_cfg->dest.format->element[0] == C1_B_Cb))
232 swap(wb_cfg->dest.plane_addr[1], wb_cfg->dest.plane_addr[2]);
233
234 SDE_DEBUG("[fb_offset:%8.8x,%8.8x,%8.8x,%8.8x]\n",
235 wb_cfg->dest.plane_addr[0],
236 wb_cfg->dest.plane_addr[1],
237 wb_cfg->dest.plane_addr[2],
238 wb_cfg->dest.plane_addr[3]);
239 SDE_DEBUG("[fb_stride:%8.8x,%8.8x,%8.8x,%8.8x]\n",
240 wb_cfg->dest.plane_pitch[0],
241 wb_cfg->dest.plane_pitch[1],
242 wb_cfg->dest.plane_pitch[2],
243 wb_cfg->dest.plane_pitch[3]);
244
abeykunf1539f72016-08-24 16:08:03 -0400245 if (hw_wb->ops.setup_roi)
246 hw_wb->ops.setup_roi(hw_wb, wb_cfg);
247
Alan Kwongbb27c092016-07-20 16:41:25 -0400248 if (hw_wb->ops.setup_outformat)
249 hw_wb->ops.setup_outformat(hw_wb, wb_cfg);
250
Alan Kwong143f50c2017-04-28 07:34:28 -0700251 if (hw_wb->ops.setup_cdp) {
252 memset(cdp_cfg, 0, sizeof(struct sde_hw_wb_cdp_cfg));
253
254 cdp_cfg->enable = phys_enc->sde_kms->catalog->perf.cdp_cfg
255 [SDE_PERF_CDP_USAGE_NRT].wr_enable;
256 cdp_cfg->ubwc_meta_enable =
257 SDE_FORMAT_IS_UBWC(wb_cfg->dest.format);
258 cdp_cfg->tile_amortize_enable =
259 SDE_FORMAT_IS_UBWC(wb_cfg->dest.format) ||
260 SDE_FORMAT_IS_TILE(wb_cfg->dest.format);
261 cdp_cfg->preload_ahead = SDE_WB_CDP_PRELOAD_AHEAD_64;
262
263 hw_wb->ops.setup_cdp(hw_wb, cdp_cfg);
264 }
265
Alan Kwongc16e0922017-05-11 14:50:46 -0700266 if (hw_wb->ops.setup_outaddress) {
267 SDE_EVT32(hw_wb->idx,
268 wb_cfg->dest.width,
269 wb_cfg->dest.height,
270 wb_cfg->dest.plane_addr[0],
271 wb_cfg->dest.plane_size[0],
272 wb_cfg->dest.plane_addr[1],
273 wb_cfg->dest.plane_size[1],
274 wb_cfg->dest.plane_addr[2],
275 wb_cfg->dest.plane_size[2],
276 wb_cfg->dest.plane_addr[3],
277 wb_cfg->dest.plane_size[3]);
Alan Kwongbb27c092016-07-20 16:41:25 -0400278 hw_wb->ops.setup_outaddress(hw_wb, wb_cfg);
Alan Kwongc16e0922017-05-11 14:50:46 -0700279 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400280}
281
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700282static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
283 bool enable)
284{
285 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
286 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
287 struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
288 struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
289 struct sde_crtc *crtc = to_sde_crtc(wb_enc->crtc);
290
291 if (!phys_enc->in_clone_mode) {
292 SDE_DEBUG("not in CWB mode. early return\n");
293 return;
294 }
295
296 memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
297 intf_cfg->intf = SDE_NONE;
298 intf_cfg->wb = hw_wb->idx;
299
300 hw_ctl = crtc->mixers[0].hw_ctl;
301 if (hw_ctl && hw_ctl->ops.update_wb_cfg) {
302 hw_ctl->ops.update_wb_cfg(hw_ctl, intf_cfg, enable);
303 SDE_DEBUG("in CWB mode adding WB for CTL_%d\n",
304 hw_ctl->idx - CTL_0);
305 }
306}
Alan Kwongbb27c092016-07-20 16:41:25 -0400307/**
308 * sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
309 * @phys_enc: Pointer to physical encoder
310 */
311static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc)
312{
313 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
314 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
315 struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
316
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700317 if (phys_enc->in_clone_mode) {
318 SDE_DEBUG("in CWB mode. early return\n");
319 return;
320 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400321
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700322 memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
Alan Kwongbb27c092016-07-20 16:41:25 -0400323 intf_cfg->intf = SDE_NONE;
324 intf_cfg->wb = hw_wb->idx;
Lloyd Atkinson55987b02016-08-16 16:57:46 -0400325 intf_cfg->mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc);
Alan Kwongbb27c092016-07-20 16:41:25 -0400326
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400327 if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg)
Alan Kwongbb27c092016-07-20 16:41:25 -0400328 phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl,
329 intf_cfg);
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700330
331}
332
333static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc,
334 struct drm_crtc_state *crtc_state)
335{
Prabhanjan Kandulaba1216f2018-07-18 16:29:23 -0700336 struct drm_encoder *encoder;
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700337 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
338 const struct sde_wb_cfg *wb_cfg = wb_enc->hw_wb->caps;
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700339
340 phys_enc->in_clone_mode = false;
341
342 /* Check if WB has CWB support */
Prabhanjan Kandula367bdf32018-06-04 20:46:07 -0700343 if (!(wb_cfg->features & BIT(SDE_WB_HAS_CWB)))
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700344 return;
345
Prabhanjan Kandulaba1216f2018-07-18 16:29:23 -0700346 /* if any other encoder is connected to same crtc enable clone mode*/
347 drm_for_each_encoder(encoder, crtc_state->crtc->dev) {
348 if (encoder->crtc != crtc_state->crtc)
349 continue;
350 if (phys_enc->parent != encoder) {
351 phys_enc->in_clone_mode = true;
352 break;
353 }
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700354 }
355
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700356 SDE_DEBUG("detect CWB - status:%d\n", phys_enc->in_clone_mode);
357}
358
359static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc,
360 struct drm_crtc_state *crtc_state,
361 struct drm_connector_state *conn_state)
362{
363 struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state);
364 struct sde_rect wb_roi = {0,};
365 int data_pt;
366 int ds_outw = 0;
367 int ds_outh = 0;
368 int ds_in_use = false;
369 int i = 0;
370 int ret = 0;
371
372 if (!phys_enc->in_clone_mode) {
373 SDE_DEBUG("not in CWB mode. early return\n");
374 goto exit;
375 }
376
377 ret = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi);
378 if (ret) {
379 SDE_ERROR("failed to get roi %d\n", ret);
380 goto exit;
381 }
382
383 data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT);
384
385 /* compute cumulative ds output dimensions if in use */
386 for (i = 0; i < cstate->num_ds; i++)
387 if (cstate->ds_cfg[i].scl3_cfg.enable) {
388 ds_in_use = true;
389 ds_outw += cstate->ds_cfg[i].scl3_cfg.dst_width;
390 ds_outh += cstate->ds_cfg[i].scl3_cfg.dst_height;
391 }
392
393 /* if ds in use check wb roi against ds output dimensions */
394 if ((data_pt == CAPTURE_DSPP_OUT) && ds_in_use &&
395 ((wb_roi.w != ds_outw) || (wb_roi.h != ds_outh))) {
396 SDE_ERROR("invalid wb roi with dest scalar [%dx%d vs %dx%d]\n",
397 wb_roi.w, wb_roi.h, ds_outw, ds_outh);
398 ret = -EINVAL;
399 goto exit;
400 }
401
402 /* validate conn roi against pu rect */
403 if (!sde_kms_rect_is_null(&cstate->crtc_roi)) {
404 if (wb_roi.w != cstate->crtc_roi.w ||
405 wb_roi.h != cstate->crtc_roi.h) {
406 SDE_ERROR("invalid wb roi with pu [%dx%d vs %dx%d]\n",
407 wb_roi.w, wb_roi.h, cstate->crtc_roi.w,
408 cstate->crtc_roi.h);
409 ret = -EINVAL;
410 goto exit;
411 }
412 }
413exit:
414 return ret;
Alan Kwongbb27c092016-07-20 16:41:25 -0400415}
416
417/**
418 * sde_encoder_phys_wb_atomic_check - verify and fixup given atomic states
419 * @phys_enc: Pointer to physical encoder
420 * @crtc_state: Pointer to CRTC atomic state
421 * @conn_state: Pointer to connector atomic state
422 */
423static int sde_encoder_phys_wb_atomic_check(
424 struct sde_encoder_phys *phys_enc,
425 struct drm_crtc_state *crtc_state,
426 struct drm_connector_state *conn_state)
427{
428 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
429 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
430 const struct sde_wb_cfg *wb_cfg = hw_wb->caps;
431 struct drm_framebuffer *fb;
432 const struct sde_format *fmt;
433 struct sde_rect wb_roi;
434 const struct drm_display_mode *mode = &crtc_state->mode;
435 int rc;
436
437 SDE_DEBUG("[atomic_check:%d,%d,\"%s\",%d,%d]\n",
438 hw_wb->idx - WB_0, mode->base.id, mode->name,
439 mode->hdisplay, mode->vdisplay);
440
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400441 if (!conn_state || !conn_state->connector) {
442 SDE_ERROR("invalid connector state\n");
443 return -EINVAL;
444 } else if (conn_state->connector->status !=
445 connector_status_connected) {
446 SDE_ERROR("connector not connected %d\n",
447 conn_state->connector->status);
448 return -EINVAL;
449 }
450
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700451 _sde_enc_phys_wb_detect_cwb(phys_enc, crtc_state);
452
Alan Kwongbb27c092016-07-20 16:41:25 -0400453 memset(&wb_roi, 0, sizeof(struct sde_rect));
454
455 rc = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi);
456 if (rc) {
457 SDE_ERROR("failed to get roi %d\n", rc);
458 return rc;
459 }
460
461 SDE_DEBUG("[roi:%u,%u,%u,%u]\n", wb_roi.x, wb_roi.y,
462 wb_roi.w, wb_roi.h);
463
Alan Kwong4212dd42017-09-19 17:22:33 -0400464 /* bypass check if commit with no framebuffer */
Alan Kwongbb27c092016-07-20 16:41:25 -0400465 fb = sde_wb_connector_state_get_output_fb(conn_state);
466 if (!fb) {
Alan Kwong4212dd42017-09-19 17:22:33 -0400467 SDE_DEBUG("no output framebuffer\n");
468 return 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400469 }
470
471 SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
472 fb->width, fb->height);
473
474 fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
475 drm_format_num_planes(fb->pixel_format));
476 if (!fmt) {
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400477 SDE_ERROR("unsupported output pixel format:%x\n",
Alan Kwongbb27c092016-07-20 16:41:25 -0400478 fb->pixel_format);
479 return -EINVAL;
480 }
481
482 SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->pixel_format,
483 fb->modifier[0]);
484
485 if (SDE_FORMAT_IS_YUV(fmt) &&
486 !(wb_cfg->features & BIT(SDE_WB_YUV_CONFIG))) {
487 SDE_ERROR("invalid output format %x\n", fmt->base.pixel_format);
488 return -EINVAL;
489 }
490
491 if (SDE_FORMAT_IS_UBWC(fmt) &&
Clarence Ip32bcb002017-03-13 12:26:44 -0700492 !(wb_cfg->features & BIT(SDE_WB_UBWC))) {
Alan Kwongbb27c092016-07-20 16:41:25 -0400493 SDE_ERROR("invalid output format %x\n", fmt->base.pixel_format);
494 return -EINVAL;
495 }
496
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400497 if (SDE_FORMAT_IS_YUV(fmt) != !!phys_enc->hw_cdm)
498 crtc_state->mode_changed = true;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400499
Alan Kwongbb27c092016-07-20 16:41:25 -0400500 if (wb_roi.w && wb_roi.h) {
501 if (wb_roi.w != mode->hdisplay) {
502 SDE_ERROR("invalid roi w=%d, mode w=%d\n", wb_roi.w,
503 mode->hdisplay);
504 return -EINVAL;
505 } else if (wb_roi.h != mode->vdisplay) {
506 SDE_ERROR("invalid roi h=%d, mode h=%d\n", wb_roi.h,
507 mode->vdisplay);
508 return -EINVAL;
509 } else if (wb_roi.x + wb_roi.w > fb->width) {
510 SDE_ERROR("invalid roi x=%d, w=%d, fb w=%d\n",
511 wb_roi.x, wb_roi.w, fb->width);
512 return -EINVAL;
513 } else if (wb_roi.y + wb_roi.h > fb->height) {
514 SDE_ERROR("invalid roi y=%d, h=%d, fb h=%d\n",
515 wb_roi.y, wb_roi.h, fb->height);
516 return -EINVAL;
517 } else if (wb_roi.w > wb_cfg->sblk->maxlinewidth) {
518 SDE_ERROR("invalid roi w=%d, maxlinewidth=%u\n",
519 wb_roi.w, wb_cfg->sblk->maxlinewidth);
520 return -EINVAL;
521 }
522 } else {
523 if (wb_roi.x || wb_roi.y) {
524 SDE_ERROR("invalid roi x=%d, y=%d\n",
525 wb_roi.x, wb_roi.y);
526 return -EINVAL;
527 } else if (fb->width != mode->hdisplay) {
528 SDE_ERROR("invalid fb w=%d, mode w=%d\n", fb->width,
529 mode->hdisplay);
530 return -EINVAL;
531 } else if (fb->height != mode->vdisplay) {
532 SDE_ERROR("invalid fb h=%d, mode h=%d\n", fb->height,
533 mode->vdisplay);
534 return -EINVAL;
535 } else if (fb->width > wb_cfg->sblk->maxlinewidth) {
536 SDE_ERROR("invalid fb w=%d, maxlinewidth=%u\n",
537 fb->width, wb_cfg->sblk->maxlinewidth);
538 return -EINVAL;
539 }
540 }
541
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700542 rc = _sde_enc_phys_wb_validate_cwb(phys_enc, crtc_state, conn_state);
543 if (rc) {
544 SDE_ERROR("failed in cwb validation %d\n", rc);
545 return rc;
546 }
547
548 return rc;
549}
550
551static void _sde_encoder_phys_wb_update_cwb_flush(
552 struct sde_encoder_phys *phys_enc)
553{
554 struct sde_encoder_phys_wb *wb_enc;
555 struct sde_hw_wb *hw_wb;
556 struct sde_hw_ctl *hw_ctl;
557 struct sde_hw_cdm *hw_cdm;
558 struct sde_crtc *crtc;
559 struct sde_crtc_state *crtc_state;
560 u32 flush_mask = 0;
561 int capture_point = 0;
562
563 if (!phys_enc->in_clone_mode) {
564 SDE_DEBUG("not in CWB mode. early return\n");
565 return;
566 }
567
568 wb_enc = to_sde_encoder_phys_wb(phys_enc);
569 crtc = to_sde_crtc(wb_enc->crtc);
570 crtc_state = to_sde_crtc_state(wb_enc->crtc->state);
571
572 hw_wb = wb_enc->hw_wb;
573 hw_cdm = phys_enc->hw_cdm;
574
575 /* In CWB mode, program actual source master sde_hw_ctl from crtc */
576 hw_ctl = crtc->mixers[0].hw_ctl;
577 if (!hw_ctl) {
578 SDE_DEBUG("[wb:%d] no ctl assigned for CWB\n",
579 hw_wb->idx - WB_0);
580 return;
581 }
582
583 capture_point = sde_crtc_get_property(crtc_state,
584 CRTC_PROP_CAPTURE_OUTPUT);
585
586 phys_enc->hw_mdptop->ops.set_cwb_ppb_cntl(phys_enc->hw_mdptop,
587 crtc->num_mixers == CRTC_DUAL_MIXERS,
588 capture_point == CAPTURE_DSPP_OUT);
589
590 if (hw_ctl->ops.get_bitmask_wb)
591 hw_ctl->ops.get_bitmask_wb(hw_ctl, &flush_mask, hw_wb->idx);
592
593 if (hw_ctl->ops.get_bitmask_cdm && hw_cdm)
594 hw_ctl->ops.get_bitmask_cdm(hw_ctl, &flush_mask, hw_cdm->idx);
595
596 if (hw_ctl->ops.update_pending_flush)
597 hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask);
Alan Kwongbb27c092016-07-20 16:41:25 -0400598}
599
600/**
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700601 * _sde_encoder_phys_wb_update_flush - flush hardware update
Alan Kwongbb27c092016-07-20 16:41:25 -0400602 * @phys_enc: Pointer to physical encoder
603 */
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700604static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
Alan Kwongbb27c092016-07-20 16:41:25 -0400605{
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700606 struct sde_encoder_phys_wb *wb_enc;
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400607 struct sde_hw_wb *hw_wb;
608 struct sde_hw_ctl *hw_ctl;
609 struct sde_hw_cdm *hw_cdm;
Alan Kwongbb27c092016-07-20 16:41:25 -0400610 u32 flush_mask = 0;
611
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400612 if (!phys_enc)
613 return;
614
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700615 wb_enc = to_sde_encoder_phys_wb(phys_enc);
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400616 hw_wb = wb_enc->hw_wb;
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400617 hw_cdm = phys_enc->hw_cdm;
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700618 hw_ctl = phys_enc->hw_ctl;
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400619
Alan Kwongbb27c092016-07-20 16:41:25 -0400620 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
621
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700622 if (phys_enc->in_clone_mode) {
623 SDE_DEBUG("in CWB mode. early return\n");
624 return;
625 }
626
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400627 if (!hw_ctl) {
628 SDE_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0);
629 return;
630 }
631
Alan Kwongbb27c092016-07-20 16:41:25 -0400632 if (hw_ctl->ops.get_bitmask_wb)
633 hw_ctl->ops.get_bitmask_wb(hw_ctl, &flush_mask, hw_wb->idx);
634
635 if (hw_ctl->ops.get_bitmask_cdm && hw_cdm)
636 hw_ctl->ops.get_bitmask_cdm(hw_ctl, &flush_mask, hw_cdm->idx);
637
638 if (hw_ctl->ops.update_pending_flush)
639 hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask);
640
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700641 if (hw_ctl->ops.get_pending_flush)
642 flush_mask = hw_ctl->ops.get_pending_flush(hw_ctl);
643
644 SDE_DEBUG("Pending flush mask for CTL_%d is 0x%x, WB %d\n",
Alan Kwongbb27c092016-07-20 16:41:25 -0400645 hw_ctl->idx - CTL_0, flush_mask, hw_wb->idx - WB_0);
646}
647
648/**
649 * sde_encoder_phys_wb_setup - setup writeback encoder
650 * @phys_enc: Pointer to physical encoder
651 */
652static void sde_encoder_phys_wb_setup(
653 struct sde_encoder_phys *phys_enc)
654{
655 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
656 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
657 struct drm_display_mode mode = phys_enc->cached_mode;
658 struct drm_framebuffer *fb;
659 struct sde_rect *wb_roi = &wb_enc->wb_roi;
660
661 SDE_DEBUG("[mode_set:%d,%d,\"%s\",%d,%d]\n",
662 hw_wb->idx - WB_0, mode.base.id, mode.name,
663 mode.hdisplay, mode.vdisplay);
664
665 memset(wb_roi, 0, sizeof(struct sde_rect));
666
Alan Kwong03b89842017-08-17 16:32:45 -0400667 /* clear writeback framebuffer - will be updated in setup_fb */
668 wb_enc->wb_fb = NULL;
669 wb_enc->wb_aspace = NULL;
670
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700671 if (phys_enc->enable_state == SDE_ENC_DISABLING) {
672 fb = wb_enc->fb_disable;
673 wb_roi->w = 0;
674 wb_roi->h = 0;
675 } else {
676 fb = sde_wb_get_output_fb(wb_enc->wb_dev);
677 sde_wb_get_output_roi(wb_enc->wb_dev, wb_roi);
678 }
679
Alan Kwongbb27c092016-07-20 16:41:25 -0400680 if (!fb) {
681 SDE_DEBUG("no output framebuffer\n");
682 return;
683 }
684
685 SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
686 fb->width, fb->height);
687
Alan Kwongbb27c092016-07-20 16:41:25 -0400688 if (wb_roi->w == 0 || wb_roi->h == 0) {
689 wb_roi->x = 0;
690 wb_roi->y = 0;
691 wb_roi->w = fb->width;
692 wb_roi->h = fb->height;
693 }
694
695 SDE_DEBUG("[roi:%u,%u,%u,%u]\n", wb_roi->x, wb_roi->y,
696 wb_roi->w, wb_roi->h);
697
698 wb_enc->wb_fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
699 drm_format_num_planes(fb->pixel_format));
700 if (!wb_enc->wb_fmt) {
701 SDE_ERROR("unsupported output pixel format: %d\n",
702 fb->pixel_format);
703 return;
704 }
705
706 SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->pixel_format,
707 fb->modifier[0]);
708
Alan Kwong5d324e42016-07-28 22:56:18 -0400709 sde_encoder_phys_wb_set_ot_limit(phys_enc);
710
Alan Kwongbb27c092016-07-20 16:41:25 -0400711 sde_encoder_phys_wb_set_traffic_shaper(phys_enc);
712
Alan Kwonga62eeb82017-04-19 08:57:55 -0700713 sde_encoder_phys_wb_set_qos_remap(phys_enc);
714
Chirag Khuranaed859f52019-11-20 18:18:12 +0530715 sde_encoder_phys_setup_cdm(phys_enc, wb_enc->wb_fmt,
716 CDM_CDWN_OUTPUT_WB, wb_roi);
Alan Kwongbb27c092016-07-20 16:41:25 -0400717
718 sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi);
719
720 sde_encoder_phys_wb_setup_cdp(phys_enc);
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700721
722 _sde_encoder_phys_wb_setup_cwb(phys_enc, true);
Alan Kwongbb27c092016-07-20 16:41:25 -0400723}
724
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700725static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
Alan Kwongbb27c092016-07-20 16:41:25 -0400726{
727 struct sde_encoder_phys_wb *wb_enc = arg;
728 struct sde_encoder_phys *phys_enc = &wb_enc->base;
729 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700730 u32 event = frame_error ? SDE_ENCODER_FRAME_EVENT_ERROR : 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400731
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700732 event |= SDE_ENCODER_FRAME_EVENT_DONE |
733 SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
734
735 SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count);
Alan Kwongbb27c092016-07-20 16:41:25 -0400736
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700737 /* don't notify upper layer for internal commit */
738 if (phys_enc->enable_state == SDE_ENC_DISABLING)
739 goto complete;
740
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700741 if (!phys_enc->in_clone_mode)
742 event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700743
744 atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0);
Alan Kwong628d19e2016-10-31 13:50:13 -0400745 if (phys_enc->parent_ops.handle_frame_done)
746 phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700747 phys_enc, event);
Alan Kwongbb27c092016-07-20 16:41:25 -0400748
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700749 if (phys_enc->parent_ops.handle_vblank_virt)
750 phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
751 phys_enc);
752
753 SDE_EVT32_IRQ(DRMID(phys_enc->parent), hw_wb->idx - WB_0, event);
Alan Kwong628d19e2016-10-31 13:50:13 -0400754
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700755complete:
Alan Kwong628d19e2016-10-31 13:50:13 -0400756 complete_all(&wb_enc->wbdone_complete);
Alan Kwongbb27c092016-07-20 16:41:25 -0400757}
758
759/**
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700760 * sde_encoder_phys_wb_done_irq - Pingpong overflow interrupt handler for CWB
761 * @arg: Pointer to writeback encoder
762 * @irq_idx: interrupt index
Alan Kwongbb27c092016-07-20 16:41:25 -0400763 */
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700764static void sde_encoder_phys_cwb_ovflow(void *arg, int irq_idx)
Alan Kwongbb27c092016-07-20 16:41:25 -0400765{
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700766 _sde_encoder_phys_wb_frame_done_helper(arg, true);
767}
768
769/**
770 * sde_encoder_phys_wb_done_irq - writeback interrupt handler
771 * @arg: Pointer to writeback encoder
772 * @irq_idx: interrupt index
773 */
774static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
775{
776 _sde_encoder_phys_wb_frame_done_helper(arg, false);
777}
778
779/**
780 * sde_encoder_phys_wb_irq_ctrl - irq control of WB
781 * @phys: Pointer to physical encoder
782 * @enable: indicates enable or disable interrupts
783 */
784static void sde_encoder_phys_wb_irq_ctrl(
785 struct sde_encoder_phys *phys, bool enable)
786{
787
788 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys);
Shubhashree Dhar5c9e2022018-09-03 15:49:42 +0530789 int index = 0, refcount;
790 int ret = 0;
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700791
792 if (!wb_enc)
793 return;
Alan Kwongbb27c092016-07-20 16:41:25 -0400794
795 if (wb_enc->bypass_irqreg)
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700796 return;
Alan Kwongbb27c092016-07-20 16:41:25 -0400797
Shubhashree Dhar5c9e2022018-09-03 15:49:42 +0530798 refcount = atomic_read(&phys->wbirq_refcount);
799
800 if (!enable && !refcount)
801 return;
802
803 SDE_EVT32(DRMID(phys->parent), enable,
804 atomic_read(&phys->wbirq_refcount));
805
806 if (enable && atomic_inc_return(&phys->wbirq_refcount) == 1) {
807 ret = sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE);
808 if (ret)
809 atomic_dec_return(&phys->wbirq_refcount);
810
811 } else if (!enable &&
812 atomic_dec_return(&phys->wbirq_refcount) == 0) {
813 ret = sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE);
814 if (ret)
815 atomic_inc_return(&phys->wbirq_refcount);
816 }
817
818 if (phys->in_clone_mode) {
819 if (enable) {
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700820 for (index = 0; index < CRTC_DUAL_MIXERS; index++)
821 sde_encoder_helper_register_irq(phys,
822 index ? INTR_IDX_PP3_OVFL
823 : INTR_IDX_PP2_OVFL);
Shubhashree Dhar5c9e2022018-09-03 15:49:42 +0530824 } else {
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700825 for (index = 0; index < CRTC_DUAL_MIXERS; index++)
826 sde_encoder_helper_unregister_irq(phys,
827 index ? INTR_IDX_PP3_OVFL
828 : INTR_IDX_PP2_OVFL);
829 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400830 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400831}
832
833/**
834 * sde_encoder_phys_wb_mode_set - set display mode
835 * @phys_enc: Pointer to physical encoder
836 * @mode: Pointer to requested display mode
837 * @adj_mode: Pointer to adjusted display mode
838 */
839static void sde_encoder_phys_wb_mode_set(
840 struct sde_encoder_phys *phys_enc,
841 struct drm_display_mode *mode,
842 struct drm_display_mode *adj_mode)
843{
844 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400845 struct sde_rm *rm = &phys_enc->sde_kms->rm;
Alan Kwongbb27c092016-07-20 16:41:25 -0400846 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400847 struct sde_rm_hw_iter iter;
848 int i, instance;
Alan Kwongbb27c092016-07-20 16:41:25 -0400849
850 phys_enc->cached_mode = *adj_mode;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400851 instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400852
853 SDE_DEBUG("[mode_set_cache:%d,%d,\"%s\",%d,%d]\n",
854 hw_wb->idx - WB_0, mode->base.id,
855 mode->name, mode->hdisplay, mode->vdisplay);
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400856
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400857 phys_enc->hw_ctl = NULL;
858 phys_enc->hw_cdm = NULL;
859
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400860 /* Retrieve previously allocated HW Resources. CTL shouldn't fail */
861 sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CTL);
862 for (i = 0; i <= instance; i++) {
863 sde_rm_get_hw(rm, &iter);
864 if (i == instance)
865 phys_enc->hw_ctl = (struct sde_hw_ctl *) iter.hw;
866 }
867
868 if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) {
869 SDE_ERROR("failed init ctl: %ld\n", PTR_ERR(phys_enc->hw_ctl));
870 phys_enc->hw_ctl = NULL;
871 return;
872 }
873
874 /* CDM is optional */
875 sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CDM);
876 for (i = 0; i <= instance; i++) {
877 sde_rm_get_hw(rm, &iter);
878 if (i == instance)
879 phys_enc->hw_cdm = (struct sde_hw_cdm *) iter.hw;
880 }
881
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400882 if (IS_ERR(phys_enc->hw_cdm)) {
883 SDE_ERROR("CDM required but not allocated: %ld\n",
884 PTR_ERR(phys_enc->hw_cdm));
885 phys_enc->hw_ctl = NULL;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400886 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400887}
888
889/**
Alan Kwongbb27c092016-07-20 16:41:25 -0400890 * sde_encoder_phys_wb_wait_for_commit_done - wait until request is committed
891 * @phys_enc: Pointer to physical encoder
892 */
893static int sde_encoder_phys_wb_wait_for_commit_done(
894 struct sde_encoder_phys *phys_enc)
895{
896 unsigned long ret;
897 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700898 u32 irq_status, event = 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400899 u64 wb_time = 0;
900 int rc = 0;
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700901 int irq_idx = phys_enc->irq[INTR_IDX_WB_DONE].irq_idx;
Alan Kwong5a50a4a2017-01-24 19:12:51 -0800902 u32 timeout = max_t(u32, wb_enc->wbdone_timeout, KICKOFF_TIMEOUT_MS);
Alan Kwongbb27c092016-07-20 16:41:25 -0400903
904 /* Return EWOULDBLOCK since we know the wait isn't necessary */
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700905 if (phys_enc->enable_state == SDE_ENC_DISABLED) {
906 SDE_ERROR("encoder already disabled\n");
Alan Kwongbb27c092016-07-20 16:41:25 -0400907 return -EWOULDBLOCK;
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700908 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400909
Alan Kwong4212dd42017-09-19 17:22:33 -0400910 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count,
911 !!wb_enc->wb_fb);
912
913 /* signal completion if commit with no framebuffer */
914 if (!wb_enc->wb_fb) {
915 SDE_DEBUG("no output framebuffer\n");
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700916 _sde_encoder_phys_wb_frame_done_helper(wb_enc, false);
Alan Kwong4212dd42017-09-19 17:22:33 -0400917 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400918
919 ret = wait_for_completion_timeout(&wb_enc->wbdone_complete,
Alan Kwong5a50a4a2017-01-24 19:12:51 -0800920 msecs_to_jiffies(timeout));
Alan Kwongbb27c092016-07-20 16:41:25 -0400921
922 if (!ret) {
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400923 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
924 wb_enc->frame_count);
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400925 irq_status = sde_core_irq_read(phys_enc->sde_kms,
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700926 irq_idx, true);
Alan Kwongbb27c092016-07-20 16:41:25 -0400927 if (irq_status) {
928 SDE_DEBUG("wb:%d done but irq not triggered\n",
Alan Kwong1124f1f2017-11-10 18:14:39 -0500929 WBID(wb_enc));
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -0700930 _sde_encoder_phys_wb_frame_done_helper(wb_enc, false);
Alan Kwongbb27c092016-07-20 16:41:25 -0400931 } else {
932 SDE_ERROR("wb:%d kickoff timed out\n",
Alan Kwong1124f1f2017-11-10 18:14:39 -0500933 WBID(wb_enc));
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700934 atomic_add_unless(
935 &phys_enc->pending_retire_fence_cnt, -1, 0);
936
937 event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
938 | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE
939 | SDE_ENCODER_FRAME_EVENT_ERROR;
Alan Kwong628d19e2016-10-31 13:50:13 -0400940 if (phys_enc->parent_ops.handle_frame_done)
941 phys_enc->parent_ops.handle_frame_done(
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700942 phys_enc->parent, phys_enc, event);
Alan Kwongbb27c092016-07-20 16:41:25 -0400943 rc = -ETIMEDOUT;
944 }
945 }
946
Alan Kwongbb27c092016-07-20 16:41:25 -0400947 if (!rc)
948 wb_enc->end_time = ktime_get();
949
950 /* once operation is done, disable traffic shaper */
951 if (wb_enc->wb_cfg.ts_cfg.en && wb_enc->hw_wb &&
952 wb_enc->hw_wb->ops.setup_trafficshaper) {
953 wb_enc->wb_cfg.ts_cfg.en = false;
954 wb_enc->hw_wb->ops.setup_trafficshaper(
955 wb_enc->hw_wb, &wb_enc->wb_cfg);
956 }
957
958 /* remove vote for iommu/clk/bus */
959 wb_enc->frame_count++;
960
961 if (!rc) {
962 wb_time = (u64)ktime_to_us(wb_enc->end_time) -
963 (u64)ktime_to_us(wb_enc->start_time);
Alan Kwong1124f1f2017-11-10 18:14:39 -0500964 SDE_DEBUG("wb:%d took %llu us\n", WBID(wb_enc), wb_time);
Alan Kwongbb27c092016-07-20 16:41:25 -0400965 }
966
Alan Kwong03b89842017-08-17 16:32:45 -0400967 /* cleanup writeback framebuffer */
968 if (wb_enc->wb_fb && wb_enc->wb_aspace) {
969 msm_framebuffer_cleanup(wb_enc->wb_fb, wb_enc->wb_aspace);
970 wb_enc->wb_fb = NULL;
971 wb_enc->wb_aspace = NULL;
972 }
973
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400974 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count,
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700975 wb_time, event, rc);
Alan Kwongbb27c092016-07-20 16:41:25 -0400976
977 return rc;
978}
979
980/**
981 * sde_encoder_phys_wb_prepare_for_kickoff - pre-kickoff processing
982 * @phys_enc: Pointer to physical encoder
Alan Kwong4aacd532017-02-04 18:51:33 -0800983 * @params: kickoff parameters
Clarence Ip85f4f4532017-10-04 12:10:13 -0400984 * Returns: Zero on success
Alan Kwongbb27c092016-07-20 16:41:25 -0400985 */
Clarence Ip85f4f4532017-10-04 12:10:13 -0400986static int sde_encoder_phys_wb_prepare_for_kickoff(
Alan Kwong4aacd532017-02-04 18:51:33 -0800987 struct sde_encoder_phys *phys_enc,
988 struct sde_encoder_kickoff_params *params)
Alan Kwongbb27c092016-07-20 16:41:25 -0400989{
990 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Alan Kwongbb27c092016-07-20 16:41:25 -0400991
992 SDE_DEBUG("[wb:%d,%u]\n", wb_enc->hw_wb->idx - WB_0,
993 wb_enc->kickoff_count);
994
Alan Kwongbb27c092016-07-20 16:41:25 -0400995 reinit_completion(&wb_enc->wbdone_complete);
996
Alan Kwongbb27c092016-07-20 16:41:25 -0400997 wb_enc->kickoff_count++;
998
999 /* set OT limit & enable traffic shaper */
1000 sde_encoder_phys_wb_setup(phys_enc);
1001
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001002 _sde_encoder_phys_wb_update_flush(phys_enc);
Alan Kwongbb27c092016-07-20 16:41:25 -04001003
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -07001004 _sde_encoder_phys_wb_update_cwb_flush(phys_enc);
1005
Alan Kwongbb27c092016-07-20 16:41:25 -04001006 /* vote for iommu/clk/bus */
1007 wb_enc->start_time = ktime_get();
1008
Lloyd Atkinsonaa0dce92016-11-23 20:16:47 -05001009 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->kickoff_count);
Clarence Ip85f4f4532017-10-04 12:10:13 -04001010 return 0;
Alan Kwongbb27c092016-07-20 16:41:25 -04001011}
1012
1013/**
Alan Kwong4212dd42017-09-19 17:22:33 -04001014 * sde_encoder_phys_wb_trigger_flush - trigger flush processing
1015 * @phys_enc: Pointer to physical encoder
1016 */
1017static void sde_encoder_phys_wb_trigger_flush(struct sde_encoder_phys *phys_enc)
1018{
1019 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1020
1021 if (!phys_enc || !wb_enc->hw_wb) {
1022 SDE_ERROR("invalid encoder\n");
1023 return;
1024 }
1025
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -07001026 /*
1027 * Bail out iff in CWB mode. In case of CWB, primary control-path
1028 * which is actually driving would trigger the flush
1029 */
1030 if (phys_enc->in_clone_mode) {
1031 SDE_DEBUG("in CWB mode. early return\n");
1032 return;
1033 }
1034
Alan Kwong4212dd42017-09-19 17:22:33 -04001035 SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0);
1036
1037 /* clear pending flush if commit with no framebuffer */
1038 if (!wb_enc->wb_fb) {
1039 SDE_DEBUG("no output framebuffer\n");
1040 return;
1041 }
1042
1043 sde_encoder_helper_trigger_flush(phys_enc);
1044}
1045
1046/**
Alan Kwongbb27c092016-07-20 16:41:25 -04001047 * sde_encoder_phys_wb_handle_post_kickoff - post-kickoff processing
1048 * @phys_enc: Pointer to physical encoder
1049 */
1050static void sde_encoder_phys_wb_handle_post_kickoff(
1051 struct sde_encoder_phys *phys_enc)
1052{
1053 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1054
1055 SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0);
1056
Lloyd Atkinson5d40d312016-09-06 08:34:13 -04001057 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc));
Alan Kwongbb27c092016-07-20 16:41:25 -04001058}
1059
1060/**
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001061 * _sde_encoder_phys_wb_init_internal_fb - create fb for internal commit
1062 * @wb_enc: Pointer to writeback encoder
1063 * @pixel_format: DRM pixel format
1064 * @width: Desired fb width
1065 * @height: Desired fb height
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001066 * @pitch: Desired fb pitch
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001067 */
1068static int _sde_encoder_phys_wb_init_internal_fb(
1069 struct sde_encoder_phys_wb *wb_enc,
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001070 uint32_t pixel_format, uint32_t width,
1071 uint32_t height, uint32_t pitch)
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001072{
1073 struct drm_device *dev;
1074 struct drm_framebuffer *fb;
1075 struct drm_mode_fb_cmd2 mode_cmd;
1076 uint32_t size;
1077 int nplanes, i, ret;
Jordan Croused8e96522017-02-13 10:14:16 -07001078 struct msm_gem_address_space *aspace;
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001079
1080 if (!wb_enc || !wb_enc->base.parent || !wb_enc->base.sde_kms) {
1081 SDE_ERROR("invalid params\n");
1082 return -EINVAL;
1083 }
1084
Jordan Croused8e96522017-02-13 10:14:16 -07001085 aspace = wb_enc->base.sde_kms->aspace[SDE_IOMMU_DOMAIN_UNSECURE];
1086 if (!aspace) {
1087 SDE_ERROR("invalid address space\n");
1088 return -EINVAL;
1089 }
1090
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001091 dev = wb_enc->base.sde_kms->dev;
1092 if (!dev) {
1093 SDE_ERROR("invalid dev\n");
1094 return -EINVAL;
1095 }
1096
1097 memset(&mode_cmd, 0, sizeof(mode_cmd));
1098 mode_cmd.pixel_format = pixel_format;
1099 mode_cmd.width = width;
1100 mode_cmd.height = height;
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001101 mode_cmd.pitches[0] = pitch;
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001102
1103 size = sde_format_get_framebuffer_size(pixel_format,
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001104 mode_cmd.width, mode_cmd.height,
1105 mode_cmd.pitches, NULL, 0);
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001106 if (!size) {
1107 SDE_DEBUG("not creating zero size buffer\n");
1108 return -EINVAL;
1109 }
1110
1111 /* allocate gem tracking object */
1112 nplanes = drm_format_num_planes(pixel_format);
1113 if (nplanes > SDE_MAX_PLANES) {
1114 SDE_ERROR("requested format has too many planes\n");
1115 return -EINVAL;
1116 }
1117 mutex_lock(&dev->struct_mutex);
1118 wb_enc->bo_disable[0] = msm_gem_new(dev, size,
1119 MSM_BO_SCANOUT | MSM_BO_WC);
1120 mutex_unlock(&dev->struct_mutex);
1121
1122 if (IS_ERR_OR_NULL(wb_enc->bo_disable[0])) {
1123 ret = PTR_ERR(wb_enc->bo_disable[0]);
1124 wb_enc->bo_disable[0] = NULL;
1125
1126 SDE_ERROR("failed to create bo, %d\n", ret);
1127 return ret;
1128 }
1129
1130 for (i = 0; i < nplanes; ++i) {
1131 wb_enc->bo_disable[i] = wb_enc->bo_disable[0];
1132 mode_cmd.pitches[i] = width *
1133 drm_format_plane_cpp(pixel_format, i);
1134 }
1135
1136 fb = msm_framebuffer_init(dev, &mode_cmd, wb_enc->bo_disable);
1137 if (IS_ERR_OR_NULL(fb)) {
1138 ret = PTR_ERR(fb);
1139 drm_gem_object_unreference(wb_enc->bo_disable[0]);
1140 wb_enc->bo_disable[0] = NULL;
1141
1142 SDE_ERROR("failed to init fb, %d\n", ret);
1143 return ret;
1144 }
1145
1146 /* prepare the backing buffer now so that it's available later */
Jordan Croused8e96522017-02-13 10:14:16 -07001147 ret = msm_framebuffer_prepare(fb, aspace);
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001148 if (!ret)
1149 wb_enc->fb_disable = fb;
1150 return ret;
1151}
1152
1153/**
1154 * _sde_encoder_phys_wb_destroy_internal_fb - deconstruct internal fb
1155 * @wb_enc: Pointer to writeback encoder
1156 */
1157static void _sde_encoder_phys_wb_destroy_internal_fb(
1158 struct sde_encoder_phys_wb *wb_enc)
1159{
1160 if (!wb_enc)
1161 return;
1162
1163 if (wb_enc->fb_disable) {
1164 drm_framebuffer_unregister_private(wb_enc->fb_disable);
1165 drm_framebuffer_remove(wb_enc->fb_disable);
1166 wb_enc->fb_disable = NULL;
1167 }
1168
1169 if (wb_enc->bo_disable[0]) {
1170 drm_gem_object_unreference(wb_enc->bo_disable[0]);
1171 wb_enc->bo_disable[0] = NULL;
1172 }
1173}
1174
1175/**
Alan Kwongbb27c092016-07-20 16:41:25 -04001176 * sde_encoder_phys_wb_enable - enable writeback encoder
1177 * @phys_enc: Pointer to physical encoder
1178 */
1179static void sde_encoder_phys_wb_enable(struct sde_encoder_phys *phys_enc)
1180{
1181 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1182 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Alan Kwong74e8ba32016-09-30 14:25:16 -04001183 struct drm_device *dev;
Alan Kwongbb27c092016-07-20 16:41:25 -04001184 struct drm_connector *connector;
1185
1186 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
1187
Alan Kwong74e8ba32016-09-30 14:25:16 -04001188 if (!wb_enc->base.parent || !wb_enc->base.parent->dev) {
1189 SDE_ERROR("invalid drm device\n");
1190 return;
1191 }
1192 dev = wb_enc->base.parent->dev;
1193
Alan Kwongbb27c092016-07-20 16:41:25 -04001194 /* find associated writeback connector */
Clarence Ip05431f32016-11-25 16:39:38 -05001195 connector = phys_enc->connector;
Alan Kwong74e8ba32016-09-30 14:25:16 -04001196
Alan Kwongbb27c092016-07-20 16:41:25 -04001197 if (!connector || connector->encoder != phys_enc->parent) {
1198 SDE_ERROR("failed to find writeback connector\n");
1199 return;
1200 }
1201 wb_enc->wb_dev = sde_wb_connector_get_wb(connector);
1202
1203 phys_enc->enable_state = SDE_ENC_ENABLED;
Harsh Sahufae4d812017-11-29 15:08:59 -08001204
1205 /*
1206 * cache the crtc in wb_enc on enable for duration of use case
1207 * for correctly servicing asynchronous irq events and timers
1208 */
1209 wb_enc->crtc = phys_enc->parent->crtc;
Alan Kwongbb27c092016-07-20 16:41:25 -04001210}
1211
1212/**
1213 * sde_encoder_phys_wb_disable - disable writeback encoder
1214 * @phys_enc: Pointer to physical encoder
1215 */
1216static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
1217{
1218 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1219 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
1220
1221 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
1222
1223 if (phys_enc->enable_state == SDE_ENC_DISABLED) {
1224 SDE_ERROR("encoder is already disabled\n");
1225 return;
1226 }
1227
1228 if (wb_enc->frame_count != wb_enc->kickoff_count) {
1229 SDE_DEBUG("[wait_for_done: wb:%d, frame:%u, kickoff:%u]\n",
1230 hw_wb->idx - WB_0, wb_enc->frame_count,
1231 wb_enc->kickoff_count);
1232 sde_encoder_phys_wb_wait_for_commit_done(phys_enc);
1233 }
1234
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001235 if (!phys_enc->hw_ctl || !phys_enc->parent ||
1236 !phys_enc->sde_kms || !wb_enc->fb_disable) {
1237 SDE_DEBUG("invalid enc, skipping extra commit\n");
1238 goto exit;
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001239 }
1240
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -07001241 /* avoid reset frame for CWB */
1242 if (phys_enc->in_clone_mode) {
1243 _sde_encoder_phys_wb_setup_cwb(phys_enc, false);
1244 phys_enc->in_clone_mode = false;
1245 goto exit;
1246 }
1247
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001248 /* reset h/w before final flush */
Clarence Ip662698e2017-09-12 18:34:16 -04001249 if (phys_enc->hw_ctl->ops.clear_pending_flush)
1250 phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl);
Raviteja Tamatamd94b2652019-02-11 17:02:39 +05301251 if (sde_encoder_helper_reset_mixers(phys_enc, NULL))
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001252 goto exit;
1253
1254 phys_enc->enable_state = SDE_ENC_DISABLING;
Alan Kwong4aacd532017-02-04 18:51:33 -08001255 sde_encoder_phys_wb_prepare_for_kickoff(phys_enc, NULL);
Shubhashree Dhar5c9e2022018-09-03 15:49:42 +05301256 sde_encoder_phys_wb_irq_ctrl(phys_enc, true);
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001257 if (phys_enc->hw_ctl->ops.trigger_flush)
1258 phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl);
1259 sde_encoder_helper_trigger_start(phys_enc);
1260 sde_encoder_phys_wb_wait_for_commit_done(phys_enc);
Shubhashree Dhar5c9e2022018-09-03 15:49:42 +05301261 sde_encoder_phys_wb_irq_ctrl(phys_enc, false);
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001262exit:
Alan Kwongbb27c092016-07-20 16:41:25 -04001263 phys_enc->enable_state = SDE_ENC_DISABLED;
Harsh Sahufae4d812017-11-29 15:08:59 -08001264 wb_enc->crtc = NULL;
Alan Kwongbb27c092016-07-20 16:41:25 -04001265}
1266
1267/**
1268 * sde_encoder_phys_wb_get_hw_resources - get hardware resources
1269 * @phys_enc: Pointer to physical encoder
1270 * @hw_res: Pointer to encoder resources
1271 */
1272static void sde_encoder_phys_wb_get_hw_resources(
1273 struct sde_encoder_phys *phys_enc,
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001274 struct sde_encoder_hw_resources *hw_res,
1275 struct drm_connector_state *conn_state)
Alan Kwongbb27c092016-07-20 16:41:25 -04001276{
1277 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Clarence Ip03521982016-08-26 10:49:47 -04001278 struct sde_hw_wb *hw_wb;
Alan Kwong4c3cf4c2016-09-25 20:08:09 -04001279 struct drm_framebuffer *fb;
Alan Kwong4212dd42017-09-19 17:22:33 -04001280 const struct sde_format *fmt = NULL;
Alan Kwongbb27c092016-07-20 16:41:25 -04001281
Clarence Ip03521982016-08-26 10:49:47 -04001282 if (!phys_enc) {
1283 SDE_ERROR("invalid encoder\n");
1284 return;
1285 }
Alan Kwong4c3cf4c2016-09-25 20:08:09 -04001286
1287 fb = sde_wb_connector_state_get_output_fb(conn_state);
Alan Kwong4212dd42017-09-19 17:22:33 -04001288 if (fb) {
1289 fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
1290 drm_format_num_planes(fb->pixel_format));
1291 if (!fmt) {
1292 SDE_ERROR("unsupported output pixel format:%d\n",
1293 fb->pixel_format);
1294 return;
1295 }
Alan Kwong4c3cf4c2016-09-25 20:08:09 -04001296 }
1297
Clarence Ip03521982016-08-26 10:49:47 -04001298 hw_wb = wb_enc->hw_wb;
Clarence Ip03521982016-08-26 10:49:47 -04001299 hw_res->wbs[hw_wb->idx - WB_0] = phys_enc->intf_mode;
Alan Kwong4212dd42017-09-19 17:22:33 -04001300 hw_res->needs_cdm = fmt ? SDE_FORMAT_IS_YUV(fmt) : false;
Alan Kwong4c3cf4c2016-09-25 20:08:09 -04001301 SDE_DEBUG("[wb:%d] intf_mode=%d needs_cdm=%d\n", hw_wb->idx - WB_0,
1302 hw_res->wbs[hw_wb->idx - WB_0],
1303 hw_res->needs_cdm);
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -04001304}
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001305
Alan Kwongbb27c092016-07-20 16:41:25 -04001306#ifdef CONFIG_DEBUG_FS
1307/**
1308 * sde_encoder_phys_wb_init_debugfs - initialize writeback encoder debugfs
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001309 * @phys_enc: Pointer to physical encoder
1310 * @debugfs_root: Pointer to virtual encoder's debugfs_root dir
Alan Kwongbb27c092016-07-20 16:41:25 -04001311 */
1312static int sde_encoder_phys_wb_init_debugfs(
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001313 struct sde_encoder_phys *phys_enc, struct dentry *debugfs_root)
Alan Kwongbb27c092016-07-20 16:41:25 -04001314{
1315 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1316
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001317 if (!phys_enc || !wb_enc->hw_wb || !debugfs_root)
Alan Kwongbb27c092016-07-20 16:41:25 -04001318 return -EINVAL;
1319
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001320 if (!debugfs_create_u32("wbdone_timeout", 0600,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001321 debugfs_root, &wb_enc->wbdone_timeout)) {
Alan Kwongbb27c092016-07-20 16:41:25 -04001322 SDE_ERROR("failed to create debugfs/wbdone_timeout\n");
1323 return -ENOMEM;
1324 }
1325
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001326 if (!debugfs_create_u32("bypass_irqreg", 0600,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001327 debugfs_root, &wb_enc->bypass_irqreg)) {
Alan Kwongbb27c092016-07-20 16:41:25 -04001328 SDE_ERROR("failed to create debugfs/bypass_irqreg\n");
1329 return -ENOMEM;
1330 }
1331
1332 return 0;
1333}
Alan Kwongbb27c092016-07-20 16:41:25 -04001334#else
Dhaval Patel48f2d0f2016-09-27 16:39:12 -07001335static int sde_encoder_phys_wb_init_debugfs(
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001336 struct sde_encoder_phys *phys_enc, struct dentry *debugfs_root)
Alan Kwongbb27c092016-07-20 16:41:25 -04001337{
Dhaval Patel48f2d0f2016-09-27 16:39:12 -07001338 return 0;
Alan Kwongbb27c092016-07-20 16:41:25 -04001339}
Alan Kwongbb27c092016-07-20 16:41:25 -04001340#endif
1341
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001342static int sde_encoder_phys_wb_late_register(struct sde_encoder_phys *phys_enc,
1343 struct dentry *debugfs_root)
1344{
1345 return sde_encoder_phys_wb_init_debugfs(phys_enc, debugfs_root);
1346}
1347
Alan Kwongbb27c092016-07-20 16:41:25 -04001348/**
1349 * sde_encoder_phys_wb_destroy - destroy writeback encoder
1350 * @phys_enc: Pointer to physical encoder
1351 */
1352static void sde_encoder_phys_wb_destroy(struct sde_encoder_phys *phys_enc)
1353{
1354 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1355 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
1356
1357 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
1358
1359 if (!phys_enc)
1360 return;
1361
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001362 _sde_encoder_phys_wb_destroy_internal_fb(wb_enc);
1363
Alan Kwongbb27c092016-07-20 16:41:25 -04001364 kfree(wb_enc);
1365}
1366
1367/**
1368 * sde_encoder_phys_wb_init_ops - initialize writeback operations
1369 * @ops: Pointer to encoder operation table
1370 */
1371static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops)
1372{
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001373 ops->late_register = sde_encoder_phys_wb_late_register;
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -04001374 ops->is_master = sde_encoder_phys_wb_is_master;
Alan Kwongbb27c092016-07-20 16:41:25 -04001375 ops->mode_set = sde_encoder_phys_wb_mode_set;
1376 ops->enable = sde_encoder_phys_wb_enable;
1377 ops->disable = sde_encoder_phys_wb_disable;
1378 ops->destroy = sde_encoder_phys_wb_destroy;
1379 ops->atomic_check = sde_encoder_phys_wb_atomic_check;
1380 ops->get_hw_resources = sde_encoder_phys_wb_get_hw_resources;
Alan Kwongbb27c092016-07-20 16:41:25 -04001381 ops->wait_for_commit_done = sde_encoder_phys_wb_wait_for_commit_done;
1382 ops->prepare_for_kickoff = sde_encoder_phys_wb_prepare_for_kickoff;
1383 ops->handle_post_kickoff = sde_encoder_phys_wb_handle_post_kickoff;
Alan Kwong4212dd42017-09-19 17:22:33 -04001384 ops->trigger_flush = sde_encoder_phys_wb_trigger_flush;
Clarence Ip110d15c2016-08-16 14:44:41 -04001385 ops->trigger_start = sde_encoder_helper_trigger_start;
Lloyd Atkinson8c49c582016-11-18 14:23:54 -05001386 ops->hw_reset = sde_encoder_helper_hw_reset;
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -07001387 ops->irq_control = sde_encoder_phys_wb_irq_ctrl;
Alan Kwongbb27c092016-07-20 16:41:25 -04001388}
1389
1390/**
1391 * sde_encoder_phys_wb_init - initialize writeback encoder
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001392 * @init: Pointer to init info structure with initialization params
Alan Kwongbb27c092016-07-20 16:41:25 -04001393 */
1394struct sde_encoder_phys *sde_encoder_phys_wb_init(
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001395 struct sde_enc_phys_init_params *p)
Alan Kwongbb27c092016-07-20 16:41:25 -04001396{
1397 struct sde_encoder_phys *phys_enc;
1398 struct sde_encoder_phys_wb *wb_enc;
1399 struct sde_hw_mdp *hw_mdp;
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -07001400 struct sde_encoder_irq *irq;
Alan Kwongbb27c092016-07-20 16:41:25 -04001401 int ret = 0;
1402
1403 SDE_DEBUG("\n");
1404
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001405 if (!p || !p->parent) {
1406 SDE_ERROR("invalid params\n");
1407 ret = -EINVAL;
1408 goto fail_alloc;
1409 }
1410
Alan Kwongbb27c092016-07-20 16:41:25 -04001411 wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL);
1412 if (!wb_enc) {
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001413 SDE_ERROR("failed to allocate wb enc\n");
Alan Kwongbb27c092016-07-20 16:41:25 -04001414 ret = -ENOMEM;
1415 goto fail_alloc;
1416 }
Lloyd Atkinsonaa0dce92016-11-23 20:16:47 -05001417 wb_enc->wbdone_timeout = KICKOFF_TIMEOUT_MS;
Alan Kwongbb27c092016-07-20 16:41:25 -04001418 init_completion(&wb_enc->wbdone_complete);
1419
1420 phys_enc = &wb_enc->base;
1421
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001422 if (p->sde_kms->vbif[VBIF_NRT]) {
Jordan Croused8e96522017-02-13 10:14:16 -07001423 wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
1424 p->sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_UNSECURE];
1425 wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] =
1426 p->sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_SECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -04001427 } else {
Jordan Croused8e96522017-02-13 10:14:16 -07001428 wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
1429 p->sde_kms->aspace[MSM_SMMU_DOMAIN_UNSECURE];
1430 wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] =
1431 p->sde_kms->aspace[MSM_SMMU_DOMAIN_SECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -04001432 }
1433
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001434 hw_mdp = sde_rm_get_mdp(&p->sde_kms->rm);
Alan Kwongbb27c092016-07-20 16:41:25 -04001435 if (IS_ERR_OR_NULL(hw_mdp)) {
1436 ret = PTR_ERR(hw_mdp);
1437 SDE_ERROR("failed to init hw_top: %d\n", ret);
1438 goto fail_mdp_init;
1439 }
1440 phys_enc->hw_mdptop = hw_mdp;
1441
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001442 /**
1443 * hw_wb resource permanently assigned to this encoder
1444 * Other resources allocated at atomic commit time by use case
1445 */
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001446 if (p->wb_idx != SDE_NONE) {
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001447 struct sde_rm_hw_iter iter;
Alan Kwongbb27c092016-07-20 16:41:25 -04001448
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001449 sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_WB);
1450 while (sde_rm_get_hw(&p->sde_kms->rm, &iter)) {
1451 struct sde_hw_wb *hw_wb = (struct sde_hw_wb *)iter.hw;
1452
1453 if (hw_wb->idx == p->wb_idx) {
1454 wb_enc->hw_wb = hw_wb;
1455 break;
1456 }
1457 }
1458
1459 if (!wb_enc->hw_wb) {
1460 ret = -EINVAL;
1461 SDE_ERROR("failed to init hw_wb%d\n", p->wb_idx - WB_0);
Alan Kwongbb27c092016-07-20 16:41:25 -04001462 goto fail_wb_init;
1463 }
Alan Kwongbb27c092016-07-20 16:41:25 -04001464 } else {
1465 ret = -EINVAL;
1466 SDE_ERROR("invalid wb_idx\n");
1467 goto fail_wb_check;
1468 }
1469
Alan Kwongbb27c092016-07-20 16:41:25 -04001470 sde_encoder_phys_wb_init_ops(&phys_enc->ops);
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001471 phys_enc->parent = p->parent;
1472 phys_enc->parent_ops = p->parent_ops;
1473 phys_enc->sde_kms = p->sde_kms;
1474 phys_enc->split_role = p->split_role;
Clarence Ip03521982016-08-26 10:49:47 -04001475 phys_enc->intf_mode = INTF_MODE_WB_LINE;
Dhaval Patel81e87882016-10-19 21:41:56 -07001476 phys_enc->intf_idx = p->intf_idx;
Lloyd Atkinson7d070942016-07-26 18:35:12 -04001477 phys_enc->enc_spinlock = p->enc_spinlock;
Raviteja Tamatam3ea60b82018-04-27 15:41:18 +05301478 phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -07001479 atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
Shubhashree Dhar5c9e2022018-09-03 15:49:42 +05301480 atomic_set(&phys_enc->wbirq_refcount, 0);
Prabhanjan Kandula77cc0ee2018-04-15 21:44:50 -07001481
1482 irq = &phys_enc->irq[INTR_IDX_WB_DONE];
1483 INIT_LIST_HEAD(&irq->cb.list);
1484 irq->name = "wb_done";
1485 irq->hw_idx = wb_enc->hw_wb->idx;
1486 irq->irq_idx = -1;
1487 irq->intr_type = sde_encoder_phys_wb_get_intr_type(wb_enc->hw_wb);
1488 irq->intr_idx = INTR_IDX_WB_DONE;
1489 irq->cb.arg = wb_enc;
1490 irq->cb.func = sde_encoder_phys_wb_done_irq;
1491
1492 irq = &phys_enc->irq[INTR_IDX_PP2_OVFL];
1493 INIT_LIST_HEAD(&irq->cb.list);
1494 irq->name = "pp2_overflow";
1495 irq->hw_idx = CWB_2;
1496 irq->irq_idx = -1;
1497 irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW;
1498 irq->intr_idx = INTR_IDX_PP2_OVFL;
1499 irq->cb.arg = wb_enc;
1500 irq->cb.func = sde_encoder_phys_cwb_ovflow;
1501
1502 irq = &phys_enc->irq[INTR_IDX_PP3_OVFL];
1503 INIT_LIST_HEAD(&irq->cb.list);
1504 irq->name = "pp3_overflow";
1505 irq->hw_idx = CWB_3;
1506 irq->irq_idx = -1;
1507 irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW;
1508 irq->intr_idx = INTR_IDX_PP3_OVFL;
1509 irq->cb.arg = wb_enc;
1510 irq->cb.func = sde_encoder_phys_cwb_ovflow;
Alan Kwongbb27c092016-07-20 16:41:25 -04001511
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001512 /* create internal buffer for disable logic */
1513 if (_sde_encoder_phys_wb_init_internal_fb(wb_enc,
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001514 DRM_FORMAT_RGB888, 2, 1, 6)) {
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001515 SDE_ERROR("failed to init internal fb\n");
1516 goto fail_wb_init;
1517 }
1518
Alan Kwongbb27c092016-07-20 16:41:25 -04001519 SDE_DEBUG("Created sde_encoder_phys_wb for wb %d\n",
1520 wb_enc->hw_wb->idx - WB_0);
1521
1522 return phys_enc;
1523
Alan Kwongbb27c092016-07-20 16:41:25 -04001524fail_wb_init:
1525fail_wb_check:
Alan Kwongbb27c092016-07-20 16:41:25 -04001526fail_mdp_init:
1527 kfree(wb_enc);
1528fail_alloc:
1529 return ERR_PTR(ret);
1530}
1531