xref: /OK3568_Linux_fs/u-boot/drivers/video/drm/rockchip_display_helper.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * (C) Copyright 2023 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <linux/hdmi.h>
8 #include <linux/compat.h>
9 #include "rockchip_display.h"
10 #include <spl_display.h>
11 
12 #define RK_BLK_SIZE 512
13 #define BMP_PROCESSED_FLAG 8399
14 
15 static uint32_t crc32_table[256];
16 
rockchip_display_make_crc32_table(void)17 void rockchip_display_make_crc32_table(void)
18 {
19 	uint32_t c;
20 	int n, k;
21 	unsigned long poly;		/* polynomial exclusive-or pattern */
22 	/* terms of polynomial defining this crc (except x^32): */
23 	static const char p[] = {0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26};
24 
25 	/* make exclusive-or pattern from polynomial (0xedb88320L) */
26 	poly = 0L;
27 	for (n = 0; n < sizeof(p) / sizeof(char); n++)
28 		poly |= 1L << (31 - p[n]);
29 
30 	for (n = 0; n < 256; n++) {
31 		c = (unsigned long)n;
32 		for (k = 0; k < 8; k++)
33 		c = c & 1 ? poly ^ (c >> 1) : c >> 1;
34 		crc32_table[n] = cpu_to_le32(c);
35 	}
36 }
37 
rockchip_display_crc32c_cal(unsigned char * data,int length)38 uint32_t rockchip_display_crc32c_cal(unsigned char *data, int length)
39 {
40 	int i;
41 	uint32_t crc;
42 	crc = 0xFFFFFFFF;
43 
44 	for (i = 0; i < length; i++) {
45 		crc = crc32_table[(crc ^ *data) & 0xff] ^ (crc >> 8);
46 		data++;
47 	}
48 
49 	return crc ^ 0xffffffff;
50 }
51 
52 /**
53  * drm_mode_max_resolution_filter - mark modes out of vop max resolution
54  * @edid_data: structure store mode list
55  * @max_output: vop max output resolution
56  */
drm_mode_max_resolution_filter(struct hdmi_edid_data * edid_data,struct vop_rect * max_output)57 void drm_mode_max_resolution_filter(struct hdmi_edid_data *edid_data,
58 				    struct vop_rect *max_output)
59 {
60 	int i;
61 
62 	for (i = 0; i < edid_data->modes; i++) {
63 		if (edid_data->mode_buf[i].hdisplay > max_output->width ||
64 		    edid_data->mode_buf[i].vdisplay > max_output->height)
65 			edid_data->mode_buf[i].invalid = true;
66 	}
67 }
68 
drm_mode_vrefresh(const struct drm_display_mode * mode)69 int drm_mode_vrefresh(const struct drm_display_mode *mode)
70 {
71 	int refresh = 0;
72 	unsigned int calc_val;
73 
74 	if (mode->vrefresh > 0) {
75 		refresh = mode->vrefresh;
76 	} else if (mode->htotal > 0 && mode->vtotal > 0) {
77 		int vtotal;
78 
79 		vtotal = mode->vtotal;
80 		/* work out vrefresh the value will be x1000 */
81 		calc_val = (mode->clock * 1000);
82 		calc_val /= mode->htotal;
83 		refresh = (calc_val + vtotal / 2) / vtotal;
84 
85 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
86 		refresh *= 2;
87 		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
88 		refresh /= 2;
89 		if (mode->vscan > 1)
90 		refresh /= mode->vscan;
91 	}
92 	return refresh;
93 }
94 
95 /**
96  * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
97  * @p: mode
98  * @adjust_flags: a combination of adjustment flags
99  *
100  * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
101  *
102  * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
103  *   interlaced modes.
104  * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
105  *   buffers containing two eyes (only adjust the timings when needed, eg. for
106  *   "frame packing" or "side by side full").
107  * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
108  *   be performed for doublescan and vscan > 1 modes respectively.
109  */
drm_mode_set_crtcinfo(struct drm_display_mode * p,int adjust_flags)110 void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
111 {
112 	if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
113 		return;
114 
115 	if (p->flags & DRM_MODE_FLAG_DBLCLK)
116 		p->crtc_clock = 2 * p->clock;
117 	else
118 		p->crtc_clock = p->clock;
119 	p->crtc_hdisplay = p->hdisplay;
120 	p->crtc_hsync_start = p->hsync_start;
121 	p->crtc_hsync_end = p->hsync_end;
122 	p->crtc_htotal = p->htotal;
123 	p->crtc_hskew = p->hskew;
124 	p->crtc_vdisplay = p->vdisplay;
125 	p->crtc_vsync_start = p->vsync_start;
126 	p->crtc_vsync_end = p->vsync_end;
127 	p->crtc_vtotal = p->vtotal;
128 
129 	if (p->flags & DRM_MODE_FLAG_INTERLACE) {
130 		if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
131 			p->crtc_vdisplay /= 2;
132 			p->crtc_vsync_start /= 2;
133 			p->crtc_vsync_end /= 2;
134 			p->crtc_vtotal /= 2;
135 		}
136 	}
137 
138 	if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
139 		if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
140 			p->crtc_vdisplay *= 2;
141 			p->crtc_vsync_start *= 2;
142 			p->crtc_vsync_end *= 2;
143 			p->crtc_vtotal *= 2;
144 		}
145 	}
146 
147 	if (!(adjust_flags & CRTC_NO_VSCAN)) {
148 		if (p->vscan > 1) {
149 			p->crtc_vdisplay *= p->vscan;
150 			p->crtc_vsync_start *= p->vscan;
151 			p->crtc_vsync_end *= p->vscan;
152 			p->crtc_vtotal *= p->vscan;
153 		}
154 	}
155 
156 	if (adjust_flags & CRTC_STEREO_DOUBLE) {
157 		unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
158 
159 		switch (layout) {
160 		case DRM_MODE_FLAG_3D_FRAME_PACKING:
161 			p->crtc_clock *= 2;
162 			p->crtc_vdisplay += p->crtc_vtotal;
163 			p->crtc_vsync_start += p->crtc_vtotal;
164 			p->crtc_vsync_end += p->crtc_vtotal;
165 			p->crtc_vtotal += p->crtc_vtotal;
166 			break;
167 		}
168 	}
169 
170 	p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
171 	p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
172 	p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
173 	p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
174 }
175 
176 /**
177  * drm_mode_is_420_only - if a given videomode can be only supported in YCBCR420
178  * output format
179  *
180  * @connector: drm connector under action.
181  * @mode: video mode to be tested.
182  *
183  * Returns:
184  * true if the mode can be supported in YCBCR420 format
185  * false if not.
186  */
drm_mode_is_420_only(const struct drm_display_info * display,struct drm_display_mode * mode)187 static bool drm_mode_is_420_only(const struct drm_display_info *display,
188 			  struct drm_display_mode *mode)
189 {
190 	u8 vic = drm_match_cea_mode(mode);
191 
192 	return test_bit(vic, display->hdmi.y420_vdb_modes);
193 }
194 
195 /**
196  * drm_mode_is_420_also - if a given videomode can be supported in YCBCR420
197  * output format also (along with RGB/YCBCR444/422)
198  *
199  * @display: display under action.
200  * @mode: video mode to be tested.
201  *
202  * Returns:
203  * true if the mode can be support YCBCR420 format
204  * false if not.
205  */
drm_mode_is_420_also(const struct drm_display_info * display,struct drm_display_mode * mode)206 static bool drm_mode_is_420_also(const struct drm_display_info *display,
207 			  struct drm_display_mode *mode)
208 {
209 	u8 vic = drm_match_cea_mode(mode);
210 
211 	return test_bit(vic, display->hdmi.y420_cmdb_modes);
212 }
213 
214 /**
215  * drm_mode_is_420 - if a given videomode can be supported in YCBCR420
216  * output format
217  *
218  * @display: display under action.
219  * @mode: video mode to be tested.
220  *
221  * Returns:
222  * true if the mode can be supported in YCBCR420 format
223  * false if not.
224  */
drm_mode_is_420(const struct drm_display_info * display,struct drm_display_mode * mode)225 bool drm_mode_is_420(const struct drm_display_info *display,
226 		     struct drm_display_mode *mode)
227 {
228 	return drm_mode_is_420_only(display, mode) ||
229 		drm_mode_is_420_also(display, mode);
230 }
231 
display_rect_calc_scale(int src,int dst)232 static int display_rect_calc_scale(int src, int dst)
233 {
234 	int scale = 0;
235 
236 	if (WARN_ON(src < 0 || dst < 0))
237 		return -EINVAL;
238 
239 	if (dst == 0)
240 		return 0;
241 
242 	src <<= 16;
243 
244 	if (src > (dst << 16))
245 		return DIV_ROUND_UP(src, dst);
246 	else
247 		scale = src / dst;
248 
249 	return scale;
250 }
251 
display_rect_calc_hscale(struct display_rect * src,struct display_rect * dst,int min_hscale,int max_hscale)252 int display_rect_calc_hscale(struct display_rect *src, struct display_rect *dst,
253 			     int min_hscale, int max_hscale)
254 {
255 	int hscale = display_rect_calc_scale(src->w, dst->w);
256 
257 	if (hscale < 0 || dst->w == 0)
258 		return hscale;
259 
260 	if (hscale < min_hscale || hscale > max_hscale)
261 		return -ERANGE;
262 
263 	return hscale;
264 }
265 
display_rect_calc_vscale(struct display_rect * src,struct display_rect * dst,int min_vscale,int max_vscale)266 int display_rect_calc_vscale(struct display_rect *src, struct display_rect *dst,
267 			     int min_vscale, int max_vscale)
268 {
269 	int vscale = display_rect_calc_scale(src->h, dst->h);
270 
271 	if (vscale < 0 || dst->h == 0)
272 		return vscale;
273 
274 	if (vscale < min_vscale || vscale > max_vscale)
275 		return -ERANGE;
276 
277 	return vscale;
278 }
279 
280