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