]>
Commit | Line | Data |
---|---|---|
c8afe684 RC |
1 | /* |
2 | * Copyright (C) 2013 Red Hat | |
3 | * Author: Rob Clark <robdclark@gmail.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License version 2 as published by | |
7 | * the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along with | |
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | ||
18 | #include "mdp4_kms.h" | |
19 | ||
20 | ||
21 | struct mdp4_plane { | |
22 | struct drm_plane base; | |
23 | const char *name; | |
24 | ||
22ba8b6b | 25 | enum mdp4_pipe pipe; |
c8afe684 RC |
26 | |
27 | uint32_t nformats; | |
28 | uint32_t formats[32]; | |
29 | ||
30 | bool enabled; | |
31 | }; | |
32 | #define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base) | |
33 | ||
34 | static struct mdp4_kms *get_kms(struct drm_plane *plane) | |
35 | { | |
36 | struct msm_drm_private *priv = plane->dev->dev_private; | |
9e0efa63 | 37 | return to_mdp4_kms(to_mdp_kms(priv->kms)); |
c8afe684 RC |
38 | } |
39 | ||
40 | static int mdp4_plane_update(struct drm_plane *plane, | |
41 | struct drm_crtc *crtc, struct drm_framebuffer *fb, | |
42 | int crtc_x, int crtc_y, | |
43 | unsigned int crtc_w, unsigned int crtc_h, | |
44 | uint32_t src_x, uint32_t src_y, | |
45 | uint32_t src_w, uint32_t src_h) | |
46 | { | |
47 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); | |
48 | ||
49 | mdp4_plane->enabled = true; | |
50 | ||
51 | if (plane->fb) | |
52 | drm_framebuffer_unreference(plane->fb); | |
53 | ||
54 | drm_framebuffer_reference(fb); | |
55 | ||
56 | return mdp4_plane_mode_set(plane, crtc, fb, | |
57 | crtc_x, crtc_y, crtc_w, crtc_h, | |
58 | src_x, src_y, src_w, src_h); | |
59 | } | |
60 | ||
61 | static int mdp4_plane_disable(struct drm_plane *plane) | |
62 | { | |
63 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); | |
a8623918 RC |
64 | DBG("%s: disable", mdp4_plane->name); |
65 | if (plane->crtc) | |
66 | mdp4_crtc_detach(plane->crtc, plane); | |
c8afe684 RC |
67 | return 0; |
68 | } | |
69 | ||
70 | static void mdp4_plane_destroy(struct drm_plane *plane) | |
71 | { | |
72 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); | |
73 | ||
74 | mdp4_plane_disable(plane); | |
75 | drm_plane_cleanup(plane); | |
76 | ||
77 | kfree(mdp4_plane); | |
78 | } | |
79 | ||
80 | /* helper to install properties which are common to planes and crtcs */ | |
81 | void mdp4_plane_install_properties(struct drm_plane *plane, | |
82 | struct drm_mode_object *obj) | |
83 | { | |
84 | // XXX | |
85 | } | |
86 | ||
87 | int mdp4_plane_set_property(struct drm_plane *plane, | |
88 | struct drm_property *property, uint64_t val) | |
89 | { | |
90 | // XXX | |
91 | return -EINVAL; | |
92 | } | |
93 | ||
94 | static const struct drm_plane_funcs mdp4_plane_funcs = { | |
95 | .update_plane = mdp4_plane_update, | |
96 | .disable_plane = mdp4_plane_disable, | |
97 | .destroy = mdp4_plane_destroy, | |
98 | .set_property = mdp4_plane_set_property, | |
99 | }; | |
100 | ||
101 | void mdp4_plane_set_scanout(struct drm_plane *plane, | |
102 | struct drm_framebuffer *fb) | |
103 | { | |
104 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); | |
105 | struct mdp4_kms *mdp4_kms = get_kms(plane); | |
22ba8b6b | 106 | enum mdp4_pipe pipe = mdp4_plane->pipe; |
c8afe684 RC |
107 | uint32_t iova; |
108 | ||
109 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe), | |
110 | MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | | |
111 | MDP4_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); | |
112 | ||
113 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_B(pipe), | |
114 | MDP4_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | | |
115 | MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); | |
116 | ||
117 | msm_gem_get_iova(msm_framebuffer_bo(fb, 0), mdp4_kms->id, &iova); | |
118 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova); | |
119 | ||
120 | plane->fb = fb; | |
121 | } | |
122 | ||
123 | #define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 | |
124 | ||
125 | int mdp4_plane_mode_set(struct drm_plane *plane, | |
126 | struct drm_crtc *crtc, struct drm_framebuffer *fb, | |
127 | int crtc_x, int crtc_y, | |
128 | unsigned int crtc_w, unsigned int crtc_h, | |
129 | uint32_t src_x, uint32_t src_y, | |
130 | uint32_t src_w, uint32_t src_h) | |
131 | { | |
132 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); | |
133 | struct mdp4_kms *mdp4_kms = get_kms(plane); | |
22ba8b6b | 134 | enum mdp4_pipe pipe = mdp4_plane->pipe; |
10a02eb6 | 135 | const struct mdp_format *format; |
c8afe684 RC |
136 | uint32_t op_mode = 0; |
137 | uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; | |
138 | uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; | |
139 | ||
140 | /* src values are in Q16 fixed point, convert to integer: */ | |
141 | src_x = src_x >> 16; | |
142 | src_y = src_y >> 16; | |
143 | src_w = src_w >> 16; | |
144 | src_h = src_h >> 16; | |
145 | ||
a8623918 RC |
146 | DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name, |
147 | fb->base.id, src_x, src_y, src_w, src_h, | |
148 | crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); | |
149 | ||
c8afe684 RC |
150 | if (src_w != crtc_w) { |
151 | op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN; | |
152 | /* TODO calc phasex_step */ | |
153 | } | |
154 | ||
155 | if (src_h != crtc_h) { | |
156 | op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN; | |
157 | /* TODO calc phasey_step */ | |
158 | } | |
159 | ||
160 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe), | |
161 | MDP4_PIPE_SRC_SIZE_WIDTH(src_w) | | |
162 | MDP4_PIPE_SRC_SIZE_HEIGHT(src_h)); | |
163 | ||
164 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_XY(pipe), | |
165 | MDP4_PIPE_SRC_XY_X(src_x) | | |
166 | MDP4_PIPE_SRC_XY_Y(src_y)); | |
167 | ||
168 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_SIZE(pipe), | |
169 | MDP4_PIPE_DST_SIZE_WIDTH(crtc_w) | | |
170 | MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h)); | |
171 | ||
172 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe), | |
7896052d RC |
173 | MDP4_PIPE_DST_XY_X(crtc_x) | |
174 | MDP4_PIPE_DST_XY_Y(crtc_y)); | |
c8afe684 RC |
175 | |
176 | mdp4_plane_set_scanout(plane, fb); | |
177 | ||
10a02eb6 | 178 | format = to_mdp_format(msm_framebuffer_format(fb)); |
c8afe684 RC |
179 | |
180 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe), | |
181 | MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | | |
182 | MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | | |
183 | MDP4_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | | |
184 | MDP4_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | | |
185 | COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) | | |
186 | MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | | |
187 | MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | | |
188 | COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT)); | |
189 | ||
190 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe), | |
191 | MDP4_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | | |
192 | MDP4_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | | |
193 | MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | | |
194 | MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); | |
195 | ||
196 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode); | |
197 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step); | |
198 | mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step); | |
199 | ||
a8623918 RC |
200 | /* TODO detach from old crtc (if we had more than one) */ |
201 | mdp4_crtc_attach(crtc, plane); | |
c8afe684 RC |
202 | |
203 | return 0; | |
204 | } | |
205 | ||
206 | static const char *pipe_names[] = { | |
207 | "VG1", "VG2", | |
208 | "RGB1", "RGB2", "RGB3", | |
209 | "VG3", "VG4", | |
210 | }; | |
211 | ||
22ba8b6b | 212 | enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane) |
c8afe684 RC |
213 | { |
214 | struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); | |
215 | return mdp4_plane->pipe; | |
216 | } | |
217 | ||
218 | /* initialize plane */ | |
219 | struct drm_plane *mdp4_plane_init(struct drm_device *dev, | |
22ba8b6b | 220 | enum mdp4_pipe pipe_id, bool private_plane) |
c8afe684 | 221 | { |
c8afe684 RC |
222 | struct drm_plane *plane = NULL; |
223 | struct mdp4_plane *mdp4_plane; | |
224 | int ret; | |
2d82d188 | 225 | enum drm_plane_type type; |
c8afe684 RC |
226 | |
227 | mdp4_plane = kzalloc(sizeof(*mdp4_plane), GFP_KERNEL); | |
228 | if (!mdp4_plane) { | |
229 | ret = -ENOMEM; | |
230 | goto fail; | |
231 | } | |
232 | ||
233 | plane = &mdp4_plane->base; | |
234 | ||
235 | mdp4_plane->pipe = pipe_id; | |
236 | mdp4_plane->name = pipe_names[pipe_id]; | |
237 | ||
a8623918 RC |
238 | mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats, |
239 | ARRAY_SIZE(mdp4_plane->formats)); | |
240 | ||
2d82d188 MR |
241 | type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; |
242 | drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs, | |
243 | mdp4_plane->formats, mdp4_plane->nformats, | |
244 | type); | |
c8afe684 RC |
245 | |
246 | mdp4_plane_install_properties(plane, &plane->base); | |
247 | ||
248 | return plane; | |
249 | ||
250 | fail: | |
251 | if (plane) | |
252 | mdp4_plane_destroy(plane); | |
253 | ||
254 | return ERR_PTR(ret); | |
255 | } |