blob: 1e5e1861473707a89860ca040aeb806cb6809161 [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.
12 *
13 */
14
Alan Kwong4c3cf4c2016-09-25 20:08:09 -040015#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
Alan Kwongbb27c092016-07-20 16:41:25 -040016
17#include <linux/jiffies.h>
18#include <linux/debugfs.h>
19
20#include "sde_encoder_phys.h"
21#include "sde_formats.h"
22#include "sde_hw_top.h"
23#include "sde_hw_interrupts.h"
Alan Kwongf5dd86c2016-08-09 18:08:17 -040024#include "sde_core_irq.h"
Alan Kwongbb27c092016-07-20 16:41:25 -040025#include "sde_wb.h"
Lloyd Atkinson8772e202016-09-26 17:52:16 -040026#include "sde_vbif.h"
Alan Kwongbb27c092016-07-20 16:41:25 -040027
28/* wait for at most 2 vsync for lowest refresh rate (24hz) */
29#define WAIT_TIMEOUT_MSEC 84
30
31#define to_sde_encoder_phys_wb(x) \
32 container_of(x, struct sde_encoder_phys_wb, base)
33
34#define DEV(phy_enc) (phy_enc->parent->dev)
35
36/**
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -040037 * sde_encoder_phys_wb_is_master - report wb always as master encoder
38 */
39static bool sde_encoder_phys_wb_is_master(struct sde_encoder_phys *phys_enc)
40{
41 return true;
42}
43
44/**
Alan Kwongbb27c092016-07-20 16:41:25 -040045 * sde_encoder_phys_wb_get_intr_type - get interrupt type based on block mode
46 * @hw_wb: Pointer to h/w writeback driver
47 */
48static enum sde_intr_type sde_encoder_phys_wb_get_intr_type(
49 struct sde_hw_wb *hw_wb)
50{
51 return (hw_wb->caps->features & BIT(SDE_WB_BLOCK_MODE)) ?
52 SDE_IRQ_TYPE_WB_ROT_COMP : SDE_IRQ_TYPE_WB_WFD_COMP;
53}
54
55/**
Alan Kwong5d324e42016-07-28 22:56:18 -040056 * sde_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface
57 * @phys_enc: Pointer to physical encoder
58 */
59static void sde_encoder_phys_wb_set_ot_limit(
60 struct sde_encoder_phys *phys_enc)
61{
62 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
63 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
64 struct sde_vbif_set_ot_params ot_params;
65
66 memset(&ot_params, 0, sizeof(ot_params));
67 ot_params.xin_id = hw_wb->caps->xin_id;
68 ot_params.num = hw_wb->idx - WB_0;
69 ot_params.width = wb_enc->wb_roi.w;
70 ot_params.height = wb_enc->wb_roi.h;
71 ot_params.is_wfd = true;
72 ot_params.frame_rate = phys_enc->cached_mode.vrefresh;
73 ot_params.vbif_idx = hw_wb->caps->vbif_idx;
74 ot_params.clk_ctrl = hw_wb->caps->clk_ctrl;
75 ot_params.rd = false;
76
77 sde_vbif_set_ot_limit(phys_enc->sde_kms, &ot_params);
78}
79
80/**
Alan Kwongbb27c092016-07-20 16:41:25 -040081 * sde_encoder_phys_wb_set_traffic_shaper - set traffic shaper for writeback
82 * @phys_enc: Pointer to physical encoder
83 */
84static void sde_encoder_phys_wb_set_traffic_shaper(
85 struct sde_encoder_phys *phys_enc)
86{
87 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
88 struct sde_hw_wb_cfg *wb_cfg = &wb_enc->wb_cfg;
89
90 /* traffic shaper is only enabled for rotator */
91 wb_cfg->ts_cfg.en = false;
92}
93
94/**
95 * sde_encoder_phys_setup_cdm - setup chroma down block
96 * @phys_enc: Pointer to physical encoder
97 * @fb: Pointer to output framebuffer
98 * @format: Output format
99 */
100void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
101 struct drm_framebuffer *fb, const struct sde_format *format,
102 struct sde_rect *wb_roi)
103{
104 struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
105 struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg;
106 int ret;
107
108 if (!SDE_FORMAT_IS_YUV(format)) {
109 SDE_DEBUG("[cdm_disable fmt:%x]\n",
110 format->base.pixel_format);
111
112 if (hw_cdm && hw_cdm->ops.disable)
113 hw_cdm->ops.disable(hw_cdm);
114
115 return;
116 }
117
118 memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg));
119
120 cdm_cfg->output_width = wb_roi->w;
121 cdm_cfg->output_height = wb_roi->h;
122 cdm_cfg->output_fmt = format;
123 cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
abeykun5ed42e12016-08-24 17:09:26 -0400124 cdm_cfg->output_bit_depth = SDE_FORMAT_IS_DX(format) ?
125 CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
Alan Kwongbb27c092016-07-20 16:41:25 -0400126
127 /* enable 10 bit logic */
128 switch (cdm_cfg->output_fmt->chroma_sample) {
129 case SDE_CHROMA_RGB:
130 cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
131 cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
132 break;
133 case SDE_CHROMA_H2V1:
134 cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
135 cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
136 break;
137 case SDE_CHROMA_420:
138 cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
139 cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
140 break;
141 case SDE_CHROMA_H1V2:
142 default:
143 SDE_ERROR("unsupported chroma sampling type\n");
144 cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
145 cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
146 break;
147 }
148
149 SDE_DEBUG("[cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
150 cdm_cfg->output_width,
151 cdm_cfg->output_height,
152 cdm_cfg->output_fmt->base.pixel_format,
153 cdm_cfg->output_type,
154 cdm_cfg->output_bit_depth,
155 cdm_cfg->h_cdwn_type,
156 cdm_cfg->v_cdwn_type);
157
158 if (hw_cdm && hw_cdm->ops.setup_cdwn) {
159 ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg);
160 if (ret < 0) {
161 SDE_ERROR("failed to setup CDM %d\n", ret);
162 return;
163 }
164 }
165
166 if (hw_cdm && hw_cdm->ops.enable) {
167 ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
168 if (ret < 0) {
169 SDE_ERROR("failed to enable CDM %d\n", ret);
170 return;
171 }
172 }
173}
174
175/**
176 * sde_encoder_phys_wb_setup_fb - setup output framebuffer
177 * @phys_enc: Pointer to physical encoder
178 * @fb: Pointer to output framebuffer
179 * @wb_roi: Pointer to output region of interest
180 */
181static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc,
182 struct drm_framebuffer *fb, struct sde_rect *wb_roi)
183{
184 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Clarence Ip03521982016-08-26 10:49:47 -0400185 struct sde_hw_wb *hw_wb;
186 struct sde_hw_wb_cfg *wb_cfg;
Alan Kwongbb27c092016-07-20 16:41:25 -0400187 const struct msm_format *format;
188 int ret, mmu_id;
189
Clarence Ip03521982016-08-26 10:49:47 -0400190 if (!phys_enc) {
191 SDE_ERROR("invalid encoder\n");
192 return;
193 }
194
195 hw_wb = wb_enc->hw_wb;
196 wb_cfg = &wb_enc->wb_cfg;
Alan Kwongbb27c092016-07-20 16:41:25 -0400197 memset(wb_cfg, 0, sizeof(struct sde_hw_wb_cfg));
198
Clarence Ip03521982016-08-26 10:49:47 -0400199 wb_cfg->intf_mode = phys_enc->intf_mode;
Alan Kwongbb27c092016-07-20 16:41:25 -0400200 wb_cfg->is_secure = (fb->flags & DRM_MODE_FB_SECURE) ? true : false;
201 mmu_id = (wb_cfg->is_secure) ?
202 wb_enc->mmu_id[SDE_IOMMU_DOMAIN_SECURE] :
203 wb_enc->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
204
205 SDE_DEBUG("[fb_secure:%d]\n", wb_cfg->is_secure);
206
207 format = msm_framebuffer_format(fb);
Dhaval Patelccbcb3d2016-08-22 11:58:14 -0700208 if (!format) {
209 SDE_DEBUG("invalid format for fb\n");
210 return;
211 }
212
Alan Kwongbb27c092016-07-20 16:41:25 -0400213 wb_cfg->dest.format = sde_get_sde_format_ext(
214 format->pixel_format,
215 fb->modifier,
216 drm_format_num_planes(fb->pixel_format));
217 if (!wb_cfg->dest.format) {
218 /* this error should be detected during atomic_check */
219 SDE_ERROR("failed to get format %x\n", format->pixel_format);
220 return;
221 }
abeykunf1539f72016-08-24 16:08:03 -0400222 wb_cfg->roi = *wb_roi;
Alan Kwongbb27c092016-07-20 16:41:25 -0400223
abeykunf1539f72016-08-24 16:08:03 -0400224 if (hw_wb->caps->features & BIT(SDE_WB_XY_ROI_OFFSET)) {
225 ret = sde_format_populate_layout(mmu_id, fb, &wb_cfg->dest);
226 if (ret) {
227 SDE_DEBUG("failed to populate layout %d\n", ret);
228 return;
229 }
230 wb_cfg->dest.width = fb->width;
231 wb_cfg->dest.height = fb->height;
232 wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes;
233 } else {
234 ret = sde_format_populate_layout_with_roi(mmu_id, fb, wb_roi,
Alan Kwongbb27c092016-07-20 16:41:25 -0400235 &wb_cfg->dest);
abeykunf1539f72016-08-24 16:08:03 -0400236 if (ret) {
237 /* this error should be detected during atomic_check */
238 SDE_DEBUG("failed to populate layout %d\n", ret);
239 return;
240 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400241 }
242
243 if ((wb_cfg->dest.format->fetch_planes == SDE_PLANE_PLANAR) &&
244 (wb_cfg->dest.format->element[0] == C1_B_Cb))
245 swap(wb_cfg->dest.plane_addr[1], wb_cfg->dest.plane_addr[2]);
246
247 SDE_DEBUG("[fb_offset:%8.8x,%8.8x,%8.8x,%8.8x]\n",
248 wb_cfg->dest.plane_addr[0],
249 wb_cfg->dest.plane_addr[1],
250 wb_cfg->dest.plane_addr[2],
251 wb_cfg->dest.plane_addr[3]);
252 SDE_DEBUG("[fb_stride:%8.8x,%8.8x,%8.8x,%8.8x]\n",
253 wb_cfg->dest.plane_pitch[0],
254 wb_cfg->dest.plane_pitch[1],
255 wb_cfg->dest.plane_pitch[2],
256 wb_cfg->dest.plane_pitch[3]);
257
abeykunf1539f72016-08-24 16:08:03 -0400258 if (hw_wb->ops.setup_roi)
259 hw_wb->ops.setup_roi(hw_wb, wb_cfg);
260
Alan Kwongbb27c092016-07-20 16:41:25 -0400261 if (hw_wb->ops.setup_outformat)
262 hw_wb->ops.setup_outformat(hw_wb, wb_cfg);
263
264 if (hw_wb->ops.setup_outaddress)
265 hw_wb->ops.setup_outaddress(hw_wb, wb_cfg);
266}
267
268/**
269 * sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
270 * @phys_enc: Pointer to physical encoder
271 */
272static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc)
273{
274 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
275 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
276 struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
277
278 memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
279
280 intf_cfg->intf = SDE_NONE;
281 intf_cfg->wb = hw_wb->idx;
Lloyd Atkinson55987b02016-08-16 16:57:46 -0400282 intf_cfg->mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc);
Alan Kwongbb27c092016-07-20 16:41:25 -0400283
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400284 if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg)
Alan Kwongbb27c092016-07-20 16:41:25 -0400285 phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl,
286 intf_cfg);
287}
288
289/**
290 * sde_encoder_phys_wb_atomic_check - verify and fixup given atomic states
291 * @phys_enc: Pointer to physical encoder
292 * @crtc_state: Pointer to CRTC atomic state
293 * @conn_state: Pointer to connector atomic state
294 */
295static int sde_encoder_phys_wb_atomic_check(
296 struct sde_encoder_phys *phys_enc,
297 struct drm_crtc_state *crtc_state,
298 struct drm_connector_state *conn_state)
299{
300 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
301 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
302 const struct sde_wb_cfg *wb_cfg = hw_wb->caps;
303 struct drm_framebuffer *fb;
304 const struct sde_format *fmt;
305 struct sde_rect wb_roi;
306 const struct drm_display_mode *mode = &crtc_state->mode;
307 int rc;
308
309 SDE_DEBUG("[atomic_check:%d,%d,\"%s\",%d,%d]\n",
310 hw_wb->idx - WB_0, mode->base.id, mode->name,
311 mode->hdisplay, mode->vdisplay);
312
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400313 if (!conn_state || !conn_state->connector) {
314 SDE_ERROR("invalid connector state\n");
315 return -EINVAL;
316 } else if (conn_state->connector->status !=
317 connector_status_connected) {
318 SDE_ERROR("connector not connected %d\n",
319 conn_state->connector->status);
320 return -EINVAL;
321 }
322
Alan Kwongbb27c092016-07-20 16:41:25 -0400323 memset(&wb_roi, 0, sizeof(struct sde_rect));
324
325 rc = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi);
326 if (rc) {
327 SDE_ERROR("failed to get roi %d\n", rc);
328 return rc;
329 }
330
331 SDE_DEBUG("[roi:%u,%u,%u,%u]\n", wb_roi.x, wb_roi.y,
332 wb_roi.w, wb_roi.h);
333
334 fb = sde_wb_connector_state_get_output_fb(conn_state);
335 if (!fb) {
336 SDE_ERROR("no output framebuffer\n");
337 return -EINVAL;
338 }
339
340 SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
341 fb->width, fb->height);
342
343 fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
344 drm_format_num_planes(fb->pixel_format));
345 if (!fmt) {
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400346 SDE_ERROR("unsupported output pixel format:%x\n",
Alan Kwongbb27c092016-07-20 16:41:25 -0400347 fb->pixel_format);
348 return -EINVAL;
349 }
350
351 SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->pixel_format,
352 fb->modifier[0]);
353
354 if (SDE_FORMAT_IS_YUV(fmt) &&
355 !(wb_cfg->features & BIT(SDE_WB_YUV_CONFIG))) {
356 SDE_ERROR("invalid output format %x\n", fmt->base.pixel_format);
357 return -EINVAL;
358 }
359
360 if (SDE_FORMAT_IS_UBWC(fmt) &&
361 !(wb_cfg->features & BIT(SDE_WB_UBWC_1_0))) {
362 SDE_ERROR("invalid output format %x\n", fmt->base.pixel_format);
363 return -EINVAL;
364 }
365
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400366 if (SDE_FORMAT_IS_YUV(fmt) != !!phys_enc->hw_cdm)
367 crtc_state->mode_changed = true;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400368
Alan Kwongbb27c092016-07-20 16:41:25 -0400369 if (wb_roi.w && wb_roi.h) {
370 if (wb_roi.w != mode->hdisplay) {
371 SDE_ERROR("invalid roi w=%d, mode w=%d\n", wb_roi.w,
372 mode->hdisplay);
373 return -EINVAL;
374 } else if (wb_roi.h != mode->vdisplay) {
375 SDE_ERROR("invalid roi h=%d, mode h=%d\n", wb_roi.h,
376 mode->vdisplay);
377 return -EINVAL;
378 } else if (wb_roi.x + wb_roi.w > fb->width) {
379 SDE_ERROR("invalid roi x=%d, w=%d, fb w=%d\n",
380 wb_roi.x, wb_roi.w, fb->width);
381 return -EINVAL;
382 } else if (wb_roi.y + wb_roi.h > fb->height) {
383 SDE_ERROR("invalid roi y=%d, h=%d, fb h=%d\n",
384 wb_roi.y, wb_roi.h, fb->height);
385 return -EINVAL;
386 } else if (wb_roi.w > wb_cfg->sblk->maxlinewidth) {
387 SDE_ERROR("invalid roi w=%d, maxlinewidth=%u\n",
388 wb_roi.w, wb_cfg->sblk->maxlinewidth);
389 return -EINVAL;
390 }
391 } else {
392 if (wb_roi.x || wb_roi.y) {
393 SDE_ERROR("invalid roi x=%d, y=%d\n",
394 wb_roi.x, wb_roi.y);
395 return -EINVAL;
396 } else if (fb->width != mode->hdisplay) {
397 SDE_ERROR("invalid fb w=%d, mode w=%d\n", fb->width,
398 mode->hdisplay);
399 return -EINVAL;
400 } else if (fb->height != mode->vdisplay) {
401 SDE_ERROR("invalid fb h=%d, mode h=%d\n", fb->height,
402 mode->vdisplay);
403 return -EINVAL;
404 } else if (fb->width > wb_cfg->sblk->maxlinewidth) {
405 SDE_ERROR("invalid fb w=%d, maxlinewidth=%u\n",
406 fb->width, wb_cfg->sblk->maxlinewidth);
407 return -EINVAL;
408 }
409 }
410
411 return 0;
412}
413
414/**
415 * sde_encoder_phys_wb_flush - flush hardware update
416 * @phys_enc: Pointer to physical encoder
417 */
418static void sde_encoder_phys_wb_flush(struct sde_encoder_phys *phys_enc)
419{
420 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
421 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
422 struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
423 struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
424 u32 flush_mask = 0;
425
426 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
427
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400428 if (!hw_ctl) {
429 SDE_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0);
430 return;
431 }
432
Alan Kwongbb27c092016-07-20 16:41:25 -0400433 if (hw_ctl->ops.get_bitmask_wb)
434 hw_ctl->ops.get_bitmask_wb(hw_ctl, &flush_mask, hw_wb->idx);
435
436 if (hw_ctl->ops.get_bitmask_cdm && hw_cdm)
437 hw_ctl->ops.get_bitmask_cdm(hw_ctl, &flush_mask, hw_cdm->idx);
438
439 if (hw_ctl->ops.update_pending_flush)
440 hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask);
441
442 SDE_DEBUG("Flushing CTL_ID %d, flush_mask %x, WB %d\n",
443 hw_ctl->idx - CTL_0, flush_mask, hw_wb->idx - WB_0);
444}
445
446/**
447 * sde_encoder_phys_wb_setup - setup writeback encoder
448 * @phys_enc: Pointer to physical encoder
449 */
450static void sde_encoder_phys_wb_setup(
451 struct sde_encoder_phys *phys_enc)
452{
453 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
454 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
455 struct drm_display_mode mode = phys_enc->cached_mode;
456 struct drm_framebuffer *fb;
457 struct sde_rect *wb_roi = &wb_enc->wb_roi;
458
459 SDE_DEBUG("[mode_set:%d,%d,\"%s\",%d,%d]\n",
460 hw_wb->idx - WB_0, mode.base.id, mode.name,
461 mode.hdisplay, mode.vdisplay);
462
463 memset(wb_roi, 0, sizeof(struct sde_rect));
464
465 fb = sde_wb_get_output_fb(wb_enc->wb_dev);
466 if (!fb) {
467 SDE_DEBUG("no output framebuffer\n");
468 return;
469 }
470
471 SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
472 fb->width, fb->height);
473
474 sde_wb_get_output_roi(wb_enc->wb_dev, wb_roi);
475 if (wb_roi->w == 0 || wb_roi->h == 0) {
476 wb_roi->x = 0;
477 wb_roi->y = 0;
478 wb_roi->w = fb->width;
479 wb_roi->h = fb->height;
480 }
481
482 SDE_DEBUG("[roi:%u,%u,%u,%u]\n", wb_roi->x, wb_roi->y,
483 wb_roi->w, wb_roi->h);
484
485 wb_enc->wb_fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
486 drm_format_num_planes(fb->pixel_format));
487 if (!wb_enc->wb_fmt) {
488 SDE_ERROR("unsupported output pixel format: %d\n",
489 fb->pixel_format);
490 return;
491 }
492
493 SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->pixel_format,
494 fb->modifier[0]);
495
Alan Kwong5d324e42016-07-28 22:56:18 -0400496 sde_encoder_phys_wb_set_ot_limit(phys_enc);
497
Alan Kwongbb27c092016-07-20 16:41:25 -0400498 sde_encoder_phys_wb_set_traffic_shaper(phys_enc);
499
500 sde_encoder_phys_setup_cdm(phys_enc, fb, wb_enc->wb_fmt, wb_roi);
501
502 sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi);
503
504 sde_encoder_phys_wb_setup_cdp(phys_enc);
505}
506
507/**
508 * sde_encoder_phys_wb_unregister_irq - unregister writeback interrupt handler
509 * @phys_enc: Pointer to physical encoder
510 */
511static int sde_encoder_phys_wb_unregister_irq(
512 struct sde_encoder_phys *phys_enc)
513{
514 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
515 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
516
517 if (wb_enc->bypass_irqreg)
518 return 0;
519
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400520 sde_core_irq_disable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
Alan Kwonga172ef52016-09-27 00:29:10 -0400521 sde_core_irq_unregister_callback(phys_enc->sde_kms, wb_enc->irq_idx,
522 &wb_enc->irq_cb);
Alan Kwongbb27c092016-07-20 16:41:25 -0400523
524 SDE_DEBUG("un-register IRQ for wb %d, irq_idx=%d\n",
525 hw_wb->idx - WB_0,
526 wb_enc->irq_idx);
527
528 return 0;
529}
530
531/**
532 * sde_encoder_phys_wb_done_irq - writeback interrupt handler
533 * @arg: Pointer to writeback encoder
534 * @irq_idx: interrupt index
535 */
536static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
537{
538 struct sde_encoder_phys_wb *wb_enc = arg;
539 struct sde_encoder_phys *phys_enc = &wb_enc->base;
540 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
541
542 SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0,
543 wb_enc->frame_count);
544
545 complete_all(&wb_enc->wbdone_complete);
546
Dhaval Patel81e87882016-10-19 21:41:56 -0700547 phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
548 phys_enc);
Alan Kwongbb27c092016-07-20 16:41:25 -0400549}
550
551/**
552 * sde_encoder_phys_wb_register_irq - register writeback interrupt handler
553 * @phys_enc: Pointer to physical encoder
554 */
555static int sde_encoder_phys_wb_register_irq(struct sde_encoder_phys *phys_enc)
556{
557 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
558 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Alan Kwonga172ef52016-09-27 00:29:10 -0400559 struct sde_irq_callback *irq_cb = &wb_enc->irq_cb;
Alan Kwongbb27c092016-07-20 16:41:25 -0400560 enum sde_intr_type intr_type;
561 int ret = 0;
562
563 if (wb_enc->bypass_irqreg)
564 return 0;
565
566 intr_type = sde_encoder_phys_wb_get_intr_type(hw_wb);
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400567 wb_enc->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms,
Alan Kwongbb27c092016-07-20 16:41:25 -0400568 intr_type, hw_wb->idx);
569 if (wb_enc->irq_idx < 0) {
570 SDE_ERROR(
571 "failed to lookup IRQ index for WB_DONE with wb=%d\n",
572 hw_wb->idx - WB_0);
573 return -EINVAL;
574 }
575
Alan Kwonga172ef52016-09-27 00:29:10 -0400576 irq_cb->func = sde_encoder_phys_wb_done_irq;
577 irq_cb->arg = wb_enc;
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400578 ret = sde_core_irq_register_callback(phys_enc->sde_kms,
Alan Kwonga172ef52016-09-27 00:29:10 -0400579 wb_enc->irq_idx, irq_cb);
Alan Kwongbb27c092016-07-20 16:41:25 -0400580 if (ret) {
581 SDE_ERROR("failed to register IRQ callback WB_DONE\n");
582 return ret;
583 }
584
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400585 ret = sde_core_irq_enable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
Alan Kwongbb27c092016-07-20 16:41:25 -0400586 if (ret) {
587 SDE_ERROR(
588 "failed to enable IRQ for WB_DONE, wb %d, irq_idx=%d\n",
589 hw_wb->idx - WB_0,
590 wb_enc->irq_idx);
591 wb_enc->irq_idx = -EINVAL;
592
593 /* Unregister callback on IRQ enable failure */
Alan Kwonga172ef52016-09-27 00:29:10 -0400594 sde_core_irq_unregister_callback(phys_enc->sde_kms,
595 wb_enc->irq_idx, irq_cb);
Alan Kwongbb27c092016-07-20 16:41:25 -0400596 return ret;
597 }
598
599 SDE_DEBUG("registered IRQ for wb %d, irq_idx=%d\n",
600 hw_wb->idx - WB_0,
601 wb_enc->irq_idx);
602
603 return ret;
604}
605
606/**
607 * sde_encoder_phys_wb_mode_set - set display mode
608 * @phys_enc: Pointer to physical encoder
609 * @mode: Pointer to requested display mode
610 * @adj_mode: Pointer to adjusted display mode
611 */
612static void sde_encoder_phys_wb_mode_set(
613 struct sde_encoder_phys *phys_enc,
614 struct drm_display_mode *mode,
615 struct drm_display_mode *adj_mode)
616{
617 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400618 struct sde_rm *rm = &phys_enc->sde_kms->rm;
Alan Kwongbb27c092016-07-20 16:41:25 -0400619 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400620 struct sde_rm_hw_iter iter;
621 int i, instance;
Alan Kwongbb27c092016-07-20 16:41:25 -0400622
623 phys_enc->cached_mode = *adj_mode;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400624 instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400625
626 SDE_DEBUG("[mode_set_cache:%d,%d,\"%s\",%d,%d]\n",
627 hw_wb->idx - WB_0, mode->base.id,
628 mode->name, mode->hdisplay, mode->vdisplay);
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400629
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400630 phys_enc->hw_ctl = NULL;
631 phys_enc->hw_cdm = NULL;
632
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400633 /* Retrieve previously allocated HW Resources. CTL shouldn't fail */
634 sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CTL);
635 for (i = 0; i <= instance; i++) {
636 sde_rm_get_hw(rm, &iter);
637 if (i == instance)
638 phys_enc->hw_ctl = (struct sde_hw_ctl *) iter.hw;
639 }
640
641 if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) {
642 SDE_ERROR("failed init ctl: %ld\n", PTR_ERR(phys_enc->hw_ctl));
643 phys_enc->hw_ctl = NULL;
644 return;
645 }
646
647 /* CDM is optional */
648 sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CDM);
649 for (i = 0; i <= instance; i++) {
650 sde_rm_get_hw(rm, &iter);
651 if (i == instance)
652 phys_enc->hw_cdm = (struct sde_hw_cdm *) iter.hw;
653 }
654
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400655 if (IS_ERR(phys_enc->hw_cdm)) {
656 SDE_ERROR("CDM required but not allocated: %ld\n",
657 PTR_ERR(phys_enc->hw_cdm));
658 phys_enc->hw_ctl = NULL;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400659 }
Alan Kwongbb27c092016-07-20 16:41:25 -0400660}
661
662/**
Alan Kwongbb27c092016-07-20 16:41:25 -0400663 * sde_encoder_phys_wb_wait_for_commit_done - wait until request is committed
664 * @phys_enc: Pointer to physical encoder
665 */
666static int sde_encoder_phys_wb_wait_for_commit_done(
667 struct sde_encoder_phys *phys_enc)
668{
669 unsigned long ret;
670 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
671 u32 irq_status;
672 u64 wb_time = 0;
673 int rc = 0;
674
675 /* Return EWOULDBLOCK since we know the wait isn't necessary */
676 if (WARN_ON(phys_enc->enable_state != SDE_ENC_ENABLED))
677 return -EWOULDBLOCK;
678
679 MSM_EVT(DEV(phys_enc), wb_enc->frame_count, 0);
680
681 ret = wait_for_completion_timeout(&wb_enc->wbdone_complete,
682 msecs_to_jiffies(wb_enc->wbdone_timeout));
683
684 if (!ret) {
685 MSM_EVT(DEV(phys_enc), wb_enc->frame_count, 0);
686
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400687 irq_status = sde_core_irq_read(phys_enc->sde_kms,
Alan Kwongbb27c092016-07-20 16:41:25 -0400688 wb_enc->irq_idx, true);
689 if (irq_status) {
690 SDE_DEBUG("wb:%d done but irq not triggered\n",
691 wb_enc->wb_dev->wb_idx - WB_0);
692 sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx);
693 } else {
694 SDE_ERROR("wb:%d kickoff timed out\n",
695 wb_enc->wb_dev->wb_idx - WB_0);
696 rc = -ETIMEDOUT;
697 }
698 }
699
700 sde_encoder_phys_wb_unregister_irq(phys_enc);
701
702 if (!rc)
703 wb_enc->end_time = ktime_get();
704
705 /* once operation is done, disable traffic shaper */
706 if (wb_enc->wb_cfg.ts_cfg.en && wb_enc->hw_wb &&
707 wb_enc->hw_wb->ops.setup_trafficshaper) {
708 wb_enc->wb_cfg.ts_cfg.en = false;
709 wb_enc->hw_wb->ops.setup_trafficshaper(
710 wb_enc->hw_wb, &wb_enc->wb_cfg);
711 }
712
713 /* remove vote for iommu/clk/bus */
714 wb_enc->frame_count++;
715
716 if (!rc) {
717 wb_time = (u64)ktime_to_us(wb_enc->end_time) -
718 (u64)ktime_to_us(wb_enc->start_time);
719 SDE_DEBUG("wb:%d took %llu us\n",
720 wb_enc->wb_dev->wb_idx - WB_0, wb_time);
721 }
722
723 MSM_EVT(DEV(phys_enc), wb_enc->frame_count, wb_time);
724
725 return rc;
726}
727
728/**
729 * sde_encoder_phys_wb_prepare_for_kickoff - pre-kickoff processing
730 * @phys_enc: Pointer to physical encoder
731 * @need_to_wait: Wait for next submission
732 */
733static void sde_encoder_phys_wb_prepare_for_kickoff(
734 struct sde_encoder_phys *phys_enc,
735 bool *need_to_wait)
736{
737 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
738 int ret;
739
740 SDE_DEBUG("[wb:%d,%u]\n", wb_enc->hw_wb->idx - WB_0,
741 wb_enc->kickoff_count);
742
743 *need_to_wait = false;
744
745 reinit_completion(&wb_enc->wbdone_complete);
746
747 ret = sde_encoder_phys_wb_register_irq(phys_enc);
748 if (ret) {
749 SDE_ERROR("failed to register irq %d\n", ret);
750 return;
751 }
752
753 wb_enc->kickoff_count++;
754
755 /* set OT limit & enable traffic shaper */
756 sde_encoder_phys_wb_setup(phys_enc);
757
758 sde_encoder_phys_wb_flush(phys_enc);
759
760 /* vote for iommu/clk/bus */
761 wb_enc->start_time = ktime_get();
762
763 MSM_EVT(DEV(phys_enc), *need_to_wait, wb_enc->kickoff_count);
764}
765
766/**
767 * sde_encoder_phys_wb_handle_post_kickoff - post-kickoff processing
768 * @phys_enc: Pointer to physical encoder
769 */
770static void sde_encoder_phys_wb_handle_post_kickoff(
771 struct sde_encoder_phys *phys_enc)
772{
773 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
774
775 SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0);
776
777 MSM_EVT(DEV(phys_enc), 0, 0);
778}
779
780/**
781 * sde_encoder_phys_wb_enable - enable writeback encoder
782 * @phys_enc: Pointer to physical encoder
783 */
784static void sde_encoder_phys_wb_enable(struct sde_encoder_phys *phys_enc)
785{
786 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
787 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
Alan Kwong74e8ba32016-09-30 14:25:16 -0400788 struct drm_device *dev;
Alan Kwongbb27c092016-07-20 16:41:25 -0400789 struct drm_connector *connector;
790
791 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
792
Alan Kwong74e8ba32016-09-30 14:25:16 -0400793 if (!wb_enc->base.parent || !wb_enc->base.parent->dev) {
794 SDE_ERROR("invalid drm device\n");
795 return;
796 }
797 dev = wb_enc->base.parent->dev;
798
Alan Kwongbb27c092016-07-20 16:41:25 -0400799 /* find associated writeback connector */
Alan Kwong74e8ba32016-09-30 14:25:16 -0400800 mutex_lock(&dev->mode_config.mutex);
Alan Kwongbb27c092016-07-20 16:41:25 -0400801 drm_for_each_connector(connector, phys_enc->parent->dev) {
802 if (connector->encoder == phys_enc->parent)
803 break;
804 }
Alan Kwong74e8ba32016-09-30 14:25:16 -0400805 mutex_unlock(&dev->mode_config.mutex);
806
Alan Kwongbb27c092016-07-20 16:41:25 -0400807 if (!connector || connector->encoder != phys_enc->parent) {
808 SDE_ERROR("failed to find writeback connector\n");
809 return;
810 }
811 wb_enc->wb_dev = sde_wb_connector_get_wb(connector);
812
813 phys_enc->enable_state = SDE_ENC_ENABLED;
814}
815
816/**
817 * sde_encoder_phys_wb_disable - disable writeback encoder
818 * @phys_enc: Pointer to physical encoder
819 */
820static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
821{
822 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
823 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
824
825 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
826
827 if (phys_enc->enable_state == SDE_ENC_DISABLED) {
828 SDE_ERROR("encoder is already disabled\n");
829 return;
830 }
831
832 if (wb_enc->frame_count != wb_enc->kickoff_count) {
833 SDE_DEBUG("[wait_for_done: wb:%d, frame:%u, kickoff:%u]\n",
834 hw_wb->idx - WB_0, wb_enc->frame_count,
835 wb_enc->kickoff_count);
836 sde_encoder_phys_wb_wait_for_commit_done(phys_enc);
837 }
838
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400839 if (phys_enc->hw_cdm && phys_enc->hw_cdm->ops.disable) {
840 SDE_DEBUG_DRIVER("[cdm_disable]\n");
841 phys_enc->hw_cdm->ops.disable(phys_enc->hw_cdm);
842 }
843
Alan Kwongbb27c092016-07-20 16:41:25 -0400844 phys_enc->enable_state = SDE_ENC_DISABLED;
845}
846
847/**
848 * sde_encoder_phys_wb_get_hw_resources - get hardware resources
849 * @phys_enc: Pointer to physical encoder
850 * @hw_res: Pointer to encoder resources
851 */
852static void sde_encoder_phys_wb_get_hw_resources(
853 struct sde_encoder_phys *phys_enc,
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400854 struct sde_encoder_hw_resources *hw_res,
855 struct drm_connector_state *conn_state)
Alan Kwongbb27c092016-07-20 16:41:25 -0400856{
857 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
Clarence Ip03521982016-08-26 10:49:47 -0400858 struct sde_hw_wb *hw_wb;
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400859 struct drm_framebuffer *fb;
860 const struct sde_format *fmt;
Alan Kwongbb27c092016-07-20 16:41:25 -0400861
Clarence Ip03521982016-08-26 10:49:47 -0400862 if (!phys_enc) {
863 SDE_ERROR("invalid encoder\n");
864 return;
865 }
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400866
867 fb = sde_wb_connector_state_get_output_fb(conn_state);
868 if (!fb) {
869 SDE_ERROR("no output framebuffer\n");
870 return;
871 }
872
873 fmt = sde_get_sde_format_ext(fb->pixel_format, fb->modifier,
874 drm_format_num_planes(fb->pixel_format));
875 if (!fmt) {
876 SDE_ERROR("unsupported output pixel format:%d\n",
877 fb->pixel_format);
878 return;
879 }
880
Clarence Ip03521982016-08-26 10:49:47 -0400881 hw_wb = wb_enc->hw_wb;
Clarence Ip03521982016-08-26 10:49:47 -0400882 hw_res->wbs[hw_wb->idx - WB_0] = phys_enc->intf_mode;
Alan Kwong4c3cf4c2016-09-25 20:08:09 -0400883 hw_res->needs_cdm = SDE_FORMAT_IS_YUV(fmt);
884 SDE_DEBUG("[wb:%d] intf_mode=%d needs_cdm=%d\n", hw_wb->idx - WB_0,
885 hw_res->wbs[hw_wb->idx - WB_0],
886 hw_res->needs_cdm);
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -0400887}
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400888
Alan Kwongbb27c092016-07-20 16:41:25 -0400889#ifdef CONFIG_DEBUG_FS
890/**
891 * sde_encoder_phys_wb_init_debugfs - initialize writeback encoder debugfs
892 * @phys_enc: Pointer to physical encoder
893 * @sde_kms: Pointer to SDE KMS object
894 */
895static int sde_encoder_phys_wb_init_debugfs(
896 struct sde_encoder_phys *phys_enc, struct sde_kms *kms)
897{
898 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
899
900 if (!phys_enc || !kms || !wb_enc->hw_wb)
901 return -EINVAL;
902
903 snprintf(wb_enc->wb_name, ARRAY_SIZE(wb_enc->wb_name), "encoder_wb%d",
904 wb_enc->hw_wb->idx - WB_0);
905
906 wb_enc->debugfs_root =
907 debugfs_create_dir(wb_enc->wb_name,
908 sde_debugfs_get_root(kms));
909 if (!wb_enc->debugfs_root) {
910 SDE_ERROR("failed to create debugfs\n");
911 return -ENOMEM;
912 }
913
914 if (!debugfs_create_u32("wbdone_timeout", 0644,
915 wb_enc->debugfs_root, &wb_enc->wbdone_timeout)) {
916 SDE_ERROR("failed to create debugfs/wbdone_timeout\n");
917 return -ENOMEM;
918 }
919
920 if (!debugfs_create_u32("bypass_irqreg", 0644,
921 wb_enc->debugfs_root, &wb_enc->bypass_irqreg)) {
922 SDE_ERROR("failed to create debugfs/bypass_irqreg\n");
923 return -ENOMEM;
924 }
925
926 return 0;
927}
928
929/**
930 * sde_encoder_phys_wb_destroy_debugfs - destroy writeback encoder debugfs
931 * @phys_enc: Pointer to physical encoder
932 */
933static void sde_encoder_phys_wb_destroy_debugfs(
934 struct sde_encoder_phys *phys_enc)
935{
936 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
937
938 if (!phys_enc)
939 return;
940
941 debugfs_remove_recursive(wb_enc->debugfs_root);
942}
943#else
Dhaval Patel48f2d0f2016-09-27 16:39:12 -0700944static int sde_encoder_phys_wb_init_debugfs(
Alan Kwongbb27c092016-07-20 16:41:25 -0400945 struct sde_encoder_phys *phys_enc, struct sde_kms *kms)
946{
Dhaval Patel48f2d0f2016-09-27 16:39:12 -0700947 return 0;
Alan Kwongbb27c092016-07-20 16:41:25 -0400948}
949static void sde_encoder_phys_wb_destroy_debugfs(
950 struct sde_encoder_phys *phys_enc)
951{
952}
953#endif
954
955/**
956 * sde_encoder_phys_wb_destroy - destroy writeback encoder
957 * @phys_enc: Pointer to physical encoder
958 */
959static void sde_encoder_phys_wb_destroy(struct sde_encoder_phys *phys_enc)
960{
961 struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
962 struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
963
964 SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
965
966 if (!phys_enc)
967 return;
968
969 sde_encoder_phys_wb_destroy_debugfs(phys_enc);
970
Alan Kwongbb27c092016-07-20 16:41:25 -0400971 kfree(wb_enc);
972}
973
974/**
975 * sde_encoder_phys_wb_init_ops - initialize writeback operations
976 * @ops: Pointer to encoder operation table
977 */
978static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops)
979{
Lloyd Atkinsone7bcdd22016-08-11 10:53:37 -0400980 ops->is_master = sde_encoder_phys_wb_is_master;
Alan Kwongbb27c092016-07-20 16:41:25 -0400981 ops->mode_set = sde_encoder_phys_wb_mode_set;
982 ops->enable = sde_encoder_phys_wb_enable;
983 ops->disable = sde_encoder_phys_wb_disable;
984 ops->destroy = sde_encoder_phys_wb_destroy;
985 ops->atomic_check = sde_encoder_phys_wb_atomic_check;
986 ops->get_hw_resources = sde_encoder_phys_wb_get_hw_resources;
Alan Kwongbb27c092016-07-20 16:41:25 -0400987 ops->wait_for_commit_done = sde_encoder_phys_wb_wait_for_commit_done;
988 ops->prepare_for_kickoff = sde_encoder_phys_wb_prepare_for_kickoff;
989 ops->handle_post_kickoff = sde_encoder_phys_wb_handle_post_kickoff;
Clarence Ip110d15c2016-08-16 14:44:41 -0400990 ops->trigger_start = sde_encoder_helper_trigger_start;
Alan Kwongbb27c092016-07-20 16:41:25 -0400991}
992
993/**
994 * sde_encoder_phys_wb_init - initialize writeback encoder
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -0400995 * @init: Pointer to init info structure with initialization params
Alan Kwongbb27c092016-07-20 16:41:25 -0400996 */
997struct sde_encoder_phys *sde_encoder_phys_wb_init(
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -0400998 struct sde_enc_phys_init_params *p)
Alan Kwongbb27c092016-07-20 16:41:25 -0400999{
1000 struct sde_encoder_phys *phys_enc;
1001 struct sde_encoder_phys_wb *wb_enc;
1002 struct sde_hw_mdp *hw_mdp;
1003 int ret = 0;
1004
1005 SDE_DEBUG("\n");
1006
1007 wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL);
1008 if (!wb_enc) {
1009 ret = -ENOMEM;
1010 goto fail_alloc;
1011 }
1012 wb_enc->irq_idx = -EINVAL;
1013 wb_enc->wbdone_timeout = WAIT_TIMEOUT_MSEC;
1014 init_completion(&wb_enc->wbdone_complete);
1015
1016 phys_enc = &wb_enc->base;
1017
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001018 if (p->sde_kms->vbif[VBIF_NRT]) {
Alan Kwongbb27c092016-07-20 16:41:25 -04001019 wb_enc->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001020 p->sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -04001021 wb_enc->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001022 p->sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -04001023 } else {
1024 wb_enc->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001025 p->sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -04001026 wb_enc->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001027 p->sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
Alan Kwongbb27c092016-07-20 16:41:25 -04001028 }
1029
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001030 hw_mdp = sde_rm_get_mdp(&p->sde_kms->rm);
Alan Kwongbb27c092016-07-20 16:41:25 -04001031 if (IS_ERR_OR_NULL(hw_mdp)) {
1032 ret = PTR_ERR(hw_mdp);
1033 SDE_ERROR("failed to init hw_top: %d\n", ret);
1034 goto fail_mdp_init;
1035 }
1036 phys_enc->hw_mdptop = hw_mdp;
1037
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001038 /**
1039 * hw_wb resource permanently assigned to this encoder
1040 * Other resources allocated at atomic commit time by use case
1041 */
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001042 if (p->wb_idx != SDE_NONE) {
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001043 struct sde_rm_hw_iter iter;
Alan Kwongbb27c092016-07-20 16:41:25 -04001044
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001045 sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_WB);
1046 while (sde_rm_get_hw(&p->sde_kms->rm, &iter)) {
1047 struct sde_hw_wb *hw_wb = (struct sde_hw_wb *)iter.hw;
1048
1049 if (hw_wb->idx == p->wb_idx) {
1050 wb_enc->hw_wb = hw_wb;
1051 break;
1052 }
1053 }
1054
1055 if (!wb_enc->hw_wb) {
1056 ret = -EINVAL;
1057 SDE_ERROR("failed to init hw_wb%d\n", p->wb_idx - WB_0);
Alan Kwongbb27c092016-07-20 16:41:25 -04001058 goto fail_wb_init;
1059 }
Alan Kwongbb27c092016-07-20 16:41:25 -04001060 } else {
1061 ret = -EINVAL;
1062 SDE_ERROR("invalid wb_idx\n");
1063 goto fail_wb_check;
1064 }
1065
Alan Kwongbb27c092016-07-20 16:41:25 -04001066 sde_encoder_phys_wb_init_ops(&phys_enc->ops);
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001067 phys_enc->parent = p->parent;
1068 phys_enc->parent_ops = p->parent_ops;
1069 phys_enc->sde_kms = p->sde_kms;
1070 phys_enc->split_role = p->split_role;
Clarence Ip03521982016-08-26 10:49:47 -04001071 phys_enc->intf_mode = INTF_MODE_WB_LINE;
Dhaval Patel81e87882016-10-19 21:41:56 -07001072 phys_enc->intf_idx = p->intf_idx;
Alan Kwongbb27c092016-07-20 16:41:25 -04001073 spin_lock_init(&phys_enc->spin_lock);
Alan Kwonga172ef52016-09-27 00:29:10 -04001074 INIT_LIST_HEAD(&wb_enc->irq_cb.list);
Alan Kwongbb27c092016-07-20 16:41:25 -04001075
Lloyd Atkinson6ef6cb52016-07-06 11:49:18 -04001076 ret = sde_encoder_phys_wb_init_debugfs(phys_enc, p->sde_kms);
Alan Kwongbb27c092016-07-20 16:41:25 -04001077 if (ret) {
1078 SDE_ERROR("failed to init debugfs %d\n", ret);
1079 goto fail_debugfs_init;
1080 }
1081
1082 SDE_DEBUG("Created sde_encoder_phys_wb for wb %d\n",
1083 wb_enc->hw_wb->idx - WB_0);
1084
1085 return phys_enc;
1086
1087fail_debugfs_init:
Alan Kwongbb27c092016-07-20 16:41:25 -04001088fail_wb_init:
1089fail_wb_check:
Alan Kwongbb27c092016-07-20 16:41:25 -04001090fail_mdp_init:
1091 kfree(wb_enc);
1092fail_alloc:
1093 return ERR_PTR(ret);
1094}
1095