blob: 42cf0154b85f3dd10bee0e1c53fa3a2be42fb30b [file] [log] [blame]
Alan Kwongbb27c092016-07-20 16:41:25 -04001/*
Lloyd Atkinson8772e202016-09-26 17:52:16 -04002 * Copyright (c) 2015-2017 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
Alan Kwongd6a38602017-03-11 22:26:25 -080033#define TO_S15D16(_x_) ((_x_) << 7)
34
35/**
36 * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix
37 *
38 */
39static struct sde_csc_cfg sde_encoder_phys_wb_rgb2yuv_601l = {
40 {
41 TO_S15D16(0x0083), TO_S15D16(0x0102), TO_S15D16(0x0032),
42 TO_S15D16(0x1fb5), TO_S15D16(0x1f6c), TO_S15D16(0x00e1),
43 TO_S15D16(0x00e1), TO_S15D16(0x1f45), TO_S15D16(0x1fdc)
44 },
45 { 0x00, 0x00, 0x00 },
46 { 0x0040, 0x0200, 0x0200 },
47 { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff },
48 { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 },
49};
50
Alan Kwongbb27c092016-07-20 16:41:25 -040051/**
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -040052 * sde_encoder_phys_wb_is_master - report wb always as master encoder
53 */
54static bool sde_encoder_phys_wb_is_master(struct sde_encoder_phys *phys_enc)
55{
56 return true;
57}
58
59/**
Alan Kwongbb27c092016-07-20 16:41:25 -040060 * sde_encoder_phys_wb_get_intr_type - get interrupt type based on block mode
61 * @hw_wb: Pointer to h/w writeback driver
62 */
63static enum sde_intr_type sde_encoder_phys_wb_get_intr_type(
64 struct sde_hw_wb *hw_wb)
65{
66 return (hw_wb->caps->features & BIT(SDE_WB_BLOCK_MODE)) ?
67 SDE_IRQ_TYPE_WB_ROT_COMP : SDE_IRQ_TYPE_WB_WFD_COMP;
68}
69
70/**
Alan Kwong5d324e42016-07-28 22:56:18 -040071 * sde_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface
72 * @phys_enc: Pointer to physical encoder
73 */
74static void sde_encoder_phys_wb_set_ot_limit(
75 struct sde_encoder_phys *phys_enc)
76{
77 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
78 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
79 struct sde_vbif_set_ot_params ot_params;
80
81 memset(&ot_params, 0, sizeof(ot_params));
82 ot_params.xin_id = hw_wb->caps->xin_id;
83 ot_params.num = hw_wb->idx - WB_0;
84 ot_params.width = wb_enc->wb_roi.w;
85 ot_params.height = wb_enc->wb_roi.h;
86 ot_params.is_wfd = true;
87 ot_params.frame_rate = phys_enc->cached_mode.vrefresh;
88 ot_params.vbif_idx = hw_wb->caps->vbif_idx;
89 ot_params.clk_ctrl = hw_wb->caps->clk_ctrl;
90 ot_params.rd = false;
91
92 sde_vbif_set_ot_limit(phys_enc->sde_kms, &ot_params);
93}
94
95/**
Alan Kwongbb27c092016-07-20 16:41:25 -040096 * sde_encoder_phys_wb_set_traffic_shaper - set traffic shaper for writeback
97 * @phys_enc: Pointer to physical encoder
98 */
99static void sde_encoder_phys_wb_set_traffic_shaper(
100 struct sde_encoder_phys *phys_enc)
101{
102 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
103 struct sde_hw_wb_cfg *wb_cfg = &wb_enc->wb_cfg;
104
105 /* traffic shaper is only enabled for rotator */
106 wb_cfg->ts_cfg.en = false;
107}
108
109/**
Alan Kwonga62eeb82017-04-19 08:57:55 -0700110 * sde_encoder_phys_wb_set_qos_remap - set QoS remapper for writeback
111 * @phys_enc: Pointer to physical encoder
112 */
113static void sde_encoder_phys_wb_set_qos_remap(
114 struct sde_encoder_phys *phys_enc)
115{
116 struct sde_encoder_phys_wb *wb_enc;
117 struct sde_hw_wb *hw_wb;
118 struct drm_crtc *crtc;
119 struct sde_vbif_set_qos_params qos_params;
120
121 if (!phys_enc || !phys_enc->parent || !phys_enc->parent->crtc) {
122 SDE_ERROR("invalid arguments\n");
123 return;
124 }
125
126 wb_enc = to_sde_encoder_phys_wb(phys_enc);
127 crtc = phys_enc->parent->crtc;
128
129 if (!wb_enc->hw_wb || !wb_enc->hw_wb->caps) {
130 SDE_ERROR("invalid writeback hardware\n");
131 return;
132 }
133
134 hw_wb = wb_enc->hw_wb;
135
136 memset(&qos_params, 0, sizeof(qos_params));
137 qos_params.vbif_idx = hw_wb->caps->vbif_idx;
138 qos_params.xin_id = hw_wb->caps->xin_id;
139 qos_params.clk_ctrl = hw_wb->caps->clk_ctrl;
140 qos_params.num = hw_wb->idx - WB_0;
141 qos_params.is_rt = sde_crtc_get_client_type(crtc) != NRT_CLIENT;
142
143 SDE_DEBUG("[qos_remap] wb:%d vbif:%d xin:%d rt:%d\n",
144 qos_params.num,
145 qos_params.vbif_idx,
146 qos_params.xin_id, qos_params.is_rt);
147
148 sde_vbif_set_qos_remap(phys_enc->sde_kms, &qos_params);
149}
150
151/**
Alan Kwongbb27c092016-07-20 16:41:25 -0400152 * sde_encoder_phys_setup_cdm - setup chroma down block
153 * @phys_enc: Pointer to physical encoder
154 * @fb: Pointer to output framebuffer
155 * @format: Output format
156 */
157void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
158 struct drm_framebuffer *fb, const struct sde_format *format,
159 struct sde_rect *wb_roi)
160{
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400161 struct sde_hw_cdm *hw_cdm;
162 struct sde_hw_cdm_cfg *cdm_cfg;
Alan Kwongbb27c092016-07-20 16:41:25 -0400163 int ret;
164
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400165 if (!phys_enc || !format)
166 return;
167
168 cdm_cfg = &phys_enc->cdm_cfg;
169 hw_cdm = phys_enc->hw_cdm;
170 if (!hw_cdm)
171 return;
172
Alan Kwongbb27c092016-07-20 16:41:25 -0400173 if (!SDE_FORMAT_IS_YUV(format)) {
174 SDE_DEBUG("[cdm_disable fmt:%x]\n",
175 format->base.pixel_format);
176
177 if (hw_cdm && hw_cdm->ops.disable)
178 hw_cdm->ops.disable(hw_cdm);
179
180 return;
181 }
182
183 memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg));
184
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400185 if (!wb_roi)
186 return;
187
Alan Kwongbb27c092016-07-20 16:41:25 -0400188 cdm_cfg->output_width = wb_roi->w;
189 cdm_cfg->output_height = wb_roi->h;
190 cdm_cfg->output_fmt = format;
191 cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
abeykun5ed42e12016-08-24 17:09:26 -0400192 cdm_cfg->output_bit_depth = SDE_FORMAT_IS_DX(format) ?
193 CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
Alan Kwongbb27c092016-07-20 16:41:25 -0400194
195 /* enable 10 bit logic */
196 switch (cdm_cfg->output_fmt->chroma_sample) {
197 case SDE_CHROMA_RGB:
198 cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
199 cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
200 break;
201 case SDE_CHROMA_H2V1:
202 cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
203 cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
204 break;
205 case SDE_CHROMA_420:
206 cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
207 cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
208 break;
209 case SDE_CHROMA_H1V2:
210 default:
211 SDE_ERROR("unsupported chroma sampling type\n");
212 cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
213 cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
214 break;
215 }
216
217 SDE_DEBUG("[cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
218 cdm_cfg->output_width,
219 cdm_cfg->output_height,
220 cdm_cfg->output_fmt->base.pixel_format,
221 cdm_cfg->output_type,
222 cdm_cfg->output_bit_depth,
223 cdm_cfg->h_cdwn_type,
224 cdm_cfg->v_cdwn_type);
225
Alan Kwongd6a38602017-03-11 22:26:25 -0800226 if (hw_cdm && hw_cdm->ops.setup_csc_data) {
227 ret = hw_cdm->ops.setup_csc_data(hw_cdm,
228 &sde_encoder_phys_wb_rgb2yuv_601l);
229 if (ret < 0) {
230 SDE_ERROR("failed to setup CSC %d\n", ret);
231 return;
232 }
233 }
234
Alan Kwongbb27c092016-07-20 16:41:25 -0400235 if (hw_cdm && hw_cdm->ops.setup_cdwn) {
236 ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg);
237 if (ret < 0) {
238 SDE_ERROR("failed to setup CDM %d\n", ret);
239 return;
240 }
241 }
242
243 if (hw_cdm && hw_cdm->ops.enable) {
244 ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
245 if (ret < 0) {
246 SDE_ERROR("failed to enable CDM %d\n", ret);
247 return;
248 }
249 }
250}
251
252/**
253 * sde_encoder_phys_wb_setup_fb - setup output framebuffer
254 * @phys_enc: Pointer to physical encoder
255 * @fb: Pointer to output framebuffer
256 * @wb_roi: Pointer to output region of interest
257 */
258static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc,
259 struct drm_framebuffer *fb, struct sde_rect *wb_roi)
260{
261 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Clarence Ip03521982016-08-26 10:49:47 -0400262 struct sde_hw_wb *hw_wb;
263 struct sde_hw_wb_cfg *wb_cfg;
Alan Kwong143f50c2017-04-28 07:34:28 -0700264 struct sde_hw_wb_cdp_cfg *cdp_cfg;
Alan Kwongbb27c092016-07-20 16:41:25 -0400265 const struct msm_format *format;
Jordan Croused8e96522017-02-13 10:14:16 -0700266 int ret;
267 struct msm_gem_address_space *aspace;
Alan Kwong03b89842017-08-17 16:32:45 -0400268 u32 fb_mode;
Alan Kwongbb27c092016-07-20 16:41:25 -0400269
Alan Kwong03b89842017-08-17 16:32:45 -0400270 if (!phys_enc || !phys_enc->sde_kms || !phys_enc->sde_kms->catalog ||
271 !phys_enc->connector) {
Clarence Ip03521982016-08-26 10:49:47 -0400272 SDE_ERROR("invalid encoder\n");
273 return;
274 }
275
276 hw_wb = wb_enc->hw_wb;
277 wb_cfg = &wb_enc->wb_cfg;
Alan Kwong143f50c2017-04-28 07:34:28 -0700278 cdp_cfg = &wb_enc->cdp_cfg;
Alan Kwongbb27c092016-07-20 16:41:25 -0400279 memset(wb_cfg, 0, sizeof(struct sde_hw_wb_cfg));
280
Clarence Ip03521982016-08-26 10:49:47 -0400281 wb_cfg->intf_mode = phys_enc->intf_mode;
Alan Kwong03b89842017-08-17 16:32:45 -0400282
283 fb_mode = sde_connector_get_property(phys_enc->connector->state,
284 CONNECTOR_PROP_FB_TRANSLATION_MODE);
285 if (phys_enc->enable_state == SDE_ENC_DISABLING)
286 wb_cfg->is_secure = false;
287 else if (fb_mode == SDE_DRM_FB_SEC)
288 wb_cfg->is_secure = true;
289 else
290 wb_cfg->is_secure = false;
291
Jordan Croused8e96522017-02-13 10:14:16 -0700292 aspace = (wb_cfg->is_secure) ?
293 wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] :
294 wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -0400295
296 SDE_DEBUG("[fb_secure:%d]\n", wb_cfg->is_secure);
297
Alan Kwong03b89842017-08-17 16:32:45 -0400298 ret = msm_framebuffer_prepare(fb, aspace);
299 if (ret) {
300 SDE_ERROR("prep fb failed, %d\n", ret);
301 return;
302 }
303
304 /* cache framebuffer for cleanup in writeback done */
305 wb_enc->wb_fb = fb;
306 wb_enc->wb_aspace = aspace;
307
Alan Kwongbb27c092016-07-20 16:41:25 -0400308 format = msm_framebuffer_format(fb);
Dhaval Patelccbcb3d2016-08-22 11:58:14 -0700309 if (!format) {
310 SDE_DEBUG("invalid format for fb\n");
311 return;
312 }
313
Alan Kwongbb27c092016-07-20 16:41:25 -0400314 wb_cfg->dest.format = sde_get_sde_format_ext(
315 format->pixel_format,
316 fb->modifier,
317 drm_format_num_planes(fb->pixel_format));
318 if (!wb_cfg->dest.format) {
319 /* this error should be detected during atomic_check */
320 SDE_ERROR("failed to get format %x\n", format->pixel_format);
321 return;
322 }
abeykunf1539f72016-08-24 16:08:03 -0400323 wb_cfg->roi = *wb_roi;
Alan Kwongbb27c092016-07-20 16:41:25 -0400324
abeykunf1539f72016-08-24 16:08:03 -0400325 if (hw_wb->caps->features & BIT(SDE_WB_XY_ROI_OFFSET)) {
Jordan Croused8e96522017-02-13 10:14:16 -0700326 ret = sde_format_populate_layout(aspace, fb, &wb_cfg->dest);
abeykunf1539f72016-08-24 16:08:03 -0400327 if (ret) {
328 SDE_DEBUG("failed to populate layout %d\n", ret);
329 return;
330 }
331 wb_cfg->dest.width = fb->width;
332 wb_cfg->dest.height = fb->height;
333 wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes;
334 } else {
Jordan Croused8e96522017-02-13 10:14:16 -0700335 ret = sde_format_populate_layout_with_roi(aspace, fb, wb_roi,
Alan Kwongbb27c092016-07-20 16:41:25 -0400336 &wb_cfg->dest);
abeykunf1539f72016-08-24 16:08:03 -0400337 if (ret) {
338 /* this error should be detected during atomic_check */
339 SDE_DEBUG("failed to populate layout %d\n", ret);
340 return;
341 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400342 }
343
344 if ((wb_cfg->dest.format->fetch_planes == SDE_PLANE_PLANAR) &&
345 (wb_cfg->dest.format->element[0] == C1_B_Cb))
346 swap(wb_cfg->dest.plane_addr[1], wb_cfg->dest.plane_addr[2]);
347
348 SDE_DEBUG("[fb_offset:%8.8x,%8.8x,%8.8x,%8.8x]\n",
349 wb_cfg->dest.plane_addr[0],
350 wb_cfg->dest.plane_addr[1],
351 wb_cfg->dest.plane_addr[2],
352 wb_cfg->dest.plane_addr[3]);
353 SDE_DEBUG("[fb_stride:%8.8x,%8.8x,%8.8x,%8.8x]\n",
354 wb_cfg->dest.plane_pitch[0],
355 wb_cfg->dest.plane_pitch[1],
356 wb_cfg->dest.plane_pitch[2],
357 wb_cfg->dest.plane_pitch[3]);
358
abeykunf1539f72016-08-24 16:08:03 -0400359 if (hw_wb->ops.setup_roi)
360 hw_wb->ops.setup_roi(hw_wb, wb_cfg);
361
Alan Kwongbb27c092016-07-20 16:41:25 -0400362 if (hw_wb->ops.setup_outformat)
363 hw_wb->ops.setup_outformat(hw_wb, wb_cfg);
364
Alan Kwong143f50c2017-04-28 07:34:28 -0700365 if (hw_wb->ops.setup_cdp) {
366 memset(cdp_cfg, 0, sizeof(struct sde_hw_wb_cdp_cfg));
367
368 cdp_cfg->enable = phys_enc->sde_kms->catalog->perf.cdp_cfg
369 [SDE_PERF_CDP_USAGE_NRT].wr_enable;
370 cdp_cfg->ubwc_meta_enable =
371 SDE_FORMAT_IS_UBWC(wb_cfg->dest.format);
372 cdp_cfg->tile_amortize_enable =
373 SDE_FORMAT_IS_UBWC(wb_cfg->dest.format) ||
374 SDE_FORMAT_IS_TILE(wb_cfg->dest.format);
375 cdp_cfg->preload_ahead = SDE_WB_CDP_PRELOAD_AHEAD_64;
376
377 hw_wb->ops.setup_cdp(hw_wb, cdp_cfg);
378 }
379
Alan Kwongc16e0922017-05-11 14:50:46 -0700380 if (hw_wb->ops.setup_outaddress) {
381 SDE_EVT32(hw_wb->idx,
382 wb_cfg->dest.width,
383 wb_cfg->dest.height,
384 wb_cfg->dest.plane_addr[0],
385 wb_cfg->dest.plane_size[0],
386 wb_cfg->dest.plane_addr[1],
387 wb_cfg->dest.plane_size[1],
388 wb_cfg->dest.plane_addr[2],
389 wb_cfg->dest.plane_size[2],
390 wb_cfg->dest.plane_addr[3],
391 wb_cfg->dest.plane_size[3]);
Alan Kwongbb27c092016-07-20 16:41:25 -0400392 hw_wb->ops.setup_outaddress(hw_wb, wb_cfg);
Alan Kwongc16e0922017-05-11 14:50:46 -0700393 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400394}
395
396/**
397 * sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
398 * @phys_enc: Pointer to physical encoder
399 */
400static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc)
401{
402 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
403 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
404 struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
405
406 memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
407
408 intf_cfg->intf = SDE_NONE;
409 intf_cfg->wb = hw_wb->idx;
Lloyd Atkinson55987b02016-08-16 16:57:46 -0400410 intf_cfg->mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc);
Alan Kwongbb27c092016-07-20 16:41:25 -0400411
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400412 if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg)
Alan Kwongbb27c092016-07-20 16:41:25 -0400413 phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl,
414 intf_cfg);
415}
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
Alan Kwongbb27c092016-07-20 16:41:25 -0400451 memset(&wb_roi, 0, sizeof(struct sde_rect));
452
453 rc = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi);
454 if (rc) {
455 SDE_ERROR("failed to get roi %d\n", rc);
456 return rc;
457 }
458
459 SDE_DEBUG("[roi:%u,%u,%u,%u]\n", wb_roi.x, wb_roi.y,
460 wb_roi.w, wb_roi.h);
461
Alan Kwong4212dd42017-09-19 17:22:33 -0400462 /* bypass check if commit with no framebuffer */
Alan Kwongbb27c092016-07-20 16:41:25 -0400463 fb = sde_wb_connector_state_get_output_fb(conn_state);
464 if (!fb) {
Alan Kwong4212dd42017-09-19 17:22:33 -0400465 SDE_DEBUG("no output framebuffer\n");
466 return 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400467 }
468
469 SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
470 fb->width, fb->height);
471
472 fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
473 drm_format_num_planes(fb->pixel_format));
474 if (!fmt) {
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400475 SDE_ERROR("unsupported output pixel format:%x\n",
Alan Kwongbb27c092016-07-20 16:41:25 -0400476 fb->pixel_format);
477 return -EINVAL;
478 }
479
480 SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->pixel_format,
481 fb->modifier[0]);
482
483 if (SDE_FORMAT_IS_YUV(fmt) &&
484 !(wb_cfg->features & BIT(SDE_WB_YUV_CONFIG))) {
485 SDE_ERROR("invalid output format %x\n", fmt->base.pixel_format);
486 return -EINVAL;
487 }
488
489 if (SDE_FORMAT_IS_UBWC(fmt) &&
Clarence Ip32bcb002017-03-13 12:26:44 -0700490 !(wb_cfg->features & BIT(SDE_WB_UBWC))) {
Alan Kwongbb27c092016-07-20 16:41:25 -0400491 SDE_ERROR("invalid output format %x\n", fmt->base.pixel_format);
492 return -EINVAL;
493 }
494
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400495 if (SDE_FORMAT_IS_YUV(fmt) != !!phys_enc->hw_cdm)
496 crtc_state->mode_changed = true;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400497
Alan Kwongbb27c092016-07-20 16:41:25 -0400498 if (wb_roi.w && wb_roi.h) {
499 if (wb_roi.w != mode->hdisplay) {
500 SDE_ERROR("invalid roi w=%d, mode w=%d\n", wb_roi.w,
501 mode->hdisplay);
502 return -EINVAL;
503 } else if (wb_roi.h != mode->vdisplay) {
504 SDE_ERROR("invalid roi h=%d, mode h=%d\n", wb_roi.h,
505 mode->vdisplay);
506 return -EINVAL;
507 } else if (wb_roi.x + wb_roi.w > fb->width) {
508 SDE_ERROR("invalid roi x=%d, w=%d, fb w=%d\n",
509 wb_roi.x, wb_roi.w, fb->width);
510 return -EINVAL;
511 } else if (wb_roi.y + wb_roi.h > fb->height) {
512 SDE_ERROR("invalid roi y=%d, h=%d, fb h=%d\n",
513 wb_roi.y, wb_roi.h, fb->height);
514 return -EINVAL;
515 } else if (wb_roi.w > wb_cfg->sblk->maxlinewidth) {
516 SDE_ERROR("invalid roi w=%d, maxlinewidth=%u\n",
517 wb_roi.w, wb_cfg->sblk->maxlinewidth);
518 return -EINVAL;
519 }
520 } else {
521 if (wb_roi.x || wb_roi.y) {
522 SDE_ERROR("invalid roi x=%d, y=%d\n",
523 wb_roi.x, wb_roi.y);
524 return -EINVAL;
525 } else if (fb->width != mode->hdisplay) {
526 SDE_ERROR("invalid fb w=%d, mode w=%d\n", fb->width,
527 mode->hdisplay);
528 return -EINVAL;
529 } else if (fb->height != mode->vdisplay) {
530 SDE_ERROR("invalid fb h=%d, mode h=%d\n", fb->height,
531 mode->vdisplay);
532 return -EINVAL;
533 } else if (fb->width > wb_cfg->sblk->maxlinewidth) {
534 SDE_ERROR("invalid fb w=%d, maxlinewidth=%u\n",
535 fb->width, wb_cfg->sblk->maxlinewidth);
536 return -EINVAL;
537 }
538 }
539
540 return 0;
541}
542
543/**
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700544 * _sde_encoder_phys_wb_update_flush - flush hardware update
Alan Kwongbb27c092016-07-20 16:41:25 -0400545 * @phys_enc: Pointer to physical encoder
546 */
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700547static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
Alan Kwongbb27c092016-07-20 16:41:25 -0400548{
549 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400550 struct sde_hw_wb *hw_wb;
551 struct sde_hw_ctl *hw_ctl;
552 struct sde_hw_cdm *hw_cdm;
Alan Kwongbb27c092016-07-20 16:41:25 -0400553 u32 flush_mask = 0;
554
Lloyd Atkinson6a5359d2017-06-21 10:18:08 -0400555 if (!phys_enc)
556 return;
557
558 hw_wb = wb_enc->hw_wb;
559 hw_ctl = phys_enc->hw_ctl;
560 hw_cdm = phys_enc->hw_cdm;
561
Alan Kwongbb27c092016-07-20 16:41:25 -0400562 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
563
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400564 if (!hw_ctl) {
565 SDE_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0);
566 return;
567 }
568
Alan Kwongbb27c092016-07-20 16:41:25 -0400569 if (hw_ctl->ops.get_bitmask_wb)
570 hw_ctl->ops.get_bitmask_wb(hw_ctl, &flush_mask, hw_wb->idx);
571
572 if (hw_ctl->ops.get_bitmask_cdm && hw_cdm)
573 hw_ctl->ops.get_bitmask_cdm(hw_ctl, &flush_mask, hw_cdm->idx);
574
575 if (hw_ctl->ops.update_pending_flush)
576 hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask);
577
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700578 if (hw_ctl->ops.get_pending_flush)
579 flush_mask = hw_ctl->ops.get_pending_flush(hw_ctl);
580
581 SDE_DEBUG("Pending flush mask for CTL_%d is 0x%x, WB %d\n",
Alan Kwongbb27c092016-07-20 16:41:25 -0400582 hw_ctl->idx - CTL_0, flush_mask, hw_wb->idx - WB_0);
583}
584
585/**
586 * sde_encoder_phys_wb_setup - setup writeback encoder
587 * @phys_enc: Pointer to physical encoder
588 */
589static void sde_encoder_phys_wb_setup(
590 struct sde_encoder_phys *phys_enc)
591{
592 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
593 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
594 struct drm_display_mode mode = phys_enc->cached_mode;
595 struct drm_framebuffer *fb;
596 struct sde_rect *wb_roi = &wb_enc->wb_roi;
597
598 SDE_DEBUG("[mode_set:%d,%d,\"%s\",%d,%d]\n",
599 hw_wb->idx - WB_0, mode.base.id, mode.name,
600 mode.hdisplay, mode.vdisplay);
601
602 memset(wb_roi, 0, sizeof(struct sde_rect));
603
Alan Kwong03b89842017-08-17 16:32:45 -0400604 /* clear writeback framebuffer - will be updated in setup_fb */
605 wb_enc->wb_fb = NULL;
606 wb_enc->wb_aspace = NULL;
607
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700608 if (phys_enc->enable_state == SDE_ENC_DISABLING) {
609 fb = wb_enc->fb_disable;
610 wb_roi->w = 0;
611 wb_roi->h = 0;
612 } else {
613 fb = sde_wb_get_output_fb(wb_enc->wb_dev);
614 sde_wb_get_output_roi(wb_enc->wb_dev, wb_roi);
615 }
616
Alan Kwongbb27c092016-07-20 16:41:25 -0400617 if (!fb) {
618 SDE_DEBUG("no output framebuffer\n");
619 return;
620 }
621
622 SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
623 fb->width, fb->height);
624
Alan Kwongbb27c092016-07-20 16:41:25 -0400625 if (wb_roi->w == 0 || wb_roi->h == 0) {
626 wb_roi->x = 0;
627 wb_roi->y = 0;
628 wb_roi->w = fb->width;
629 wb_roi->h = fb->height;
630 }
631
632 SDE_DEBUG("[roi:%u,%u,%u,%u]\n", wb_roi->x, wb_roi->y,
633 wb_roi->w, wb_roi->h);
634
635 wb_enc->wb_fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
636 drm_format_num_planes(fb->pixel_format));
637 if (!wb_enc->wb_fmt) {
638 SDE_ERROR("unsupported output pixel format: %d\n",
639 fb->pixel_format);
640 return;
641 }
642
643 SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->pixel_format,
644 fb->modifier[0]);
645
Alan Kwong5d324e42016-07-28 22:56:18 -0400646 sde_encoder_phys_wb_set_ot_limit(phys_enc);
647
Alan Kwongbb27c092016-07-20 16:41:25 -0400648 sde_encoder_phys_wb_set_traffic_shaper(phys_enc);
649
Alan Kwonga62eeb82017-04-19 08:57:55 -0700650 sde_encoder_phys_wb_set_qos_remap(phys_enc);
651
Alan Kwongbb27c092016-07-20 16:41:25 -0400652 sde_encoder_phys_setup_cdm(phys_enc, fb, wb_enc->wb_fmt, wb_roi);
653
654 sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi);
655
656 sde_encoder_phys_wb_setup_cdp(phys_enc);
657}
658
659/**
660 * sde_encoder_phys_wb_unregister_irq - unregister writeback interrupt handler
661 * @phys_enc: Pointer to physical encoder
662 */
663static int sde_encoder_phys_wb_unregister_irq(
664 struct sde_encoder_phys *phys_enc)
665{
666 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
667 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
668
669 if (wb_enc->bypass_irqreg)
670 return 0;
671
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400672 sde_core_irq_disable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
Alan Kwonga172ef52016-09-27 00:29:10 -0400673 sde_core_irq_unregister_callback(phys_enc->sde_kms, wb_enc->irq_idx,
674 &wb_enc->irq_cb);
Alan Kwongbb27c092016-07-20 16:41:25 -0400675
676 SDE_DEBUG("un-register IRQ for wb %d, irq_idx=%d\n",
677 hw_wb->idx - WB_0,
678 wb_enc->irq_idx);
679
680 return 0;
681}
682
683/**
684 * sde_encoder_phys_wb_done_irq - writeback interrupt handler
685 * @arg: Pointer to writeback encoder
686 * @irq_idx: interrupt index
687 */
688static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
689{
690 struct sde_encoder_phys_wb *wb_enc = arg;
691 struct sde_encoder_phys *phys_enc = &wb_enc->base;
692 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700693 u32 event = 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400694
695 SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0,
696 wb_enc->frame_count);
697
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700698 /* don't notify upper layer for internal commit */
699 if (phys_enc->enable_state == SDE_ENC_DISABLING)
700 goto complete;
701
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700702 event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
703 | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE
704 | SDE_ENCODER_FRAME_EVENT_DONE;
705
706 atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0);
Alan Kwong628d19e2016-10-31 13:50:13 -0400707 if (phys_enc->parent_ops.handle_frame_done)
708 phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700709 phys_enc, event);
Alan Kwongbb27c092016-07-20 16:41:25 -0400710
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700711 if (phys_enc->parent_ops.handle_vblank_virt)
712 phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
713 phys_enc);
714
715 SDE_EVT32_IRQ(DRMID(phys_enc->parent), hw_wb->idx - WB_0, event);
Alan Kwong628d19e2016-10-31 13:50:13 -0400716
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700717complete:
Alan Kwong628d19e2016-10-31 13:50:13 -0400718 complete_all(&wb_enc->wbdone_complete);
Alan Kwongbb27c092016-07-20 16:41:25 -0400719}
720
721/**
722 * sde_encoder_phys_wb_register_irq - register writeback interrupt handler
723 * @phys_enc: Pointer to physical encoder
724 */
725static int sde_encoder_phys_wb_register_irq(struct sde_encoder_phys *phys_enc)
726{
727 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
728 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Alan Kwonga172ef52016-09-27 00:29:10 -0400729 struct sde_irq_callback *irq_cb = &wb_enc->irq_cb;
Alan Kwongbb27c092016-07-20 16:41:25 -0400730 enum sde_intr_type intr_type;
731 int ret = 0;
732
733 if (wb_enc->bypass_irqreg)
734 return 0;
735
736 intr_type = sde_encoder_phys_wb_get_intr_type(hw_wb);
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400737 wb_enc->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms,
Alan Kwongbb27c092016-07-20 16:41:25 -0400738 intr_type, hw_wb->idx);
739 if (wb_enc->irq_idx < 0) {
740 SDE_ERROR(
741 "failed to lookup IRQ index for WB_DONE with wb=%d\n",
742 hw_wb->idx - WB_0);
743 return -EINVAL;
744 }
745
Alan Kwonga172ef52016-09-27 00:29:10 -0400746 irq_cb->func = sde_encoder_phys_wb_done_irq;
747 irq_cb->arg = wb_enc;
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400748 ret = sde_core_irq_register_callback(phys_enc->sde_kms,
Alan Kwonga172ef52016-09-27 00:29:10 -0400749 wb_enc->irq_idx, irq_cb);
Alan Kwongbb27c092016-07-20 16:41:25 -0400750 if (ret) {
751 SDE_ERROR("failed to register IRQ callback WB_DONE\n");
752 return ret;
753 }
754
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400755 ret = sde_core_irq_enable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
Alan Kwongbb27c092016-07-20 16:41:25 -0400756 if (ret) {
757 SDE_ERROR(
758 "failed to enable IRQ for WB_DONE, wb %d, irq_idx=%d\n",
759 hw_wb->idx - WB_0,
760 wb_enc->irq_idx);
761 wb_enc->irq_idx = -EINVAL;
762
763 /* Unregister callback on IRQ enable failure */
Alan Kwonga172ef52016-09-27 00:29:10 -0400764 sde_core_irq_unregister_callback(phys_enc->sde_kms,
765 wb_enc->irq_idx, irq_cb);
Alan Kwongbb27c092016-07-20 16:41:25 -0400766 return ret;
767 }
768
769 SDE_DEBUG("registered IRQ for wb %d, irq_idx=%d\n",
770 hw_wb->idx - WB_0,
771 wb_enc->irq_idx);
772
773 return ret;
774}
775
776/**
777 * sde_encoder_phys_wb_mode_set - set display mode
778 * @phys_enc: Pointer to physical encoder
779 * @mode: Pointer to requested display mode
780 * @adj_mode: Pointer to adjusted display mode
781 */
782static void sde_encoder_phys_wb_mode_set(
783 struct sde_encoder_phys *phys_enc,
784 struct drm_display_mode *mode,
785 struct drm_display_mode *adj_mode)
786{
787 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400788 struct sde_rm *rm = &phys_enc->sde_kms->rm;
Alan Kwongbb27c092016-07-20 16:41:25 -0400789 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400790 struct sde_rm_hw_iter iter;
791 int i, instance;
Alan Kwongbb27c092016-07-20 16:41:25 -0400792
793 phys_enc->cached_mode = *adj_mode;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400794 instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400795
796 SDE_DEBUG("[mode_set_cache:%d,%d,\"%s\",%d,%d]\n",
797 hw_wb->idx - WB_0, mode->base.id,
798 mode->name, mode->hdisplay, mode->vdisplay);
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400799
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400800 phys_enc->hw_ctl = NULL;
801 phys_enc->hw_cdm = NULL;
802
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400803 /* Retrieve previously allocated HW Resources. CTL shouldn't fail */
804 sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CTL);
805 for (i = 0; i <= instance; i++) {
806 sde_rm_get_hw(rm, &iter);
807 if (i == instance)
808 phys_enc->hw_ctl = (struct sde_hw_ctl *) iter.hw;
809 }
810
811 if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) {
812 SDE_ERROR("failed init ctl: %ld\n", PTR_ERR(phys_enc->hw_ctl));
813 phys_enc->hw_ctl = NULL;
814 return;
815 }
816
817 /* CDM is optional */
818 sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CDM);
819 for (i = 0; i <= instance; i++) {
820 sde_rm_get_hw(rm, &iter);
821 if (i == instance)
822 phys_enc->hw_cdm = (struct sde_hw_cdm *) iter.hw;
823 }
824
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400825 if (IS_ERR(phys_enc->hw_cdm)) {
826 SDE_ERROR("CDM required but not allocated: %ld\n",
827 PTR_ERR(phys_enc->hw_cdm));
828 phys_enc->hw_ctl = NULL;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400829 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400830}
831
832/**
Alan Kwongbb27c092016-07-20 16:41:25 -0400833 * sde_encoder_phys_wb_wait_for_commit_done - wait until request is committed
834 * @phys_enc: Pointer to physical encoder
835 */
836static int sde_encoder_phys_wb_wait_for_commit_done(
837 struct sde_encoder_phys *phys_enc)
838{
839 unsigned long ret;
840 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700841 u32 irq_status, event = 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400842 u64 wb_time = 0;
843 int rc = 0;
Alan Kwong5a50a4a2017-01-24 19:12:51 -0800844 u32 timeout = max_t(u32, wb_enc->wbdone_timeout, KICKOFF_TIMEOUT_MS);
Alan Kwongbb27c092016-07-20 16:41:25 -0400845
846 /* Return EWOULDBLOCK since we know the wait isn't necessary */
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700847 if (phys_enc->enable_state == SDE_ENC_DISABLED) {
848 SDE_ERROR("encoder already disabled\n");
Alan Kwongbb27c092016-07-20 16:41:25 -0400849 return -EWOULDBLOCK;
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700850 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400851
Alan Kwong4212dd42017-09-19 17:22:33 -0400852 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count,
853 !!wb_enc->wb_fb);
854
855 /* signal completion if commit with no framebuffer */
856 if (!wb_enc->wb_fb) {
857 SDE_DEBUG("no output framebuffer\n");
858 sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx);
859 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400860
861 ret = wait_for_completion_timeout(&wb_enc->wbdone_complete,
Alan Kwong5a50a4a2017-01-24 19:12:51 -0800862 msecs_to_jiffies(timeout));
Alan Kwongbb27c092016-07-20 16:41:25 -0400863
864 if (!ret) {
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400865 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
866 wb_enc->frame_count);
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400867 irq_status = sde_core_irq_read(phys_enc->sde_kms,
Alan Kwongbb27c092016-07-20 16:41:25 -0400868 wb_enc->irq_idx, true);
869 if (irq_status) {
870 SDE_DEBUG("wb:%d done but irq not triggered\n",
Alan Kwong1124f1f2017-11-10 18:14:39 -0500871 WBID(wb_enc));
Alan Kwongbb27c092016-07-20 16:41:25 -0400872 sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx);
873 } else {
874 SDE_ERROR("wb:%d kickoff timed out\n",
Alan Kwong1124f1f2017-11-10 18:14:39 -0500875 WBID(wb_enc));
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700876 atomic_add_unless(
877 &phys_enc->pending_retire_fence_cnt, -1, 0);
878
879 event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
880 | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE
881 | SDE_ENCODER_FRAME_EVENT_ERROR;
Alan Kwong628d19e2016-10-31 13:50:13 -0400882 if (phys_enc->parent_ops.handle_frame_done)
883 phys_enc->parent_ops.handle_frame_done(
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700884 phys_enc->parent, phys_enc, event);
Alan Kwongbb27c092016-07-20 16:41:25 -0400885 rc = -ETIMEDOUT;
886 }
887 }
888
889 sde_encoder_phys_wb_unregister_irq(phys_enc);
890
891 if (!rc)
892 wb_enc->end_time = ktime_get();
893
894 /* once operation is done, disable traffic shaper */
895 if (wb_enc->wb_cfg.ts_cfg.en && wb_enc->hw_wb &&
896 wb_enc->hw_wb->ops.setup_trafficshaper) {
897 wb_enc->wb_cfg.ts_cfg.en = false;
898 wb_enc->hw_wb->ops.setup_trafficshaper(
899 wb_enc->hw_wb, &wb_enc->wb_cfg);
900 }
901
902 /* remove vote for iommu/clk/bus */
903 wb_enc->frame_count++;
904
905 if (!rc) {
906 wb_time = (u64)ktime_to_us(wb_enc->end_time) -
907 (u64)ktime_to_us(wb_enc->start_time);
Alan Kwong1124f1f2017-11-10 18:14:39 -0500908 SDE_DEBUG("wb:%d took %llu us\n", WBID(wb_enc), wb_time);
Alan Kwongbb27c092016-07-20 16:41:25 -0400909 }
910
Alan Kwong03b89842017-08-17 16:32:45 -0400911 /* cleanup writeback framebuffer */
912 if (wb_enc->wb_fb && wb_enc->wb_aspace) {
913 msm_framebuffer_cleanup(wb_enc->wb_fb, wb_enc->wb_aspace);
914 wb_enc->wb_fb = NULL;
915 wb_enc->wb_aspace = NULL;
916 }
917
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400918 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count,
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -0700919 wb_time, event, rc);
Alan Kwongbb27c092016-07-20 16:41:25 -0400920
921 return rc;
922}
923
924/**
925 * sde_encoder_phys_wb_prepare_for_kickoff - pre-kickoff processing
926 * @phys_enc: Pointer to physical encoder
Alan Kwong4aacd532017-02-04 18:51:33 -0800927 * @params: kickoff parameters
Clarence Ip85f4f4532017-10-04 12:10:13 -0400928 * Returns: Zero on success
Alan Kwongbb27c092016-07-20 16:41:25 -0400929 */
Clarence Ip85f4f4532017-10-04 12:10:13 -0400930static int sde_encoder_phys_wb_prepare_for_kickoff(
Alan Kwong4aacd532017-02-04 18:51:33 -0800931 struct sde_encoder_phys *phys_enc,
932 struct sde_encoder_kickoff_params *params)
Alan Kwongbb27c092016-07-20 16:41:25 -0400933{
934 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
935 int ret;
936
937 SDE_DEBUG("[wb:%d,%u]\n", wb_enc->hw_wb->idx - WB_0,
938 wb_enc->kickoff_count);
939
Alan Kwongbb27c092016-07-20 16:41:25 -0400940 reinit_completion(&wb_enc->wbdone_complete);
941
942 ret = sde_encoder_phys_wb_register_irq(phys_enc);
943 if (ret) {
944 SDE_ERROR("failed to register irq %d\n", ret);
Clarence Ip85f4f4532017-10-04 12:10:13 -0400945 return ret;
Alan Kwongbb27c092016-07-20 16:41:25 -0400946 }
947
948 wb_enc->kickoff_count++;
949
950 /* set OT limit & enable traffic shaper */
951 sde_encoder_phys_wb_setup(phys_enc);
952
Clarence Ip9c65f7b2017-03-20 06:48:15 -0700953 _sde_encoder_phys_wb_update_flush(phys_enc);
Alan Kwongbb27c092016-07-20 16:41:25 -0400954
955 /* vote for iommu/clk/bus */
956 wb_enc->start_time = ktime_get();
957
Lloyd Atkinsonaa0dce92016-11-23 20:16:47 -0500958 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->kickoff_count);
Clarence Ip85f4f4532017-10-04 12:10:13 -0400959 return 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400960}
961
962/**
Alan Kwong4212dd42017-09-19 17:22:33 -0400963 * sde_encoder_phys_wb_trigger_flush - trigger flush processing
964 * @phys_enc: Pointer to physical encoder
965 */
966static void sde_encoder_phys_wb_trigger_flush(struct sde_encoder_phys *phys_enc)
967{
968 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
969
970 if (!phys_enc || !wb_enc->hw_wb) {
971 SDE_ERROR("invalid encoder\n");
972 return;
973 }
974
975 SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0);
976
977 /* clear pending flush if commit with no framebuffer */
978 if (!wb_enc->wb_fb) {
979 SDE_DEBUG("no output framebuffer\n");
980 return;
981 }
982
983 sde_encoder_helper_trigger_flush(phys_enc);
984}
985
986/**
Alan Kwongbb27c092016-07-20 16:41:25 -0400987 * sde_encoder_phys_wb_handle_post_kickoff - post-kickoff processing
988 * @phys_enc: Pointer to physical encoder
989 */
990static void sde_encoder_phys_wb_handle_post_kickoff(
991 struct sde_encoder_phys *phys_enc)
992{
993 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
994
995 SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0);
996
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400997 SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc));
Alan Kwongbb27c092016-07-20 16:41:25 -0400998}
999
1000/**
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001001 * _sde_encoder_phys_wb_init_internal_fb - create fb for internal commit
1002 * @wb_enc: Pointer to writeback encoder
1003 * @pixel_format: DRM pixel format
1004 * @width: Desired fb width
1005 * @height: Desired fb height
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001006 * @pitch: Desired fb pitch
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001007 */
1008static int _sde_encoder_phys_wb_init_internal_fb(
1009 struct sde_encoder_phys_wb *wb_enc,
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001010 uint32_t pixel_format, uint32_t width,
1011 uint32_t height, uint32_t pitch)
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001012{
1013 struct drm_device *dev;
1014 struct drm_framebuffer *fb;
1015 struct drm_mode_fb_cmd2 mode_cmd;
1016 uint32_t size;
1017 int nplanes, i, ret;
Jordan Croused8e96522017-02-13 10:14:16 -07001018 struct msm_gem_address_space *aspace;
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001019
1020 if (!wb_enc || !wb_enc->base.parent || !wb_enc->base.sde_kms) {
1021 SDE_ERROR("invalid params\n");
1022 return -EINVAL;
1023 }
1024
Jordan Croused8e96522017-02-13 10:14:16 -07001025 aspace = wb_enc->base.sde_kms->aspace[SDE_IOMMU_DOMAIN_UNSECURE];
1026 if (!aspace) {
1027 SDE_ERROR("invalid address space\n");
1028 return -EINVAL;
1029 }
1030
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001031 dev = wb_enc->base.sde_kms->dev;
1032 if (!dev) {
1033 SDE_ERROR("invalid dev\n");
1034 return -EINVAL;
1035 }
1036
1037 memset(&mode_cmd, 0, sizeof(mode_cmd));
1038 mode_cmd.pixel_format = pixel_format;
1039 mode_cmd.width = width;
1040 mode_cmd.height = height;
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001041 mode_cmd.pitches[0] = pitch;
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001042
1043 size = sde_format_get_framebuffer_size(pixel_format,
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001044 mode_cmd.width, mode_cmd.height,
1045 mode_cmd.pitches, NULL, 0);
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001046 if (!size) {
1047 SDE_DEBUG("not creating zero size buffer\n");
1048 return -EINVAL;
1049 }
1050
1051 /* allocate gem tracking object */
1052 nplanes = drm_format_num_planes(pixel_format);
1053 if (nplanes > SDE_MAX_PLANES) {
1054 SDE_ERROR("requested format has too many planes\n");
1055 return -EINVAL;
1056 }
1057 mutex_lock(&dev->struct_mutex);
1058 wb_enc->bo_disable[0] = msm_gem_new(dev, size,
1059 MSM_BO_SCANOUT | MSM_BO_WC);
1060 mutex_unlock(&dev->struct_mutex);
1061
1062 if (IS_ERR_OR_NULL(wb_enc->bo_disable[0])) {
1063 ret = PTR_ERR(wb_enc->bo_disable[0]);
1064 wb_enc->bo_disable[0] = NULL;
1065
1066 SDE_ERROR("failed to create bo, %d\n", ret);
1067 return ret;
1068 }
1069
1070 for (i = 0; i < nplanes; ++i) {
1071 wb_enc->bo_disable[i] = wb_enc->bo_disable[0];
1072 mode_cmd.pitches[i] = width *
1073 drm_format_plane_cpp(pixel_format, i);
1074 }
1075
1076 fb = msm_framebuffer_init(dev, &mode_cmd, wb_enc->bo_disable);
1077 if (IS_ERR_OR_NULL(fb)) {
1078 ret = PTR_ERR(fb);
1079 drm_gem_object_unreference(wb_enc->bo_disable[0]);
1080 wb_enc->bo_disable[0] = NULL;
1081
1082 SDE_ERROR("failed to init fb, %d\n", ret);
1083 return ret;
1084 }
1085
1086 /* prepare the backing buffer now so that it's available later */
Jordan Croused8e96522017-02-13 10:14:16 -07001087 ret = msm_framebuffer_prepare(fb, aspace);
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001088 if (!ret)
1089 wb_enc->fb_disable = fb;
1090 return ret;
1091}
1092
1093/**
1094 * _sde_encoder_phys_wb_destroy_internal_fb - deconstruct internal fb
1095 * @wb_enc: Pointer to writeback encoder
1096 */
1097static void _sde_encoder_phys_wb_destroy_internal_fb(
1098 struct sde_encoder_phys_wb *wb_enc)
1099{
1100 if (!wb_enc)
1101 return;
1102
1103 if (wb_enc->fb_disable) {
1104 drm_framebuffer_unregister_private(wb_enc->fb_disable);
1105 drm_framebuffer_remove(wb_enc->fb_disable);
1106 wb_enc->fb_disable = NULL;
1107 }
1108
1109 if (wb_enc->bo_disable[0]) {
1110 drm_gem_object_unreference(wb_enc->bo_disable[0]);
1111 wb_enc->bo_disable[0] = NULL;
1112 }
1113}
1114
1115/**
Alan Kwongbb27c092016-07-20 16:41:25 -04001116 * sde_encoder_phys_wb_enable - enable writeback encoder
1117 * @phys_enc: Pointer to physical encoder
1118 */
1119static void sde_encoder_phys_wb_enable(struct sde_encoder_phys *phys_enc)
1120{
1121 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1122 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Alan Kwong74e8ba32016-09-30 14:25:16 -04001123 struct drm_device *dev;
Alan Kwongbb27c092016-07-20 16:41:25 -04001124 struct drm_connector *connector;
1125
1126 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
1127
Alan Kwong74e8ba32016-09-30 14:25:16 -04001128 if (!wb_enc->base.parent || !wb_enc->base.parent->dev) {
1129 SDE_ERROR("invalid drm device\n");
1130 return;
1131 }
1132 dev = wb_enc->base.parent->dev;
1133
Alan Kwongbb27c092016-07-20 16:41:25 -04001134 /* find associated writeback connector */
Clarence Ip05431f32016-11-25 16:39:38 -05001135 connector = phys_enc->connector;
Alan Kwong74e8ba32016-09-30 14:25:16 -04001136
Alan Kwongbb27c092016-07-20 16:41:25 -04001137 if (!connector || connector->encoder != phys_enc->parent) {
1138 SDE_ERROR("failed to find writeback connector\n");
1139 return;
1140 }
1141 wb_enc->wb_dev = sde_wb_connector_get_wb(connector);
1142
1143 phys_enc->enable_state = SDE_ENC_ENABLED;
1144}
1145
1146/**
1147 * sde_encoder_phys_wb_disable - disable writeback encoder
1148 * @phys_enc: Pointer to physical encoder
1149 */
1150static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
1151{
1152 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1153 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
1154
1155 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
1156
1157 if (phys_enc->enable_state == SDE_ENC_DISABLED) {
1158 SDE_ERROR("encoder is already disabled\n");
1159 return;
1160 }
1161
1162 if (wb_enc->frame_count != wb_enc->kickoff_count) {
1163 SDE_DEBUG("[wait_for_done: wb:%d, frame:%u, kickoff:%u]\n",
1164 hw_wb->idx - WB_0, wb_enc->frame_count,
1165 wb_enc->kickoff_count);
1166 sde_encoder_phys_wb_wait_for_commit_done(phys_enc);
1167 }
1168
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001169 if (!phys_enc->hw_ctl || !phys_enc->parent ||
1170 !phys_enc->sde_kms || !wb_enc->fb_disable) {
1171 SDE_DEBUG("invalid enc, skipping extra commit\n");
1172 goto exit;
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001173 }
1174
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001175 /* reset h/w before final flush */
Clarence Ip662698e2017-09-12 18:34:16 -04001176 if (phys_enc->hw_ctl->ops.clear_pending_flush)
1177 phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl);
1178 if (sde_encoder_helper_reset_mixers(phys_enc, wb_enc->fb_disable))
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001179 goto exit;
1180
1181 phys_enc->enable_state = SDE_ENC_DISABLING;
Alan Kwong4aacd532017-02-04 18:51:33 -08001182 sde_encoder_phys_wb_prepare_for_kickoff(phys_enc, NULL);
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001183 if (phys_enc->hw_ctl->ops.trigger_flush)
1184 phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl);
1185 sde_encoder_helper_trigger_start(phys_enc);
1186 sde_encoder_phys_wb_wait_for_commit_done(phys_enc);
1187exit:
Alan Kwongbb27c092016-07-20 16:41:25 -04001188 phys_enc->enable_state = SDE_ENC_DISABLED;
1189}
1190
1191/**
1192 * sde_encoder_phys_wb_get_hw_resources - get hardware resources
1193 * @phys_enc: Pointer to physical encoder
1194 * @hw_res: Pointer to encoder resources
1195 */
1196static void sde_encoder_phys_wb_get_hw_resources(
1197 struct sde_encoder_phys *phys_enc,
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001198 struct sde_encoder_hw_resources *hw_res,
1199 struct drm_connector_state *conn_state)
Alan Kwongbb27c092016-07-20 16:41:25 -04001200{
1201 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Clarence Ip03521982016-08-26 10:49:47 -04001202 struct sde_hw_wb *hw_wb;
Alan Kwong4c3cf4c2016-09-25 20:08:09 -04001203 struct drm_framebuffer *fb;
Alan Kwong4212dd42017-09-19 17:22:33 -04001204 const struct sde_format *fmt = NULL;
Alan Kwongbb27c092016-07-20 16:41:25 -04001205
Clarence Ip03521982016-08-26 10:49:47 -04001206 if (!phys_enc) {
1207 SDE_ERROR("invalid encoder\n");
1208 return;
1209 }
Alan Kwong4c3cf4c2016-09-25 20:08:09 -04001210
1211 fb = sde_wb_connector_state_get_output_fb(conn_state);
Alan Kwong4212dd42017-09-19 17:22:33 -04001212 if (fb) {
1213 fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
1214 drm_format_num_planes(fb->pixel_format));
1215 if (!fmt) {
1216 SDE_ERROR("unsupported output pixel format:%d\n",
1217 fb->pixel_format);
1218 return;
1219 }
Alan Kwong4c3cf4c2016-09-25 20:08:09 -04001220 }
1221
Clarence Ip03521982016-08-26 10:49:47 -04001222 hw_wb = wb_enc->hw_wb;
Clarence Ip03521982016-08-26 10:49:47 -04001223 hw_res->wbs[hw_wb->idx - WB_0] = phys_enc->intf_mode;
Alan Kwong4212dd42017-09-19 17:22:33 -04001224 hw_res->needs_cdm = fmt ? SDE_FORMAT_IS_YUV(fmt) : false;
Alan Kwong4c3cf4c2016-09-25 20:08:09 -04001225 SDE_DEBUG("[wb:%d] intf_mode=%d needs_cdm=%d\n", hw_wb->idx - WB_0,
1226 hw_res->wbs[hw_wb->idx - WB_0],
1227 hw_res->needs_cdm);
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -04001228}
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001229
Alan Kwongbb27c092016-07-20 16:41:25 -04001230#ifdef CONFIG_DEBUG_FS
1231/**
1232 * sde_encoder_phys_wb_init_debugfs - initialize writeback encoder debugfs
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001233 * @phys_enc: Pointer to physical encoder
1234 * @debugfs_root: Pointer to virtual encoder's debugfs_root dir
Alan Kwongbb27c092016-07-20 16:41:25 -04001235 */
1236static int sde_encoder_phys_wb_init_debugfs(
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001237 struct sde_encoder_phys *phys_enc, struct dentry *debugfs_root)
Alan Kwongbb27c092016-07-20 16:41:25 -04001238{
1239 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1240
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001241 if (!phys_enc || !wb_enc->hw_wb || !debugfs_root)
Alan Kwongbb27c092016-07-20 16:41:25 -04001242 return -EINVAL;
1243
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001244 if (!debugfs_create_u32("wbdone_timeout", 0600,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001245 debugfs_root, &wb_enc->wbdone_timeout)) {
Alan Kwongbb27c092016-07-20 16:41:25 -04001246 SDE_ERROR("failed to create debugfs/wbdone_timeout\n");
1247 return -ENOMEM;
1248 }
1249
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001250 if (!debugfs_create_u32("bypass_irqreg", 0600,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001251 debugfs_root, &wb_enc->bypass_irqreg)) {
Alan Kwongbb27c092016-07-20 16:41:25 -04001252 SDE_ERROR("failed to create debugfs/bypass_irqreg\n");
1253 return -ENOMEM;
1254 }
1255
1256 return 0;
1257}
Alan Kwongbb27c092016-07-20 16:41:25 -04001258#else
Dhaval Patel48f2d0f2016-09-27 16:39:12 -07001259static int sde_encoder_phys_wb_init_debugfs(
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001260 struct sde_encoder_phys *phys_enc, struct dentry *debugfs_root)
Alan Kwongbb27c092016-07-20 16:41:25 -04001261{
Dhaval Patel48f2d0f2016-09-27 16:39:12 -07001262 return 0;
Alan Kwongbb27c092016-07-20 16:41:25 -04001263}
Alan Kwongbb27c092016-07-20 16:41:25 -04001264#endif
1265
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001266static int sde_encoder_phys_wb_late_register(struct sde_encoder_phys *phys_enc,
1267 struct dentry *debugfs_root)
1268{
1269 return sde_encoder_phys_wb_init_debugfs(phys_enc, debugfs_root);
1270}
1271
Alan Kwongbb27c092016-07-20 16:41:25 -04001272/**
1273 * sde_encoder_phys_wb_destroy - destroy writeback encoder
1274 * @phys_enc: Pointer to physical encoder
1275 */
1276static void sde_encoder_phys_wb_destroy(struct sde_encoder_phys *phys_enc)
1277{
1278 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
1279 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
1280
1281 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
1282
1283 if (!phys_enc)
1284 return;
1285
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001286 _sde_encoder_phys_wb_destroy_internal_fb(wb_enc);
1287
Alan Kwongbb27c092016-07-20 16:41:25 -04001288 kfree(wb_enc);
1289}
1290
1291/**
1292 * sde_encoder_phys_wb_init_ops - initialize writeback operations
1293 * @ops: Pointer to encoder operation table
1294 */
1295static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops)
1296{
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001297 ops->late_register = sde_encoder_phys_wb_late_register;
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -04001298 ops->is_master = sde_encoder_phys_wb_is_master;
Alan Kwongbb27c092016-07-20 16:41:25 -04001299 ops->mode_set = sde_encoder_phys_wb_mode_set;
1300 ops->enable = sde_encoder_phys_wb_enable;
1301 ops->disable = sde_encoder_phys_wb_disable;
1302 ops->destroy = sde_encoder_phys_wb_destroy;
1303 ops->atomic_check = sde_encoder_phys_wb_atomic_check;
1304 ops->get_hw_resources = sde_encoder_phys_wb_get_hw_resources;
Alan Kwongbb27c092016-07-20 16:41:25 -04001305 ops->wait_for_commit_done = sde_encoder_phys_wb_wait_for_commit_done;
1306 ops->prepare_for_kickoff = sde_encoder_phys_wb_prepare_for_kickoff;
1307 ops->handle_post_kickoff = sde_encoder_phys_wb_handle_post_kickoff;
Alan Kwong4212dd42017-09-19 17:22:33 -04001308 ops->trigger_flush = sde_encoder_phys_wb_trigger_flush;
Clarence Ip110d15c2016-08-16 14:44:41 -04001309 ops->trigger_start = sde_encoder_helper_trigger_start;
Lloyd Atkinson8c49c582016-11-18 14:23:54 -05001310 ops->hw_reset = sde_encoder_helper_hw_reset;
Alan Kwongbb27c092016-07-20 16:41:25 -04001311}
1312
1313/**
1314 * sde_encoder_phys_wb_init - initialize writeback encoder
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001315 * @init: Pointer to init info structure with initialization params
Alan Kwongbb27c092016-07-20 16:41:25 -04001316 */
1317struct sde_encoder_phys *sde_encoder_phys_wb_init(
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001318 struct sde_enc_phys_init_params *p)
Alan Kwongbb27c092016-07-20 16:41:25 -04001319{
1320 struct sde_encoder_phys *phys_enc;
1321 struct sde_encoder_phys_wb *wb_enc;
1322 struct sde_hw_mdp *hw_mdp;
1323 int ret = 0;
1324
1325 SDE_DEBUG("\n");
1326
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001327 if (!p || !p->parent) {
1328 SDE_ERROR("invalid params\n");
1329 ret = -EINVAL;
1330 goto fail_alloc;
1331 }
1332
Alan Kwongbb27c092016-07-20 16:41:25 -04001333 wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL);
1334 if (!wb_enc) {
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001335 SDE_ERROR("failed to allocate wb enc\n");
Alan Kwongbb27c092016-07-20 16:41:25 -04001336 ret = -ENOMEM;
1337 goto fail_alloc;
1338 }
1339 wb_enc->irq_idx = -EINVAL;
Lloyd Atkinsonaa0dce92016-11-23 20:16:47 -05001340 wb_enc->wbdone_timeout = KICKOFF_TIMEOUT_MS;
Alan Kwongbb27c092016-07-20 16:41:25 -04001341 init_completion(&wb_enc->wbdone_complete);
1342
1343 phys_enc = &wb_enc->base;
1344
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001345 if (p->sde_kms->vbif[VBIF_NRT]) {
Jordan Croused8e96522017-02-13 10:14:16 -07001346 wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
1347 p->sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_UNSECURE];
1348 wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] =
1349 p->sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_SECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -04001350 } else {
Jordan Croused8e96522017-02-13 10:14:16 -07001351 wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
1352 p->sde_kms->aspace[MSM_SMMU_DOMAIN_UNSECURE];
1353 wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] =
1354 p->sde_kms->aspace[MSM_SMMU_DOMAIN_SECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -04001355 }
1356
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001357 hw_mdp = sde_rm_get_mdp(&p->sde_kms->rm);
Alan Kwongbb27c092016-07-20 16:41:25 -04001358 if (IS_ERR_OR_NULL(hw_mdp)) {
1359 ret = PTR_ERR(hw_mdp);
1360 SDE_ERROR("failed to init hw_top: %d\n", ret);
1361 goto fail_mdp_init;
1362 }
1363 phys_enc->hw_mdptop = hw_mdp;
1364
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001365 /**
1366 * hw_wb resource permanently assigned to this encoder
1367 * Other resources allocated at atomic commit time by use case
1368 */
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001369 if (p->wb_idx != SDE_NONE) {
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001370 struct sde_rm_hw_iter iter;
Alan Kwongbb27c092016-07-20 16:41:25 -04001371
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001372 sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_WB);
1373 while (sde_rm_get_hw(&p->sde_kms->rm, &iter)) {
1374 struct sde_hw_wb *hw_wb = (struct sde_hw_wb *)iter.hw;
1375
1376 if (hw_wb->idx == p->wb_idx) {
1377 wb_enc->hw_wb = hw_wb;
1378 break;
1379 }
1380 }
1381
1382 if (!wb_enc->hw_wb) {
1383 ret = -EINVAL;
1384 SDE_ERROR("failed to init hw_wb%d\n", p->wb_idx - WB_0);
Alan Kwongbb27c092016-07-20 16:41:25 -04001385 goto fail_wb_init;
1386 }
Alan Kwongbb27c092016-07-20 16:41:25 -04001387 } else {
1388 ret = -EINVAL;
1389 SDE_ERROR("invalid wb_idx\n");
1390 goto fail_wb_check;
1391 }
1392
Alan Kwongbb27c092016-07-20 16:41:25 -04001393 sde_encoder_phys_wb_init_ops(&phys_enc->ops);
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001394 phys_enc->parent = p->parent;
1395 phys_enc->parent_ops = p->parent_ops;
1396 phys_enc->sde_kms = p->sde_kms;
1397 phys_enc->split_role = p->split_role;
Clarence Ip03521982016-08-26 10:49:47 -04001398 phys_enc->intf_mode = INTF_MODE_WB_LINE;
Dhaval Patel81e87882016-10-19 21:41:56 -07001399 phys_enc->intf_idx = p->intf_idx;
Lloyd Atkinson7d070942016-07-26 18:35:12 -04001400 phys_enc->enc_spinlock = p->enc_spinlock;
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -07001401 atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
Alan Kwonga172ef52016-09-27 00:29:10 -04001402 INIT_LIST_HEAD(&wb_enc->irq_cb.list);
Alan Kwongbb27c092016-07-20 16:41:25 -04001403
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001404 /* create internal buffer for disable logic */
1405 if (_sde_encoder_phys_wb_init_internal_fb(wb_enc,
Narendra Muppalla58a64e22017-07-24 10:54:47 -07001406 DRM_FORMAT_RGB888, 2, 1, 6)) {
Clarence Ip9c65f7b2017-03-20 06:48:15 -07001407 SDE_ERROR("failed to init internal fb\n");
1408 goto fail_wb_init;
1409 }
1410
Alan Kwongbb27c092016-07-20 16:41:25 -04001411 SDE_DEBUG("Created sde_encoder_phys_wb for wb %d\n",
1412 wb_enc->hw_wb->idx - WB_0);
1413
1414 return phys_enc;
1415
Alan Kwongbb27c092016-07-20 16:41:25 -04001416fail_wb_init:
1417fail_wb_check:
Alan Kwongbb27c092016-07-20 16:41:25 -04001418fail_mdp_init:
1419 kfree(wb_enc);
1420fail_alloc:
1421 return ERR_PTR(ret);
1422}
1423