Commit | Line | Data |
---|---|---|
119f5173 CH |
1 | /* |
2 | * Copyright (c) 2015 MediaTek Inc. | |
3 | * Author: CK Hu <ck.hu@mediatek.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | */ | |
14 | ||
15 | #include <drm/drmP.h> | |
16 | #include <drm/drm_atomic.h> | |
17 | #include <drm/drm_atomic_helper.h> | |
18 | #include <drm/drm_plane_helper.h> | |
19 | ||
20 | #include "mtk_drm_crtc.h" | |
21 | #include "mtk_drm_ddp_comp.h" | |
22 | #include "mtk_drm_drv.h" | |
23 | #include "mtk_drm_fb.h" | |
24 | #include "mtk_drm_gem.h" | |
25 | #include "mtk_drm_plane.h" | |
26 | ||
27 | static const u32 formats[] = { | |
28 | DRM_FORMAT_XRGB8888, | |
29 | DRM_FORMAT_ARGB8888, | |
30 | DRM_FORMAT_RGB565, | |
170748db BH |
31 | DRM_FORMAT_UYVY, |
32 | DRM_FORMAT_YUYV, | |
119f5173 CH |
33 | }; |
34 | ||
119f5173 CH |
35 | static void mtk_plane_reset(struct drm_plane *plane) |
36 | { | |
37 | struct mtk_plane_state *state; | |
38 | ||
39 | if (plane->state) { | |
903daff6 | 40 | __drm_atomic_helper_plane_destroy_state(plane->state); |
119f5173 CH |
41 | |
42 | state = to_mtk_plane_state(plane->state); | |
43 | memset(state, 0, sizeof(*state)); | |
44 | } else { | |
45 | state = kzalloc(sizeof(*state), GFP_KERNEL); | |
46 | if (!state) | |
47 | return; | |
48 | plane->state = &state->base; | |
49 | } | |
50 | ||
51 | state->base.plane = plane; | |
52 | state->pending.format = DRM_FORMAT_RGB565; | |
53 | } | |
54 | ||
55 | static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) | |
56 | { | |
57 | struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state); | |
58 | struct mtk_plane_state *state; | |
59 | ||
60 | state = kzalloc(sizeof(*state), GFP_KERNEL); | |
61 | if (!state) | |
62 | return NULL; | |
63 | ||
64 | __drm_atomic_helper_plane_duplicate_state(plane, &state->base); | |
65 | ||
66 | WARN_ON(state->base.plane != plane); | |
67 | ||
68 | state->pending = old_state->pending; | |
69 | ||
70 | return &state->base; | |
71 | } | |
72 | ||
73 | static void mtk_drm_plane_destroy_state(struct drm_plane *plane, | |
74 | struct drm_plane_state *state) | |
75 | { | |
2f701695 | 76 | __drm_atomic_helper_plane_destroy_state(state); |
119f5173 CH |
77 | kfree(to_mtk_plane_state(state)); |
78 | } | |
79 | ||
80 | static const struct drm_plane_funcs mtk_plane_funcs = { | |
81 | .update_plane = drm_atomic_helper_update_plane, | |
82 | .disable_plane = drm_atomic_helper_disable_plane, | |
83 | .destroy = drm_plane_cleanup, | |
84 | .reset = mtk_plane_reset, | |
85 | .atomic_duplicate_state = mtk_plane_duplicate_state, | |
86 | .atomic_destroy_state = mtk_drm_plane_destroy_state, | |
87 | }; | |
88 | ||
89 | static int mtk_plane_atomic_check(struct drm_plane *plane, | |
90 | struct drm_plane_state *state) | |
91 | { | |
92 | struct drm_framebuffer *fb = state->fb; | |
93 | struct drm_crtc_state *crtc_state; | |
119f5173 CH |
94 | struct drm_rect clip = { 0, }; |
95 | ||
96 | if (!fb) | |
97 | return 0; | |
98 | ||
99 | if (!mtk_fb_get_gem_obj(fb)) { | |
100 | DRM_DEBUG_KMS("buffer is null\n"); | |
101 | return -EFAULT; | |
102 | } | |
103 | ||
104 | if (!state->crtc) | |
105 | return 0; | |
106 | ||
107 | crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); | |
108 | if (IS_ERR(crtc_state)) | |
109 | return PTR_ERR(crtc_state); | |
110 | ||
111 | clip.x2 = crtc_state->mode.hdisplay; | |
112 | clip.y2 = crtc_state->mode.vdisplay; | |
113 | ||
0e4faf67 VS |
114 | return drm_plane_helper_check_state(state, &clip, |
115 | DRM_PLANE_HELPER_NO_SCALING, | |
116 | DRM_PLANE_HELPER_NO_SCALING, | |
117 | true, true); | |
119f5173 CH |
118 | } |
119 | ||
120 | static void mtk_plane_atomic_update(struct drm_plane *plane, | |
121 | struct drm_plane_state *old_state) | |
122 | { | |
123 | struct mtk_plane_state *state = to_mtk_plane_state(plane->state); | |
f176cbf6 DK |
124 | struct drm_crtc *crtc = plane->state->crtc; |
125 | struct drm_framebuffer *fb = plane->state->fb; | |
119f5173 CH |
126 | struct drm_gem_object *gem; |
127 | struct mtk_drm_gem_obj *mtk_gem; | |
f176cbf6 DK |
128 | unsigned int pitch, format; |
129 | dma_addr_t addr; | |
119f5173 | 130 | |
f176cbf6 | 131 | if (!crtc || WARN_ON(!fb)) |
119f5173 CH |
132 | return; |
133 | ||
f176cbf6 | 134 | gem = mtk_fb_get_gem_obj(fb); |
119f5173 | 135 | mtk_gem = to_mtk_gem_obj(gem); |
f176cbf6 DK |
136 | addr = mtk_gem->dma_addr; |
137 | pitch = fb->pitches[0]; | |
438b74a5 | 138 | format = fb->format->format; |
f176cbf6 | 139 | |
353c8598 | 140 | addr += (plane->state->src.x1 >> 16) * fb->format->cpp[0]; |
f176cbf6 DK |
141 | addr += (plane->state->src.y1 >> 16) * pitch; |
142 | ||
143 | state->pending.enable = true; | |
144 | state->pending.pitch = pitch; | |
145 | state->pending.format = format; | |
146 | state->pending.addr = addr; | |
147 | state->pending.x = plane->state->dst.x1; | |
148 | state->pending.y = plane->state->dst.y1; | |
149 | state->pending.width = drm_rect_width(&plane->state->dst); | |
150 | state->pending.height = drm_rect_height(&plane->state->dst); | |
151 | wmb(); /* Make sure the above parameters are set before update */ | |
152 | state->pending.dirty = true; | |
119f5173 CH |
153 | } |
154 | ||
155 | static void mtk_plane_atomic_disable(struct drm_plane *plane, | |
156 | struct drm_plane_state *old_state) | |
157 | { | |
158 | struct mtk_plane_state *state = to_mtk_plane_state(plane->state); | |
159 | ||
160 | state->pending.enable = false; | |
161 | wmb(); /* Make sure the above parameter is set before update */ | |
162 | state->pending.dirty = true; | |
163 | } | |
164 | ||
165 | static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = { | |
166 | .atomic_check = mtk_plane_atomic_check, | |
167 | .atomic_update = mtk_plane_atomic_update, | |
168 | .atomic_disable = mtk_plane_atomic_disable, | |
169 | }; | |
170 | ||
5bfafad8 | 171 | int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane, |
0d5a32b7 | 172 | unsigned long possible_crtcs, enum drm_plane_type type) |
119f5173 CH |
173 | { |
174 | int err; | |
175 | ||
5bfafad8 | 176 | err = drm_universal_plane_init(dev, plane, possible_crtcs, |
119f5173 | 177 | &mtk_plane_funcs, formats, |
e6fc3b68 | 178 | ARRAY_SIZE(formats), NULL, type, NULL); |
119f5173 CH |
179 | if (err) { |
180 | DRM_ERROR("failed to initialize plane\n"); | |
181 | return err; | |
182 | } | |
183 | ||
5bfafad8 | 184 | drm_plane_helper_add(plane, &mtk_plane_helper_funcs); |
119f5173 CH |
185 | |
186 | return 0; | |
187 | } |