11
11
#include <linux/interconnect.h>
12
12
#include <linux/module.h>
13
13
#include <linux/of_device.h>
14
+ #include <linux/pm_domain.h>
15
+ #include <linux/pm_opp.h>
14
16
#include <linux/pm_runtime.h>
15
17
#include <linux/reset.h>
16
18
19
+ #include <soc/tegra/common.h>
17
20
#include <soc/tegra/pmc.h>
18
21
19
22
#include <drm/drm_atomic.h>
@@ -890,11 +893,9 @@ static int tegra_cursor_atomic_check(struct drm_plane *plane,
890
893
return 0 ;
891
894
}
892
895
893
- static void tegra_cursor_atomic_update (struct drm_plane * plane ,
894
- struct drm_atomic_state * state )
896
+ static void __tegra_cursor_atomic_update (struct drm_plane * plane ,
897
+ struct drm_plane_state * new_state )
895
898
{
896
- struct drm_plane_state * new_state = drm_atomic_get_new_plane_state (state ,
897
- plane );
898
899
struct tegra_plane_state * tegra_plane_state = to_tegra_plane_state (new_state );
899
900
struct tegra_dc * dc = to_tegra_dc (new_state -> crtc );
900
901
struct tegra_drm * tegra = plane -> dev -> dev_private ;
@@ -990,6 +991,14 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
990
991
tegra_dc_writel (dc , value , DC_DISP_CURSOR_POSITION );
991
992
}
992
993
994
+ static void tegra_cursor_atomic_update (struct drm_plane * plane ,
995
+ struct drm_atomic_state * state )
996
+ {
997
+ struct drm_plane_state * new_state = drm_atomic_get_new_plane_state (state , plane );
998
+
999
+ __tegra_cursor_atomic_update (plane , new_state );
1000
+ }
1001
+
993
1002
static void tegra_cursor_atomic_disable (struct drm_plane * plane ,
994
1003
struct drm_atomic_state * state )
995
1004
{
@@ -1009,12 +1018,78 @@ static void tegra_cursor_atomic_disable(struct drm_plane *plane,
1009
1018
tegra_dc_writel (dc , value , DC_DISP_DISP_WIN_OPTIONS );
1010
1019
}
1011
1020
1021
+ static int tegra_cursor_atomic_async_check (struct drm_plane * plane , struct drm_atomic_state * state )
1022
+ {
1023
+ struct drm_plane_state * new_state = drm_atomic_get_new_plane_state (state , plane );
1024
+ struct drm_crtc_state * crtc_state ;
1025
+ int min_scale , max_scale ;
1026
+ int err ;
1027
+
1028
+ crtc_state = drm_atomic_get_existing_crtc_state (state , new_state -> crtc );
1029
+ if (WARN_ON (!crtc_state ))
1030
+ return - EINVAL ;
1031
+
1032
+ if (!crtc_state -> active )
1033
+ return - EINVAL ;
1034
+
1035
+ if (plane -> state -> crtc != new_state -> crtc ||
1036
+ plane -> state -> src_w != new_state -> src_w ||
1037
+ plane -> state -> src_h != new_state -> src_h ||
1038
+ plane -> state -> crtc_w != new_state -> crtc_w ||
1039
+ plane -> state -> crtc_h != new_state -> crtc_h ||
1040
+ plane -> state -> fb != new_state -> fb ||
1041
+ plane -> state -> fb == NULL )
1042
+ return - EINVAL ;
1043
+
1044
+ min_scale = (1 << 16 ) / 8 ;
1045
+ max_scale = (8 << 16 ) / 1 ;
1046
+
1047
+ err = drm_atomic_helper_check_plane_state (new_state , crtc_state , min_scale , max_scale ,
1048
+ true, true);
1049
+ if (err < 0 )
1050
+ return err ;
1051
+
1052
+ if (new_state -> visible != plane -> state -> visible )
1053
+ return - EINVAL ;
1054
+
1055
+ return 0 ;
1056
+ }
1057
+
1058
+ static void tegra_cursor_atomic_async_update (struct drm_plane * plane ,
1059
+ struct drm_atomic_state * state )
1060
+ {
1061
+ struct drm_plane_state * new_state = drm_atomic_get_new_plane_state (state , plane );
1062
+ struct tegra_dc * dc = to_tegra_dc (new_state -> crtc );
1063
+
1064
+ plane -> state -> src_x = new_state -> src_x ;
1065
+ plane -> state -> src_y = new_state -> src_y ;
1066
+ plane -> state -> crtc_x = new_state -> crtc_x ;
1067
+ plane -> state -> crtc_y = new_state -> crtc_y ;
1068
+
1069
+ if (new_state -> visible ) {
1070
+ struct tegra_plane * p = to_tegra_plane (plane );
1071
+ u32 value ;
1072
+
1073
+ __tegra_cursor_atomic_update (plane , new_state );
1074
+
1075
+ value = (WIN_A_ACT_REQ << p -> index ) << 8 | GENERAL_UPDATE ;
1076
+ tegra_dc_writel (dc , value , DC_CMD_STATE_CONTROL );
1077
+ (void )tegra_dc_readl (dc , DC_CMD_STATE_CONTROL );
1078
+
1079
+ value = (WIN_A_ACT_REQ << p -> index ) | GENERAL_ACT_REQ ;
1080
+ tegra_dc_writel (dc , value , DC_CMD_STATE_CONTROL );
1081
+ (void )tegra_dc_readl (dc , DC_CMD_STATE_CONTROL );
1082
+ }
1083
+ }
1084
+
1012
1085
static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
1013
1086
.prepare_fb = tegra_plane_prepare_fb ,
1014
1087
.cleanup_fb = tegra_plane_cleanup_fb ,
1015
1088
.atomic_check = tegra_cursor_atomic_check ,
1016
1089
.atomic_update = tegra_cursor_atomic_update ,
1017
1090
.atomic_disable = tegra_cursor_atomic_disable ,
1091
+ .atomic_async_check = tegra_cursor_atomic_async_check ,
1092
+ .atomic_async_update = tegra_cursor_atomic_async_update ,
1018
1093
};
1019
1094
1020
1095
static const uint64_t linear_modifiers [] = {
@@ -1267,9 +1342,9 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm,
1267
1342
err = PTR_ERR (planes [i ]);
1268
1343
1269
1344
while (i -- )
1270
- tegra_plane_funcs . destroy (planes [i ]);
1345
+ planes [ i ] -> funcs -> destroy (planes [i ]);
1271
1346
1272
- tegra_plane_funcs . destroy (primary );
1347
+ primary -> funcs -> destroy (primary );
1273
1348
return ERR_PTR (err );
1274
1349
}
1275
1350
}
@@ -1762,10 +1837,55 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc,
1762
1837
return 0 ;
1763
1838
}
1764
1839
1765
- static void tegra_dc_commit_state (struct tegra_dc * dc ,
1766
- struct tegra_dc_state * state )
1840
+ static void tegra_dc_update_voltage_state (struct tegra_dc * dc ,
1841
+ struct tegra_dc_state * state )
1842
+ {
1843
+ unsigned long rate , pstate ;
1844
+ struct dev_pm_opp * opp ;
1845
+ int err ;
1846
+
1847
+ if (!dc -> has_opp_table )
1848
+ return ;
1849
+
1850
+ /* calculate actual pixel clock rate which depends on internal divider */
1851
+ rate = DIV_ROUND_UP (clk_get_rate (dc -> clk ) * 2 , state -> div + 2 );
1852
+
1853
+ /* find suitable OPP for the rate */
1854
+ opp = dev_pm_opp_find_freq_ceil (dc -> dev , & rate );
1855
+
1856
+ /*
1857
+ * Very high resolution modes may results in a clock rate that is
1858
+ * above the characterized maximum. In this case it's okay to fall
1859
+ * back to the characterized maximum.
1860
+ */
1861
+ if (opp == ERR_PTR (- ERANGE ))
1862
+ opp = dev_pm_opp_find_freq_floor (dc -> dev , & rate );
1863
+
1864
+ if (IS_ERR (opp )) {
1865
+ dev_err (dc -> dev , "failed to find OPP for %luHz: %pe\n" ,
1866
+ rate , opp );
1867
+ return ;
1868
+ }
1869
+
1870
+ pstate = dev_pm_opp_get_required_pstate (opp , 0 );
1871
+ dev_pm_opp_put (opp );
1872
+
1873
+ /*
1874
+ * The minimum core voltage depends on the pixel clock rate (which
1875
+ * depends on internal clock divider of the CRTC) and not on the
1876
+ * rate of the display controller clock. This is why we're not using
1877
+ * dev_pm_opp_set_rate() API and instead controlling the power domain
1878
+ * directly.
1879
+ */
1880
+ err = dev_pm_genpd_set_performance_state (dc -> dev , pstate );
1881
+ if (err )
1882
+ dev_err (dc -> dev , "failed to set power domain state to %lu: %d\n" ,
1883
+ pstate , err );
1884
+ }
1885
+
1886
+ static void tegra_dc_set_clock_rate (struct tegra_dc * dc ,
1887
+ struct tegra_dc_state * state )
1767
1888
{
1768
- u32 value ;
1769
1889
int err ;
1770
1890
1771
1891
err = clk_set_parent (dc -> clk , state -> clk );
@@ -1797,10 +1917,7 @@ static void tegra_dc_commit_state(struct tegra_dc *dc,
1797
1917
state -> div );
1798
1918
DRM_DEBUG_KMS ("pclk: %lu\n" , state -> pclk );
1799
1919
1800
- if (!dc -> soc -> has_nvdisplay ) {
1801
- value = SHIFT_CLK_DIVIDER (state -> div ) | PIXEL_CLK_DIVIDER_PCD1 ;
1802
- tegra_dc_writel (dc , value , DC_DISP_DISP_CLOCK_CONTROL );
1803
- }
1920
+ tegra_dc_update_voltage_state (dc , state );
1804
1921
}
1805
1922
1806
1923
static void tegra_dc_stop (struct tegra_dc * dc )
@@ -1991,6 +2108,13 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc,
1991
2108
err = host1x_client_suspend (& dc -> client );
1992
2109
if (err < 0 )
1993
2110
dev_err (dc -> dev , "failed to suspend: %d\n" , err );
2111
+
2112
+ if (dc -> has_opp_table ) {
2113
+ err = dev_pm_genpd_set_performance_state (dc -> dev , 0 );
2114
+ if (err )
2115
+ dev_err (dc -> dev ,
2116
+ "failed to clear power domain state: %d\n" , err );
2117
+ }
1994
2118
}
1995
2119
1996
2120
static void tegra_crtc_atomic_enable (struct drm_crtc * crtc ,
@@ -2002,6 +2126,9 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
2002
2126
u32 value ;
2003
2127
int err ;
2004
2128
2129
+ /* apply PLL changes */
2130
+ tegra_dc_set_clock_rate (dc , crtc_state );
2131
+
2005
2132
err = host1x_client_resume (& dc -> client );
2006
2133
if (err < 0 ) {
2007
2134
dev_err (dc -> dev , "failed to resume: %d\n" , err );
@@ -2076,8 +2203,11 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
2076
2203
else
2077
2204
tegra_dc_writel (dc , 0 , DC_DISP_BORDER_COLOR );
2078
2205
2079
- /* apply PLL and pixel clock changes */
2080
- tegra_dc_commit_state (dc , crtc_state );
2206
+ /* apply pixel clock changes */
2207
+ if (!dc -> soc -> has_nvdisplay ) {
2208
+ value = SHIFT_CLK_DIVIDER (crtc_state -> div ) | PIXEL_CLK_DIVIDER_PCD1 ;
2209
+ tegra_dc_writel (dc , value , DC_DISP_DISP_CLOCK_CONTROL );
2210
+ }
2081
2211
2082
2212
/* program display mode */
2083
2213
tegra_dc_set_timings (dc , mode );
@@ -2107,6 +2237,12 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
2107
2237
tegra_dc_writel (dc , value , DC_COM_RG_UNDERFLOW );
2108
2238
}
2109
2239
2240
+ if (dc -> rgb ) {
2241
+ /* XXX: parameterize? */
2242
+ value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE ;
2243
+ tegra_dc_writel (dc , value , DC_DISP_SHIFT_CLOCK_OPTIONS );
2244
+ }
2245
+
2110
2246
tegra_dc_commit (dc );
2111
2247
2112
2248
drm_crtc_vblank_on (crtc );
@@ -2685,6 +2821,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
2685
2821
.has_win_b_vfilter_mem_client = true,
2686
2822
.has_win_c_without_vert_filter = true,
2687
2823
.plane_tiled_memory_bandwidth_x2 = false,
2824
+ .has_pll_d2_out0 = false,
2688
2825
};
2689
2826
2690
2827
static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
@@ -2707,6 +2844,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
2707
2844
.has_win_b_vfilter_mem_client = true,
2708
2845
.has_win_c_without_vert_filter = false,
2709
2846
.plane_tiled_memory_bandwidth_x2 = true,
2847
+ .has_pll_d2_out0 = true,
2710
2848
};
2711
2849
2712
2850
static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
@@ -2729,6 +2867,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
2729
2867
.has_win_b_vfilter_mem_client = false,
2730
2868
.has_win_c_without_vert_filter = false,
2731
2869
.plane_tiled_memory_bandwidth_x2 = true,
2870
+ .has_pll_d2_out0 = true,
2732
2871
};
2733
2872
2734
2873
static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
@@ -2751,6 +2890,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
2751
2890
.has_win_b_vfilter_mem_client = false,
2752
2891
.has_win_c_without_vert_filter = false,
2753
2892
.plane_tiled_memory_bandwidth_x2 = false,
2893
+ .has_pll_d2_out0 = true,
2754
2894
};
2755
2895
2756
2896
static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
@@ -2773,6 +2913,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
2773
2913
.has_win_b_vfilter_mem_client = false,
2774
2914
.has_win_c_without_vert_filter = false,
2775
2915
.plane_tiled_memory_bandwidth_x2 = false,
2916
+ .has_pll_d2_out0 = true,
2776
2917
};
2777
2918
2778
2919
static const struct tegra_windowgroup_soc tegra186_dc_wgrps [] = {
@@ -2823,6 +2964,7 @@ static const struct tegra_dc_soc_info tegra186_dc_soc_info = {
2823
2964
.wgrps = tegra186_dc_wgrps ,
2824
2965
.num_wgrps = ARRAY_SIZE (tegra186_dc_wgrps ),
2825
2966
.plane_tiled_memory_bandwidth_x2 = false,
2967
+ .has_pll_d2_out0 = false,
2826
2968
};
2827
2969
2828
2970
static const struct tegra_windowgroup_soc tegra194_dc_wgrps [] = {
@@ -2873,6 +3015,7 @@ static const struct tegra_dc_soc_info tegra194_dc_soc_info = {
2873
3015
.wgrps = tegra194_dc_wgrps ,
2874
3016
.num_wgrps = ARRAY_SIZE (tegra194_dc_wgrps ),
2875
3017
.plane_tiled_memory_bandwidth_x2 = false,
3018
+ .has_pll_d2_out0 = false,
2876
3019
};
2877
3020
2878
3021
static const struct of_device_id tegra_dc_of_match [] = {
@@ -2973,6 +3116,23 @@ static int tegra_dc_couple(struct tegra_dc *dc)
2973
3116
return 0 ;
2974
3117
}
2975
3118
3119
+ static int tegra_dc_init_opp_table (struct tegra_dc * dc )
3120
+ {
3121
+ struct tegra_core_opp_params opp_params = {};
3122
+ int err ;
3123
+
3124
+ err = devm_tegra_core_dev_init_opp_table (dc -> dev , & opp_params );
3125
+ if (err && err != - ENODEV )
3126
+ return err ;
3127
+
3128
+ if (err )
3129
+ dc -> has_opp_table = false;
3130
+ else
3131
+ dc -> has_opp_table = true;
3132
+
3133
+ return 0 ;
3134
+ }
3135
+
2976
3136
static int tegra_dc_probe (struct platform_device * pdev )
2977
3137
{
2978
3138
u64 dma_mask = dma_get_mask (pdev -> dev .parent );
@@ -3038,6 +3198,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
3038
3198
tegra_powergate_power_off (dc -> powergate );
3039
3199
}
3040
3200
3201
+ err = tegra_dc_init_opp_table (dc );
3202
+ if (err < 0 )
3203
+ return err ;
3204
+
3041
3205
dc -> regs = devm_platform_ioremap_resource (pdev , 0 );
3042
3206
if (IS_ERR (dc -> regs ))
3043
3207
return PTR_ERR (dc -> regs );
0 commit comments