@@ -832,10 +832,14 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
832
832
return & plane -> base ;
833
833
}
834
834
835
- static const u32 tegra_cursor_plane_formats [] = {
835
+ static const u32 tegra_legacy_cursor_plane_formats [] = {
836
836
DRM_FORMAT_RGBA8888 ,
837
837
};
838
838
839
+ static const u32 tegra_cursor_plane_formats [] = {
840
+ DRM_FORMAT_ARGB8888 ,
841
+ };
842
+
839
843
static int tegra_cursor_atomic_check (struct drm_plane * plane ,
840
844
struct drm_atomic_state * state )
841
845
{
@@ -875,12 +879,24 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
875
879
plane );
876
880
struct tegra_plane_state * tegra_plane_state = to_tegra_plane_state (new_state );
877
881
struct tegra_dc * dc = to_tegra_dc (new_state -> crtc );
878
- u32 value = CURSOR_CLIP_DISPLAY ;
882
+ struct tegra_drm * tegra = plane -> dev -> dev_private ;
883
+ #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
884
+ u64 dma_mask = * dc -> dev -> dma_mask ;
885
+ #endif
886
+ unsigned int x , y ;
887
+ u32 value = 0 ;
879
888
880
889
/* rien ne va plus */
881
890
if (!new_state -> crtc || !new_state -> fb )
882
891
return ;
883
892
893
+ /*
894
+ * Legacy display supports hardware clipping of the cursor, but
895
+ * nvdisplay relies on software to clip the cursor to the screen.
896
+ */
897
+ if (!dc -> soc -> has_nvdisplay )
898
+ value |= CURSOR_CLIP_DISPLAY ;
899
+
884
900
switch (new_state -> crtc_w ) {
885
901
case 32 :
886
902
value |= CURSOR_SIZE_32x32 ;
@@ -908,7 +924,7 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
908
924
tegra_dc_writel (dc , value , DC_DISP_CURSOR_START_ADDR );
909
925
910
926
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
911
- value = (tegra_plane_state -> iova [0 ] >> 32 ) & 0x3 ;
927
+ value = (tegra_plane_state -> iova [0 ] >> 32 ) & ( dma_mask >> 32 ) ;
912
928
tegra_dc_writel (dc , value , DC_DISP_CURSOR_START_ADDR_HI );
913
929
#endif
914
930
@@ -920,15 +936,39 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
920
936
value = tegra_dc_readl (dc , DC_DISP_BLEND_CURSOR_CONTROL );
921
937
value &= ~CURSOR_DST_BLEND_MASK ;
922
938
value &= ~CURSOR_SRC_BLEND_MASK ;
923
- value |= CURSOR_MODE_NORMAL ;
939
+
940
+ if (dc -> soc -> has_nvdisplay )
941
+ value &= ~CURSOR_COMPOSITION_MODE_XOR ;
942
+ else
943
+ value |= CURSOR_MODE_NORMAL ;
944
+
924
945
value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC ;
925
946
value |= CURSOR_SRC_BLEND_K1_TIMES_SRC ;
926
947
value |= CURSOR_ALPHA ;
927
948
tegra_dc_writel (dc , value , DC_DISP_BLEND_CURSOR_CONTROL );
928
949
950
+ /* nvdisplay relies on software for clipping */
951
+ if (dc -> soc -> has_nvdisplay ) {
952
+ struct drm_rect src ;
953
+
954
+ x = new_state -> dst .x1 ;
955
+ y = new_state -> dst .y1 ;
956
+
957
+ drm_rect_fp_to_int (& src , & new_state -> src );
958
+
959
+ value = (src .y1 & tegra -> vmask ) << 16 | (src .x1 & tegra -> hmask );
960
+ tegra_dc_writel (dc , value , DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR );
961
+
962
+ value = (drm_rect_height (& src ) & tegra -> vmask ) << 16 |
963
+ (drm_rect_width (& src ) & tegra -> hmask );
964
+ tegra_dc_writel (dc , value , DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR );
965
+ } else {
966
+ x = new_state -> crtc_x ;
967
+ y = new_state -> crtc_y ;
968
+ }
969
+
929
970
/* position the cursor */
930
- value = (new_state -> crtc_y & 0x3fff ) << 16 |
931
- (new_state -> crtc_x & 0x3fff );
971
+ value = ((y & tegra -> vmask ) << 16 ) | (x & tegra -> hmask );
932
972
tegra_dc_writel (dc , value , DC_DISP_CURSOR_POSITION );
933
973
}
934
974
@@ -982,8 +1022,13 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
982
1022
plane -> index = 6 ;
983
1023
plane -> dc = dc ;
984
1024
985
- num_formats = ARRAY_SIZE (tegra_cursor_plane_formats );
986
- formats = tegra_cursor_plane_formats ;
1025
+ if (!dc -> soc -> has_nvdisplay ) {
1026
+ num_formats = ARRAY_SIZE (tegra_legacy_cursor_plane_formats );
1027
+ formats = tegra_legacy_cursor_plane_formats ;
1028
+ } else {
1029
+ num_formats = ARRAY_SIZE (tegra_cursor_plane_formats );
1030
+ formats = tegra_cursor_plane_formats ;
1031
+ }
987
1032
988
1033
err = drm_universal_plane_init (drm , & plane -> base , possible_crtcs ,
989
1034
& tegra_plane_funcs , formats ,
@@ -2035,6 +2080,16 @@ static bool tegra_dc_has_window_groups(struct tegra_dc *dc)
2035
2080
return false;
2036
2081
}
2037
2082
2083
+ static int tegra_dc_early_init (struct host1x_client * client )
2084
+ {
2085
+ struct drm_device * drm = dev_get_drvdata (client -> host );
2086
+ struct tegra_drm * tegra = drm -> dev_private ;
2087
+
2088
+ tegra -> num_crtcs ++ ;
2089
+
2090
+ return 0 ;
2091
+ }
2092
+
2038
2093
static int tegra_dc_init (struct host1x_client * client )
2039
2094
{
2040
2095
struct drm_device * drm = dev_get_drvdata (client -> host );
@@ -2045,6 +2100,12 @@ static int tegra_dc_init(struct host1x_client *client)
2045
2100
struct drm_plane * cursor = NULL ;
2046
2101
int err ;
2047
2102
2103
+ /*
2104
+ * DC has been reset by now, so VBLANK syncpoint can be released
2105
+ * for general use.
2106
+ */
2107
+ host1x_syncpt_release_vblank_reservation (client , 26 + dc -> pipe );
2108
+
2048
2109
/*
2049
2110
* XXX do not register DCs with no window groups because we cannot
2050
2111
* assign a primary plane to them, which in turn will cause KMS to
@@ -2111,6 +2172,12 @@ static int tegra_dc_init(struct host1x_client *client)
2111
2172
if (dc -> soc -> pitch_align > tegra -> pitch_align )
2112
2173
tegra -> pitch_align = dc -> soc -> pitch_align ;
2113
2174
2175
+ /* track maximum resolution */
2176
+ if (dc -> soc -> has_nvdisplay )
2177
+ drm -> mode_config .max_width = drm -> mode_config .max_height = 16384 ;
2178
+ else
2179
+ drm -> mode_config .max_width = drm -> mode_config .max_height = 4096 ;
2180
+
2114
2181
err = tegra_dc_rgb_init (drm , dc );
2115
2182
if (err < 0 && err != - ENODEV ) {
2116
2183
dev_err (dc -> dev , "failed to initialize RGB output: %d\n" , err );
@@ -2141,7 +2208,7 @@ static int tegra_dc_init(struct host1x_client *client)
2141
2208
drm_plane_cleanup (primary );
2142
2209
2143
2210
host1x_client_iommu_detach (client );
2144
- host1x_syncpt_free (dc -> syncpt );
2211
+ host1x_syncpt_put (dc -> syncpt );
2145
2212
2146
2213
return err ;
2147
2214
}
@@ -2166,7 +2233,17 @@ static int tegra_dc_exit(struct host1x_client *client)
2166
2233
}
2167
2234
2168
2235
host1x_client_iommu_detach (client );
2169
- host1x_syncpt_free (dc -> syncpt );
2236
+ host1x_syncpt_put (dc -> syncpt );
2237
+
2238
+ return 0 ;
2239
+ }
2240
+
2241
+ static int tegra_dc_late_exit (struct host1x_client * client )
2242
+ {
2243
+ struct drm_device * drm = dev_get_drvdata (client -> host );
2244
+ struct tegra_drm * tegra = drm -> dev_private ;
2245
+
2246
+ tegra -> num_crtcs -- ;
2170
2247
2171
2248
return 0 ;
2172
2249
}
@@ -2235,8 +2312,10 @@ static int tegra_dc_runtime_resume(struct host1x_client *client)
2235
2312
}
2236
2313
2237
2314
static const struct host1x_client_ops dc_client_ops = {
2315
+ .early_init = tegra_dc_early_init ,
2238
2316
.init = tegra_dc_init ,
2239
2317
.exit = tegra_dc_exit ,
2318
+ .late_exit = tegra_dc_late_exit ,
2240
2319
.suspend = tegra_dc_runtime_suspend ,
2241
2320
.resume = tegra_dc_runtime_resume ,
2242
2321
};
@@ -2246,6 +2325,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
2246
2325
.supports_interlacing = false,
2247
2326
.supports_cursor = false,
2248
2327
.supports_block_linear = false,
2328
+ .supports_sector_layout = false,
2249
2329
.has_legacy_blending = true,
2250
2330
.pitch_align = 8 ,
2251
2331
.has_powergate = false,
@@ -2265,6 +2345,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
2265
2345
.supports_interlacing = false,
2266
2346
.supports_cursor = false,
2267
2347
.supports_block_linear = false,
2348
+ .supports_sector_layout = false,
2268
2349
.has_legacy_blending = true,
2269
2350
.pitch_align = 8 ,
2270
2351
.has_powergate = false,
@@ -2284,6 +2365,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
2284
2365
.supports_interlacing = false,
2285
2366
.supports_cursor = false,
2286
2367
.supports_block_linear = false,
2368
+ .supports_sector_layout = false,
2287
2369
.has_legacy_blending = true,
2288
2370
.pitch_align = 64 ,
2289
2371
.has_powergate = true,
@@ -2303,6 +2385,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
2303
2385
.supports_interlacing = true,
2304
2386
.supports_cursor = true,
2305
2387
.supports_block_linear = true,
2388
+ .supports_sector_layout = false,
2306
2389
.has_legacy_blending = false,
2307
2390
.pitch_align = 64 ,
2308
2391
.has_powergate = true,
@@ -2322,6 +2405,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
2322
2405
.supports_interlacing = true,
2323
2406
.supports_cursor = true,
2324
2407
.supports_block_linear = true,
2408
+ .supports_sector_layout = false,
2325
2409
.has_legacy_blending = false,
2326
2410
.pitch_align = 64 ,
2327
2411
.has_powergate = true,
@@ -2375,6 +2459,7 @@ static const struct tegra_dc_soc_info tegra186_dc_soc_info = {
2375
2459
.supports_interlacing = true,
2376
2460
.supports_cursor = true,
2377
2461
.supports_block_linear = true,
2462
+ .supports_sector_layout = false,
2378
2463
.has_legacy_blending = false,
2379
2464
.pitch_align = 64 ,
2380
2465
.has_powergate = false,
@@ -2423,6 +2508,7 @@ static const struct tegra_dc_soc_info tegra194_dc_soc_info = {
2423
2508
.supports_interlacing = true,
2424
2509
.supports_cursor = true,
2425
2510
.supports_block_linear = true,
2511
+ .supports_sector_layout = true,
2426
2512
.has_legacy_blending = false,
2427
2513
.pitch_align = 64 ,
2428
2514
.has_powergate = false,
@@ -2532,9 +2618,16 @@ static int tegra_dc_couple(struct tegra_dc *dc)
2532
2618
2533
2619
static int tegra_dc_probe (struct platform_device * pdev )
2534
2620
{
2621
+ u64 dma_mask = dma_get_mask (pdev -> dev .parent );
2535
2622
struct tegra_dc * dc ;
2536
2623
int err ;
2537
2624
2625
+ err = dma_coerce_mask_and_coherent (& pdev -> dev , dma_mask );
2626
+ if (err < 0 ) {
2627
+ dev_err (& pdev -> dev , "failed to set DMA mask: %d\n" , err );
2628
+ return err ;
2629
+ }
2630
+
2538
2631
dc = devm_kzalloc (& pdev -> dev , sizeof (* dc ), GFP_KERNEL );
2539
2632
if (!dc )
2540
2633
return - ENOMEM ;
0 commit comments