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 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 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 */ 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 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 */ 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 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 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 */ 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 */ 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 */ 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 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 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 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