aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2018-03-21 00:04:38 -0400
committerDave Airlie <airlied@redhat.com>2018-03-21 00:04:38 -0400
commit19c800caa682d9e20087d7b98af49301cf1ab039 (patch)
treee9ee7e7161c91f8d0ceedddabec7b1747cb13705
parent4f6dd8d6858b6fc0a3babbd2510f99c2bc84f2cb (diff)
parent27e92f1f1600c214bf649daddb9b88b68330a8d1 (diff)
Merge tag 'drm/tegra/for-4.17-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next
drm/tegra: Changes for v4.17-rc1 This fixes mmap() for fbdev devices by providing a custom implementation based on the KMS variant. This is a fairly exotic case these days, hence why it is not flagged for stable. There is also support for dedicating one of the overlay planes to serve as a hardware cursor on older Tegra that did support hardware cursors but not RGBA formats for it. Planes will now also export the IN_FORMATS property by supporting the various block-linear tiling modifiers for RGBA pixel formats. Other than that, there's a bit of cleanup of DMA API abuse, use of the private object infrastructure for global state (rather than subclassing atomic state objects) and an implementation of ->{begin,end}_cpu_access callbacks for PRIME exported buffers, which allow users to perform cache maintenance on these buffers. * tag 'drm/tegra/for-4.17-rc1' of git://anongit.freedesktop.org/tegra/linux: drm/tegra: prime: Implement ->{begin,end}_cpu_access() drm/tegra: gem: Map pages via the DMA API drm/tegra: hub: Use private object for global state drm/tegra: fb: Properly support linear modifier drm/tegra: plane: Support format modifiers drm/tegra: dc: Dedicate overlay plane to cursor on older Tegra's drm/tegra: plane: Make tegra_plane_get_overlap_index() static drm/tegra: fb: Implement ->fb_mmap() callback drm/tegra: gem: Make __tegra_gem_mmap() available more widely drm/tegra: gem: Reshuffle declarations
-rw-r--r--drivers/gpu/drm/tegra/dc.c82
-rw-r--r--drivers/gpu/drm/tegra/dc.h1
-rw-r--r--drivers/gpu/drm/tegra/drm.c36
-rw-r--r--drivers/gpu/drm/tegra/drm.h14
-rw-r--r--drivers/gpu/drm/tegra/fb.c25
-rw-r--r--drivers/gpu/drm/tegra/gem.c69
-rw-r--r--drivers/gpu/drm/tegra/gem.h5
-rw-r--r--drivers/gpu/drm/tegra/hub.c125
-rw-r--r--drivers/gpu/drm/tegra/hub.h17
-rw-r--r--drivers/gpu/drm/tegra/plane.c20
10 files changed, 280 insertions, 114 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 49df2db2ad46..71152776b04c 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -383,6 +383,12 @@ static const u32 tegra20_primary_formats[] = {
383 DRM_FORMAT_XRGB8888, 383 DRM_FORMAT_XRGB8888,
384}; 384};
385 385
386static const u64 tegra20_modifiers[] = {
387 DRM_FORMAT_MOD_LINEAR,
388 DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED,
389 DRM_FORMAT_MOD_INVALID
390};
391
386static const u32 tegra114_primary_formats[] = { 392static const u32 tegra114_primary_formats[] = {
387 DRM_FORMAT_ARGB4444, 393 DRM_FORMAT_ARGB4444,
388 DRM_FORMAT_ARGB1555, 394 DRM_FORMAT_ARGB1555,
@@ -430,6 +436,17 @@ static const u32 tegra124_primary_formats[] = {
430 DRM_FORMAT_BGRX8888, 436 DRM_FORMAT_BGRX8888,
431}; 437};
432 438
439static const u64 tegra124_modifiers[] = {
440 DRM_FORMAT_MOD_LINEAR,
441 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
442 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
443 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
444 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
445 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
446 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
447 DRM_FORMAT_MOD_INVALID
448};
449
433static int tegra_plane_atomic_check(struct drm_plane *plane, 450static int tegra_plane_atomic_check(struct drm_plane *plane,
434 struct drm_plane_state *state) 451 struct drm_plane_state *state)
435{ 452{
@@ -596,6 +613,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
596 enum drm_plane_type type = DRM_PLANE_TYPE_PRIMARY; 613 enum drm_plane_type type = DRM_PLANE_TYPE_PRIMARY;
597 struct tegra_plane *plane; 614 struct tegra_plane *plane;
598 unsigned int num_formats; 615 unsigned int num_formats;
616 const u64 *modifiers;
599 const u32 *formats; 617 const u32 *formats;
600 int err; 618 int err;
601 619
@@ -610,10 +628,11 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
610 628
611 num_formats = dc->soc->num_primary_formats; 629 num_formats = dc->soc->num_primary_formats;
612 formats = dc->soc->primary_formats; 630 formats = dc->soc->primary_formats;
631 modifiers = dc->soc->modifiers;
613 632
614 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, 633 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
615 &tegra_plane_funcs, formats, 634 &tegra_plane_funcs, formats,
616 num_formats, NULL, type, NULL); 635 num_formats, modifiers, type, NULL);
617 if (err < 0) { 636 if (err < 0) {
618 kfree(plane); 637 kfree(plane);
619 return ERR_PTR(err); 638 return ERR_PTR(err);
@@ -864,11 +883,13 @@ static const u32 tegra124_overlay_formats[] = {
864 883
865static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, 884static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
866 struct tegra_dc *dc, 885 struct tegra_dc *dc,
867 unsigned int index) 886 unsigned int index,
887 bool cursor)
868{ 888{
869 unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm); 889 unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm);
870 struct tegra_plane *plane; 890 struct tegra_plane *plane;
871 unsigned int num_formats; 891 unsigned int num_formats;
892 enum drm_plane_type type;
872 const u32 *formats; 893 const u32 *formats;
873 int err; 894 int err;
874 895
@@ -883,10 +904,14 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
883 num_formats = dc->soc->num_overlay_formats; 904 num_formats = dc->soc->num_overlay_formats;
884 formats = dc->soc->overlay_formats; 905 formats = dc->soc->overlay_formats;
885 906
907 if (!cursor)
908 type = DRM_PLANE_TYPE_OVERLAY;
909 else
910 type = DRM_PLANE_TYPE_CURSOR;
911
886 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, 912 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
887 &tegra_plane_funcs, formats, 913 &tegra_plane_funcs, formats,
888 num_formats, NULL, 914 num_formats, NULL, type, NULL);
889 DRM_PLANE_TYPE_OVERLAY, NULL);
890 if (err < 0) { 915 if (err < 0) {
891 kfree(plane); 916 kfree(plane);
892 return ERR_PTR(err); 917 return ERR_PTR(err);
@@ -938,6 +963,7 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm,
938 struct tegra_dc *dc) 963 struct tegra_dc *dc)
939{ 964{
940 struct drm_plane *planes[2], *primary; 965 struct drm_plane *planes[2], *primary;
966 unsigned int planes_num;
941 unsigned int i; 967 unsigned int i;
942 int err; 968 int err;
943 969
@@ -945,8 +971,14 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm,
945 if (IS_ERR(primary)) 971 if (IS_ERR(primary))
946 return primary; 972 return primary;
947 973
948 for (i = 0; i < 2; i++) { 974 if (dc->soc->supports_cursor)
949 planes[i] = tegra_dc_overlay_plane_create(drm, dc, 1 + i); 975 planes_num = 2;
976 else
977 planes_num = 1;
978
979 for (i = 0; i < planes_num; i++) {
980 planes[i] = tegra_dc_overlay_plane_create(drm, dc, 1 + i,
981 false);
950 if (IS_ERR(planes[i])) { 982 if (IS_ERR(planes[i])) {
951 err = PTR_ERR(planes[i]); 983 err = PTR_ERR(planes[i]);
952 984
@@ -1704,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
1704 drm_crtc_vblank_on(crtc); 1736 drm_crtc_vblank_on(crtc);
1705} 1737}
1706 1738
1707static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
1708 struct drm_crtc_state *state)
1709{
1710 struct tegra_atomic_state *s = to_tegra_atomic_state(state->state);
1711 struct tegra_dc_state *tegra = to_dc_state(state);
1712
1713 /*
1714 * The display hub display clock needs to be fed by the display clock
1715 * with the highest frequency to ensure proper functioning of all the
1716 * displays.
1717 *
1718 * Note that this isn't used before Tegra186, but it doesn't hurt and
1719 * conditionalizing it would make the code less clean.
1720 */
1721 if (state->active) {
1722 if (!s->clk_disp || tegra->pclk > s->rate) {
1723 s->dc = to_tegra_dc(crtc);
1724 s->clk_disp = s->dc->clk;
1725 s->rate = tegra->pclk;
1726 }
1727 }
1728
1729 return 0;
1730}
1731
1732static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, 1739static void tegra_crtc_atomic_begin(struct drm_crtc *crtc,
1733 struct drm_crtc_state *old_crtc_state) 1740 struct drm_crtc_state *old_crtc_state)
1734{ 1741{
@@ -1765,7 +1772,6 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
1765} 1772}
1766 1773
1767static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { 1774static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
1768 .atomic_check = tegra_crtc_atomic_check,
1769 .atomic_begin = tegra_crtc_atomic_begin, 1775 .atomic_begin = tegra_crtc_atomic_begin,
1770 .atomic_flush = tegra_crtc_atomic_flush, 1776 .atomic_flush = tegra_crtc_atomic_flush,
1771 .atomic_enable = tegra_crtc_atomic_enable, 1777 .atomic_enable = tegra_crtc_atomic_enable,
@@ -1864,6 +1870,13 @@ static int tegra_dc_init(struct host1x_client *client)
1864 err = PTR_ERR(cursor); 1870 err = PTR_ERR(cursor);
1865 goto cleanup; 1871 goto cleanup;
1866 } 1872 }
1873 } else {
1874 /* dedicate one overlay to mouse cursor */
1875 cursor = tegra_dc_overlay_plane_create(drm, dc, 2, true);
1876 if (IS_ERR(cursor)) {
1877 err = PTR_ERR(cursor);
1878 goto cleanup;
1879 }
1867 } 1880 }
1868 1881
1869 err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor, 1882 err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor,
@@ -1954,6 +1967,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
1954 .primary_formats = tegra20_primary_formats, 1967 .primary_formats = tegra20_primary_formats,
1955 .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), 1968 .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),
1956 .overlay_formats = tegra20_overlay_formats, 1969 .overlay_formats = tegra20_overlay_formats,
1970 .modifiers = tegra20_modifiers,
1957}; 1971};
1958 1972
1959static const struct tegra_dc_soc_info tegra30_dc_soc_info = { 1973static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
@@ -1970,6 +1984,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
1970 .primary_formats = tegra20_primary_formats, 1984 .primary_formats = tegra20_primary_formats,
1971 .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), 1985 .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),
1972 .overlay_formats = tegra20_overlay_formats, 1986 .overlay_formats = tegra20_overlay_formats,
1987 .modifiers = tegra20_modifiers,
1973}; 1988};
1974 1989
1975static const struct tegra_dc_soc_info tegra114_dc_soc_info = { 1990static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
@@ -1986,6 +2001,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
1986 .primary_formats = tegra114_primary_formats, 2001 .primary_formats = tegra114_primary_formats,
1987 .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), 2002 .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),
1988 .overlay_formats = tegra114_overlay_formats, 2003 .overlay_formats = tegra114_overlay_formats,
2004 .modifiers = tegra20_modifiers,
1989}; 2005};
1990 2006
1991static const struct tegra_dc_soc_info tegra124_dc_soc_info = { 2007static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
@@ -2002,6 +2018,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
2002 .primary_formats = tegra114_primary_formats, 2018 .primary_formats = tegra114_primary_formats,
2003 .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats), 2019 .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats),
2004 .overlay_formats = tegra114_overlay_formats, 2020 .overlay_formats = tegra114_overlay_formats,
2021 .modifiers = tegra124_modifiers,
2005}; 2022};
2006 2023
2007static const struct tegra_dc_soc_info tegra210_dc_soc_info = { 2024static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
@@ -2018,6 +2035,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
2018 .primary_formats = tegra114_primary_formats, 2035 .primary_formats = tegra114_primary_formats,
2019 .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), 2036 .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),
2020 .overlay_formats = tegra114_overlay_formats, 2037 .overlay_formats = tegra114_overlay_formats,
2038 .modifiers = tegra124_modifiers,
2021}; 2039};
2022 2040
2023static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = { 2041static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = {
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 096a81ad6d8d..d2b50d32de4d 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -66,6 +66,7 @@ struct tegra_dc_soc_info {
66 unsigned int num_primary_formats; 66 unsigned int num_primary_formats;
67 const u32 *overlay_formats; 67 const u32 *overlay_formats;
68 unsigned int num_overlay_formats; 68 unsigned int num_overlay_formats;
69 const u64 *modifiers;
69}; 70};
70 71
71struct tegra_dc { 72struct tegra_dc {
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index d50bddb2e447..e20e013151f0 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm,
42 if (err < 0) 42 if (err < 0)
43 return err; 43 return err;
44 44
45 err = tegra_display_hub_atomic_check(drm, state);
46 if (err < 0)
47 return err;
48
45 err = drm_atomic_normalize_zpos(drm, state); 49 err = drm_atomic_normalize_zpos(drm, state);
46 if (err < 0) 50 if (err < 0)
47 return err; 51 return err;
@@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm,
56 return 0; 60 return 0;
57} 61}
58 62
59static struct drm_atomic_state *
60tegra_atomic_state_alloc(struct drm_device *drm)
61{
62 struct tegra_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
63
64 if (!state || drm_atomic_state_init(drm, &state->base) < 0) {
65 kfree(state);
66 return NULL;
67 }
68
69 return &state->base;
70}
71
72static void tegra_atomic_state_clear(struct drm_atomic_state *state)
73{
74 struct tegra_atomic_state *tegra = to_tegra_atomic_state(state);
75
76 drm_atomic_state_default_clear(state);
77 tegra->clk_disp = NULL;
78 tegra->dc = NULL;
79 tegra->rate = 0;
80}
81
82static void tegra_atomic_state_free(struct drm_atomic_state *state)
83{
84 drm_atomic_state_default_release(state);
85 kfree(state);
86}
87
88static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { 63static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
89 .fb_create = tegra_fb_create, 64 .fb_create = tegra_fb_create,
90#ifdef CONFIG_DRM_FBDEV_EMULATION 65#ifdef CONFIG_DRM_FBDEV_EMULATION
@@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
92#endif 67#endif
93 .atomic_check = tegra_atomic_check, 68 .atomic_check = tegra_atomic_check,
94 .atomic_commit = drm_atomic_helper_commit, 69 .atomic_commit = drm_atomic_helper_commit,
95 .atomic_state_alloc = tegra_atomic_state_alloc,
96 .atomic_state_clear = tegra_atomic_state_clear,
97 .atomic_state_free = tegra_atomic_state_free,
98}; 70};
99 71
100static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state) 72static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state)
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 73b661ce7086..4f41aaec8530 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -42,20 +42,6 @@ struct tegra_fbdev {
42}; 42};
43#endif 43#endif
44 44
45struct tegra_atomic_state {
46 struct drm_atomic_state base;
47
48 struct clk *clk_disp;
49 struct tegra_dc *dc;
50 unsigned long rate;
51};
52
53static inline struct tegra_atomic_state *
54to_tegra_atomic_state(struct drm_atomic_state *state)
55{
56 return container_of(state, struct tegra_atomic_state, base);
57}
58
59struct tegra_drm { 45struct tegra_drm {
60 struct drm_device *drm; 46 struct drm_device *drm;
61 47
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 001cb77e2f59..e69434909a42 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -55,6 +55,11 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
55 uint64_t modifier = fb->base.modifier; 55 uint64_t modifier = fb->base.modifier;
56 56
57 switch (modifier) { 57 switch (modifier) {
58 case DRM_FORMAT_MOD_LINEAR:
59 tiling->mode = TEGRA_BO_TILING_MODE_PITCH;
60 tiling->value = 0;
61 break;
62
58 case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED: 63 case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
59 tiling->mode = TEGRA_BO_TILING_MODE_TILED; 64 tiling->mode = TEGRA_BO_TILING_MODE_TILED;
60 tiling->value = 0; 65 tiling->value = 0;
@@ -91,9 +96,7 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
91 break; 96 break;
92 97
93 default: 98 default:
94 /* TODO: handle YUV formats? */ 99 return -EINVAL;
95 *tiling = fb->planes[0]->tiling;
96 break;
97 } 100 }
98 101
99 return 0; 102 return 0;
@@ -224,12 +227,28 @@ unreference:
224} 227}
225 228
226#ifdef CONFIG_DRM_FBDEV_EMULATION 229#ifdef CONFIG_DRM_FBDEV_EMULATION
230static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
231{
232 struct drm_fb_helper *helper = info->par;
233 struct tegra_bo *bo;
234 int err;
235
236 bo = tegra_fb_get_plane(helper->fb, 0);
237
238 err = drm_gem_mmap_obj(&bo->gem, bo->gem.size, vma);
239 if (err < 0)
240 return err;
241
242 return __tegra_gem_mmap(&bo->gem, vma);
243}
244
227static struct fb_ops tegra_fb_ops = { 245static struct fb_ops tegra_fb_ops = {
228 .owner = THIS_MODULE, 246 .owner = THIS_MODULE,
229 DRM_FB_HELPER_DEFAULT_OPS, 247 DRM_FB_HELPER_DEFAULT_OPS,
230 .fb_fillrect = drm_fb_helper_sys_fillrect, 248 .fb_fillrect = drm_fb_helper_sys_fillrect,
231 .fb_copyarea = drm_fb_helper_sys_copyarea, 249 .fb_copyarea = drm_fb_helper_sys_copyarea,
232 .fb_imageblit = drm_fb_helper_sys_imageblit, 250 .fb_imageblit = drm_fb_helper_sys_imageblit,
251 .fb_mmap = tegra_fb_mmap,
233}; 252};
234 253
235static int tegra_fbdev_probe(struct drm_fb_helper *helper, 254static int tegra_fbdev_probe(struct drm_fb_helper *helper,
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 49b9bf28f872..8b0b4ff64bb4 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -203,6 +203,8 @@ free:
203static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) 203static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo)
204{ 204{
205 if (bo->pages) { 205 if (bo->pages) {
206 dma_unmap_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents,
207 DMA_BIDIRECTIONAL);
206 drm_gem_put_pages(&bo->gem, bo->pages, true, true); 208 drm_gem_put_pages(&bo->gem, bo->pages, true, true);
207 sg_free_table(bo->sgt); 209 sg_free_table(bo->sgt);
208 kfree(bo->sgt); 210 kfree(bo->sgt);
@@ -213,8 +215,7 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo)
213 215
214static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) 216static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
215{ 217{
216 struct scatterlist *s; 218 int err;
217 unsigned int i;
218 219
219 bo->pages = drm_gem_get_pages(&bo->gem); 220 bo->pages = drm_gem_get_pages(&bo->gem);
220 if (IS_ERR(bo->pages)) 221 if (IS_ERR(bo->pages))
@@ -223,27 +224,26 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
223 bo->num_pages = bo->gem.size >> PAGE_SHIFT; 224 bo->num_pages = bo->gem.size >> PAGE_SHIFT;
224 225
225 bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); 226 bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages);
226 if (IS_ERR(bo->sgt)) 227 if (IS_ERR(bo->sgt)) {
228 err = PTR_ERR(bo->sgt);
227 goto put_pages; 229 goto put_pages;
230 }
228 231
229 /* 232 err = dma_map_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents,
230 * Fake up the SG table so that dma_sync_sg_for_device() can be used 233 DMA_BIDIRECTIONAL);
231 * to flush the pages associated with it. 234 if (err == 0) {
232 * 235 err = -EFAULT;
233 * TODO: Replace this by drm_clflash_sg() once it can be implemented 236 goto free_sgt;
234 * without relying on symbols that are not exported. 237 }
235 */
236 for_each_sg(bo->sgt->sgl, s, bo->sgt->nents, i)
237 sg_dma_address(s) = sg_phys(s);
238
239 dma_sync_sg_for_device(drm->dev, bo->sgt->sgl, bo->sgt->nents,
240 DMA_TO_DEVICE);
241 238
242 return 0; 239 return 0;
243 240
241free_sgt:
242 sg_free_table(bo->sgt);
243 kfree(bo->sgt);
244put_pages: 244put_pages:
245 drm_gem_put_pages(&bo->gem, bo->pages, false, false); 245 drm_gem_put_pages(&bo->gem, bo->pages, false, false);
246 return PTR_ERR(bo->sgt); 246 return err;
247} 247}
248 248
249static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) 249static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo)
@@ -459,8 +459,7 @@ const struct vm_operations_struct tegra_bo_vm_ops = {
459 .close = drm_gem_vm_close, 459 .close = drm_gem_vm_close,
460}; 460};
461 461
462static int tegra_gem_mmap(struct drm_gem_object *gem, 462int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma)
463 struct vm_area_struct *vma)
464{ 463{
465 struct tegra_bo *bo = to_tegra_bo(gem); 464 struct tegra_bo *bo = to_tegra_bo(gem);
466 465
@@ -507,7 +506,7 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma)
507 506
508 gem = vma->vm_private_data; 507 gem = vma->vm_private_data;
509 508
510 return tegra_gem_mmap(gem, vma); 509 return __tegra_gem_mmap(gem, vma);
511} 510}
512 511
513static struct sg_table * 512static struct sg_table *
@@ -569,6 +568,34 @@ static void tegra_gem_prime_release(struct dma_buf *buf)
569 drm_gem_dmabuf_release(buf); 568 drm_gem_dmabuf_release(buf);
570} 569}
571 570
571static int tegra_gem_prime_begin_cpu_access(struct dma_buf *buf,
572 enum dma_data_direction direction)
573{
574 struct drm_gem_object *gem = buf->priv;
575 struct tegra_bo *bo = to_tegra_bo(gem);
576 struct drm_device *drm = gem->dev;
577
578 if (bo->pages)
579 dma_sync_sg_for_cpu(drm->dev, bo->sgt->sgl, bo->sgt->nents,
580 DMA_FROM_DEVICE);
581
582 return 0;
583}
584
585static int tegra_gem_prime_end_cpu_access(struct dma_buf *buf,
586 enum dma_data_direction direction)
587{
588 struct drm_gem_object *gem = buf->priv;
589 struct tegra_bo *bo = to_tegra_bo(gem);
590 struct drm_device *drm = gem->dev;
591
592 if (bo->pages)
593 dma_sync_sg_for_device(drm->dev, bo->sgt->sgl, bo->sgt->nents,
594 DMA_TO_DEVICE);
595
596 return 0;
597}
598
572static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, 599static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf,
573 unsigned long page) 600 unsigned long page)
574{ 601{
@@ -600,7 +627,7 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma)
600 if (err < 0) 627 if (err < 0)
601 return err; 628 return err;
602 629
603 return tegra_gem_mmap(gem, vma); 630 return __tegra_gem_mmap(gem, vma);
604} 631}
605 632
606static void *tegra_gem_prime_vmap(struct dma_buf *buf) 633static void *tegra_gem_prime_vmap(struct dma_buf *buf)
@@ -619,6 +646,8 @@ static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = {
619 .map_dma_buf = tegra_gem_prime_map_dma_buf, 646 .map_dma_buf = tegra_gem_prime_map_dma_buf,
620 .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, 647 .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf,
621 .release = tegra_gem_prime_release, 648 .release = tegra_gem_prime_release,
649 .begin_cpu_access = tegra_gem_prime_begin_cpu_access,
650 .end_cpu_access = tegra_gem_prime_end_cpu_access,
622 .map_atomic = tegra_gem_prime_kmap_atomic, 651 .map_atomic = tegra_gem_prime_kmap_atomic,
623 .unmap_atomic = tegra_gem_prime_kunmap_atomic, 652 .unmap_atomic = tegra_gem_prime_kunmap_atomic,
624 .map = tegra_gem_prime_kmap, 653 .map = tegra_gem_prime_kmap,
diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h
index 8eb9fd24ef0e..6bd7dd7e55b4 100644
--- a/drivers/gpu/drm/tegra/gem.h
+++ b/drivers/gpu/drm/tegra/gem.h
@@ -68,10 +68,11 @@ void tegra_bo_free_object(struct drm_gem_object *gem);
68int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, 68int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
69 struct drm_mode_create_dumb *args); 69 struct drm_mode_create_dumb *args);
70 70
71int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma);
72
73extern const struct vm_operations_struct tegra_bo_vm_ops; 71extern const struct vm_operations_struct tegra_bo_vm_ops;
74 72
73int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma);
74int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma);
75
75struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, 76struct dma_buf *tegra_gem_prime_export(struct drm_device *drm,
76 struct drm_gem_object *gem, 77 struct drm_gem_object *gem,
77 int flags); 78 int flags);
diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c
index e10a47d57313..9a3f23d4780f 100644
--- a/drivers/gpu/drm/tegra/hub.c
+++ b/drivers/gpu/drm/tegra/hub.c
@@ -49,6 +49,17 @@ static const u32 tegra_shared_plane_formats[] = {
49 DRM_FORMAT_YUV422, 49 DRM_FORMAT_YUV422,
50}; 50};
51 51
52static const u64 tegra_shared_plane_modifiers[] = {
53 DRM_FORMAT_MOD_LINEAR,
54 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
55 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
56 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
57 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
58 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
59 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
60 DRM_FORMAT_MOD_INVALID
61};
62
52static inline unsigned int tegra_plane_offset(struct tegra_plane *plane, 63static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
53 unsigned int offset) 64 unsigned int offset)
54{ 65{
@@ -527,6 +538,7 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
527 unsigned int possible_crtcs = 0x7; 538 unsigned int possible_crtcs = 0x7;
528 struct tegra_shared_plane *plane; 539 struct tegra_shared_plane *plane;
529 unsigned int num_formats; 540 unsigned int num_formats;
541 const u64 *modifiers;
530 struct drm_plane *p; 542 struct drm_plane *p;
531 const u32 *formats; 543 const u32 *formats;
532 int err; 544 int err;
@@ -545,10 +557,11 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
545 557
546 num_formats = ARRAY_SIZE(tegra_shared_plane_formats); 558 num_formats = ARRAY_SIZE(tegra_shared_plane_formats);
547 formats = tegra_shared_plane_formats; 559 formats = tegra_shared_plane_formats;
560 modifiers = tegra_shared_plane_modifiers;
548 561
549 err = drm_universal_plane_init(drm, p, possible_crtcs, 562 err = drm_universal_plane_init(drm, p, possible_crtcs,
550 &tegra_plane_funcs, formats, 563 &tegra_plane_funcs, formats,
551 num_formats, NULL, type, NULL); 564 num_formats, modifiers, type, NULL);
552 if (err < 0) { 565 if (err < 0) {
553 kfree(plane); 566 kfree(plane);
554 return ERR_PTR(err); 567 return ERR_PTR(err);
@@ -560,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
560 return p; 573 return p;
561} 574}
562 575
576static struct drm_private_state *
577tegra_display_hub_duplicate_state(struct drm_private_obj *obj)
578{
579 struct tegra_display_hub_state *state;
580
581 state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
582 if (!state)
583 return NULL;
584
585 __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
586
587 return &state->base;
588}
589
590static void tegra_display_hub_destroy_state(struct drm_private_obj *obj,
591 struct drm_private_state *state)
592{
593 struct tegra_display_hub_state *hub_state =
594 to_tegra_display_hub_state(state);
595
596 kfree(hub_state);
597}
598
599static const struct drm_private_state_funcs tegra_display_hub_state_funcs = {
600 .atomic_duplicate_state = tegra_display_hub_duplicate_state,
601 .atomic_destroy_state = tegra_display_hub_destroy_state,
602};
603
604static struct tegra_display_hub_state *
605tegra_display_hub_get_state(struct tegra_display_hub *hub,
606 struct drm_atomic_state *state)
607{
608 struct drm_device *drm = dev_get_drvdata(hub->client.parent);
609 struct drm_private_state *priv;
610
611 WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex));
612
613 priv = drm_atomic_get_private_obj_state(state, &hub->base);
614 if (IS_ERR(priv))
615 return ERR_CAST(priv);
616
617 return to_tegra_display_hub_state(priv);
618}
619
620int tegra_display_hub_atomic_check(struct drm_device *drm,
621 struct drm_atomic_state *state)
622{
623 struct tegra_drm *tegra = drm->dev_private;
624 struct tegra_display_hub_state *hub_state;
625 struct drm_crtc_state *old, *new;
626 struct drm_crtc *crtc;
627 unsigned int i;
628
629 if (!tegra->hub)
630 return 0;
631
632 hub_state = tegra_display_hub_get_state(tegra->hub, state);
633 if (IS_ERR(hub_state))
634 return PTR_ERR(hub_state);
635
636 /*
637 * The display hub display clock needs to be fed by the display clock
638 * with the highest frequency to ensure proper functioning of all the
639 * displays.
640 *
641 * Note that this isn't used before Tegra186, but it doesn't hurt and
642 * conditionalizing it would make the code less clean.
643 */
644 for_each_oldnew_crtc_in_state(state, crtc, old, new, i) {
645 struct tegra_dc_state *dc = to_dc_state(new);
646
647 if (new->active) {
648 if (!hub_state->clk || dc->pclk > hub_state->rate) {
649 hub_state->dc = to_tegra_dc(dc->base.crtc);
650 hub_state->clk = hub_state->dc->clk;
651 hub_state->rate = dc->pclk;
652 }
653 }
654 }
655
656 return 0;
657}
658
563static void tegra_display_hub_update(struct tegra_dc *dc) 659static void tegra_display_hub_update(struct tegra_dc *dc)
564{ 660{
565 u32 value; 661 u32 value;
@@ -585,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc)
585void tegra_display_hub_atomic_commit(struct drm_device *drm, 681void tegra_display_hub_atomic_commit(struct drm_device *drm,
586 struct drm_atomic_state *state) 682 struct drm_atomic_state *state)
587{ 683{
588 struct tegra_atomic_state *s = to_tegra_atomic_state(state);
589 struct tegra_drm *tegra = drm->dev_private; 684 struct tegra_drm *tegra = drm->dev_private;
590 struct tegra_display_hub *hub = tegra->hub; 685 struct tegra_display_hub *hub = tegra->hub;
686 struct tegra_display_hub_state *hub_state;
591 struct device *dev = hub->client.dev; 687 struct device *dev = hub->client.dev;
592 int err; 688 int err;
593 689
594 if (s->clk_disp) { 690 hub_state = tegra_display_hub_get_state(hub, state);
595 err = clk_set_rate(s->clk_disp, s->rate); 691
692 if (hub_state->clk) {
693 err = clk_set_rate(hub_state->clk, hub_state->rate);
596 if (err < 0) 694 if (err < 0)
597 dev_err(dev, "failed to set rate of %pC to %lu Hz\n", 695 dev_err(dev, "failed to set rate of %pC to %lu Hz\n",
598 s->clk_disp, s->rate); 696 hub_state->clk, hub_state->rate);
599 697
600 err = clk_set_parent(hub->clk_disp, s->clk_disp); 698 err = clk_set_parent(hub->clk_disp, hub_state->clk);
601 if (err < 0) 699 if (err < 0)
602 dev_err(dev, "failed to set parent of %pC to %pC: %d\n", 700 dev_err(dev, "failed to set parent of %pC to %pC: %d\n",
603 hub->clk_disp, s->clk_disp, err); 701 hub->clk_disp, hub_state->clk, err);
604 } 702 }
605 703
606 if (s->dc) 704 if (hub_state->dc)
607 tegra_display_hub_update(s->dc); 705 tegra_display_hub_update(hub_state->dc);
608} 706}
609 707
610static int tegra_display_hub_init(struct host1x_client *client) 708static int tegra_display_hub_init(struct host1x_client *client)
@@ -612,6 +710,14 @@ static int tegra_display_hub_init(struct host1x_client *client)
612 struct tegra_display_hub *hub = to_tegra_display_hub(client); 710 struct tegra_display_hub *hub = to_tegra_display_hub(client);
613 struct drm_device *drm = dev_get_drvdata(client->parent); 711 struct drm_device *drm = dev_get_drvdata(client->parent);
614 struct tegra_drm *tegra = drm->dev_private; 712 struct tegra_drm *tegra = drm->dev_private;
713 struct tegra_display_hub_state *state;
714
715 state = kzalloc(sizeof(*state), GFP_KERNEL);
716 if (!state)
717 return -ENOMEM;
718
719 drm_atomic_private_obj_init(&hub->base, &state->base,
720 &tegra_display_hub_state_funcs);
615 721
616 tegra->hub = hub; 722 tegra->hub = hub;
617 723
@@ -623,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client)
623 struct drm_device *drm = dev_get_drvdata(client->parent); 729 struct drm_device *drm = dev_get_drvdata(client->parent);
624 struct tegra_drm *tegra = drm->dev_private; 730 struct tegra_drm *tegra = drm->dev_private;
625 731
732 drm_atomic_private_obj_fini(&tegra->hub->base);
626 tegra->hub = NULL; 733 tegra->hub = NULL;
627 734
628 return 0; 735 return 0;
diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h
index 890a47cd05c3..85b8bf41a395 100644
--- a/drivers/gpu/drm/tegra/hub.h
+++ b/drivers/gpu/drm/tegra/hub.h
@@ -41,6 +41,7 @@ struct tegra_display_hub_soc {
41}; 41};
42 42
43struct tegra_display_hub { 43struct tegra_display_hub {
44 struct drm_private_obj base;
44 struct host1x_client client; 45 struct host1x_client client;
45 struct clk *clk_disp; 46 struct clk *clk_disp;
46 struct clk *clk_dsc; 47 struct clk *clk_dsc;
@@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client)
57 return container_of(client, struct tegra_display_hub, client); 58 return container_of(client, struct tegra_display_hub, client);
58} 59}
59 60
61struct tegra_display_hub_state {
62 struct drm_private_state base;
63
64 struct tegra_dc *dc;
65 unsigned long rate;
66 struct clk *clk;
67};
68
69static inline struct tegra_display_hub_state *
70to_tegra_display_hub_state(struct drm_private_state *priv)
71{
72 return container_of(priv, struct tegra_display_hub_state, base);
73}
74
60struct tegra_dc; 75struct tegra_dc;
61struct tegra_plane; 76struct tegra_plane;
62 77
@@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
68 unsigned int wgrp, 83 unsigned int wgrp,
69 unsigned int index); 84 unsigned int index);
70 85
86int tegra_display_hub_atomic_check(struct drm_device *drm,
87 struct drm_atomic_state *state);
71void tegra_display_hub_atomic_commit(struct drm_device *drm, 88void tegra_display_hub_atomic_commit(struct drm_device *drm,
72 struct drm_atomic_state *state); 89 struct drm_atomic_state *state);
73 90
diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c
index a056fbf83b53..6d6e2d0091eb 100644
--- a/drivers/gpu/drm/tegra/plane.c
+++ b/drivers/gpu/drm/tegra/plane.c
@@ -68,6 +68,21 @@ static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
68 kfree(state); 68 kfree(state);
69} 69}
70 70
71static bool tegra_plane_format_mod_supported(struct drm_plane *plane,
72 uint32_t format,
73 uint64_t modifier)
74{
75 const struct drm_format_info *info = drm_format_info(format);
76
77 if (modifier == DRM_FORMAT_MOD_LINEAR)
78 return true;
79
80 if (info->num_planes == 1)
81 return true;
82
83 return false;
84}
85
71const struct drm_plane_funcs tegra_plane_funcs = { 86const struct drm_plane_funcs tegra_plane_funcs = {
72 .update_plane = drm_atomic_helper_update_plane, 87 .update_plane = drm_atomic_helper_update_plane,
73 .disable_plane = drm_atomic_helper_disable_plane, 88 .disable_plane = drm_atomic_helper_disable_plane,
@@ -75,6 +90,7 @@ const struct drm_plane_funcs tegra_plane_funcs = {
75 .reset = tegra_plane_reset, 90 .reset = tegra_plane_reset,
76 .atomic_duplicate_state = tegra_plane_atomic_duplicate_state, 91 .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
77 .atomic_destroy_state = tegra_plane_atomic_destroy_state, 92 .atomic_destroy_state = tegra_plane_atomic_destroy_state,
93 .format_mod_supported = tegra_plane_format_mod_supported,
78}; 94};
79 95
80int tegra_plane_state_add(struct tegra_plane *plane, 96int tegra_plane_state_add(struct tegra_plane *plane,
@@ -296,8 +312,8 @@ int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
296 return -EINVAL; 312 return -EINVAL;
297} 313}
298 314
299unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, 315static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
300 struct tegra_plane *other) 316 struct tegra_plane *other)
301{ 317{
302 unsigned int index = 0, i; 318 unsigned int index = 0, i;
303 319