Commit | Line | Data |
---|---|---|
1802d0be | 1 | // SPDX-License-Identifier: GPL-2.0-only |
119f5173 CH |
2 | /* |
3 | * Copyright (c) 2015 MediaTek Inc. | |
4 | * Author: CK Hu <ck.hu@mediatek.com> | |
119f5173 CH |
5 | */ |
6 | ||
119f5173 CH |
7 | #include <drm/drm_atomic.h> |
8 | #include <drm/drm_atomic_helper.h> | |
920fffcc | 9 | #include <drm/drm_atomic_uapi.h> |
820c1707 TZ |
10 | #include <drm/drm_fourcc.h> |
11 | #include <drm/drm_gem_atomic_helper.h> | |
119f5173 CH |
12 | #include <drm/drm_plane_helper.h> |
13 | ||
14 | #include "mtk_drm_crtc.h" | |
15 | #include "mtk_drm_ddp_comp.h" | |
16 | #include "mtk_drm_drv.h" | |
119f5173 CH |
17 | #include "mtk_drm_gem.h" |
18 | #include "mtk_drm_plane.h" | |
19 | ||
20 | static const u32 formats[] = { | |
21 | DRM_FORMAT_XRGB8888, | |
22 | DRM_FORMAT_ARGB8888, | |
ed24d5d0 SP |
23 | DRM_FORMAT_BGRX8888, |
24 | DRM_FORMAT_BGRA8888, | |
25 | DRM_FORMAT_ABGR8888, | |
26 | DRM_FORMAT_XBGR8888, | |
27 | DRM_FORMAT_RGB888, | |
28 | DRM_FORMAT_BGR888, | |
119f5173 | 29 | DRM_FORMAT_RGB565, |
170748db BH |
30 | DRM_FORMAT_UYVY, |
31 | DRM_FORMAT_YUYV, | |
119f5173 CH |
32 | }; |
33 | ||
119f5173 CH |
34 | static void mtk_plane_reset(struct drm_plane *plane) |
35 | { | |
36 | struct mtk_plane_state *state; | |
37 | ||
38 | if (plane->state) { | |
903daff6 | 39 | __drm_atomic_helper_plane_destroy_state(plane->state); |
119f5173 CH |
40 | |
41 | state = to_mtk_plane_state(plane->state); | |
42 | memset(state, 0, sizeof(*state)); | |
43 | } else { | |
44 | state = kzalloc(sizeof(*state), GFP_KERNEL); | |
45 | if (!state) | |
46 | return; | |
119f5173 CH |
47 | } |
48 | ||
d95b00f1 MY |
49 | __drm_atomic_helper_plane_reset(plane, &state->base); |
50 | ||
119f5173 CH |
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 | ||
d327bc37 | 60 | state = kmalloc(sizeof(*state), GFP_KERNEL); |
119f5173 CH |
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 | ||
920fffcc | 80 | static int mtk_plane_atomic_async_check(struct drm_plane *plane, |
5ddb0bd4 | 81 | struct drm_atomic_state *state) |
920fffcc | 82 | { |
5ddb0bd4 MR |
83 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, |
84 | plane); | |
920fffcc | 85 | struct drm_crtc_state *crtc_state; |
551c5f55 | 86 | int ret; |
920fffcc | 87 | |
5ddb0bd4 | 88 | if (plane != new_plane_state->crtc->cursor) |
920fffcc BH |
89 | return -EINVAL; |
90 | ||
91 | if (!plane->state) | |
92 | return -EINVAL; | |
93 | ||
94 | if (!plane->state->fb) | |
95 | return -EINVAL; | |
96 | ||
5ddb0bd4 MR |
97 | ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane, |
98 | to_mtk_plane_state(new_plane_state)); | |
551c5f55 BH |
99 | if (ret) |
100 | return ret; | |
101 | ||
5ddb0bd4 MR |
102 | if (state) |
103 | crtc_state = drm_atomic_get_existing_crtc_state(state, | |
104 | new_plane_state->crtc); | |
920fffcc | 105 | else /* Special case for asynchronous cursor updates. */ |
5ddb0bd4 | 106 | crtc_state = new_plane_state->crtc->state; |
920fffcc BH |
107 | |
108 | return drm_atomic_helper_check_plane_state(plane->state, crtc_state, | |
109 | DRM_PLANE_HELPER_NO_SCALING, | |
110 | DRM_PLANE_HELPER_NO_SCALING, | |
111 | true, true); | |
112 | } | |
113 | ||
1a64a7af | 114 | static void mtk_plane_update_new_state(struct drm_plane_state *new_state, |
115 | struct mtk_plane_state *mtk_plane_state) | |
116 | { | |
117 | struct drm_framebuffer *fb = new_state->fb; | |
118 | struct drm_gem_object *gem; | |
119 | struct mtk_drm_gem_obj *mtk_gem; | |
120 | unsigned int pitch, format; | |
121 | dma_addr_t addr; | |
122 | ||
123 | gem = fb->obj[0]; | |
124 | mtk_gem = to_mtk_gem_obj(gem); | |
125 | addr = mtk_gem->dma_addr; | |
126 | pitch = fb->pitches[0]; | |
127 | format = fb->format->format; | |
128 | ||
129 | addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; | |
130 | addr += (new_state->src.y1 >> 16) * pitch; | |
131 | ||
132 | mtk_plane_state->pending.enable = true; | |
133 | mtk_plane_state->pending.pitch = pitch; | |
134 | mtk_plane_state->pending.format = format; | |
135 | mtk_plane_state->pending.addr = addr; | |
136 | mtk_plane_state->pending.x = new_state->dst.x1; | |
137 | mtk_plane_state->pending.y = new_state->dst.y1; | |
138 | mtk_plane_state->pending.width = drm_rect_width(&new_state->dst); | |
139 | mtk_plane_state->pending.height = drm_rect_height(&new_state->dst); | |
140 | mtk_plane_state->pending.rotation = new_state->rotation; | |
141 | } | |
142 | ||
920fffcc | 143 | static void mtk_plane_atomic_async_update(struct drm_plane *plane, |
5ddb0bd4 | 144 | struct drm_atomic_state *state) |
920fffcc | 145 | { |
5ddb0bd4 MR |
146 | struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, |
147 | plane); | |
148 | struct mtk_plane_state *new_plane_state = to_mtk_plane_state(plane->state); | |
920fffcc BH |
149 | |
150 | plane->state->crtc_x = new_state->crtc_x; | |
151 | plane->state->crtc_y = new_state->crtc_y; | |
152 | plane->state->crtc_h = new_state->crtc_h; | |
153 | plane->state->crtc_w = new_state->crtc_w; | |
154 | plane->state->src_x = new_state->src_x; | |
155 | plane->state->src_y = new_state->src_y; | |
156 | plane->state->src_h = new_state->src_h; | |
157 | plane->state->src_w = new_state->src_w; | |
c12b59ad | 158 | swap(plane->state->fb, new_state->fb); |
920fffcc | 159 | |
1a64a7af | 160 | mtk_plane_update_new_state(new_state, new_plane_state); |
161 | wmb(); /* Make sure the above parameters are set before update */ | |
162 | new_plane_state->pending.async_dirty = true; | |
977697e2 | 163 | mtk_drm_crtc_async_update(new_state->crtc, plane, state); |
920fffcc BH |
164 | } |
165 | ||
119f5173 CH |
166 | static const struct drm_plane_funcs mtk_plane_funcs = { |
167 | .update_plane = drm_atomic_helper_update_plane, | |
168 | .disable_plane = drm_atomic_helper_disable_plane, | |
169 | .destroy = drm_plane_cleanup, | |
170 | .reset = mtk_plane_reset, | |
171 | .atomic_duplicate_state = mtk_plane_duplicate_state, | |
172 | .atomic_destroy_state = mtk_drm_plane_destroy_state, | |
173 | }; | |
174 | ||
175 | static int mtk_plane_atomic_check(struct drm_plane *plane, | |
7c11b99a | 176 | struct drm_atomic_state *state) |
119f5173 | 177 | { |
7c11b99a MR |
178 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, |
179 | plane); | |
ba5c1649 | 180 | struct drm_framebuffer *fb = new_plane_state->fb; |
119f5173 | 181 | struct drm_crtc_state *crtc_state; |
f7c710d1 | 182 | int ret; |
119f5173 CH |
183 | |
184 | if (!fb) | |
185 | return 0; | |
186 | ||
ba5c1649 | 187 | if (WARN_ON(!new_plane_state->crtc)) |
119f5173 CH |
188 | return 0; |
189 | ||
ba5c1649 MR |
190 | ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane, |
191 | to_mtk_plane_state(new_plane_state)); | |
f7c710d1 SP |
192 | if (ret) |
193 | return ret; | |
194 | ||
dec92020 | 195 | crtc_state = drm_atomic_get_crtc_state(state, |
ba5c1649 | 196 | new_plane_state->crtc); |
119f5173 CH |
197 | if (IS_ERR(crtc_state)) |
198 | return PTR_ERR(crtc_state); | |
199 | ||
ba5c1649 MR |
200 | return drm_atomic_helper_check_plane_state(new_plane_state, |
201 | crtc_state, | |
a01cb8ba VS |
202 | DRM_PLANE_HELPER_NO_SCALING, |
203 | DRM_PLANE_HELPER_NO_SCALING, | |
204 | true, true); | |
119f5173 CH |
205 | } |
206 | ||
c0b8892e | 207 | static void mtk_plane_atomic_disable(struct drm_plane *plane, |
977697e2 | 208 | struct drm_atomic_state *state) |
c0b8892e | 209 | { |
37418bf1 MR |
210 | struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, |
211 | plane); | |
41016fe1 MR |
212 | struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state); |
213 | mtk_plane_state->pending.enable = false; | |
c0b8892e | 214 | wmb(); /* Make sure the above parameter is set before update */ |
41016fe1 | 215 | mtk_plane_state->pending.dirty = true; |
c0b8892e HYW |
216 | } |
217 | ||
119f5173 | 218 | static void mtk_plane_atomic_update(struct drm_plane *plane, |
977697e2 | 219 | struct drm_atomic_state *state) |
119f5173 | 220 | { |
37418bf1 MR |
221 | struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, |
222 | plane); | |
41016fe1 | 223 | struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state); |
119f5173 | 224 | |
1a64a7af | 225 | if (!new_state->crtc || WARN_ON(!new_state->fb)) |
119f5173 CH |
226 | return; |
227 | ||
e05162c0 | 228 | if (!new_state->visible) { |
977697e2 | 229 | mtk_plane_atomic_disable(plane, state); |
c0b8892e HYW |
230 | return; |
231 | } | |
232 | ||
1a64a7af | 233 | mtk_plane_update_new_state(new_state, mtk_plane_state); |
f176cbf6 | 234 | wmb(); /* Make sure the above parameters are set before update */ |
41016fe1 | 235 | mtk_plane_state->pending.dirty = true; |
119f5173 CH |
236 | } |
237 | ||
119f5173 CH |
238 | static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = { |
239 | .atomic_check = mtk_plane_atomic_check, | |
240 | .atomic_update = mtk_plane_atomic_update, | |
241 | .atomic_disable = mtk_plane_atomic_disable, | |
920fffcc BH |
242 | .atomic_async_update = mtk_plane_atomic_async_update, |
243 | .atomic_async_check = mtk_plane_atomic_async_check, | |
119f5173 CH |
244 | }; |
245 | ||
5bfafad8 | 246 | int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane, |
ef87d3e2 SP |
247 | unsigned long possible_crtcs, enum drm_plane_type type, |
248 | unsigned int supported_rotations) | |
119f5173 CH |
249 | { |
250 | int err; | |
251 | ||
5bfafad8 | 252 | err = drm_universal_plane_init(dev, plane, possible_crtcs, |
119f5173 | 253 | &mtk_plane_funcs, formats, |
e6fc3b68 | 254 | ARRAY_SIZE(formats), NULL, type, NULL); |
119f5173 CH |
255 | if (err) { |
256 | DRM_ERROR("failed to initialize plane\n"); | |
257 | return err; | |
258 | } | |
259 | ||
ef87d3e2 SP |
260 | if (supported_rotations & ~DRM_MODE_ROTATE_0) { |
261 | err = drm_plane_create_rotation_property(plane, | |
262 | DRM_MODE_ROTATE_0, | |
263 | supported_rotations); | |
264 | if (err) | |
265 | DRM_INFO("Create rotation property failed\n"); | |
266 | } | |
267 | ||
5bfafad8 | 268 | drm_plane_helper_add(plane, &mtk_plane_helper_funcs); |
119f5173 CH |
269 | |
270 | return 0; | |
271 | } |