xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_vop.c (revision 257c8a70660eec65519a481f1dd33e4e060766c8)
1 /*
2  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <config.h>
8 #include <common.h>
9 #include <errno.h>
10 #include <malloc.h>
11 #include <fdtdec.h>
12 #include <fdt_support.h>
13 #include <asm/unaligned.h>
14 #include <asm/io.h>
15 #include <linux/list.h>
16 #include <linux/media-bus-format.h>
17 #include <clk.h>
18 #include <asm/arch/clock.h>
19 #include <linux/err.h>
20 #include <dm/device.h>
21 #include <dm/read.h>
22 #include <syscon.h>
23 #include <regmap.h>
24 
25 #include "rockchip_display.h"
26 #include "rockchip_crtc.h"
27 #include "rockchip_connector.h"
28 #include "rockchip_vop.h"
29 
30 static inline int us_to_vertical_line(struct drm_display_mode *mode, int us)
31 {
32 	return us * mode->clock / mode->htotal / 1000;
33 }
34 
35 static inline void set_vop_mcu_rs(struct vop *vop, int v)
36 {
37 	if (dm_gpio_is_valid(&vop->mcu_rs_gpio))
38 		dm_gpio_set_value(&vop->mcu_rs_gpio, v);
39 	else
40 		VOP_CTRL_SET(vop, mcu_rs, v);
41 }
42 
43 static int to_vop_csc_mode(int csc_mode)
44 {
45 	switch (csc_mode) {
46 	case V4L2_COLORSPACE_SMPTE170M:
47 		return CSC_BT601L;
48 	case V4L2_COLORSPACE_REC709:
49 	case V4L2_COLORSPACE_DEFAULT:
50 		return CSC_BT709L;
51 	case V4L2_COLORSPACE_JPEG:
52 		return CSC_BT601F;
53 	case V4L2_COLORSPACE_BT2020:
54 		return CSC_BT2020;
55 	default:
56 		return CSC_BT709L;
57 	}
58 }
59 
60 static bool is_yuv_output(uint32_t bus_format)
61 {
62 	switch (bus_format) {
63 	case MEDIA_BUS_FMT_YUV8_1X24:
64 	case MEDIA_BUS_FMT_YUV10_1X30:
65 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
66 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
67 	case MEDIA_BUS_FMT_YUYV8_2X8:
68 	case MEDIA_BUS_FMT_YVYU8_2X8:
69 	case MEDIA_BUS_FMT_UYVY8_2X8:
70 	case MEDIA_BUS_FMT_VYUY8_2X8:
71 	case MEDIA_BUS_FMT_YUYV8_1X16:
72 	case MEDIA_BUS_FMT_YVYU8_1X16:
73 	case MEDIA_BUS_FMT_UYVY8_1X16:
74 	case MEDIA_BUS_FMT_VYUY8_1X16:
75 		return true;
76 	default:
77 		return false;
78 	}
79 }
80 
81 static bool is_uv_swap(uint32_t bus_format, uint32_t output_mode)
82 {
83 	/*
84 	 * FIXME:
85 	 *
86 	 * There is no media type for YUV444 output,
87 	 * so when out_mode is AAAA or P888, assume output is YUV444 on
88 	 * yuv format.
89 	 *
90 	 * From H/W testing, YUV444 mode need a rb swap.
91 	 */
92 	if ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
93 	     bus_format == MEDIA_BUS_FMT_YUV10_1X30) &&
94 	    (output_mode == ROCKCHIP_OUT_MODE_AAAA ||
95 	     output_mode == ROCKCHIP_OUT_MODE_P888))
96 		return true;
97 	else
98 		return false;
99 }
100 
101 static bool is_rb_swap(uint32_t bus_format, uint32_t output_mode)
102 {
103 	/*
104 	 * The default component order of serial rgb3x8 formats
105 	 * is BGR. So it is needed to enable RB swap.
106 	 */
107 	if (bus_format == MEDIA_BUS_FMT_RGB888_3X8 ||
108 	    bus_format == MEDIA_BUS_FMT_RGB888_DUMMY_4X8)
109 		return true;
110 	else
111 		return false;
112 }
113 
114 static int rockchip_vop_init_gamma(struct vop *vop, struct display_state *state)
115 {
116 	struct crtc_state *crtc_state = &state->crtc_state;
117 	struct connector_state *conn_state = &state->conn_state;
118 	u32 *lut = conn_state->gamma.lut;
119 	fdt_size_t lut_size;
120 	int i, lut_len;
121 	u32 *lut_regs;
122 
123 	if (!conn_state->gamma.lut)
124 		return 0;
125 
126 	i = dev_read_stringlist_search(crtc_state->dev, "reg-names", "gamma_lut");
127 	if (i < 0) {
128 		printf("Warning: vop not support gamma\n");
129 		return 0;
130 	}
131 	lut_regs = (u32 *)dev_read_addr_size(crtc_state->dev, "reg", &lut_size);
132 	if (lut_regs == (u32 *)FDT_ADDR_T_NONE) {
133 		printf("failed to get gamma lut register\n");
134 		return 0;
135 	}
136 	lut_len = lut_size / 4;
137 	if (lut_len != 256 && lut_len != 1024) {
138 		printf("Warning: unsupport gamma lut table[%d]\n", lut_len);
139 		return 0;
140 	}
141 
142 	if (conn_state->gamma.size != lut_len) {
143 		int size = conn_state->gamma.size;
144 		u32 j, r, g, b, color;
145 
146 		for (i = 0; i < lut_len; i++) {
147 			j = i * size / lut_len;
148 			r = lut[j] / size / size * lut_len / size;
149 			g = lut[j] / size % size * lut_len / size;
150 			b = lut[j] % size * lut_len / size;
151 			color = r * lut_len * lut_len + g * lut_len + b;
152 
153 			writel(color, lut_regs + (i << 2));
154 		}
155 	} else {
156 		for (i = 0; i < lut_len; i++)
157 			writel(lut[i], lut_regs + (i << 2));
158 	}
159 
160 	VOP_CTRL_SET(vop, dsp_lut_en, 1);
161 	VOP_CTRL_SET(vop, update_gamma_lut, 1);
162 
163 	return 0;
164 }
165 
166 static void vop_post_config(struct display_state *state, struct vop *vop)
167 {
168 	struct connector_state *conn_state = &state->conn_state;
169 	struct drm_display_mode *mode = &conn_state->mode;
170 	u16 vtotal = mode->crtc_vtotal;
171 	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
172 	u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
173 	u16 hdisplay = mode->crtc_hdisplay;
174 	u16 vdisplay = mode->crtc_vdisplay;
175 	u16 hsize = hdisplay * (conn_state->overscan.left_margin + conn_state->overscan.right_margin) / 200;
176 	u16 vsize = vdisplay * (conn_state->overscan.top_margin + conn_state->overscan.bottom_margin) / 200;
177 	u16 hact_end, vact_end;
178 	u32 val;
179 
180 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
181 		vsize = round_down(vsize, 2);
182 
183 	hact_st += hdisplay * (100 - conn_state->overscan.left_margin) / 200;
184 	hact_end = hact_st + hsize;
185 	val = hact_st << 16;
186 	val |= hact_end;
187 
188 	VOP_CTRL_SET(vop, hpost_st_end, val);
189 	vact_st += vdisplay * (100 - conn_state->overscan.top_margin) / 200;
190 	vact_end = vact_st + vsize;
191 	val = vact_st << 16;
192 	val |= vact_end;
193 	VOP_CTRL_SET(vop, vpost_st_end, val);
194 	val = scl_cal_scale2(vdisplay, vsize) << 16;
195 	val |= scl_cal_scale2(hdisplay, hsize);
196 	VOP_CTRL_SET(vop, post_scl_factor, val);
197 #define POST_HORIZONTAL_SCALEDOWN_EN(x)		((x) << 0)
198 #define POST_VERTICAL_SCALEDOWN_EN(x)		((x) << 1)
199 	VOP_CTRL_SET(vop, post_scl_ctrl,
200 		     POST_HORIZONTAL_SCALEDOWN_EN(hdisplay != hsize) |
201 		     POST_VERTICAL_SCALEDOWN_EN(vdisplay != vsize));
202 	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
203 		u16 vact_st_f1 = vtotal + vact_st + 1;
204 		u16 vact_end_f1 = vact_st_f1 + vsize;
205 
206 		val = vact_st_f1 << 16 | vact_end_f1;
207 		VOP_CTRL_SET(vop, vpost_st_end_f1, val);
208 	}
209 }
210 
211 static void vop_mcu_bypass_mode_setup(struct display_state *state, struct vop *vop)
212 {
213 	/*
214 	 * If mcu_hold_mode is 1, set 1 to mcu_frame_st will
215 	 * refresh one frame from ddr. So mcu_frame_st is needed
216 	 * to be initialized as 0.
217 	 */
218 	VOP_CTRL_SET(vop, mcu_frame_st, 0);
219 	VOP_CTRL_SET(vop, mcu_clk_sel, 1);
220 	VOP_CTRL_SET(vop, mcu_type, 1);
221 
222 	VOP_CTRL_SET(vop, mcu_hold_mode, 1);
223 	VOP_CTRL_SET(vop, mcu_pix_total, 53);
224 	VOP_CTRL_SET(vop, mcu_cs_pst, 6);
225 	VOP_CTRL_SET(vop, mcu_cs_pend, 48);
226 	VOP_CTRL_SET(vop, mcu_rw_pst, 12);
227 	VOP_CTRL_SET(vop, mcu_rw_pend, 30);
228 }
229 
230 static void vop_mcu_mode_setup(struct display_state *state, struct vop *vop)
231 {
232 	struct crtc_state *crtc_state = &state->crtc_state;
233 
234 	/*
235 	 * If mcu_hold_mode is 1, set 1 to mcu_frame_st will
236 	 * refresh one frame from ddr. So mcu_frame_st is needed
237 	 * to be initialized as 0.
238 	 */
239 	VOP_CTRL_SET(vop, mcu_frame_st, 0);
240 	VOP_CTRL_SET(vop, mcu_clk_sel, 1);
241 	VOP_CTRL_SET(vop, mcu_type, 1);
242 
243 	VOP_CTRL_SET(vop, mcu_hold_mode, 1);
244 	VOP_CTRL_SET(vop, mcu_pix_total, crtc_state->mcu_timing.mcu_pix_total);
245 	VOP_CTRL_SET(vop, mcu_cs_pst, crtc_state->mcu_timing.mcu_cs_pst);
246 	VOP_CTRL_SET(vop, mcu_cs_pend, crtc_state->mcu_timing.mcu_cs_pend);
247 	VOP_CTRL_SET(vop, mcu_rw_pst, crtc_state->mcu_timing.mcu_rw_pst);
248 	VOP_CTRL_SET(vop, mcu_rw_pend, crtc_state->mcu_timing.mcu_rw_pend);
249 }
250 
251 static int rockchip_vop_preinit(struct display_state *state)
252 {
253 	const struct vop_data *vop_data = state->crtc_state.crtc->data;
254 
255 	state->crtc_state.max_output = vop_data->max_output;
256 
257 	return 0;
258 }
259 
260 static int rockchip_vop_init(struct display_state *state)
261 {
262 	struct crtc_state *crtc_state = &state->crtc_state;
263 	struct connector_state *conn_state = &state->conn_state;
264 	struct drm_display_mode *mode = &conn_state->mode;
265 	const struct rockchip_crtc *crtc = crtc_state->crtc;
266 	const struct vop_data *vop_data = crtc->data;
267 	struct vop *vop;
268 	struct regmap *map;
269 	u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
270 	u16 hdisplay = mode->crtc_hdisplay;
271 	u16 htotal = mode->crtc_htotal;
272 	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
273 	u16 hact_end = hact_st + hdisplay;
274 	u16 vdisplay = mode->crtc_vdisplay;
275 	u16 vtotal = mode->crtc_vtotal;
276 	u16 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
277 	u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
278 	u16 vact_end = vact_st + vdisplay;
279 	u32 val, act_end;
280 	int ret;
281 	bool yuv_overlay = false, post_r2y_en = false, post_y2r_en = false;
282 	u16 post_csc_mode;
283 	bool dclk_inv;
284 	char output_type_name[30] = {0};
285 
286 	vop = malloc(sizeof(*vop));
287 	if (!vop)
288 		return -ENOMEM;
289 	memset(vop, 0, sizeof(*vop));
290 
291 	crtc_state->private = vop;
292 	vop->data = vop_data;
293 	vop->regs = dev_read_addr_ptr(crtc_state->dev);
294 	vop->regsbak = malloc(vop_data->reg_len);
295 	vop->win = vop_data->win;
296 	vop->win_offset = vop_data->win_offset;
297 	vop->ctrl = vop_data->ctrl;
298 
299 	map = syscon_regmap_lookup_by_phandle(crtc_state->dev, "rockchip,grf");
300 	vop->grf_ctrl = regmap_get_range(map, 0);
301 	if (vop->grf_ctrl <= 0)
302 		printf("%s: Get syscon grf failed (ret=%p)\n", __func__, vop->grf_ctrl);
303 	map = syscon_regmap_lookup_by_phandle(crtc_state->dev, "rockchip,vo0-grf");
304 	vop->vo0_grf_ctrl = regmap_get_range(map, 0);
305 	if (vop->vo0_grf_ctrl <= 0)
306 		printf("%s: Get syscon vo0_grf failed (ret=%p)\n", __func__, vop->vo0_grf_ctrl);
307 
308 	vop->line_flag = vop_data->line_flag;
309 	vop->csc_table = vop_data->csc_table;
310 	vop->win_csc = vop_data->win_csc;
311 	vop->version = vop_data->version;
312 
313 	printf("VOP:0x%8p update mode to: %dx%d%s%d, type:%s\n",
314 	       vop->regs, mode->crtc_hdisplay, mode->vdisplay,
315 	       mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",
316 	       mode->vrefresh,
317 	       rockchip_get_output_if_name(conn_state->output_if, output_type_name));
318 
319 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
320 	ret = clk_set_defaults(crtc_state->dev);
321 	if (ret)
322 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
323 
324 	ret = clk_get_by_name(crtc_state->dev, "dclk_vop", &crtc_state->dclk);
325 	if (!ret)
326 		ret = clk_set_rate(&crtc_state->dclk, mode->crtc_clock * 1000);
327 	if (IS_ERR_VALUE(ret)) {
328 		printf("%s: Failed to set dclk: ret=%d\n", __func__, ret);
329 		return ret;
330 	}
331 	printf("VOP:0x%8p set crtc_clock to %dKHz\n", vop->regs, mode->crtc_clock);
332 
333 	memcpy(vop->regsbak, vop->regs, vop_data->reg_len);
334 
335 	rockchip_vop_init_gamma(vop, state);
336 
337 	ret = gpio_request_by_name(crtc_state->dev, "mcu-rs-gpios",
338 				   0, &vop->mcu_rs_gpio, GPIOD_IS_OUT);
339 	if (ret && ret != -ENOENT)
340 		printf("%s: Cannot get mcu rs GPIO: %d\n", __func__, ret);
341 
342 	VOP_CTRL_SET(vop, global_regdone_en, 1);
343 	VOP_CTRL_SET(vop, axi_outstanding_max_num, 30);
344 	VOP_CTRL_SET(vop, axi_max_outstanding_en, 1);
345 	VOP_CTRL_SET(vop, reg_done_frm, 1);
346 	VOP_CTRL_SET(vop, win_gate[0], 1);
347 	VOP_CTRL_SET(vop, win_gate[1], 1);
348 	VOP_CTRL_SET(vop, win_channel[0], 0x12);
349 	VOP_CTRL_SET(vop, win_channel[1], 0x34);
350 	VOP_CTRL_SET(vop, win_channel[2], 0x56);
351 	VOP_CTRL_SET(vop, dsp_blank, 0);
352 
353 	if (vop->version == VOP_VERSION(2, 0xd)) {
354 		VOP_GRF_SET(vop, grf_ctrl, grf_vopl_sel, 1);
355 		VOP_CTRL_SET(vop, enable, 1);
356 	}
357 
358 	dclk_inv = (conn_state->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) ? 1 : 0;
359 	/* For improving signal quality, dclk need to be inverted by default on rv1106. */
360 	if ((VOP_MAJOR(vop->version) == 2 && VOP_MINOR(vop->version) == 12))
361 		dclk_inv = !dclk_inv;
362 	VOP_CTRL_SET(vop, dclk_pol, dclk_inv);
363 
364 	val = 0x8;
365 	val |= (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
366 	val |= (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
367 	VOP_CTRL_SET(vop, pin_pol, val);
368 
369 	switch (conn_state->type) {
370 	case DRM_MODE_CONNECTOR_LVDS:
371 		VOP_CTRL_SET(vop, rgb_en, 1);
372 		VOP_CTRL_SET(vop, rgb_pin_pol, val);
373 		VOP_CTRL_SET(vop, rgb_dclk_pol, dclk_inv);
374 		VOP_CTRL_SET(vop, lvds_en, 1);
375 		VOP_CTRL_SET(vop, lvds_pin_pol, val);
376 		VOP_CTRL_SET(vop, lvds_dclk_pol, dclk_inv);
377 		if (!IS_ERR_OR_NULL(vop->grf_ctrl))
378 			VOP_GRF_SET(vop, grf_ctrl, grf_dclk_inv, dclk_inv);
379 		break;
380 	case DRM_MODE_CONNECTOR_eDP:
381 		VOP_CTRL_SET(vop, edp_en, 1);
382 		VOP_CTRL_SET(vop, edp_pin_pol, val);
383 		VOP_CTRL_SET(vop, edp_dclk_pol, dclk_inv);
384 		VOP_CTRL_SET(vop, inf_out_en, 1);
385 		VOP_GRF_SET(vop, vo0_grf_ctrl, grf_edp_ch_sel, 1);
386 		break;
387 	case DRM_MODE_CONNECTOR_HDMIA:
388 		VOP_CTRL_SET(vop, hdmi_en, 1);
389 		VOP_CTRL_SET(vop, hdmi_pin_pol, val);
390 		VOP_CTRL_SET(vop, hdmi_dclk_pol, 1);
391 		VOP_CTRL_SET(vop, inf_out_en, 1);
392 		VOP_GRF_SET(vop, vo0_grf_ctrl, grf_hdmi_ch_sel, 1);
393 		VOP_GRF_SET(vop, vo0_grf_ctrl, grf_hdmi_pin_pol, val);
394 		VOP_GRF_SET(vop, vo0_grf_ctrl, grf_hdmi_1to4_en, val);
395 		break;
396 	case DRM_MODE_CONNECTOR_DSI:
397 		/*
398 		 * RK3576 DSI CTRL hsync/vsync polarity is positive and can't update,
399 		 * so set VOP hsync/vsync polarity as positive by default.
400 		 */
401 		if (vop->version == VOP_VERSION(2, 0xd))
402 			val = BIT(HSYNC_POSITIVE) | BIT(VSYNC_POSITIVE);
403 		VOP_CTRL_SET(vop, mipi_en, 1);
404 		VOP_CTRL_SET(vop, mipi_pin_pol, val);
405 		VOP_CTRL_SET(vop, mipi_dclk_pol, dclk_inv);
406 		VOP_CTRL_SET(vop, mipi_dual_channel_en,
407 			!!(conn_state->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE));
408 		VOP_CTRL_SET(vop, data01_swap,
409 			!!(conn_state->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP) ||
410 			crtc_state->dual_channel_swap);
411 		VOP_CTRL_SET(vop, inf_out_en, 1);
412 		VOP_GRF_SET(vop, vo0_grf_ctrl, grf_mipi_ch_sel, 1);
413 		VOP_GRF_SET(vop, vo0_grf_ctrl, grf_mipi_mode, 1);
414 		VOP_GRF_SET(vop, vo0_grf_ctrl, grf_mipi_pin_pol, val);
415 		VOP_GRF_SET(vop, vo0_grf_ctrl, grf_mipi_1to4_en, 1);
416 		break;
417 	case DRM_MODE_CONNECTOR_DisplayPort:
418 		VOP_CTRL_SET(vop, dp_dclk_pol, 0);
419 		VOP_CTRL_SET(vop, dp_pin_pol, val);
420 		VOP_CTRL_SET(vop, dp_en, 1);
421 		break;
422 	case DRM_MODE_CONNECTOR_TV:
423 		if (vdisplay == CVBS_PAL_VDISPLAY)
424 			VOP_CTRL_SET(vop, tve_sw_mode, 1);
425 		else
426 			VOP_CTRL_SET(vop, tve_sw_mode, 0);
427 		VOP_CTRL_SET(vop, tve_dclk_pol, 1);
428 		VOP_CTRL_SET(vop, tve_dclk_en, 1);
429 		/* use the same pol reg with hdmi */
430 		VOP_CTRL_SET(vop, hdmi_pin_pol, val);
431 		VOP_CTRL_SET(vop, sw_genlock, 1);
432 		VOP_CTRL_SET(vop, sw_uv_offset_en, 1);
433 		VOP_CTRL_SET(vop, dither_up, 1);
434 		break;
435 	default:
436 		printf("unsupport connector_type[%d]\n", conn_state->type);
437 	}
438 
439 	if (conn_state->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
440 	    !(vop_data->feature & VOP_FEATURE_OUTPUT_10BIT))
441 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
442 
443 	switch (conn_state->bus_format) {
444 	case MEDIA_BUS_FMT_RGB565_1X16:
445 		val = DITHER_DOWN_EN(1) | DITHER_DOWN_MODE(RGB888_TO_RGB565);
446 		break;
447 	case MEDIA_BUS_FMT_RGB666_1X18:
448 	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
449 	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
450 	case MEDIA_BUS_FMT_RGB666_1X7X3_JEIDA:
451 		val = DITHER_DOWN_EN(1) | DITHER_DOWN_MODE(RGB888_TO_RGB666);
452 		break;
453 	case MEDIA_BUS_FMT_YUV8_1X24:
454 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
455 		val = DITHER_DOWN_EN(0) | PRE_DITHER_DOWN_EN(1);
456 		break;
457 	case MEDIA_BUS_FMT_YUV10_1X30:
458 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
459 		val = DITHER_DOWN_EN(0) | PRE_DITHER_DOWN_EN(0);
460 		break;
461 	case MEDIA_BUS_FMT_RGB888_1X24:
462 	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
463 	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
464 	default:
465 		val = DITHER_DOWN_EN(0) | PRE_DITHER_DOWN_EN(0);
466 		break;
467 	}
468 	if (conn_state->output_mode == ROCKCHIP_OUT_MODE_AAAA)
469 		val |= PRE_DITHER_DOWN_EN(0);
470 	else
471 		val |= PRE_DITHER_DOWN_EN(1);
472 	val |= DITHER_DOWN_MODE_SEL(DITHER_DOWN_ALLEGRO);
473 	VOP_CTRL_SET(vop, dither_down, val);
474 
475 	VOP_CTRL_SET(vop, dclk_ddr,
476 		     conn_state->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0);
477 	VOP_CTRL_SET(vop, hdmi_dclk_out_en,
478 		     conn_state->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0);
479 
480 	if (is_uv_swap(conn_state->bus_format, conn_state->output_mode) ||
481 	    is_rb_swap(conn_state->bus_format, conn_state->output_mode))
482 		VOP_CTRL_SET(vop, dsp_rb_swap, 1);
483 	else
484 		VOP_CTRL_SET(vop, dsp_data_swap, 0);
485 
486 	VOP_CTRL_SET(vop, out_mode, conn_state->output_mode);
487 
488 	if (VOP_CTRL_SUPPORT(vop, overlay_mode)) {
489 		yuv_overlay = is_yuv_output(conn_state->bus_format);
490 		VOP_CTRL_SET(vop, overlay_mode, yuv_overlay);
491 	}
492 	/*
493 	 * todo: r2y for win csc
494 	 */
495 	VOP_CTRL_SET(vop, dsp_out_yuv, is_yuv_output(conn_state->bus_format));
496 
497 	if (yuv_overlay) {
498 		if (!is_yuv_output(conn_state->bus_format))
499 			post_y2r_en = true;
500 	} else {
501 		if (is_yuv_output(conn_state->bus_format))
502 			post_r2y_en = true;
503 	}
504 
505 	crtc_state->yuv_overlay = yuv_overlay;
506 	post_csc_mode = to_vop_csc_mode(conn_state->color_space);
507 	VOP_CTRL_SET(vop, bcsh_r2y_en, post_r2y_en);
508 	VOP_CTRL_SET(vop, bcsh_y2r_en, post_y2r_en);
509 	VOP_CTRL_SET(vop, bcsh_r2y_csc_mode, post_csc_mode);
510 	VOP_CTRL_SET(vop, bcsh_y2r_csc_mode, post_csc_mode);
511 
512 	/*
513 	 * Background color is 10bit depth if vop version >= 3.5
514 	 */
515 	if (!is_yuv_output(conn_state->bus_format))
516 		val = 0;
517 	else if (VOP_MAJOR(vop->version) == 3 &&
518 		 VOP_MINOR(vop->version) >= 5)
519 		val = 0x20010200;
520 	else
521 		val = 0x801080;
522 	VOP_CTRL_SET(vop, dsp_background, val);
523 
524 	VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len);
525 	val = hact_st << 16;
526 	val |= hact_end;
527 	VOP_CTRL_SET(vop, hact_st_end, val);
528 	val = vact_st << 16;
529 	val |= vact_end;
530 	VOP_CTRL_SET(vop, vact_st_end, val);
531 	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
532 		u16 vact_st_f1 = vtotal + vact_st + 1;
533 		u16 vact_end_f1 = vact_st_f1 + vdisplay;
534 
535 		val = vact_st_f1 << 16 | vact_end_f1;
536 		VOP_CTRL_SET(vop, vact_st_end_f1, val);
537 
538 		val = vtotal << 16 | (vtotal + vsync_len);
539 		VOP_CTRL_SET(vop, vs_st_end_f1, val);
540 		VOP_CTRL_SET(vop, dsp_interlace, 1);
541 		VOP_CTRL_SET(vop, p2i_en, 1);
542 		vtotal += vtotal + 1;
543 		act_end = vact_end_f1;
544 	} else {
545 		VOP_CTRL_SET(vop, dsp_interlace, 0);
546 		VOP_CTRL_SET(vop, p2i_en, 0);
547 		act_end = vact_end;
548 	}
549 	VOP_CTRL_SET(vop, vtotal_pw, (vtotal << 16) | vsync_len);
550 	vop_post_config(state, vop);
551 	VOP_CTRL_SET(vop, core_dclk_div,
552 		     !!(mode->flags & DRM_MODE_FLAG_DBLCLK));
553 
554 	VOP_LINE_FLAG_SET(vop, line_flag_num[0], act_end - 3);
555 	VOP_LINE_FLAG_SET(vop, line_flag_num[1],
556 			  act_end - us_to_vertical_line(mode, 1000));
557 	if (state->crtc_state.mcu_timing.mcu_pix_total > 0)
558 		vop_mcu_mode_setup(state, vop);
559 	vop_cfg_done(vop);
560 
561 	return 0;
562 }
563 
564 static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
565 				  uint32_t dst, bool is_horizontal,
566 				  int vsu_mode, int *vskiplines)
567 {
568 	uint16_t val = 1 << SCL_FT_DEFAULT_FIXPOINT_SHIFT;
569 
570 	if (is_horizontal) {
571 		if (mode == SCALE_UP)
572 			val = GET_SCL_FT_BIC(src, dst);
573 		else if (mode == SCALE_DOWN)
574 			val = GET_SCL_FT_BILI_DN(src, dst);
575 	} else {
576 		if (mode == SCALE_UP) {
577 			if (vsu_mode == SCALE_UP_BIL)
578 				val = GET_SCL_FT_BILI_UP(src, dst);
579 			else
580 				val = GET_SCL_FT_BIC(src, dst);
581 		} else if (mode == SCALE_DOWN) {
582 			if (vskiplines) {
583 				*vskiplines = scl_get_vskiplines(src, dst);
584 				val = scl_get_bili_dn_vskip(src, dst,
585 							    *vskiplines);
586 			} else {
587 				val = GET_SCL_FT_BILI_DN(src, dst);
588 			}
589 		}
590 	}
591 
592 	return val;
593 }
594 
595 static void scl_vop_cal_scl_fac(struct vop *vop,
596 				uint32_t src_w, uint32_t src_h, uint32_t dst_w,
597 				uint32_t dst_h, uint32_t pixel_format)
598 {
599 	uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode;
600 	uint16_t cbcr_hor_scl_mode = SCALE_NONE;
601 	uint16_t cbcr_ver_scl_mode = SCALE_NONE;
602 	int hsub = drm_format_horz_chroma_subsampling(pixel_format);
603 	int vsub = drm_format_vert_chroma_subsampling(pixel_format);
604 	bool is_yuv = false;
605 	uint16_t cbcr_src_w = src_w / hsub;
606 	uint16_t cbcr_src_h = src_h / vsub;
607 	uint16_t vsu_mode;
608 	uint16_t lb_mode;
609 	uint32_t val;
610 	int vskiplines = 0;
611 
612 	if (!vop->win->scl)
613 		return;
614 
615 	if (!vop->win->scl->ext) {
616 		VOP_SCL_SET(vop, scale_yrgb_x,
617 			    scl_cal_scale2(src_w, dst_w));
618 		VOP_SCL_SET(vop, scale_yrgb_y,
619 			    scl_cal_scale2(src_h, dst_h));
620 		if (is_yuv) {
621 			VOP_SCL_SET(vop, scale_cbcr_x,
622 				    scl_cal_scale2(src_w, dst_w));
623 			VOP_SCL_SET(vop, scale_cbcr_y,
624 				    scl_cal_scale2(src_h, dst_h));
625 		}
626 		return;
627 	}
628 
629 	yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
630 	yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
631 
632 	if (is_yuv) {
633 		cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);
634 		cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);
635 		if (cbcr_hor_scl_mode == SCALE_DOWN)
636 			lb_mode = scl_vop_cal_lb_mode(dst_w, true);
637 		else
638 			lb_mode = scl_vop_cal_lb_mode(cbcr_src_w, true);
639 	} else {
640 		if (yrgb_hor_scl_mode == SCALE_DOWN)
641 			lb_mode = scl_vop_cal_lb_mode(dst_w, false);
642 		else
643 			lb_mode = scl_vop_cal_lb_mode(src_w, false);
644 	}
645 
646 	VOP_SCL_SET_EXT(vop, lb_mode, lb_mode);
647 	if (lb_mode == LB_RGB_3840X2) {
648 		if (yrgb_ver_scl_mode != SCALE_NONE) {
649 			printf("ERROR : not allow yrgb ver scale\n");
650 			return;
651 		}
652 		if (cbcr_ver_scl_mode != SCALE_NONE) {
653 			printf("ERROR : not allow cbcr ver scale\n");
654 			return;
655 		}
656 		vsu_mode = SCALE_UP_BIL;
657 	} else if (lb_mode == LB_RGB_2560X4) {
658 		vsu_mode = SCALE_UP_BIL;
659 	} else {
660 		vsu_mode = SCALE_UP_BIC;
661 	}
662 
663 	val = scl_vop_cal_scale(yrgb_hor_scl_mode, src_w, dst_w,
664 				true, 0, NULL);
665 	VOP_SCL_SET(vop, scale_yrgb_x, val);
666 	val = scl_vop_cal_scale(yrgb_ver_scl_mode, src_h, dst_h,
667 				false, vsu_mode, &vskiplines);
668 	VOP_SCL_SET(vop, scale_yrgb_y, val);
669 
670 	VOP_SCL_SET_EXT(vop, vsd_yrgb_gt4, vskiplines == 4);
671 	VOP_SCL_SET_EXT(vop, vsd_yrgb_gt2, vskiplines == 2);
672 
673 	VOP_SCL_SET_EXT(vop, yrgb_hor_scl_mode, yrgb_hor_scl_mode);
674 	VOP_SCL_SET_EXT(vop, yrgb_ver_scl_mode, yrgb_ver_scl_mode);
675 	VOP_SCL_SET_EXT(vop, yrgb_hsd_mode, SCALE_DOWN_BIL);
676 	VOP_SCL_SET_EXT(vop, yrgb_vsd_mode, SCALE_DOWN_BIL);
677 	VOP_SCL_SET_EXT(vop, yrgb_vsu_mode, vsu_mode);
678 	if (is_yuv) {
679 		val = scl_vop_cal_scale(cbcr_hor_scl_mode, cbcr_src_w,
680 					dst_w, true, 0, NULL);
681 		VOP_SCL_SET(vop, scale_cbcr_x, val);
682 		val = scl_vop_cal_scale(cbcr_ver_scl_mode, cbcr_src_h,
683 					dst_h, false, vsu_mode, &vskiplines);
684 		VOP_SCL_SET(vop, scale_cbcr_y, val);
685 
686 		VOP_SCL_SET_EXT(vop, vsd_cbcr_gt4, vskiplines == 4);
687 		VOP_SCL_SET_EXT(vop, vsd_cbcr_gt2, vskiplines == 2);
688 		VOP_SCL_SET_EXT(vop, cbcr_hor_scl_mode, cbcr_hor_scl_mode);
689 		VOP_SCL_SET_EXT(vop, cbcr_ver_scl_mode, cbcr_ver_scl_mode);
690 		VOP_SCL_SET_EXT(vop, cbcr_hsd_mode, SCALE_DOWN_BIL);
691 		VOP_SCL_SET_EXT(vop, cbcr_vsd_mode, SCALE_DOWN_BIL);
692 		VOP_SCL_SET_EXT(vop, cbcr_vsu_mode, vsu_mode);
693 	}
694 }
695 
696 static void vop_load_csc_table(struct vop *vop, u32 offset, const u32 *table)
697 {
698 	int i;
699 
700 	/*
701 	 * so far the csc offset is not 0 and in the feature the csc offset
702 	 * impossible be 0, so when the offset is 0, should return here.
703 	 */
704 	if (!table || offset == 0)
705 		return;
706 
707 	for (i = 0; i < 8; i++)
708 		vop_writel(vop, offset + i * 4, table[i]);
709 }
710 
711 static int rockchip_vop_setup_csc_table(struct display_state *state)
712 {
713 	struct crtc_state *crtc_state = &state->crtc_state;
714 	struct connector_state *conn_state = &state->conn_state;
715 	struct vop *vop = crtc_state->private;
716 	const uint32_t *csc_table = NULL;
717 
718 	if (!vop->csc_table || !crtc_state->yuv_overlay)
719 		return 0;
720 	/* todo: only implement r2y*/
721 	switch (conn_state->color_space) {
722 	case V4L2_COLORSPACE_SMPTE170M:
723 		csc_table = vop->csc_table->r2y_bt601_12_235;
724 		break;
725 	case V4L2_COLORSPACE_REC709:
726 	case V4L2_COLORSPACE_DEFAULT:
727 	case V4L2_COLORSPACE_JPEG:
728 		csc_table = vop->csc_table->r2y_bt709;
729 		break;
730 	case V4L2_COLORSPACE_BT2020:
731 		csc_table = vop->csc_table->r2y_bt2020;
732 		break;
733 	default:
734 		csc_table = vop->csc_table->r2y_bt601;
735 		break;
736 	}
737 
738 	vop_load_csc_table(vop, vop->win_csc->r2y_offset, csc_table);
739 	VOP_WIN_CSC_SET(vop, r2y_en, 1);
740 
741 	return 0;
742 }
743 
744 static int rockchip_vop_set_plane(struct display_state *state)
745 {
746 	struct crtc_state *crtc_state = &state->crtc_state;
747 	const struct rockchip_crtc *crtc = crtc_state->crtc;
748 	const struct vop_data *vop_data = crtc->data;
749 	struct connector_state *conn_state = &state->conn_state;
750 	struct drm_display_mode *mode = &conn_state->mode;
751 	u32 act_info, dsp_info, dsp_st, dsp_stx, dsp_sty;
752 	struct vop *vop = crtc_state->private;
753 	int src_w = crtc_state->src_rect.w;
754 	int src_h = crtc_state->src_rect.h;
755 	int crtc_x = crtc_state->crtc_rect.x;
756 	int crtc_y = crtc_state->crtc_rect.y;
757 	int crtc_w = crtc_state->crtc_rect.w;
758 	int crtc_h = crtc_state->crtc_rect.h;
759 	int xvir = crtc_state->xvir;
760 	int x_mirror = 0, y_mirror = 0;
761 
762 	if (crtc_w > crtc_state->max_output.width) {
763 		printf("ERROR: output w[%d] exceeded max width[%d]\n",
764 		       crtc_w, crtc_state->max_output.width);
765 		return -EINVAL;
766 	}
767 
768 	if ((vop->version == VOP_VERSION(2, 2) || vop->version == VOP_VERSION(2, 0xd)) &&
769 	    (mode->flags & DRM_MODE_FLAG_INTERLACE))
770 		crtc_h = crtc_h / 2;
771 
772 	act_info = (src_h - 1) << 16;
773 	act_info |= (src_w - 1) & 0xffff;
774 
775 	dsp_info = (crtc_h - 1) << 16;
776 	dsp_info |= (crtc_w - 1) & 0xffff;
777 
778 	dsp_stx = crtc_x + mode->crtc_htotal - mode->crtc_hsync_start;
779 	dsp_sty = crtc_y + mode->crtc_vtotal - mode->crtc_vsync_start;
780 	if ((vop->version == VOP_VERSION(2, 2) || vop->version == VOP_VERSION(2, 0xd)) &&
781 	    (mode->flags & DRM_MODE_FLAG_INTERLACE))
782 		dsp_sty = crtc_y / 2 + mode->crtc_vtotal - mode->crtc_vsync_start;
783 	dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff);
784 	/*
785 	 * vop full need to treats rgb888 as bgr888 so we reverse the rb swap to workaround
786 	 */
787 	if (crtc_state->format == ROCKCHIP_FMT_RGB888 && VOP_MAJOR(vop_data->version) == 3)
788 		crtc_state->rb_swap = !crtc_state->rb_swap;
789 
790 	if (mode->flags & DRM_MODE_FLAG_YMIRROR)
791 		y_mirror = 1;
792 	else
793 		y_mirror = 0;
794 	if (mode->flags & DRM_MODE_FLAG_XMIRROR)
795 		x_mirror = 1;
796 	else
797 		x_mirror = 0;
798 	if (crtc_state->ymirror ^ y_mirror)
799 		y_mirror = 1;
800 	else
801 		y_mirror = 0;
802 	if (y_mirror) {
803 		if (VOP_CTRL_SUPPORT(vop, ymirror))
804 			crtc_state->dma_addr += (src_h - 1) * xvir * 4;
805 		else
806 			y_mirror = 0;
807 		}
808 	VOP_CTRL_SET(vop, ymirror, y_mirror);
809 	VOP_CTRL_SET(vop, xmirror, x_mirror);
810 
811 	VOP_WIN_SET(vop, format, crtc_state->format);
812 	VOP_WIN_SET(vop, yrgb_vir, xvir);
813 	VOP_WIN_SET(vop, yrgb_mst, crtc_state->dma_addr);
814 
815 	scl_vop_cal_scl_fac(vop, src_w, src_h, crtc_w, crtc_h,
816 			    crtc_state->format);
817 
818 	VOP_WIN_SET(vop, act_info, act_info);
819 	VOP_WIN_SET(vop, dsp_info, dsp_info);
820 	VOP_WIN_SET(vop, dsp_st, dsp_st);
821 	VOP_WIN_SET(vop, rb_swap, crtc_state->rb_swap);
822 
823 	VOP_WIN_SET(vop, src_alpha_ctl, 0);
824 
825 	rockchip_vop_setup_csc_table(state);
826 	VOP_WIN_SET(vop, enable, 1);
827 	VOP_WIN_SET(vop, gate, 1);
828 	vop_cfg_done(vop);
829 
830 	return 0;
831 }
832 
833 static int rockchip_vop_prepare(struct display_state *state)
834 {
835 	return 0;
836 }
837 
838 static int rockchip_vop_enable(struct display_state *state)
839 {
840 	struct crtc_state *crtc_state = &state->crtc_state;
841 	struct vop *vop = crtc_state->private;
842 
843 	VOP_CTRL_SET(vop, standby, 0);
844 	vop_cfg_done(vop);
845 	if (crtc_state->mcu_timing.mcu_pix_total > 0)
846 		VOP_CTRL_SET(vop, mcu_hold_mode, 0);
847 
848 	return 0;
849 }
850 
851 static int rockchip_vop_disable(struct display_state *state)
852 {
853 	struct crtc_state *crtc_state = &state->crtc_state;
854 	struct vop *vop = crtc_state->private;
855 
856 	VOP_CTRL_SET(vop, standby, 1);
857 	vop_cfg_done(vop);
858 	return 0;
859 }
860 
861 static int rockchip_vop_fixup_dts(struct display_state *state, void *blob)
862 {
863 #if 0
864 	struct crtc_state *crtc_state = &state->crtc_state;
865 	struct panel_state *pstate = &state->panel_state;
866 	uint32_t phandle;
867 	char path[100];
868 	int ret, dsp_lut_node;
869 
870 	if (!ofnode_valid(pstate->dsp_lut_node))
871 		return 0;
872 	ret = fdt_get_path(state->blob, pstate->dsp_lut_node, path, sizeof(path));
873 	if (ret < 0) {
874 		printf("failed to get dsp_lut path[%s], ret=%d\n",
875 			path, ret);
876 		return ret;
877 	}
878 
879 	dsp_lut_node = fdt_path_offset(blob, path);
880 	phandle = fdt_get_phandle(blob, dsp_lut_node);
881 	if (!phandle) {
882 		phandle = fdt_alloc_phandle(blob);
883 		if (!phandle) {
884 			printf("failed to alloc phandle\n");
885 			return -ENOMEM;
886 		}
887 
888 		fdt_set_phandle(blob, dsp_lut_node, phandle);
889 	}
890 
891 	ret = fdt_get_path(state->blob, crtc_state->node, path, sizeof(path));
892 	if (ret < 0) {
893 		printf("failed to get route path[%s], ret=%d\n",
894 			path, ret);
895 		return ret;
896 	}
897 
898 	do_fixup_by_path_u32(blob, path, "dsp-lut", phandle, 1);
899 #endif
900 	return 0;
901 }
902 
903 static int rockchip_vop_send_mcu_cmd(struct display_state *state, u32 type, u32 value)
904 {
905 	struct crtc_state *crtc_state = &state->crtc_state;
906 	struct connector_state *conn_state = &state->conn_state;
907 	struct drm_display_mode *mode = &conn_state->mode;
908 	struct vop *vop = crtc_state->private;
909 	int ret;
910 
911 	if (vop->version == VOP_VERSION(2, 0xd)) {
912 		/*
913 		 * 1.set mcu bypass mode timing.
914 		 * 2.set dclk rate to 150M.
915 		 */
916 		if ((type == MCU_SETBYPASS) && value) {
917 			vop_mcu_bypass_mode_setup(state, vop);
918 			ret = clk_set_rate(&crtc_state->dclk, 150000000);
919 			if (IS_ERR_VALUE(ret)) {
920 				printf("%s: Failed to set dclk: ret=%d\n", __func__, ret);
921 				return ret;
922 			}
923 		}
924 	}
925 
926 	if (vop) {
927 		switch (type) {
928 		case MCU_WRCMD:
929 			set_vop_mcu_rs(vop, 0);
930 			VOP_CTRL_SET(vop, mcu_rw_bypass_port, value);
931 			set_vop_mcu_rs(vop, 1);
932 			break;
933 		case MCU_WRDATA:
934 			set_vop_mcu_rs(vop, 1);
935 			VOP_CTRL_SET(vop, mcu_rw_bypass_port, value);
936 			break;
937 		case MCU_SETBYPASS:
938 			VOP_CTRL_SET(vop, mcu_bypass, value ? 1 : 0);
939 			break;
940 		default:
941 			break;
942 		}
943 	}
944 
945 	if (vop->version == VOP_VERSION(2, 0xd)) {
946 		/*
947 		 * 1.restore mcu data mode timing.
948 		 * 2.restore dclk rate to crtc_clock.
949 		 */
950 		if ((type == MCU_SETBYPASS) && !value) {
951 			vop_mcu_mode_setup(state, vop);
952 			ret = clk_set_rate(&crtc_state->dclk, mode->crtc_clock * 1000);
953 			if (IS_ERR_VALUE(ret)) {
954 				printf("%s: Failed to set dclk: ret=%d\n", __func__, ret);
955 				return ret;
956 			}
957 		}
958 	}
959 
960 	return 0;
961 }
962 
963 static int rockchip_vop_mode_valid(struct display_state *state)
964 {
965 	struct connector_state *conn_state = &state->conn_state;
966 	struct drm_display_mode *mode = &conn_state->mode;
967 	struct videomode vm;
968 
969 	drm_display_mode_to_videomode(mode, &vm);
970 
971 	if (vm.hactive < 32 || vm.vactive < 32 ||
972 	    (vm.hfront_porch * vm.hsync_len * vm.hback_porch *
973 	     vm.vfront_porch * vm.vsync_len * vm.vback_porch == 0)) {
974 		printf("ERROR: unsupported display timing\n");
975 		return -EINVAL;
976 	}
977 
978 	return 0;
979 }
980 
981 static int rockchip_vop_plane_check(struct display_state *state)
982 {
983 	struct crtc_state *crtc_state = &state->crtc_state;
984 	const struct rockchip_crtc *crtc = crtc_state->crtc;
985 	const struct vop_data *vop_data = crtc->data;
986 	const struct vop_win *win = vop_data->win;
987 	struct display_rect *src = &crtc_state->src_rect;
988 	struct display_rect *dst = &crtc_state->crtc_rect;
989 	int min_scale, max_scale;
990 	int hscale, vscale;
991 
992 	min_scale = win->scl ? FRAC_16_16(1, 8) : VOP_PLANE_NO_SCALING;
993 	max_scale = win->scl ? FRAC_16_16(8, 1) : VOP_PLANE_NO_SCALING;
994 
995 	hscale = display_rect_calc_hscale(src, dst, min_scale, max_scale);
996 	vscale = display_rect_calc_vscale(src, dst, min_scale, max_scale);
997 	if (hscale < 0 || vscale < 0) {
998 		printf("ERROR: scale factor is out of range\n");
999 		return -ERANGE;
1000 	}
1001 
1002 	return 0;
1003 }
1004 
1005 static int rockchip_vop_mode_fixup(struct display_state *state)
1006 {
1007 	struct crtc_state *crtc_state = &state->crtc_state;
1008 	struct connector_state *conn_state = &state->conn_state;
1009 	struct drm_display_mode *mode = &conn_state->mode;
1010 
1011 	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
1012 
1013 	mode->crtc_clock *= rockchip_drm_get_cycles_per_pixel(conn_state->bus_format);
1014 	if (crtc_state->mcu_timing.mcu_pix_total)
1015 		mode->crtc_clock *= crtc_state->mcu_timing.mcu_pix_total + 1;
1016 
1017 	return 0;
1018 }
1019 
1020 const struct rockchip_crtc_funcs rockchip_vop_funcs = {
1021 	.preinit = rockchip_vop_preinit,
1022 	.init = rockchip_vop_init,
1023 	.set_plane = rockchip_vop_set_plane,
1024 	.prepare = rockchip_vop_prepare,
1025 	.enable = rockchip_vop_enable,
1026 	.disable = rockchip_vop_disable,
1027 	.fixup_dts = rockchip_vop_fixup_dts,
1028 	.send_mcu_cmd = rockchip_vop_send_mcu_cmd,
1029 	.mode_valid = rockchip_vop_mode_valid,
1030 	.plane_check = rockchip_vop_plane_check,
1031 	.mode_fixup = rockchip_vop_mode_fixup,
1032 };
1033