xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_vop.c (revision 15a7587bba2ffa33a2e08d02a707fe54b7e24d94)
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 
23 #include "rockchip_display.h"
24 #include "rockchip_crtc.h"
25 #include "rockchip_connector.h"
26 #include "rockchip_vop.h"
27 
28 static inline int us_to_vertical_line(struct drm_display_mode *mode, int us)
29 {
30 	return us * mode->clock / mode->htotal / 1000;
31 }
32 
33 static int rockchip_vop_init_gamma(struct vop *vop, struct display_state *state)
34 {
35 	struct crtc_state *crtc_state = &state->crtc_state;
36 	struct connector_state *conn_state = &state->conn_state;
37 	u32 *lut = conn_state->gamma.lut;
38 	fdt_size_t lut_size;
39 	int i, lut_len;
40 	u32 *lut_regs;
41 
42 	if (!conn_state->gamma.lut)
43 		return 0;
44 
45 	i = dev_read_stringlist_search(crtc_state->dev, "reg-names", "gamma_lut");
46 	if (i < 0) {
47 		printf("Warning: vop not support gamma\n");
48 		return 0;
49 	}
50 	lut_regs = (u32 *)dev_read_addr_size(crtc_state->dev, "reg", &lut_size);
51 	if (lut_regs == (u32 *)FDT_ADDR_T_NONE) {
52 		printf("failed to get gamma lut register\n");
53 		return 0;
54 	}
55 	lut_len = lut_size / 4;
56 	if (lut_len != 256 && lut_len != 1024) {
57 		printf("Warning: unsupport gamma lut table[%d]\n", lut_len);
58 		return 0;
59 	}
60 
61 	if (conn_state->gamma.size != lut_len) {
62 		int size = conn_state->gamma.size;
63 		u32 j, r, g, b, color;
64 
65 		for (i = 0; i < lut_len; i++) {
66 			j = i * size / lut_len;
67 			r = lut[j] / size / size * lut_len / size;
68 			g = lut[j] / size % size * lut_len / size;
69 			b = lut[j] % size * lut_len / size;
70 			color = r * lut_len * lut_len + g * lut_len + b;
71 
72 			writel(color, lut_regs + (i << 2));
73 		}
74 	} else {
75 		for (i = 0; i < lut_len; i++)
76 			writel(lut[i], lut_regs + (i << 2));
77 	}
78 
79 	VOP_CTRL_SET(vop, dsp_lut_en, 1);
80 	VOP_CTRL_SET(vop, update_gamma_lut, 1);
81 
82 	return 0;
83 }
84 
85 static int rockchip_vop_init(struct display_state *state)
86 {
87 	struct crtc_state *crtc_state = &state->crtc_state;
88 	struct connector_state *conn_state = &state->conn_state;
89 	struct drm_display_mode *mode = &conn_state->mode;
90 	const struct rockchip_crtc *crtc = crtc_state->crtc;
91 	const struct vop_data *vop_data = crtc->data;
92 	struct vop *vop;
93 	u16 hsync_len = mode->hsync_end - mode->hsync_start;
94 	u16 hdisplay = mode->hdisplay;
95 	u16 htotal = mode->htotal;
96 	u16 hact_st = mode->htotal - mode->hsync_start;
97 	u16 hact_end = hact_st + hdisplay;
98 	u16 vdisplay = mode->vdisplay;
99 	u16 vtotal = mode->vtotal;
100 	u16 vsync_len = mode->vsync_end - mode->vsync_start;
101 	u16 vact_st = mode->vtotal - mode->vsync_start;
102 	u16 vact_end = vact_st + vdisplay;
103 	struct clk dclk, aclk;
104 	u32 val;
105 	int ret;
106 
107 	vop = malloc(sizeof(*vop));
108 	if (!vop)
109 		return -ENOMEM;
110 	memset(vop, 0, sizeof(*vop));
111 
112 	crtc_state->private = vop;
113 	vop->regs = dev_read_addr_ptr(crtc_state->dev);
114 	vop->regsbak = malloc(vop_data->reg_len);
115 	vop->win = vop_data->win;
116 	vop->win_offset = vop_data->win_offset;
117 	vop->ctrl = vop_data->ctrl;
118 	vop->line_flag = vop_data->line_flag;
119 	vop->version = vop_data->version;
120 
121 	/*
122 	 * TODO:
123 	 * Set Dclk pll parent
124 	 */
125 
126 	ret = clk_get_by_name(crtc_state->dev, "dclk_vop", &dclk);
127 	if (!ret)
128 		ret = clk_set_rate(&dclk, mode->clock * 1000);
129 	if (IS_ERR_VALUE(ret)) {
130 		printf("%s: Failed to set dclk: ret=%d\n", __func__, ret);
131 		return ret;
132 	}
133 
134 	ret = clk_get_by_name(crtc_state->dev, "aclk_vop", &aclk);
135 	if (!ret)
136 		ret = clk_set_rate(&aclk, 400 * 1000 * 1000);
137 	if (IS_ERR_VALUE(ret))
138 		printf("%s: Failed to set aclk: ret=%d\n", __func__, ret);
139 
140 	memcpy(vop->regsbak, vop->regs, vop_data->reg_len);
141 
142 	rockchip_vop_init_gamma(vop, state);
143 
144 	VOP_CTRL_SET(vop, global_regdone_en, 1);
145 	VOP_CTRL_SET(vop, win_gate[0], 1);
146 	VOP_CTRL_SET(vop, win_gate[1], 1);
147 	VOP_CTRL_SET(vop, dsp_blank, 0);
148 
149 	val = 0x8;
150 	val |= (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
151 	val |= (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
152 	VOP_CTRL_SET(vop, pin_pol, val);
153 
154 	switch (conn_state->type) {
155 	case DRM_MODE_CONNECTOR_LVDS:
156 		VOP_CTRL_SET(vop, rgb_en, 1);
157 		VOP_CTRL_SET(vop, rgb_pin_pol, val);
158 		break;
159 	case DRM_MODE_CONNECTOR_eDP:
160 		VOP_CTRL_SET(vop, edp_en, 1);
161 		VOP_CTRL_SET(vop, edp_pin_pol, val);
162 		break;
163 	case DRM_MODE_CONNECTOR_HDMIA:
164 		VOP_CTRL_SET(vop, hdmi_en, 1);
165 		VOP_CTRL_SET(vop, hdmi_pin_pol, val);
166 		break;
167 	case DRM_MODE_CONNECTOR_DSI:
168 		VOP_CTRL_SET(vop, mipi_en, 1);
169 		VOP_CTRL_SET(vop, mipi_pin_pol, val);
170 		VOP_CTRL_SET(vop, mipi_dual_channel_en,
171 			!!(conn_state->output_type & ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL));
172 		VOP_CTRL_SET(vop, data01_swap,
173 			!!(conn_state->output_type & ROCKCHIP_OUTPUT_DSI_DUAL_LINK));
174 		break;
175 	default:
176 		printf("unsupport connector_type[%d]\n", conn_state->type);
177 	}
178 
179 	if (conn_state->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
180 	    !(vop_data->feature & VOP_FEATURE_OUTPUT_10BIT))
181 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
182 
183 	switch (conn_state->bus_format) {
184 	case MEDIA_BUS_FMT_RGB565_1X16:
185 		val = DITHER_DOWN_EN(1) | DITHER_DOWN_MODE(RGB888_TO_RGB565);
186 		break;
187 	case MEDIA_BUS_FMT_RGB666_1X18:
188 	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
189 		val = DITHER_DOWN_EN(1) | DITHER_DOWN_MODE(RGB888_TO_RGB666);
190 		break;
191 	case MEDIA_BUS_FMT_RGB888_1X24:
192 	default:
193 		val = DITHER_DOWN_EN(0) | PRE_DITHER_DOWN_EN(0);
194 		break;
195 	}
196 	if (conn_state->output_mode == ROCKCHIP_OUT_MODE_AAAA)
197 		val |= PRE_DITHER_DOWN_EN(0);
198 	else
199 		val |= PRE_DITHER_DOWN_EN(1);
200 	val |= DITHER_DOWN_MODE_SEL(DITHER_DOWN_ALLEGRO);
201 	VOP_CTRL_SET(vop, dither_down, val);
202 
203 	VOP_CTRL_SET(vop, out_mode, conn_state->output_mode);
204 	VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len);
205 	val = hact_st << 16;
206 	val |= hact_end;
207 	VOP_CTRL_SET(vop, hact_st_end, val);
208 	VOP_CTRL_SET(vop, hpost_st_end, val);
209 	VOP_CTRL_SET(vop, vtotal_pw, (vtotal << 16) | vsync_len);
210 	val = vact_st << 16;
211 	val |= vact_end;
212 	VOP_CTRL_SET(vop, vact_st_end, val);
213 	VOP_CTRL_SET(vop, vpost_st_end, val);
214 	VOP_CTRL_SET(vop, standby, 1);
215 	VOP_LINE_FLAG_SET(vop, line_flag_num[0], vact_end - 3);
216 	VOP_LINE_FLAG_SET(vop, line_flag_num[1],
217 			  vact_end - us_to_vertical_line(mode, 1000));
218 	vop_cfg_done(vop);
219 
220 	return 0;
221 }
222 
223 static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
224 				  uint32_t dst, bool is_horizontal,
225 				  int vsu_mode, int *vskiplines)
226 {
227 	uint16_t val = 1 << SCL_FT_DEFAULT_FIXPOINT_SHIFT;
228 
229 	if (is_horizontal) {
230 		if (mode == SCALE_UP)
231 			val = GET_SCL_FT_BIC(src, dst);
232 		else if (mode == SCALE_DOWN)
233 			val = GET_SCL_FT_BILI_DN(src, dst);
234 	} else {
235 		if (mode == SCALE_UP) {
236 			if (vsu_mode == SCALE_UP_BIL)
237 				val = GET_SCL_FT_BILI_UP(src, dst);
238 			else
239 				val = GET_SCL_FT_BIC(src, dst);
240 		} else if (mode == SCALE_DOWN) {
241 			if (vskiplines) {
242 				*vskiplines = scl_get_vskiplines(src, dst);
243 				val = scl_get_bili_dn_vskip(src, dst,
244 							    *vskiplines);
245 			} else {
246 				val = GET_SCL_FT_BILI_DN(src, dst);
247 			}
248 		}
249 	}
250 
251 	return val;
252 }
253 
254 static void scl_vop_cal_scl_fac(struct vop *vop,
255 				uint32_t src_w, uint32_t src_h, uint32_t dst_w,
256 				uint32_t dst_h, uint32_t pixel_format)
257 {
258 	uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode;
259 	uint16_t cbcr_hor_scl_mode = SCALE_NONE;
260 	uint16_t cbcr_ver_scl_mode = SCALE_NONE;
261 	int hsub = drm_format_horz_chroma_subsampling(pixel_format);
262 	int vsub = drm_format_vert_chroma_subsampling(pixel_format);
263 	bool is_yuv = false;
264 	uint16_t cbcr_src_w = src_w / hsub;
265 	uint16_t cbcr_src_h = src_h / vsub;
266 	uint16_t vsu_mode;
267 	uint16_t lb_mode;
268 	uint32_t val;
269 	int vskiplines = 0;
270 
271 	if (!vop->win->scl)
272 		return;
273 
274 	if (dst_w > 3840) {
275 		printf("Maximum destination width (3840) exceeded\n");
276 		return;
277 	}
278 
279 	if (!vop->win->scl->ext) {
280 		VOP_SCL_SET(vop, scale_yrgb_x,
281 			    scl_cal_scale2(src_w, dst_w));
282 		VOP_SCL_SET(vop, scale_yrgb_y,
283 			    scl_cal_scale2(src_h, dst_h));
284 		if (is_yuv) {
285 			VOP_SCL_SET(vop, scale_cbcr_x,
286 				    scl_cal_scale2(src_w, dst_w));
287 			VOP_SCL_SET(vop, scale_cbcr_y,
288 				    scl_cal_scale2(src_h, dst_h));
289 		}
290 		return;
291 	}
292 
293 	yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
294 	yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
295 
296 	if (is_yuv) {
297 		cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);
298 		cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);
299 		if (cbcr_hor_scl_mode == SCALE_DOWN)
300 			lb_mode = scl_vop_cal_lb_mode(dst_w, true);
301 		else
302 			lb_mode = scl_vop_cal_lb_mode(cbcr_src_w, true);
303 	} else {
304 		if (yrgb_hor_scl_mode == SCALE_DOWN)
305 			lb_mode = scl_vop_cal_lb_mode(dst_w, false);
306 		else
307 			lb_mode = scl_vop_cal_lb_mode(src_w, false);
308 	}
309 
310 	VOP_SCL_SET_EXT(vop, lb_mode, lb_mode);
311 	if (lb_mode == LB_RGB_3840X2) {
312 		if (yrgb_ver_scl_mode != SCALE_NONE) {
313 			printf("ERROR : not allow yrgb ver scale\n");
314 			return;
315 		}
316 		if (cbcr_ver_scl_mode != SCALE_NONE) {
317 			printf("ERROR : not allow cbcr ver scale\n");
318 			return;
319 		}
320 		vsu_mode = SCALE_UP_BIL;
321 	} else if (lb_mode == LB_RGB_2560X4) {
322 		vsu_mode = SCALE_UP_BIL;
323 	} else {
324 		vsu_mode = SCALE_UP_BIC;
325 	}
326 
327 	val = scl_vop_cal_scale(yrgb_hor_scl_mode, src_w, dst_w,
328 				true, 0, NULL);
329 	VOP_SCL_SET(vop, scale_yrgb_x, val);
330 	val = scl_vop_cal_scale(yrgb_ver_scl_mode, src_h, dst_h,
331 				false, vsu_mode, &vskiplines);
332 	VOP_SCL_SET(vop, scale_yrgb_y, val);
333 
334 	VOP_SCL_SET_EXT(vop, vsd_yrgb_gt4, vskiplines == 4);
335 	VOP_SCL_SET_EXT(vop, vsd_yrgb_gt2, vskiplines == 2);
336 
337 	VOP_SCL_SET_EXT(vop, yrgb_hor_scl_mode, yrgb_hor_scl_mode);
338 	VOP_SCL_SET_EXT(vop, yrgb_ver_scl_mode, yrgb_ver_scl_mode);
339 	VOP_SCL_SET_EXT(vop, yrgb_hsd_mode, SCALE_DOWN_BIL);
340 	VOP_SCL_SET_EXT(vop, yrgb_vsd_mode, SCALE_DOWN_BIL);
341 	VOP_SCL_SET_EXT(vop, yrgb_vsu_mode, vsu_mode);
342 	if (is_yuv) {
343 		val = scl_vop_cal_scale(cbcr_hor_scl_mode, cbcr_src_w,
344 					dst_w, true, 0, NULL);
345 		VOP_SCL_SET(vop, scale_cbcr_x, val);
346 		val = scl_vop_cal_scale(cbcr_ver_scl_mode, cbcr_src_h,
347 					dst_h, false, vsu_mode, &vskiplines);
348 		VOP_SCL_SET(vop, scale_cbcr_y, val);
349 
350 		VOP_SCL_SET_EXT(vop, vsd_cbcr_gt4, vskiplines == 4);
351 		VOP_SCL_SET_EXT(vop, vsd_cbcr_gt2, vskiplines == 2);
352 		VOP_SCL_SET_EXT(vop, cbcr_hor_scl_mode, cbcr_hor_scl_mode);
353 		VOP_SCL_SET_EXT(vop, cbcr_ver_scl_mode, cbcr_ver_scl_mode);
354 		VOP_SCL_SET_EXT(vop, cbcr_hsd_mode, SCALE_DOWN_BIL);
355 		VOP_SCL_SET_EXT(vop, cbcr_vsd_mode, SCALE_DOWN_BIL);
356 		VOP_SCL_SET_EXT(vop, cbcr_vsu_mode, vsu_mode);
357 	}
358 }
359 
360 static int rockchip_vop_set_plane(struct display_state *state)
361 {
362 	struct crtc_state *crtc_state = &state->crtc_state;
363 	struct connector_state *conn_state = &state->conn_state;
364 	struct drm_display_mode *mode = &conn_state->mode;
365 	u32 act_info, dsp_info, dsp_st, dsp_stx, dsp_sty;
366 	struct vop *vop = crtc_state->private;
367 	int src_w = crtc_state->src_w;
368 	int src_h = crtc_state->src_h;
369 	int crtc_x = crtc_state->crtc_x;
370 	int crtc_y = crtc_state->crtc_y;
371 	int crtc_w = crtc_state->crtc_w;
372 	int crtc_h = crtc_state->crtc_h;
373 	int xvir = crtc_state->xvir;
374 
375 	act_info = (src_h - 1) << 16;
376 	act_info |= (src_w - 1) & 0xffff;
377 
378 	dsp_info = (crtc_h - 1) << 16;
379 	dsp_info |= (crtc_w - 1) & 0xffff;
380 
381 	dsp_stx = crtc_x + mode->htotal - mode->hsync_start;
382 	dsp_sty = crtc_y + mode->vtotal - mode->vsync_start;
383 	dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff);
384 
385 	if (crtc_state->ymirror)
386 		crtc_state->dma_addr += (src_h - 1) * xvir * 4;
387 	VOP_WIN_SET(vop, ymirror, crtc_state->ymirror);
388 	VOP_WIN_SET(vop, format, crtc_state->format);
389 	VOP_WIN_SET(vop, yrgb_vir, xvir);
390 	VOP_WIN_SET(vop, yrgb_mst, crtc_state->dma_addr);
391 
392 	scl_vop_cal_scl_fac(vop, src_w, src_h, crtc_w, crtc_h,
393 			    crtc_state->format);
394 
395 	VOP_WIN_SET(vop, act_info, act_info);
396 	VOP_WIN_SET(vop, dsp_info, dsp_info);
397 	VOP_WIN_SET(vop, dsp_st, dsp_st);
398 	VOP_WIN_SET(vop, rb_swap, crtc_state->rb_swap);
399 
400 	VOP_WIN_SET(vop, src_alpha_ctl, 0);
401 
402 	VOP_WIN_SET(vop, enable, 1);
403 	vop_cfg_done(vop);
404 
405 	return 0;
406 }
407 
408 static int rockchip_vop_prepare(struct display_state *state)
409 {
410 	return 0;
411 }
412 
413 static int rockchip_vop_enable(struct display_state *state)
414 {
415 	struct crtc_state *crtc_state = &state->crtc_state;
416 	struct vop *vop = crtc_state->private;
417 
418 	VOP_CTRL_SET(vop, standby, 0);
419 	vop_cfg_done(vop);
420 
421 	return 0;
422 }
423 
424 static int rockchip_vop_disable(struct display_state *state)
425 {
426 	struct crtc_state *crtc_state = &state->crtc_state;
427 	struct vop *vop = crtc_state->private;
428 
429 	VOP_CTRL_SET(vop, standby, 1);
430 	vop_cfg_done(vop);
431 	return 0;
432 }
433 
434 static int rockchip_vop_fixup_dts(struct display_state *state, void *blob)
435 {
436 #if 0
437 	struct crtc_state *crtc_state = &state->crtc_state;
438 	struct panel_state *pstate = &state->panel_state;
439 	uint32_t phandle;
440 	char path[100];
441 	int ret, dsp_lut_node;
442 
443 	if (!ofnode_valid(pstate->dsp_lut_node))
444 		return 0;
445 	ret = fdt_get_path(state->blob, pstate->dsp_lut_node, path, sizeof(path));
446 	if (ret < 0) {
447 		printf("failed to get dsp_lut path[%s], ret=%d\n",
448 			path, ret);
449 		return ret;
450 	}
451 
452 	dsp_lut_node = fdt_path_offset(blob, path);
453 	phandle = fdt_get_phandle(blob, dsp_lut_node);
454 	if (!phandle) {
455 		phandle = fdt_alloc_phandle(blob);
456 		if (!phandle) {
457 			printf("failed to alloc phandle\n");
458 			return -ENOMEM;
459 		}
460 
461 		fdt_set_phandle(blob, dsp_lut_node, phandle);
462 	}
463 
464 	ret = fdt_get_path(state->blob, crtc_state->node, path, sizeof(path));
465 	if (ret < 0) {
466 		printf("failed to get route path[%s], ret=%d\n",
467 			path, ret);
468 		return ret;
469 	}
470 
471 	do_fixup_by_path_u32(blob, path, "dsp-lut", phandle, 1);
472 #endif
473 	return 0;
474 }
475 
476 const struct rockchip_crtc_funcs rockchip_vop_funcs = {
477 	.init = rockchip_vop_init,
478 	.set_plane = rockchip_vop_set_plane,
479 	.prepare = rockchip_vop_prepare,
480 	.enable = rockchip_vop_enable,
481 	.disable = rockchip_vop_disable,
482 	.fixup_dts = rockchip_vop_fixup_dts,
483 };
484