xref: /OK3568_Linux_fs/kernel/drivers/misc/rk628/rk628_post_process.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Author: Wyon Bi <bivvy.bi@rock-chips.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #include "rk628.h"
8*4882a593Smuzhiyun #include "rk628_config.h"
9*4882a593Smuzhiyun #include "rk628_cru.h"
10*4882a593Smuzhiyun 
calc_dsp_frm_hst_vst(const struct rk628_display_mode * src,const struct rk628_display_mode * dst,u32 * dsp_frame_hst,u32 * dsp_frame_vst)11*4882a593Smuzhiyun static void calc_dsp_frm_hst_vst(const struct rk628_display_mode *src,
12*4882a593Smuzhiyun 				 const struct rk628_display_mode *dst,
13*4882a593Smuzhiyun 				 u32 *dsp_frame_hst,
14*4882a593Smuzhiyun 				 u32 *dsp_frame_vst)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun 	u32 bp_in, bp_out;
17*4882a593Smuzhiyun 	u32 v_scale_ratio;
18*4882a593Smuzhiyun 	u64 t_frm_st;
19*4882a593Smuzhiyun 	u64 t_bp_in, t_bp_out, t_delta, tin;
20*4882a593Smuzhiyun 	u32 src_pixclock, dst_pixclock;
21*4882a593Smuzhiyun 	u32 dst_htotal, dst_hsync_len, dst_hback_porch;
22*4882a593Smuzhiyun 	u32 dst_vsync_len, dst_vback_porch, dst_vactive;
23*4882a593Smuzhiyun 	u32 src_htotal, src_hsync_len, src_hback_porch;
24*4882a593Smuzhiyun 	u32 src_vtotal, src_vsync_len, src_vback_porch, src_vactive;
25*4882a593Smuzhiyun 	u32 rem;
26*4882a593Smuzhiyun 	u32 x;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	src_pixclock = div_u64(1000000000llu, src->clock);
29*4882a593Smuzhiyun 	dst_pixclock = div_u64(1000000000llu, dst->clock);
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	src_hsync_len = src->hsync_end - src->hsync_start;
32*4882a593Smuzhiyun 	src_hback_porch = src->htotal - src->hsync_end;
33*4882a593Smuzhiyun 	src_htotal = src->htotal;
34*4882a593Smuzhiyun 	src_vsync_len = src->vsync_end - src->vsync_start;
35*4882a593Smuzhiyun 	src_vback_porch = src->vtotal - src->vsync_end;
36*4882a593Smuzhiyun 	src_vactive = src->vdisplay;
37*4882a593Smuzhiyun 	src_vtotal = src->vtotal;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	dst_hsync_len = dst->hsync_end - dst->hsync_start;
40*4882a593Smuzhiyun 	dst_hback_porch = dst->htotal - dst->hsync_end;
41*4882a593Smuzhiyun 	dst_htotal = dst->htotal;
42*4882a593Smuzhiyun 	dst_vsync_len = dst->vsync_end - dst->vsync_start;
43*4882a593Smuzhiyun 	dst_vback_porch = dst->vtotal - dst->vsync_end;
44*4882a593Smuzhiyun 	dst_vactive = dst->vdisplay;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	bp_in = (src_vback_porch + src_vsync_len) * src_htotal +
47*4882a593Smuzhiyun 		src_hsync_len + src_hback_porch;
48*4882a593Smuzhiyun 	bp_out = (dst_vback_porch + dst_vsync_len) * dst_htotal +
49*4882a593Smuzhiyun 		 dst_hsync_len + dst_hback_porch;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	t_bp_in = bp_in * src_pixclock;
52*4882a593Smuzhiyun 	t_bp_out = bp_out * dst_pixclock;
53*4882a593Smuzhiyun 	tin = src_vtotal * src_htotal * src_pixclock;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	v_scale_ratio = src_vactive / dst_vactive;
56*4882a593Smuzhiyun 	x = 5;
57*4882a593Smuzhiyun __retry:
58*4882a593Smuzhiyun 	if (v_scale_ratio <= 2)
59*4882a593Smuzhiyun 		t_delta = x * src_htotal * src_pixclock;
60*4882a593Smuzhiyun 	else
61*4882a593Smuzhiyun 		t_delta = 12 * src_htotal * src_pixclock;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (t_bp_in + t_delta > t_bp_out)
64*4882a593Smuzhiyun 		t_frm_st = (t_bp_in + t_delta - t_bp_out);
65*4882a593Smuzhiyun 	else
66*4882a593Smuzhiyun 		t_frm_st = tin - (t_bp_out - (t_bp_in + t_delta));
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	do_div(t_frm_st, src_pixclock);
69*4882a593Smuzhiyun 	rem = do_div(t_frm_st, src_htotal);
70*4882a593Smuzhiyun 	if ((t_frm_st < 2 || t_frm_st > 14) && x < 12) {
71*4882a593Smuzhiyun 		x++;
72*4882a593Smuzhiyun 		goto __retry;
73*4882a593Smuzhiyun 	}
74*4882a593Smuzhiyun 	if (t_frm_st < 2 || t_frm_st > 14)
75*4882a593Smuzhiyun 		t_frm_st = 4;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	*dsp_frame_hst = rem;
78*4882a593Smuzhiyun 	*dsp_frame_vst = t_frm_st;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
rk628_post_process_scaler_init(struct rk628 * rk628,struct rk628_display_mode * src,const struct rk628_display_mode * dst)81*4882a593Smuzhiyun static void rk628_post_process_scaler_init(struct rk628 *rk628,
82*4882a593Smuzhiyun 					   struct rk628_display_mode *src,
83*4882a593Smuzhiyun 					   const struct rk628_display_mode *dst)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	u32 dsp_frame_hst, dsp_frame_vst;
86*4882a593Smuzhiyun 	u32 scl_hor_mode, scl_ver_mode;
87*4882a593Smuzhiyun 	u32 scl_v_factor, scl_h_factor;
88*4882a593Smuzhiyun 	u32 dsp_htotal, dsp_hs_end, dsp_hact_st, dsp_hact_end;
89*4882a593Smuzhiyun 	u32 dsp_vtotal, dsp_vs_end, dsp_vact_st, dsp_vact_end;
90*4882a593Smuzhiyun 	u32 dsp_hbor_end, dsp_hbor_st, dsp_vbor_end, dsp_vbor_st;
91*4882a593Smuzhiyun 	u16 bor_right = 0, bor_left = 0, bor_up = 0, bor_down = 0;
92*4882a593Smuzhiyun 	u8 hor_down_mode = 0, ver_down_mode = 0;
93*4882a593Smuzhiyun 	u32 dst_hsync_len, dst_hback_porch, dst_hfront_porch, dst_hactive;
94*4882a593Smuzhiyun 	u32 dst_vsync_len, dst_vback_porch, dst_vfront_porch, dst_vactive;
95*4882a593Smuzhiyun 	u32 src_hactive;
96*4882a593Smuzhiyun 	u32 src_vactive;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	src_hactive = src->hdisplay;
99*4882a593Smuzhiyun 	src_vactive = src->vdisplay;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	dst_hactive = dst->hdisplay;
102*4882a593Smuzhiyun 	dst_hsync_len = dst->hsync_end - dst->hsync_start;
103*4882a593Smuzhiyun 	dst_hback_porch = dst->htotal - dst->hsync_end;
104*4882a593Smuzhiyun 	dst_hfront_porch = dst->hsync_start - dst->hdisplay;
105*4882a593Smuzhiyun 	dst_vsync_len = dst->vsync_end - dst->vsync_start;
106*4882a593Smuzhiyun 	dst_vback_porch = dst->vtotal - dst->vsync_end;
107*4882a593Smuzhiyun 	dst_vfront_porch = dst->vsync_start - dst->vdisplay;
108*4882a593Smuzhiyun 	dst_vactive = dst->vdisplay;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	dsp_htotal = dst_hsync_len + dst_hback_porch +
111*4882a593Smuzhiyun 		     dst_hactive + dst_hfront_porch;
112*4882a593Smuzhiyun 	dsp_vtotal = dst_vsync_len + dst_vback_porch +
113*4882a593Smuzhiyun 		     dst_vactive + dst_vfront_porch;
114*4882a593Smuzhiyun 	dsp_hs_end = dst_hsync_len;
115*4882a593Smuzhiyun 	dsp_vs_end = dst_vsync_len;
116*4882a593Smuzhiyun 	dsp_hbor_end = dst_hsync_len + dst_hback_porch + dst_hactive;
117*4882a593Smuzhiyun 	dsp_hbor_st = dst_hsync_len + dst_hback_porch;
118*4882a593Smuzhiyun 	dsp_vbor_end = dst_vsync_len + dst_vback_porch + dst_vactive;
119*4882a593Smuzhiyun 	dsp_vbor_st = dst_vsync_len + dst_vback_porch;
120*4882a593Smuzhiyun 	dsp_hact_st = dsp_hbor_st + bor_left;
121*4882a593Smuzhiyun 	dsp_hact_end = dsp_hbor_end - bor_right;
122*4882a593Smuzhiyun 	dsp_vact_st = dsp_vbor_st + bor_up;
123*4882a593Smuzhiyun 	dsp_vact_end = dsp_vbor_end - bor_down;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	calc_dsp_frm_hst_vst(src, dst, &dsp_frame_hst, &dsp_frame_vst);
126*4882a593Smuzhiyun 	dev_info(rk628->dev, "dsp_frame_vst:%d  dsp_frame_hst:%d\n",
127*4882a593Smuzhiyun 		 dsp_frame_vst, dsp_frame_hst);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (src_hactive > dst_hactive) {
130*4882a593Smuzhiyun 		scl_hor_mode = 2;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 		if (hor_down_mode == 0) {
133*4882a593Smuzhiyun 			if ((src_hactive - 1) / (dst_hactive - 1) > 2)
134*4882a593Smuzhiyun 				scl_h_factor = ((src_hactive - 1) << 14) /
135*4882a593Smuzhiyun 						(dst_hactive - 1);
136*4882a593Smuzhiyun 			else
137*4882a593Smuzhiyun 				scl_h_factor = ((src_hactive - 2) << 14) /
138*4882a593Smuzhiyun 						(dst_hactive - 1);
139*4882a593Smuzhiyun 		} else {
140*4882a593Smuzhiyun 			scl_h_factor = (dst_hactive << 16) / (src_hactive - 1);
141*4882a593Smuzhiyun 		}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	} else if (src_hactive == dst_hactive) {
144*4882a593Smuzhiyun 		scl_hor_mode = 0;
145*4882a593Smuzhiyun 		scl_h_factor = 0;
146*4882a593Smuzhiyun 	} else {
147*4882a593Smuzhiyun 		scl_hor_mode = 1;
148*4882a593Smuzhiyun 		scl_h_factor = ((src_hactive - 1) << 16) / (dst_hactive - 1);
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	if (src_vactive > dst_vactive) {
152*4882a593Smuzhiyun 		scl_ver_mode = 2;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 		if (ver_down_mode == 0) {
155*4882a593Smuzhiyun 			if ((src_vactive - 1) / (dst_vactive - 1) > 2)
156*4882a593Smuzhiyun 				scl_v_factor = ((src_vactive - 1) << 14) /
157*4882a593Smuzhiyun 						(dst_vactive - 1);
158*4882a593Smuzhiyun 			else
159*4882a593Smuzhiyun 				scl_v_factor = ((src_vactive - 2) << 14) /
160*4882a593Smuzhiyun 						(dst_vactive - 1);
161*4882a593Smuzhiyun 		} else {
162*4882a593Smuzhiyun 			scl_v_factor = (dst_vactive << 16) / (src_vactive - 1);
163*4882a593Smuzhiyun 		}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	} else if (src_vactive == dst_vactive) {
166*4882a593Smuzhiyun 		scl_ver_mode = 0;
167*4882a593Smuzhiyun 		scl_v_factor = 0;
168*4882a593Smuzhiyun 	} else {
169*4882a593Smuzhiyun 		scl_ver_mode = 1;
170*4882a593Smuzhiyun 		scl_v_factor = ((src_vactive - 1) << 16) / (dst_vactive - 1);
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON0, SW_HRES_MASK,
174*4882a593Smuzhiyun 			      SW_HRES(src_hactive));
175*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON0, SCL_VER_DOWN_MODE(ver_down_mode) |
176*4882a593Smuzhiyun 			SCL_HOR_DOWN_MODE(hor_down_mode) |
177*4882a593Smuzhiyun 			SCL_VER_MODE(scl_ver_mode) |
178*4882a593Smuzhiyun 			SCL_HOR_MODE(scl_hor_mode));
179*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON1, SCL_V_FACTOR(scl_v_factor) |
180*4882a593Smuzhiyun 			SCL_H_FACTOR(scl_h_factor));
181*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON2, DSP_FRAME_VST(dsp_frame_vst) |
182*4882a593Smuzhiyun 			DSP_FRAME_HST(dsp_frame_hst));
183*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON3, DSP_HS_END(dsp_hs_end) |
184*4882a593Smuzhiyun 			DSP_HTOTAL(dsp_htotal));
185*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON4, DSP_HACT_END(dsp_hact_end) |
186*4882a593Smuzhiyun 			DSP_HACT_ST(dsp_hact_st));
187*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON5, DSP_VS_END(dsp_vs_end) |
188*4882a593Smuzhiyun 			DSP_VTOTAL(dsp_vtotal));
189*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON6, DSP_VACT_END(dsp_vact_end) |
190*4882a593Smuzhiyun 			DSP_VACT_ST(dsp_vact_st));
191*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON7, DSP_HBOR_END(dsp_hbor_end) |
192*4882a593Smuzhiyun 			DSP_HBOR_ST(dsp_hbor_st));
193*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON8, DSP_VBOR_END(dsp_vbor_end) |
194*4882a593Smuzhiyun 			DSP_VBOR_ST(dsp_vbor_st));
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
rk628_post_process_init(struct rk628 * rk628)197*4882a593Smuzhiyun void rk628_post_process_init(struct rk628 *rk628)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	struct rk628_display_mode *src = &rk628->src_mode;
200*4882a593Smuzhiyun 	const struct rk628_display_mode *dst = &rk628->dst_mode;
201*4882a593Smuzhiyun 	u64 dst_rate, src_rate;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	src_rate = src->clock * 1000;
204*4882a593Smuzhiyun 	dst_rate = src_rate * dst->vdisplay * dst->htotal;
205*4882a593Smuzhiyun 	do_div(dst_rate, (src->vdisplay * src->htotal));
206*4882a593Smuzhiyun 	do_div(dst_rate, 1000);
207*4882a593Smuzhiyun 	dev_info(rk628->dev, "src %dx%d clock:%d\n",
208*4882a593Smuzhiyun 		 src->hdisplay, src->vdisplay, src->clock);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	dev_info(rk628->dev, "dst %dx%d clock:%llu\n",
211*4882a593Smuzhiyun 		 dst->hdisplay, dst->vdisplay, dst_rate);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	rk628_cru_clk_set_rate(rk628, CGU_CLK_RX_READ, src->clock * 1000);
214*4882a593Smuzhiyun 	rk628_cru_clk_set_rate(rk628, CGU_SCLK_VOP, dst_rate * 1000);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	if (rk628->output_mode == OUTPUT_MODE_HDMI) {
217*4882a593Smuzhiyun 		rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_VSYNC_POL_MASK,
218*4882a593Smuzhiyun 				      SW_VSYNC_POL(rk628->sync_pol));
219*4882a593Smuzhiyun 		rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_HSYNC_POL_MASK,
220*4882a593Smuzhiyun 				      SW_HSYNC_POL(rk628->sync_pol));
221*4882a593Smuzhiyun 	} else {
222*4882a593Smuzhiyun 		if (src->flags & DRM_MODE_FLAG_PVSYNC)
223*4882a593Smuzhiyun 			rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
224*4882a593Smuzhiyun 					      SW_VSYNC_POL_MASK, SW_VSYNC_POL(1));
225*4882a593Smuzhiyun 		if (src->flags & DRM_MODE_FLAG_PHSYNC)
226*4882a593Smuzhiyun 			rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
227*4882a593Smuzhiyun 					      SW_HSYNC_POL_MASK,
228*4882a593Smuzhiyun 					      SW_HSYNC_POL(1));
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	rk628_post_process_scaler_init(rk628, src, dst);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
rk628_post_process_csc(struct rk628 * rk628)234*4882a593Smuzhiyun static void rk628_post_process_csc(struct rk628 *rk628)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	enum bus_format in_fmt, out_fmt;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	in_fmt = rk628_get_input_bus_format(rk628);
239*4882a593Smuzhiyun 	out_fmt = rk628_get_output_bus_format(rk628);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if (in_fmt == out_fmt) {
242*4882a593Smuzhiyun 		if (out_fmt == BUS_FMT_YUV422) {
243*4882a593Smuzhiyun 			rk628_i2c_write(rk628, GRF_CSC_CTRL_CON,
244*4882a593Smuzhiyun 					SW_YUV2VYU_SWP(1) |
245*4882a593Smuzhiyun 					SW_R2Y_EN(0));
246*4882a593Smuzhiyun 			return;
247*4882a593Smuzhiyun 		}
248*4882a593Smuzhiyun 		rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_R2Y_EN(0));
249*4882a593Smuzhiyun 		rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_Y2R_EN(0));
250*4882a593Smuzhiyun 		return;
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	if (in_fmt == BUS_FMT_RGB)
254*4882a593Smuzhiyun 		rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_R2Y_EN(1));
255*4882a593Smuzhiyun 	else if (out_fmt == BUS_FMT_RGB)
256*4882a593Smuzhiyun 		rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_Y2R_EN(1));
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
rk628_post_process_enable(struct rk628 * rk628)259*4882a593Smuzhiyun void rk628_post_process_enable(struct rk628 *rk628)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	rk628_post_process_csc(rk628);
262*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON0, SCL_EN(1));
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
rk628_post_process_disable(struct rk628 * rk628)265*4882a593Smuzhiyun void rk628_post_process_disable(struct rk628 *rk628)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	rk628_i2c_write(rk628, GRF_SCALER_CON0, SCL_EN(0));
268*4882a593Smuzhiyun }
269