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, | |
31 | }; | |
32 | ||
5bfafad8 | 33 | static void mtk_plane_enable(struct drm_plane *plane, |
0e4faf67 | 34 | dma_addr_t addr) |
119f5173 | 35 | { |
119f5173 CH |
36 | struct mtk_plane_state *state = to_mtk_plane_state(plane->state); |
37 | unsigned int pitch, format; | |
0e4faf67 | 38 | bool enable; |
119f5173 | 39 | |
0e4faf67 VS |
40 | if (WARN_ON(!plane->state)) |
41 | return; | |
42 | ||
43 | enable = state->base.visible; | |
44 | ||
45 | if (WARN_ON(enable && !plane->state->fb)) | |
119f5173 CH |
46 | return; |
47 | ||
48 | if (plane->state->fb) { | |
49 | pitch = plane->state->fb->pitches[0]; | |
50 | format = plane->state->fb->pixel_format; | |
51 | } else { | |
52 | pitch = 0; | |
53 | format = DRM_FORMAT_RGBA8888; | |
54 | } | |
55 | ||
0e4faf67 VS |
56 | addr += (state->base.src.x1 >> 16) * 4; |
57 | addr += (state->base.src.y1 >> 16) * pitch; | |
119f5173 CH |
58 | |
59 | state->pending.enable = enable; | |
60 | state->pending.pitch = pitch; | |
61 | state->pending.format = format; | |
62 | state->pending.addr = addr; | |
0e4faf67 VS |
63 | state->pending.x = state->base.dst.x1; |
64 | state->pending.y = state->base.dst.y1; | |
65 | state->pending.width = drm_rect_width(&state->base.dst); | |
66 | state->pending.height = drm_rect_height(&state->base.dst); | |
119f5173 CH |
67 | wmb(); /* Make sure the above parameters are set before update */ |
68 | state->pending.dirty = true; | |
69 | } | |
70 | ||
71 | static void mtk_plane_reset(struct drm_plane *plane) | |
72 | { | |
73 | struct mtk_plane_state *state; | |
74 | ||
75 | if (plane->state) { | |
76 | if (plane->state->fb) | |
77 | drm_framebuffer_unreference(plane->state->fb); | |
78 | ||
79 | state = to_mtk_plane_state(plane->state); | |
80 | memset(state, 0, sizeof(*state)); | |
81 | } else { | |
82 | state = kzalloc(sizeof(*state), GFP_KERNEL); | |
83 | if (!state) | |
84 | return; | |
85 | plane->state = &state->base; | |
86 | } | |
87 | ||
88 | state->base.plane = plane; | |
89 | state->pending.format = DRM_FORMAT_RGB565; | |
90 | } | |
91 | ||
92 | static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) | |
93 | { | |
94 | struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state); | |
95 | struct mtk_plane_state *state; | |
96 | ||
97 | state = kzalloc(sizeof(*state), GFP_KERNEL); | |
98 | if (!state) | |
99 | return NULL; | |
100 | ||
101 | __drm_atomic_helper_plane_duplicate_state(plane, &state->base); | |
102 | ||
103 | WARN_ON(state->base.plane != plane); | |
104 | ||
105 | state->pending = old_state->pending; | |
106 | ||
107 | return &state->base; | |
108 | } | |
109 | ||
110 | static void mtk_drm_plane_destroy_state(struct drm_plane *plane, | |
111 | struct drm_plane_state *state) | |
112 | { | |
2f701695 | 113 | __drm_atomic_helper_plane_destroy_state(state); |
119f5173 CH |
114 | kfree(to_mtk_plane_state(state)); |
115 | } | |
116 | ||
117 | static const struct drm_plane_funcs mtk_plane_funcs = { | |
118 | .update_plane = drm_atomic_helper_update_plane, | |
119 | .disable_plane = drm_atomic_helper_disable_plane, | |
120 | .destroy = drm_plane_cleanup, | |
121 | .reset = mtk_plane_reset, | |
122 | .atomic_duplicate_state = mtk_plane_duplicate_state, | |
123 | .atomic_destroy_state = mtk_drm_plane_destroy_state, | |
124 | }; | |
125 | ||
126 | static int mtk_plane_atomic_check(struct drm_plane *plane, | |
127 | struct drm_plane_state *state) | |
128 | { | |
129 | struct drm_framebuffer *fb = state->fb; | |
130 | struct drm_crtc_state *crtc_state; | |
119f5173 CH |
131 | struct drm_rect clip = { 0, }; |
132 | ||
133 | if (!fb) | |
134 | return 0; | |
135 | ||
136 | if (!mtk_fb_get_gem_obj(fb)) { | |
137 | DRM_DEBUG_KMS("buffer is null\n"); | |
138 | return -EFAULT; | |
139 | } | |
140 | ||
141 | if (!state->crtc) | |
142 | return 0; | |
143 | ||
144 | crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); | |
145 | if (IS_ERR(crtc_state)) | |
146 | return PTR_ERR(crtc_state); | |
147 | ||
148 | clip.x2 = crtc_state->mode.hdisplay; | |
149 | clip.y2 = crtc_state->mode.vdisplay; | |
150 | ||
0e4faf67 VS |
151 | return drm_plane_helper_check_state(state, &clip, |
152 | DRM_PLANE_HELPER_NO_SCALING, | |
153 | DRM_PLANE_HELPER_NO_SCALING, | |
154 | true, true); | |
119f5173 CH |
155 | } |
156 | ||
157 | static void mtk_plane_atomic_update(struct drm_plane *plane, | |
158 | struct drm_plane_state *old_state) | |
159 | { | |
160 | struct mtk_plane_state *state = to_mtk_plane_state(plane->state); | |
161 | struct drm_crtc *crtc = state->base.crtc; | |
162 | struct drm_gem_object *gem; | |
163 | struct mtk_drm_gem_obj *mtk_gem; | |
119f5173 CH |
164 | |
165 | if (!crtc) | |
166 | return; | |
167 | ||
119f5173 CH |
168 | gem = mtk_fb_get_gem_obj(state->base.fb); |
169 | mtk_gem = to_mtk_gem_obj(gem); | |
5bfafad8 | 170 | mtk_plane_enable(plane, mtk_gem->dma_addr); |
119f5173 CH |
171 | } |
172 | ||
173 | static void mtk_plane_atomic_disable(struct drm_plane *plane, | |
174 | struct drm_plane_state *old_state) | |
175 | { | |
176 | struct mtk_plane_state *state = to_mtk_plane_state(plane->state); | |
177 | ||
178 | state->pending.enable = false; | |
179 | wmb(); /* Make sure the above parameter is set before update */ | |
180 | state->pending.dirty = true; | |
181 | } | |
182 | ||
183 | static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = { | |
184 | .atomic_check = mtk_plane_atomic_check, | |
185 | .atomic_update = mtk_plane_atomic_update, | |
186 | .atomic_disable = mtk_plane_atomic_disable, | |
187 | }; | |
188 | ||
5bfafad8 | 189 | int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane, |
0d5a32b7 | 190 | unsigned long possible_crtcs, enum drm_plane_type type) |
119f5173 CH |
191 | { |
192 | int err; | |
193 | ||
5bfafad8 | 194 | err = drm_universal_plane_init(dev, plane, possible_crtcs, |
119f5173 CH |
195 | &mtk_plane_funcs, formats, |
196 | ARRAY_SIZE(formats), type, NULL); | |
197 | if (err) { | |
198 | DRM_ERROR("failed to initialize plane\n"); | |
199 | return err; | |
200 | } | |
201 | ||
5bfafad8 | 202 | drm_plane_helper_add(plane, &mtk_plane_helper_funcs); |
119f5173 CH |
203 | |
204 | return 0; | |
205 | } |