Skip to content

Commit 63b0951

Browse files
committed
Merge tag 'drm/tegra/for-5.17-rc1' of https://gitlab.freedesktop.org/drm/tegra into drm-next
drm/tegra: Changes for v5.17-rc1 This contains a fairly large rework that makes the buffer objects behave more according to what the DMA-BUF infrastructure expects. A buffer object cache is implemented on top of that to make certain operations such as page-flipping more efficient by avoiding needless map/unmap operations. This in turn is useful to implement asynchronous commits to support legacy cursor updates. Another fairly big addition is the NVDEC driver. This uses the updated UABI introduced in v5.15-rc1 to provide access to the video decode engines found on Tegra210 and later. This also includes some power management improvements that are useful on older devices in particular because they, together with a bunch of other changes across the kernel, allow the system to scale down frequency and voltages when mostly idle and prevent these devices from becoming excessively hot. The remainder of these changes is an assortment of cleanups and minor fixes. Signed-off-by: Dave Airlie <[email protected]> From: Thierry Reding <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
2 parents b06103b + d210919 commit 63b0951

File tree

33 files changed

+2020
-498
lines changed

33 files changed

+2020
-498
lines changed

drivers/gpu/drm/tegra/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ config DRM_TEGRA
1212
select INTERCONNECT
1313
select IOMMU_IOVA
1414
select CEC_CORE if CEC_NOTIFIER
15+
select SND_SIMPLE_CARD if SND_SOC_TEGRA20_SPDIF
16+
select SND_SOC_HDMI_CODEC if SND_SOC_TEGRA20_SPDIF
17+
select SND_AUDIO_GRAPH_CARD if SND_SOC_TEGRA20_SPDIF
1518
help
1619
Choose this option if you have an NVIDIA Tegra SoC.
1720

drivers/gpu/drm/tegra/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ tegra-drm-y := \
2323
gr2d.o \
2424
gr3d.o \
2525
falcon.o \
26-
vic.o
26+
vic.o \
27+
nvdec.o
2728

2829
tegra-drm-y += trace.o
2930

drivers/gpu/drm/tegra/dc.c

Lines changed: 179 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
#include <linux/interconnect.h>
1212
#include <linux/module.h>
1313
#include <linux/of_device.h>
14+
#include <linux/pm_domain.h>
15+
#include <linux/pm_opp.h>
1416
#include <linux/pm_runtime.h>
1517
#include <linux/reset.h>
1618

19+
#include <soc/tegra/common.h>
1720
#include <soc/tegra/pmc.h>
1821

1922
#include <drm/drm_atomic.h>
@@ -890,11 +893,9 @@ static int tegra_cursor_atomic_check(struct drm_plane *plane,
890893
return 0;
891894
}
892895

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)
895898
{
896-
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
897-
plane);
898899
struct tegra_plane_state *tegra_plane_state = to_tegra_plane_state(new_state);
899900
struct tegra_dc *dc = to_tegra_dc(new_state->crtc);
900901
struct tegra_drm *tegra = plane->dev->dev_private;
@@ -990,6 +991,14 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
990991
tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
991992
}
992993

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+
9931002
static void tegra_cursor_atomic_disable(struct drm_plane *plane,
9941003
struct drm_atomic_state *state)
9951004
{
@@ -1009,12 +1018,78 @@ static void tegra_cursor_atomic_disable(struct drm_plane *plane,
10091018
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
10101019
}
10111020

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+
10121085
static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
10131086
.prepare_fb = tegra_plane_prepare_fb,
10141087
.cleanup_fb = tegra_plane_cleanup_fb,
10151088
.atomic_check = tegra_cursor_atomic_check,
10161089
.atomic_update = tegra_cursor_atomic_update,
10171090
.atomic_disable = tegra_cursor_atomic_disable,
1091+
.atomic_async_check = tegra_cursor_atomic_async_check,
1092+
.atomic_async_update = tegra_cursor_atomic_async_update,
10181093
};
10191094

10201095
static const uint64_t linear_modifiers[] = {
@@ -1267,9 +1342,9 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm,
12671342
err = PTR_ERR(planes[i]);
12681343

12691344
while (i--)
1270-
tegra_plane_funcs.destroy(planes[i]);
1345+
planes[i]->funcs->destroy(planes[i]);
12711346

1272-
tegra_plane_funcs.destroy(primary);
1347+
primary->funcs->destroy(primary);
12731348
return ERR_PTR(err);
12741349
}
12751350
}
@@ -1762,10 +1837,55 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc,
17621837
return 0;
17631838
}
17641839

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)
17671888
{
1768-
u32 value;
17691889
int err;
17701890

17711891
err = clk_set_parent(dc->clk, state->clk);
@@ -1797,10 +1917,7 @@ static void tegra_dc_commit_state(struct tegra_dc *dc,
17971917
state->div);
17981918
DRM_DEBUG_KMS("pclk: %lu\n", state->pclk);
17991919

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);
18041921
}
18051922

18061923
static void tegra_dc_stop(struct tegra_dc *dc)
@@ -1991,6 +2108,13 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc,
19912108
err = host1x_client_suspend(&dc->client);
19922109
if (err < 0)
19932110
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+
}
19942118
}
19952119

19962120
static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
@@ -2002,6 +2126,9 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
20022126
u32 value;
20032127
int err;
20042128

2129+
/* apply PLL changes */
2130+
tegra_dc_set_clock_rate(dc, crtc_state);
2131+
20052132
err = host1x_client_resume(&dc->client);
20062133
if (err < 0) {
20072134
dev_err(dc->dev, "failed to resume: %d\n", err);
@@ -2076,8 +2203,11 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
20762203
else
20772204
tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
20782205

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+
}
20812211

20822212
/* program display mode */
20832213
tegra_dc_set_timings(dc, mode);
@@ -2107,6 +2237,12 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
21072237
tegra_dc_writel(dc, value, DC_COM_RG_UNDERFLOW);
21082238
}
21092239

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+
21102246
tegra_dc_commit(dc);
21112247

21122248
drm_crtc_vblank_on(crtc);
@@ -2685,6 +2821,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
26852821
.has_win_b_vfilter_mem_client = true,
26862822
.has_win_c_without_vert_filter = true,
26872823
.plane_tiled_memory_bandwidth_x2 = false,
2824+
.has_pll_d2_out0 = false,
26882825
};
26892826

26902827
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 = {
27072844
.has_win_b_vfilter_mem_client = true,
27082845
.has_win_c_without_vert_filter = false,
27092846
.plane_tiled_memory_bandwidth_x2 = true,
2847+
.has_pll_d2_out0 = true,
27102848
};
27112849

27122850
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 = {
27292867
.has_win_b_vfilter_mem_client = false,
27302868
.has_win_c_without_vert_filter = false,
27312869
.plane_tiled_memory_bandwidth_x2 = true,
2870+
.has_pll_d2_out0 = true,
27322871
};
27332872

27342873
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 = {
27512890
.has_win_b_vfilter_mem_client = false,
27522891
.has_win_c_without_vert_filter = false,
27532892
.plane_tiled_memory_bandwidth_x2 = false,
2893+
.has_pll_d2_out0 = true,
27542894
};
27552895

27562896
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 = {
27732913
.has_win_b_vfilter_mem_client = false,
27742914
.has_win_c_without_vert_filter = false,
27752915
.plane_tiled_memory_bandwidth_x2 = false,
2916+
.has_pll_d2_out0 = true,
27762917
};
27772918

27782919
static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = {
@@ -2823,6 +2964,7 @@ static const struct tegra_dc_soc_info tegra186_dc_soc_info = {
28232964
.wgrps = tegra186_dc_wgrps,
28242965
.num_wgrps = ARRAY_SIZE(tegra186_dc_wgrps),
28252966
.plane_tiled_memory_bandwidth_x2 = false,
2967+
.has_pll_d2_out0 = false,
28262968
};
28272969

28282970
static const struct tegra_windowgroup_soc tegra194_dc_wgrps[] = {
@@ -2873,6 +3015,7 @@ static const struct tegra_dc_soc_info tegra194_dc_soc_info = {
28733015
.wgrps = tegra194_dc_wgrps,
28743016
.num_wgrps = ARRAY_SIZE(tegra194_dc_wgrps),
28753017
.plane_tiled_memory_bandwidth_x2 = false,
3018+
.has_pll_d2_out0 = false,
28763019
};
28773020

28783021
static const struct of_device_id tegra_dc_of_match[] = {
@@ -2973,6 +3116,23 @@ static int tegra_dc_couple(struct tegra_dc *dc)
29733116
return 0;
29743117
}
29753118

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+
29763136
static int tegra_dc_probe(struct platform_device *pdev)
29773137
{
29783138
u64 dma_mask = dma_get_mask(pdev->dev.parent);
@@ -3038,6 +3198,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
30383198
tegra_powergate_power_off(dc->powergate);
30393199
}
30403200

3201+
err = tegra_dc_init_opp_table(dc);
3202+
if (err < 0)
3203+
return err;
3204+
30413205
dc->regs = devm_platform_ioremap_resource(pdev, 0);
30423206
if (IS_ERR(dc->regs))
30433207
return PTR_ERR(dc->regs);

drivers/gpu/drm/tegra/dc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ struct tegra_dc_soc_info {
7676
bool has_win_b_vfilter_mem_client;
7777
bool has_win_c_without_vert_filter;
7878
bool plane_tiled_memory_bandwidth_x2;
79+
bool has_pll_d2_out0;
7980
};
8081

8182
struct tegra_dc {
@@ -100,6 +101,8 @@ struct tegra_dc {
100101
struct drm_info_list *debugfs_files;
101102

102103
const struct tegra_dc_soc_info *soc;
104+
105+
bool has_opp_table;
103106
};
104107

105108
static inline struct tegra_dc *

0 commit comments

Comments
 (0)