@@ -253,6 +253,7 @@ enum vc4_vec_tv_mode_id {
253253struct vc4_vec_tv_mode {
254254 const struct drm_display_mode * interlaced_mode ;
255255 const struct drm_display_mode * progressive_mode ;
256+ const struct drm_display_mode * scaled_progressive_mode ;
256257 u32 config0 ;
257258 u32 config1 ;
258259 u32 custom_freq ;
@@ -298,6 +299,12 @@ static const struct drm_display_mode drm_mode_240p = {
298299 240 , 240 + 3 , 240 + 3 + 3 , 262 , 0 , 0 )
299300};
300301
302+ static const struct drm_display_mode drm_mode_scaled_480p = {
303+ DRM_MODE ("720x480 (scaled)" , DRM_MODE_TYPE_DRIVER , 2 * 13500 ,
304+ 720 , 720 + 14 , 720 + 14 + 64 , 720 + 14 + 64 + 60 , 0 ,
305+ 2 * 240 , 2 * (240 + 3 ), 2 * (240 + 3 + 3 ), 2 * 262 , 0 , 0 )
306+ };
307+
301308static const struct drm_display_mode drm_mode_576i = {
302309 DRM_MODE ("720x576i" , DRM_MODE_TYPE_DRIVER , 13500 ,
303310 720 , 720 + 20 , 720 + 20 + 64 , 720 + 20 + 64 + 60 , 0 ,
@@ -311,56 +318,70 @@ static const struct drm_display_mode drm_mode_288p = {
311318 288 , 288 + 2 , 288 + 2 + 3 , 312 , 0 , 0 )
312319};
313320
321+ static const struct drm_display_mode drm_mode_scaled_576p = {
322+ DRM_MODE ("720x576 (scaled)" , DRM_MODE_TYPE_DRIVER , 2 * 13500 ,
323+ 720 , 720 + 20 , 720 + 20 + 64 , 720 + 20 + 64 + 60 , 0 ,
324+ 2 * 288 , 2 * (288 + 2 ), 2 * (288 + 2 + 3 ), 2 * 312 , 0 , 0 )
325+ };
326+
314327static const struct vc4_vec_tv_mode vc4_vec_tv_modes [] = {
315328 [VC4_VEC_TV_MODE_NTSC ] = {
316329 .interlaced_mode = & drm_mode_480i ,
317330 .progressive_mode = & drm_mode_240p ,
331+ .scaled_progressive_mode = & drm_mode_scaled_480p ,
318332 .config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN ,
319333 .config1 = VEC_CONFIG1_C_CVBS_CVBS ,
320334 },
321335 [VC4_VEC_TV_MODE_NTSC_J ] = {
322336 .interlaced_mode = & drm_mode_480i ,
323337 .progressive_mode = & drm_mode_240p ,
338+ .scaled_progressive_mode = & drm_mode_scaled_480p ,
324339 .config0 = VEC_CONFIG0_NTSC_STD ,
325340 .config1 = VEC_CONFIG1_C_CVBS_CVBS ,
326341 },
327342 [VC4_VEC_TV_MODE_NTSC_443 ] = {
328343 /* NTSC with PAL chroma frequency */
329344 .interlaced_mode = & drm_mode_480i ,
330345 .progressive_mode = & drm_mode_240p ,
346+ .scaled_progressive_mode = & drm_mode_scaled_480p ,
331347 .config0 = VEC_CONFIG0_NTSC_STD ,
332348 .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ ,
333349 .custom_freq = 0x2a098acb ,
334350 },
335351 [VC4_VEC_TV_MODE_PAL ] = {
336352 .interlaced_mode = & drm_mode_576i ,
337353 .progressive_mode = & drm_mode_288p ,
354+ .scaled_progressive_mode = & drm_mode_scaled_576p ,
338355 .config0 = VEC_CONFIG0_PAL_BDGHI_STD ,
339356 .config1 = VEC_CONFIG1_C_CVBS_CVBS ,
340357 },
341358 [VC4_VEC_TV_MODE_PAL_M ] = {
342359 .interlaced_mode = & drm_mode_480i ,
343360 .progressive_mode = & drm_mode_240p ,
361+ .scaled_progressive_mode = & drm_mode_scaled_480p ,
344362 .config0 = VEC_CONFIG0_PAL_M_STD ,
345363 .config1 = VEC_CONFIG1_C_CVBS_CVBS ,
346364 },
347365 [VC4_VEC_TV_MODE_PAL_N ] = {
348366 .interlaced_mode = & drm_mode_576i ,
349367 .progressive_mode = & drm_mode_288p ,
368+ .scaled_progressive_mode = & drm_mode_scaled_576p ,
350369 .config0 = VEC_CONFIG0_PAL_N_STD ,
351370 .config1 = VEC_CONFIG1_C_CVBS_CVBS ,
352371 },
353372 [VC4_VEC_TV_MODE_PAL60 ] = {
354373 /* PAL-M with chroma frequency of regular PAL */
355374 .interlaced_mode = & drm_mode_480i ,
356375 .progressive_mode = & drm_mode_240p ,
376+ .scaled_progressive_mode = & drm_mode_scaled_480p ,
357377 .config0 = VEC_CONFIG0_PAL_M_STD ,
358378 .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ ,
359379 .custom_freq = 0x2a098acb ,
360380 },
361381 [VC4_VEC_TV_MODE_SECAM ] = {
362382 .interlaced_mode = & drm_mode_576i ,
363383 .progressive_mode = & drm_mode_288p ,
384+ .scaled_progressive_mode = & drm_mode_scaled_576p ,
364385 .config0 = VEC_CONFIG0_SECAM_STD ,
365386 .config1 = VEC_CONFIG1_C_CVBS_CVBS ,
366387 .custom_freq = 0x29c71c72 ,
@@ -420,32 +441,43 @@ static void vc4_vec_connector_destroy(struct drm_connector *connector)
420441static int vc4_vec_connector_get_modes (struct drm_connector * connector )
421442{
422443 struct drm_connector_state * state = connector -> state ;
423- struct drm_display_mode * interlaced_mode , * progressive_mode ;
444+ struct drm_display_mode * interlaced_mode ;
445+ struct drm_display_mode * progressive_mode ;
446+ struct drm_display_mode * scaled_progressive_mode ;
424447
425448 interlaced_mode =
426449 drm_mode_duplicate (connector -> dev ,
427450 vc4_vec_tv_modes [state -> tv .mode ].interlaced_mode );
428451 progressive_mode =
429452 drm_mode_duplicate (connector -> dev ,
430453 vc4_vec_tv_modes [state -> tv .mode ].progressive_mode );
431- if (!interlaced_mode || !progressive_mode ) {
454+ scaled_progressive_mode =
455+ drm_mode_duplicate (connector -> dev ,
456+ vc4_vec_tv_modes [state -> tv .mode ].scaled_progressive_mode );
457+ if (!interlaced_mode || !progressive_mode || !scaled_progressive_mode ) {
432458 DRM_ERROR ("Failed to create a new display mode\n" );
433459 drm_mode_destroy (connector -> dev , interlaced_mode );
434460 drm_mode_destroy (connector -> dev , progressive_mode );
461+ drm_mode_destroy (connector -> dev , scaled_progressive_mode );
435462 return - ENOMEM ;
436463 }
437464
438465 if (connector -> cmdline_mode .specified &&
439466 connector -> cmdline_mode .refresh_specified &&
440- !connector -> cmdline_mode .interlace )
467+ !connector -> cmdline_mode .interlace ) {
441468 /* progressive mode set at boot, let's make it preferred */
442- progressive_mode -> type |= DRM_MODE_TYPE_PREFERRED ;
443- else
469+ if (connector -> cmdline_mode .yres > 300 )
470+ scaled_progressive_mode -> type |= DRM_MODE_TYPE_PREFERRED ;
471+ else
472+ progressive_mode -> type |= DRM_MODE_TYPE_PREFERRED ;
473+ } else {
444474 /* otherwise, interlaced mode is preferred */
445475 interlaced_mode -> type |= DRM_MODE_TYPE_PREFERRED ;
476+ }
446477
447478 drm_mode_probed_add (connector , interlaced_mode );
448479 drm_mode_probed_add (connector , progressive_mode );
480+ drm_mode_probed_add (connector , scaled_progressive_mode );
449481
450482 return 1 ;
451483}
@@ -628,6 +660,27 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
628660 const struct drm_display_mode * reference_mode =
629661 vc4_vec_tv_modes [conn_state -> tv .mode ].interlaced_mode ;
630662
663+ if (!(crtc_state -> adjusted_mode .flags & DRM_MODE_FLAG_INTERLACE ) &&
664+ crtc_state -> adjusted_mode .vtotal > 312 ) {
665+ /* vertically scaled progressive mode */
666+ if (crtc_state -> adjusted_mode .crtc_vdisplay % 2 != 0 ||
667+ crtc_state -> adjusted_mode .crtc_vsync_start % 2 != 0 ||
668+ crtc_state -> adjusted_mode .crtc_vsync_end % 2 != 0 ||
669+ crtc_state -> adjusted_mode .crtc_vtotal % 2 != 0 )
670+ return - EINVAL ;
671+
672+ crtc_state -> adjusted_mode .clock /= 2 ;
673+ crtc_state -> adjusted_mode .crtc_clock /= 2 ;
674+ crtc_state -> adjusted_mode .vdisplay /= 2 ;
675+ crtc_state -> adjusted_mode .crtc_vdisplay /= 2 ;
676+ crtc_state -> adjusted_mode .vsync_start /= 2 ;
677+ crtc_state -> adjusted_mode .crtc_vsync_start /= 2 ;
678+ crtc_state -> adjusted_mode .vsync_end /= 2 ;
679+ crtc_state -> adjusted_mode .crtc_vsync_end /= 2 ;
680+ crtc_state -> adjusted_mode .vtotal /= 2 ;
681+ crtc_state -> adjusted_mode .crtc_vtotal /= 2 ;
682+ }
683+
631684 if (crtc_state -> adjusted_mode .crtc_clock != reference_mode -> clock ||
632685 crtc_state -> adjusted_mode .crtc_htotal != reference_mode -> htotal ||
633686 crtc_state -> adjusted_mode .crtc_hdisplay % 4 != 0 ||
0 commit comments