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