diff options
author | Dave Airlie <airlied@redhat.com> | 2018-03-21 00:04:38 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-03-21 00:04:38 -0400 |
commit | 19c800caa682d9e20087d7b98af49301cf1ab039 (patch) | |
tree | e9ee7e7161c91f8d0ceedddabec7b1747cb13705 | |
parent | 4f6dd8d6858b6fc0a3babbd2510f99c2bc84f2cb (diff) | |
parent | 27e92f1f1600c214bf649daddb9b88b68330a8d1 (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.c | 82 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/fb.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.c | 69 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.c | 125 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.h | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/plane.c | 20 |
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 | ||
386 | static const u64 tegra20_modifiers[] = { | ||
387 | DRM_FORMAT_MOD_LINEAR, | ||
388 | DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED, | ||
389 | DRM_FORMAT_MOD_INVALID | ||
390 | }; | ||
391 | |||
386 | static const u32 tegra114_primary_formats[] = { | 392 | static 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 | ||
439 | static 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 | |||
433 | static int tegra_plane_atomic_check(struct drm_plane *plane, | 450 | static 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 | ||
865 | static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, | 884 | static 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 | ||
1707 | static 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 | |||
1732 | static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, | 1739 | static 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 | ||
1767 | static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { | 1774 | static 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 | ||
1959 | static const struct tegra_dc_soc_info tegra30_dc_soc_info = { | 1973 | static 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 | ||
1975 | static const struct tegra_dc_soc_info tegra114_dc_soc_info = { | 1990 | static 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 | ||
1991 | static const struct tegra_dc_soc_info tegra124_dc_soc_info = { | 2007 | static 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 | ||
2007 | static const struct tegra_dc_soc_info tegra210_dc_soc_info = { | 2024 | static 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 | ||
2023 | static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = { | 2041 | static 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 | ||
71 | struct tegra_dc { | 72 | struct 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 | ||
59 | static struct drm_atomic_state * | ||
60 | tegra_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 | |||
72 | static 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 | |||
82 | static void tegra_atomic_state_free(struct drm_atomic_state *state) | ||
83 | { | ||
84 | drm_atomic_state_default_release(state); | ||
85 | kfree(state); | ||
86 | } | ||
87 | |||
88 | static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { | 63 | static 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 | ||
100 | static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state) | 72 | static 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 | ||
45 | struct 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 | |||
53 | static inline struct tegra_atomic_state * | ||
54 | to_tegra_atomic_state(struct drm_atomic_state *state) | ||
55 | { | ||
56 | return container_of(state, struct tegra_atomic_state, base); | ||
57 | } | ||
58 | |||
59 | struct tegra_drm { | 45 | struct 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 |
230 | static 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 | |||
227 | static struct fb_ops tegra_fb_ops = { | 245 | static 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 | ||
235 | static int tegra_fbdev_probe(struct drm_fb_helper *helper, | 254 | static 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: | |||
203 | static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) | 203 | static 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 | ||
214 | static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) | 216 | static 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 | ||
241 | free_sgt: | ||
242 | sg_free_table(bo->sgt); | ||
243 | kfree(bo->sgt); | ||
244 | put_pages: | 244 | put_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 | ||
249 | static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) | 249 | static 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 | ||
462 | static int tegra_gem_mmap(struct drm_gem_object *gem, | 462 | int __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 | ||
513 | static struct sg_table * | 512 | static 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 | ||
571 | static 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 | |||
585 | static 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 | |||
572 | static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, | 599 | static 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 | ||
606 | static void *tegra_gem_prime_vmap(struct dma_buf *buf) | 633 | static 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); | |||
68 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, | 68 | int 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 | ||
71 | int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); | ||
72 | |||
73 | extern const struct vm_operations_struct tegra_bo_vm_ops; | 71 | extern const struct vm_operations_struct tegra_bo_vm_ops; |
74 | 72 | ||
73 | int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma); | ||
74 | int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); | ||
75 | |||
75 | struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, | 76 | struct 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 | ||
52 | static 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 | |||
52 | static inline unsigned int tegra_plane_offset(struct tegra_plane *plane, | 63 | static 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 | ||
576 | static struct drm_private_state * | ||
577 | tegra_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 | |||
590 | static 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 | |||
599 | static 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 | |||
604 | static struct tegra_display_hub_state * | ||
605 | tegra_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 | |||
620 | int 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 | |||
563 | static void tegra_display_hub_update(struct tegra_dc *dc) | 659 | static 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) | |||
585 | void tegra_display_hub_atomic_commit(struct drm_device *drm, | 681 | void 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 | ||
610 | static int tegra_display_hub_init(struct host1x_client *client) | 708 | static 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 | ||
43 | struct tegra_display_hub { | 43 | struct 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 | ||
61 | struct 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 | |||
69 | static inline struct tegra_display_hub_state * | ||
70 | to_tegra_display_hub_state(struct drm_private_state *priv) | ||
71 | { | ||
72 | return container_of(priv, struct tegra_display_hub_state, base); | ||
73 | } | ||
74 | |||
60 | struct tegra_dc; | 75 | struct tegra_dc; |
61 | struct tegra_plane; | 76 | struct 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 | ||
86 | int tegra_display_hub_atomic_check(struct drm_device *drm, | ||
87 | struct drm_atomic_state *state); | ||
71 | void tegra_display_hub_atomic_commit(struct drm_device *drm, | 88 | void 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 | ||
71 | static 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 | |||
71 | const struct drm_plane_funcs tegra_plane_funcs = { | 86 | const 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 | ||
80 | int tegra_plane_state_add(struct tegra_plane *plane, | 96 | int 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 | ||
299 | unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, | 315 | static 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 | ||