2323#include "dc.h"
2424#include "plane.h"
2525
26+ #define NFB 24
27+
2628static const u32 tegra_shared_plane_formats [] = {
2729 DRM_FORMAT_ARGB1555 ,
2830 DRM_FORMAT_RGB565 ,
@@ -292,6 +294,74 @@ static int tegra_shared_plane_set_owner(struct tegra_plane *plane,
292294 return 0 ;
293295}
294296
297+ static void tegra_shared_plane_setup_scaler (struct tegra_plane * plane )
298+ {
299+ static const unsigned int coeffs [192 ] = {
300+ 0x00000000 , 0x3c70e400 , 0x3bb037e4 , 0x0c51cc9c ,
301+ 0x00100001 , 0x3bf0dbfa , 0x3d00f406 , 0x3fe003ff ,
302+ 0x00300002 , 0x3b80cbf5 , 0x3da1040d , 0x3fb003fe ,
303+ 0x00400002 , 0x3b20bff1 , 0x3e511015 , 0x3f9003fc ,
304+ 0x00500002 , 0x3ad0b3ed , 0x3f21201d , 0x3f5003fb ,
305+ 0x00500003 , 0x3aa0a3e9 , 0x3ff13026 , 0x3f2007f9 ,
306+ 0x00500403 , 0x3a7097e6 , 0x00e1402f , 0x3ee007f7 ,
307+ 0x00500403 , 0x3a608be4 , 0x01d14c38 , 0x3ea00bf6 ,
308+ 0x00500403 , 0x3a507fe2 , 0x02e15c42 , 0x3e500ff4 ,
309+ 0x00500402 , 0x3a6073e1 , 0x03f16c4d , 0x3e000ff2 ,
310+ 0x00400402 , 0x3a706be0 , 0x05117858 , 0x3db013f0 ,
311+ 0x00300402 , 0x3a905fe0 , 0x06318863 , 0x3d6017ee ,
312+ 0x00300402 , 0x3ab057e0 , 0x0771986e , 0x3d001beb ,
313+ 0x00200001 , 0x3af04fe1 , 0x08a1a47a , 0x3cb023e9 ,
314+ 0x00100001 , 0x3b2047e2 , 0x09e1b485 , 0x3c6027e7 ,
315+ 0x00100000 , 0x3b703fe2 , 0x0b11c091 , 0x3c002fe6 ,
316+ 0x3f203800 , 0x0391103f , 0x3ff0a014 , 0x0811606c ,
317+ 0x3f2037ff , 0x0351083c , 0x03e11842 , 0x3f203c00 ,
318+ 0x3f302fff , 0x03010439 , 0x04311c45 , 0x3f104401 ,
319+ 0x3f302fff , 0x02c0fc35 , 0x04812448 , 0x3f104802 ,
320+ 0x3f4027ff , 0x0270f832 , 0x04c1284b , 0x3f205003 ,
321+ 0x3f4023ff , 0x0230f030 , 0x0511304e , 0x3f205403 ,
322+ 0x3f601fff , 0x01f0e82d , 0x05613451 , 0x3f205c04 ,
323+ 0x3f701bfe , 0x01b0e02a , 0x05a13c54 , 0x3f306006 ,
324+ 0x3f7017fe , 0x0170d827 , 0x05f14057 , 0x3f406807 ,
325+ 0x3f8017ff , 0x0140d424 , 0x0641445a , 0x3f406c08 ,
326+ 0x3fa013ff , 0x0100cc22 , 0x0681485d , 0x3f507409 ,
327+ 0x3fa00fff , 0x00d0c41f , 0x06d14c60 , 0x3f607c0b ,
328+ 0x3fc00fff , 0x0090bc1c , 0x07115063 , 0x3f80840c ,
329+ 0x3fd00bff , 0x0070b41a , 0x07515465 , 0x3f908c0e ,
330+ 0x3fe007ff , 0x0040b018 , 0x07915868 , 0x3fb0900f ,
331+ 0x3ff00400 , 0x0010a816 , 0x07d15c6a , 0x3fd09811 ,
332+ 0x00a04c0e , 0x0460f442 , 0x0240a827 , 0x05c15859 ,
333+ 0x0090440d , 0x0440f040 , 0x0480fc43 , 0x00b05010 ,
334+ 0x0080400c , 0x0410ec3e , 0x04910044 , 0x00d05411 ,
335+ 0x0070380b , 0x03f0e83d , 0x04b10846 , 0x00e05812 ,
336+ 0x0060340a , 0x03d0e43b , 0x04d10c48 , 0x00f06013 ,
337+ 0x00503009 , 0x03b0e039 , 0x04e11449 , 0x01106415 ,
338+ 0x00402c08 , 0x0390d838 , 0x05011c4b , 0x01206c16 ,
339+ 0x00302807 , 0x0370d436 , 0x0511204c , 0x01407018 ,
340+ 0x00302406 , 0x0340d034 , 0x0531244e , 0x01507419 ,
341+ 0x00202005 , 0x0320cc32 , 0x05412c50 , 0x01707c1b ,
342+ 0x00101c04 , 0x0300c431 , 0x05613451 , 0x0180801d ,
343+ 0x00101803 , 0x02e0c02f , 0x05713853 , 0x01a0881e ,
344+ 0x00101002 , 0x02b0bc2d , 0x05814054 , 0x01c08c20 ,
345+ 0x00000c02 , 0x02a0b82c , 0x05914455 , 0x01e09421 ,
346+ 0x00000801 , 0x0280b02a , 0x05a14c57 , 0x02009c23 ,
347+ 0x00000400 , 0x0260ac28 , 0x05b15458 , 0x0220a025 ,
348+ };
349+ unsigned int ratio , row , column ;
350+
351+ for (ratio = 0 ; ratio <= 2 ; ratio ++ ) {
352+ for (row = 0 ; row <= 15 ; row ++ ) {
353+ for (column = 0 ; column <= 3 ; column ++ ) {
354+ unsigned int index = (ratio << 6 ) + (row << 2 ) + column ;
355+ u32 value ;
356+
357+ value = COEFF_INDEX (index ) | COEFF_DATA (coeffs [index ]);
358+ tegra_plane_writel (plane , value ,
359+ DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF );
360+ }
361+ }
362+ }
363+ }
364+
295365static void tegra_dc_assign_shared_plane (struct tegra_dc * dc ,
296366 struct tegra_plane * plane )
297367{
@@ -337,6 +407,8 @@ static void tegra_dc_assign_shared_plane(struct tegra_dc *dc,
337407 value |= THREAD_GROUP_ENABLE ;
338408 tegra_plane_writel (plane , value , DC_WIN_CORE_IHUB_THREAD_GROUP );
339409
410+ tegra_shared_plane_setup_scaler (plane );
411+
340412 tegra_shared_plane_update (plane );
341413 tegra_shared_plane_activate (plane );
342414}
@@ -444,6 +516,18 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
444516 host1x_client_suspend (& dc -> client );
445517}
446518
519+ static inline u32 compute_phase_incr (fixed20_12 in , unsigned int out )
520+ {
521+ u64 tmp , tmp1 , tmp2 ;
522+
523+ tmp = (u64 )dfixed_trunc (in );
524+ tmp2 = (u64 )out ;
525+ tmp1 = (tmp << NFB ) + (tmp2 >> 1 );
526+ do_div (tmp1 , tmp2 );
527+
528+ return lower_32_bits (tmp1 );
529+ }
530+
447531static void tegra_shared_plane_atomic_update (struct drm_plane * plane ,
448532 struct drm_atomic_state * state )
449533{
@@ -454,8 +538,10 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
454538 unsigned int zpos = new_state -> normalized_zpos ;
455539 struct drm_framebuffer * fb = new_state -> fb ;
456540 struct tegra_plane * p = to_tegra_plane (plane );
457- dma_addr_t base ;
458- u32 value ;
541+ u32 value , min_width , bypass = 0 ;
542+ dma_addr_t base , addr_flag = 0 ;
543+ unsigned int bpc ;
544+ bool yuv , planar ;
459545 int err ;
460546
461547 /* rien ne va plus */
@@ -473,6 +559,8 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
473559 return ;
474560 }
475561
562+ yuv = tegra_plane_format_is_yuv (tegra_plane_state -> format , & planar , & bpc );
563+
476564 tegra_dc_assign_shared_plane (dc , p );
477565
478566 tegra_plane_writel (p , VCOUNTER , DC_WIN_CORE_ACT_CONTROL );
@@ -491,28 +579,65 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
491579 value = K2 (255 ) | K1 (255 ) | WINDOW_LAYER_DEPTH (255 - zpos );
492580 tegra_plane_writel (p , value , DC_WIN_BLEND_LAYER_CONTROL );
493581
494- /* bypass scaling */
582+ /* scaling */
583+ min_width = min (new_state -> src_w >> 16 , new_state -> crtc_w );
584+
585+ value = tegra_plane_readl (p , DC_WINC_PRECOMP_WGRP_PIPE_CAPC );
586+
587+ if (min_width < MAX_PIXELS_5TAP444 (value )) {
588+ value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5 ;
589+ } else {
590+ value = tegra_plane_readl (p , DC_WINC_PRECOMP_WGRP_PIPE_CAPE );
591+
592+ if (min_width < MAX_PIXELS_2TAP444 (value ))
593+ value = HORIZONTAL_TAPS_2 | VERTICAL_TAPS_2 ;
594+ else
595+ dev_err (dc -> dev , "invalid minimum width: %u\n" , min_width );
596+ }
597+
495598 value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5 ;
496599 tegra_plane_writel (p , value , DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER );
497600
498- value = INPUT_SCALER_VBYPASS | INPUT_SCALER_HBYPASS ;
499- tegra_plane_writel (p , value , DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE );
601+ if (new_state -> src_w != new_state -> crtc_w << 16 ) {
602+ fixed20_12 width = dfixed_init (new_state -> src_w >> 16 );
603+ u32 incr = compute_phase_incr (width , new_state -> crtc_w ) & ~0x1 ;
604+ u32 init = (1 << (NFB - 1 )) + (incr >> 1 );
605+
606+ tegra_plane_writel (p , incr , DC_WIN_SET_INPUT_SCALER_HPHASE_INCR );
607+ tegra_plane_writel (p , init , DC_WIN_SET_INPUT_SCALER_H_START_PHASE );
608+ } else {
609+ bypass |= INPUT_SCALER_HBYPASS ;
610+ }
611+
612+ if (new_state -> src_h != new_state -> crtc_h << 16 ) {
613+ fixed20_12 height = dfixed_init (new_state -> src_h >> 16 );
614+ u32 incr = compute_phase_incr (height , new_state -> crtc_h ) & ~0x1 ;
615+ u32 init = (1 << (NFB - 1 )) + (incr >> 1 );
616+
617+ tegra_plane_writel (p , incr , DC_WIN_SET_INPUT_SCALER_VPHASE_INCR );
618+ tegra_plane_writel (p , init , DC_WIN_SET_INPUT_SCALER_V_START_PHASE );
619+ } else {
620+ bypass |= INPUT_SCALER_VBYPASS ;
621+ }
622+
623+ tegra_plane_writel (p , bypass , DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE );
500624
501625 /* disable compression */
502626 tegra_plane_writel (p , 0 , DC_WINBUF_CDE_CONTROL );
503627
504- base = tegra_plane_state -> iova [0 ] + fb -> offsets [0 ];
505-
506628#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
507629 /*
508630 * Physical address bit 39 in Tegra194 is used as a switch for special
509631 * logic that swizzles the memory using either the legacy Tegra or the
510632 * dGPU sector layout.
511633 */
512634 if (tegra_plane_state -> tiling .sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU )
513- base | = BIT_ULL (39 );
635+ addr_flag = BIT_ULL (39 );
514636#endif
515637
638+ base = tegra_plane_state -> iova [0 ] + fb -> offsets [0 ];
639+ base |= addr_flag ;
640+
516641 tegra_plane_writel (p , tegra_plane_state -> format , DC_WIN_COLOR_DEPTH );
517642 tegra_plane_writel (p , 0 , DC_WIN_PRECOMP_WGRP_PARAMS );
518643
@@ -526,7 +651,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
526651 value = WIN_ENABLE | COLOR_EXPAND ;
527652 tegra_plane_writel (p , value , DC_WIN_WIN_OPTIONS );
528653
529- value = V_SIZE (new_state -> crtc_h ) | H_SIZE (new_state -> crtc_w );
654+ value = V_SIZE (new_state -> src_h >> 16 ) | H_SIZE (new_state -> src_w >> 16 );
530655 tegra_plane_writel (p , value , DC_WIN_CROPPED_SIZE );
531656
532657 tegra_plane_writel (p , upper_32_bits (base ), DC_WINBUF_START_ADDR_HI );
@@ -535,7 +660,44 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
535660 value = PITCH (fb -> pitches [0 ]);
536661 tegra_plane_writel (p , value , DC_WIN_PLANAR_STORAGE );
537662
538- value = CLAMP_BEFORE_BLEND | DEGAMMA_SRGB | INPUT_RANGE_FULL ;
663+ if (yuv && planar ) {
664+ base = tegra_plane_state -> iova [1 ] + fb -> offsets [1 ];
665+ base |= addr_flag ;
666+
667+ tegra_plane_writel (p , upper_32_bits (base ), DC_WINBUF_START_ADDR_HI_U );
668+ tegra_plane_writel (p , lower_32_bits (base ), DC_WINBUF_START_ADDR_U );
669+
670+ base = tegra_plane_state -> iova [2 ] + fb -> offsets [2 ];
671+ base |= addr_flag ;
672+
673+ tegra_plane_writel (p , upper_32_bits (base ), DC_WINBUF_START_ADDR_HI_V );
674+ tegra_plane_writel (p , lower_32_bits (base ), DC_WINBUF_START_ADDR_V );
675+
676+ value = PITCH_U (fb -> pitches [2 ]) | PITCH_V (fb -> pitches [2 ]);
677+ tegra_plane_writel (p , value , DC_WIN_PLANAR_STORAGE_UV );
678+ } else {
679+ tegra_plane_writel (p , 0 , DC_WINBUF_START_ADDR_U );
680+ tegra_plane_writel (p , 0 , DC_WINBUF_START_ADDR_HI_U );
681+ tegra_plane_writel (p , 0 , DC_WINBUF_START_ADDR_V );
682+ tegra_plane_writel (p , 0 , DC_WINBUF_START_ADDR_HI_V );
683+ tegra_plane_writel (p , 0 , DC_WIN_PLANAR_STORAGE_UV );
684+ }
685+
686+ value = CLAMP_BEFORE_BLEND | INPUT_RANGE_FULL ;
687+
688+ if (yuv ) {
689+ if (bpc < 12 )
690+ value |= DEGAMMA_YUV8_10 ;
691+ else
692+ value |= DEGAMMA_YUV12 ;
693+
694+ /* XXX parameterize */
695+ value |= COLOR_SPACE_YUV_2020 ;
696+ } else {
697+ if (!tegra_plane_format_is_indexed (tegra_plane_state -> format ))
698+ value |= DEGAMMA_SRGB ;
699+ }
700+
539701 tegra_plane_writel (p , value , DC_WIN_SET_PARAMS );
540702
541703 value = OFFSET_X (new_state -> src_y >> 16 ) |
0 commit comments