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 p->crtc_clock = p->clock;
116 p->crtc_hdisplay = p->hdisplay;
117 p->crtc_hsync_start = p->hsync_start;
118 p->crtc_hsync_end = p->hsync_end;
119 p->crtc_htotal = p->htotal;
120 p->crtc_hskew = p->hskew;
121 p->crtc_vdisplay = p->vdisplay;
122 p->crtc_vsync_start = p->vsync_start;
123 p->crtc_vsync_end = p->vsync_end;
124 p->crtc_vtotal = p->vtotal;
125
126 if (p->flags & DRM_MODE_FLAG_INTERLACE) {
127 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
128 p->crtc_vdisplay /= 2;
129 p->crtc_vsync_start /= 2;
130 p->crtc_vsync_end /= 2;
131 p->crtc_vtotal /= 2;
132 }
133 }
134
135 if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
136 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
137 p->crtc_vdisplay *= 2;
138 p->crtc_vsync_start *= 2;
139 p->crtc_vsync_end *= 2;
140 p->crtc_vtotal *= 2;
141 }
142 }
143
144 if (!(adjust_flags & CRTC_NO_VSCAN)) {
145 if (p->vscan > 1) {
146 p->crtc_vdisplay *= p->vscan;
147 p->crtc_vsync_start *= p->vscan;
148 p->crtc_vsync_end *= p->vscan;
149 p->crtc_vtotal *= p->vscan;
150 }
151 }
152
153 if (adjust_flags & CRTC_STEREO_DOUBLE) {
154 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
155
156 switch (layout) {
157 case DRM_MODE_FLAG_3D_FRAME_PACKING:
158 p->crtc_clock *= 2;
159 p->crtc_vdisplay += p->crtc_vtotal;
160 p->crtc_vsync_start += p->crtc_vtotal;
161 p->crtc_vsync_end += p->crtc_vtotal;
162 p->crtc_vtotal += p->crtc_vtotal;
163 break;
164 }
165 }
166
167 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
168 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
169 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
170 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
171 }
172
drm_mode_convert_to_origin_mode(struct drm_display_mode * mode)173 void drm_mode_convert_to_origin_mode(struct drm_display_mode *mode)
174 {
175 u16 hactive, hfp, hsync, hbp;
176
177 hactive = mode->hdisplay;
178 hfp = mode->hsync_start - mode->hdisplay;
179 hsync = mode->hsync_end - mode->hsync_start;
180 hbp = mode->htotal - mode->hsync_end;
181
182 mode->clock /= 2;
183 mode->crtc_clock /= 2;
184 mode->hdisplay = hactive / 2;
185 mode->hsync_start = mode->hdisplay + hfp / 2;
186 mode->hsync_end = mode->hsync_start + hsync / 2;
187 mode->htotal = mode->hsync_end + hbp / 2;
188 }
189
drm_mode_convert_to_split_mode(struct drm_display_mode * mode)190 void drm_mode_convert_to_split_mode(struct drm_display_mode *mode)
191 {
192 u16 hactive, hfp, hsync, hbp;
193
194 hactive = mode->hdisplay;
195 hfp = mode->hsync_start - mode->hdisplay;
196 hsync = mode->hsync_end - mode->hsync_start;
197 hbp = mode->htotal - mode->hsync_end;
198
199 mode->clock *= 2;
200 mode->crtc_clock *= 2;
201 mode->hdisplay = hactive * 2;
202 mode->hsync_start = mode->hdisplay + hfp * 2;
203 mode->hsync_end = mode->hsync_start + hsync * 2;
204 mode->htotal = mode->hsync_end + hbp * 2;
205 }
206
207 /**
208 * drm_mode_is_420_only - if a given videomode can be only supported in YCBCR420
209 * output format
210 *
211 * @connector: drm connector under action.
212 * @mode: video mode to be tested.
213 *
214 * Returns:
215 * true if the mode can be supported in YCBCR420 format
216 * false if not.
217 */
drm_mode_is_420_only(const struct drm_display_info * display,struct drm_display_mode * mode)218 bool drm_mode_is_420_only(const struct drm_display_info *display,
219 struct drm_display_mode *mode)
220 {
221 u8 vic = drm_match_cea_mode(mode);
222
223 return test_bit(vic, display->hdmi.y420_vdb_modes);
224 }
225
226 /**
227 * drm_mode_is_420_also - if a given videomode can be supported in YCBCR420
228 * output format also (along with RGB/YCBCR444/422)
229 *
230 * @display: display under action.
231 * @mode: video mode to be tested.
232 *
233 * Returns:
234 * true if the mode can be support YCBCR420 format
235 * false if not.
236 */
drm_mode_is_420_also(const struct drm_display_info * display,struct drm_display_mode * mode)237 bool drm_mode_is_420_also(const struct drm_display_info *display,
238 struct drm_display_mode *mode)
239 {
240 u8 vic = drm_match_cea_mode(mode);
241
242 return test_bit(vic, display->hdmi.y420_cmdb_modes);
243 }
244
245 /**
246 * drm_mode_is_420 - if a given videomode can be supported in YCBCR420
247 * output format
248 *
249 * @display: display under action.
250 * @mode: video mode to be tested.
251 *
252 * Returns:
253 * true if the mode can be supported in YCBCR420 format
254 * false if not.
255 */
drm_mode_is_420(const struct drm_display_info * display,struct drm_display_mode * mode)256 bool drm_mode_is_420(const struct drm_display_info *display,
257 struct drm_display_mode *mode)
258 {
259 return drm_mode_is_420_only(display, mode) ||
260 drm_mode_is_420_also(display, mode);
261 }
262
display_rect_calc_scale(int src,int dst)263 static int display_rect_calc_scale(int src, int dst)
264 {
265 int scale = 0;
266
267 if (WARN_ON(src < 0 || dst < 0))
268 return -EINVAL;
269
270 if (dst == 0)
271 return 0;
272
273 src <<= 16;
274
275 if (src > (dst << 16))
276 return DIV_ROUND_UP(src, dst);
277 else
278 scale = src / dst;
279
280 return scale;
281 }
282
display_rect_calc_hscale(struct display_rect * src,struct display_rect * dst,int min_hscale,int max_hscale)283 int display_rect_calc_hscale(struct display_rect *src, struct display_rect *dst,
284 int min_hscale, int max_hscale)
285 {
286 int hscale = display_rect_calc_scale(src->w, dst->w);
287
288 if (hscale < 0 || dst->w == 0)
289 return hscale;
290
291 if (hscale < min_hscale || hscale > max_hscale)
292 return -ERANGE;
293
294 return hscale;
295 }
296
display_rect_calc_vscale(struct display_rect * src,struct display_rect * dst,int min_vscale,int max_vscale)297 int display_rect_calc_vscale(struct display_rect *src, struct display_rect *dst,
298 int min_vscale, int max_vscale)
299 {
300 int vscale = display_rect_calc_scale(src->h, dst->h);
301
302 if (vscale < 0 || dst->h == 0)
303 return vscale;
304
305 if (vscale < min_vscale || vscale > max_vscale)
306 return -ERANGE;
307
308 return vscale;
309 }
310
311