blob: cecb8eba5c320b42a11c797f64e26be5ab93e146 [file] [log] [blame]
Philipp Zabelb8d181e2013-10-10 16:18:45 +02001/*
2 * i.MX IPUv3 DP Overlay Planes
3 *
4 * Copyright (C) 2013 Philipp Zabel, Pengutronix
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <drm/drmP.h>
Liu Ying5f2f9112016-07-08 17:40:59 +080017#include <drm/drm_atomic.h>
Liu Ying255c35f2016-07-08 17:40:56 +080018#include <drm/drm_atomic_helper.h>
Philipp Zabelb8d181e2013-10-10 16:18:45 +020019#include <drm/drm_fb_cma_helper.h>
20#include <drm/drm_gem_cma_helper.h>
Liu Ying33f14232016-07-08 17:40:55 +080021#include <drm/drm_plane_helper.h>
Philipp Zabelb8d181e2013-10-10 16:18:45 +020022
Philipp Zabel39b90042013-09-30 16:13:39 +020023#include "video/imx-ipu-v3.h"
Philipp Zabelb8d181e2013-10-10 16:18:45 +020024#include "ipuv3-plane.h"
25
Philipp Zabel3df07392016-07-06 15:47:11 +020026static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
27{
28 return container_of(p, struct ipu_plane, base);
29}
Philipp Zabelb8d181e2013-10-10 16:18:45 +020030
31static const uint32_t ipu_plane_formats[] = {
Philipp Zabelc639a1c2014-12-12 13:40:38 +010032 DRM_FORMAT_ARGB1555,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020033 DRM_FORMAT_XRGB1555,
Philipp Zabelc639a1c2014-12-12 13:40:38 +010034 DRM_FORMAT_ABGR1555,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020035 DRM_FORMAT_XBGR1555,
Philipp Zabelc639a1c2014-12-12 13:40:38 +010036 DRM_FORMAT_RGBA5551,
37 DRM_FORMAT_BGRA5551,
Lucas Stachcb166a32015-08-04 17:22:06 +020038 DRM_FORMAT_ARGB4444,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020039 DRM_FORMAT_ARGB8888,
40 DRM_FORMAT_XRGB8888,
41 DRM_FORMAT_ABGR8888,
42 DRM_FORMAT_XBGR8888,
Philipp Zabel59d6b712015-04-16 15:56:40 +020043 DRM_FORMAT_RGBA8888,
44 DRM_FORMAT_RGBX8888,
45 DRM_FORMAT_BGRA8888,
46 DRM_FORMAT_BGRA8888,
Philipp Zabel79321312016-02-12 14:35:55 +010047 DRM_FORMAT_UYVY,
48 DRM_FORMAT_VYUY,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020049 DRM_FORMAT_YUYV,
50 DRM_FORMAT_YVYU,
51 DRM_FORMAT_YUV420,
52 DRM_FORMAT_YVU420,
Philipp Zabeleae13c92016-10-18 12:31:40 +020053 DRM_FORMAT_YUV422,
54 DRM_FORMAT_YVU422,
55 DRM_FORMAT_YUV444,
56 DRM_FORMAT_YVU444,
57 DRM_FORMAT_NV12,
58 DRM_FORMAT_NV16,
Enrico Jorns33bee522015-11-24 16:29:22 +010059 DRM_FORMAT_RGB565,
Philipp Zabelf6b50ef2016-07-22 12:02:45 +020060 DRM_FORMAT_RGB565_A8,
61 DRM_FORMAT_BGR565_A8,
62 DRM_FORMAT_RGB888_A8,
63 DRM_FORMAT_BGR888_A8,
64 DRM_FORMAT_RGBX8888_A8,
65 DRM_FORMAT_BGRX8888_A8,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020066};
67
68int ipu_plane_irq(struct ipu_plane *ipu_plane)
69{
70 return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
71 IPU_IRQ_EOF);
72}
73
Liu Ying33f14232016-07-08 17:40:55 +080074static inline unsigned long
Philipp Zabel0bfd56f2016-07-22 12:01:11 +020075drm_plane_state_to_eba(struct drm_plane_state *state, int plane)
Liu Ying33f14232016-07-08 17:40:55 +080076{
77 struct drm_framebuffer *fb = state->fb;
78 struct drm_gem_cma_object *cma_obj;
Philipp Zabel03ee3da2016-10-19 10:50:26 +020079 int x = state->src.x1 >> 16;
80 int y = state->src.y1 >> 16;
Liu Ying33f14232016-07-08 17:40:55 +080081
Philipp Zabel0bfd56f2016-07-22 12:01:11 +020082 cma_obj = drm_fb_cma_get_gem_obj(fb, plane);
Liu Ying33f14232016-07-08 17:40:55 +080083 BUG_ON(!cma_obj);
84
Philipp Zabel0bfd56f2016-07-22 12:01:11 +020085 return cma_obj->paddr + fb->offsets[plane] + fb->pitches[plane] * y +
86 fb->format->cpp[plane] * x;
Liu Ying33f14232016-07-08 17:40:55 +080087}
88
89static inline unsigned long
90drm_plane_state_to_ubo(struct drm_plane_state *state)
91{
92 struct drm_framebuffer *fb = state->fb;
93 struct drm_gem_cma_object *cma_obj;
Philipp Zabel0bfd56f2016-07-22 12:01:11 +020094 unsigned long eba = drm_plane_state_to_eba(state, 0);
Philipp Zabel03ee3da2016-10-19 10:50:26 +020095 int x = state->src.x1 >> 16;
96 int y = state->src.y1 >> 16;
Liu Ying33f14232016-07-08 17:40:55 +080097
98 cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
99 BUG_ON(!cma_obj);
100
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200101 x /= drm_format_horz_chroma_subsampling(fb->format->format);
102 y /= drm_format_vert_chroma_subsampling(fb->format->format);
Philipp Zabelf2fa3532016-10-18 12:26:19 +0200103
104 return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
Ville Syrjälä353c8592016-12-14 23:30:57 +0200105 fb->format->cpp[1] * x - eba;
Liu Ying33f14232016-07-08 17:40:55 +0800106}
107
108static inline unsigned long
109drm_plane_state_to_vbo(struct drm_plane_state *state)
110{
111 struct drm_framebuffer *fb = state->fb;
112 struct drm_gem_cma_object *cma_obj;
Philipp Zabel0bfd56f2016-07-22 12:01:11 +0200113 unsigned long eba = drm_plane_state_to_eba(state, 0);
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200114 int x = state->src.x1 >> 16;
115 int y = state->src.y1 >> 16;
Liu Ying33f14232016-07-08 17:40:55 +0800116
117 cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
118 BUG_ON(!cma_obj);
119
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200120 x /= drm_format_horz_chroma_subsampling(fb->format->format);
121 y /= drm_format_vert_chroma_subsampling(fb->format->format);
Philipp Zabelf2fa3532016-10-18 12:26:19 +0200122
123 return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y +
Ville Syrjälä353c8592016-12-14 23:30:57 +0200124 fb->format->cpp[2] * x - eba;
Liu Ying33f14232016-07-08 17:40:55 +0800125}
126
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200127void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
128{
129 if (!IS_ERR_OR_NULL(ipu_plane->dp))
130 ipu_dp_put(ipu_plane->dp);
131 if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
132 ipu_dmfc_put(ipu_plane->dmfc);
133 if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
134 ipu_idmac_put(ipu_plane->ipu_ch);
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200135 if (!IS_ERR_OR_NULL(ipu_plane->alpha_ch))
136 ipu_idmac_put(ipu_plane->alpha_ch);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200137}
138
139int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
140{
141 int ret;
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200142 int alpha_ch;
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200143
144 ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
145 if (IS_ERR(ipu_plane->ipu_ch)) {
146 ret = PTR_ERR(ipu_plane->ipu_ch);
147 DRM_ERROR("failed to get idmac channel: %d\n", ret);
148 return ret;
149 }
150
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200151 alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma);
152 if (alpha_ch >= 0) {
153 ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch);
154 if (IS_ERR(ipu_plane->alpha_ch)) {
155 ret = PTR_ERR(ipu_plane->alpha_ch);
156 DRM_ERROR("failed to get alpha idmac channel %d: %d\n",
157 alpha_ch, ret);
158 return ret;
159 }
160 }
161
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200162 ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
163 if (IS_ERR(ipu_plane->dmfc)) {
164 ret = PTR_ERR(ipu_plane->dmfc);
165 DRM_ERROR("failed to get dmfc: ret %d\n", ret);
166 goto err_out;
167 }
168
169 if (ipu_plane->dp_flow >= 0) {
170 ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
171 if (IS_ERR(ipu_plane->dp)) {
172 ret = PTR_ERR(ipu_plane->dp);
173 DRM_ERROR("failed to get dp flow: %d\n", ret);
174 goto err_out;
175 }
176 }
177
178 return 0;
179err_out:
180 ipu_plane_put_resources(ipu_plane);
181
182 return ret;
183}
184
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200185static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
186{
187 switch (ipu_plane->base.state->fb->format->format) {
188 case DRM_FORMAT_RGB565_A8:
189 case DRM_FORMAT_BGR565_A8:
190 case DRM_FORMAT_RGB888_A8:
191 case DRM_FORMAT_BGR888_A8:
192 case DRM_FORMAT_RGBX8888_A8:
193 case DRM_FORMAT_BGRX8888_A8:
194 return true;
195 default:
196 return false;
197 }
198}
199
Liu Ying33f14232016-07-08 17:40:55 +0800200static void ipu_plane_enable(struct ipu_plane *ipu_plane)
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200201{
Philipp Zabel285bbb02014-04-14 23:53:20 +0200202 if (ipu_plane->dp)
203 ipu_dp_enable(ipu_plane->ipu);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200204 ipu_dmfc_enable_channel(ipu_plane->dmfc);
205 ipu_idmac_enable_channel(ipu_plane->ipu_ch);
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200206 if (ipu_plane_separate_alpha(ipu_plane))
207 ipu_idmac_enable_channel(ipu_plane->alpha_ch);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200208 if (ipu_plane->dp)
209 ipu_dp_enable_channel(ipu_plane->dp);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200210}
211
Philipp Zabeleb8c8882017-02-24 18:31:05 +0100212void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200213{
Lucas Stachdf4b2232016-08-11 11:18:50 +0200214 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
215
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200216 ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
217
Philipp Zabeleb8c8882017-02-24 18:31:05 +0100218 if (ipu_plane->dp && disable_dp_channel)
219 ipu_dp_disable_channel(ipu_plane->dp, false);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200220 ipu_idmac_disable_channel(ipu_plane->ipu_ch);
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200221 if (ipu_plane->alpha_ch)
222 ipu_idmac_disable_channel(ipu_plane->alpha_ch);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200223 ipu_dmfc_disable_channel(ipu_plane->dmfc);
Philipp Zabel285bbb02014-04-14 23:53:20 +0200224 if (ipu_plane->dp)
225 ipu_dp_disable(ipu_plane->ipu);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200226}
227
Philipp Zabeleb8c8882017-02-24 18:31:05 +0100228void ipu_plane_disable_deferred(struct drm_plane *plane)
229{
230 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
231
232 if (ipu_plane->disabling) {
233 ipu_plane->disabling = false;
234 ipu_plane_disable(ipu_plane, false);
235 }
236}
237EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred);
238
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200239static void ipu_plane_destroy(struct drm_plane *plane)
240{
241 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
242
243 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
244
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200245 drm_plane_cleanup(plane);
246 kfree(ipu_plane);
247}
248
Liu Ying8b3ce872016-05-24 18:10:40 +0800249static const struct drm_plane_funcs ipu_plane_funcs = {
Liu Ying5f2f9112016-07-08 17:40:59 +0800250 .update_plane = drm_atomic_helper_update_plane,
251 .disable_plane = drm_atomic_helper_disable_plane,
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200252 .destroy = ipu_plane_destroy,
Liu Ying255c35f2016-07-08 17:40:56 +0800253 .reset = drm_atomic_helper_plane_reset,
254 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
255 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200256};
257
Liu Ying33f14232016-07-08 17:40:55 +0800258static int ipu_plane_atomic_check(struct drm_plane *plane,
259 struct drm_plane_state *state)
260{
261 struct drm_plane_state *old_state = plane->state;
262 struct drm_crtc_state *crtc_state;
263 struct device *dev = plane->dev->dev;
264 struct drm_framebuffer *fb = state->fb;
265 struct drm_framebuffer *old_fb = old_state->fb;
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200266 unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200267 bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
268 struct drm_rect clip;
Philipp Zabel5fb57ab2016-10-18 12:30:36 +0200269 int hsub, vsub;
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200270 int ret;
Liu Ying33f14232016-07-08 17:40:55 +0800271
272 /* Ok to disable */
273 if (!fb)
Liu Ying5f2f9112016-07-08 17:40:59 +0800274 return 0;
275
276 if (!state->crtc)
277 return -EINVAL;
278
279 crtc_state =
280 drm_atomic_get_existing_crtc_state(state->state, state->crtc);
281 if (WARN_ON(!crtc_state))
282 return -EINVAL;
Liu Ying33f14232016-07-08 17:40:55 +0800283
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200284 clip.x1 = 0;
285 clip.y1 = 0;
286 clip.x2 = crtc_state->adjusted_mode.hdisplay;
287 clip.y2 = crtc_state->adjusted_mode.vdisplay;
288 ret = drm_plane_helper_check_state(state, &clip,
289 DRM_PLANE_HELPER_NO_SCALING,
290 DRM_PLANE_HELPER_NO_SCALING,
291 can_position, true);
292 if (ret)
293 return ret;
294
Liu Ying33f14232016-07-08 17:40:55 +0800295 /* CRTC should be enabled */
Liu Ying5f2f9112016-07-08 17:40:59 +0800296 if (!crtc_state->enable)
Liu Ying33f14232016-07-08 17:40:55 +0800297 return -EINVAL;
298
Liu Ying33f14232016-07-08 17:40:55 +0800299 switch (plane->type) {
300 case DRM_PLANE_TYPE_PRIMARY:
Liu Ying33f14232016-07-08 17:40:55 +0800301 /* full plane minimum width is 13 pixels */
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200302 if (drm_rect_width(&state->dst) < 13)
Liu Ying33f14232016-07-08 17:40:55 +0800303 return -EINVAL;
304 break;
305 case DRM_PLANE_TYPE_OVERLAY:
Liu Ying33f14232016-07-08 17:40:55 +0800306 break;
307 default:
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200308 dev_warn(dev, "Unsupported plane type %d\n", plane->type);
Liu Ying33f14232016-07-08 17:40:55 +0800309 return -EINVAL;
310 }
311
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200312 if (drm_rect_height(&state->dst) < 2)
Liu Ying33f14232016-07-08 17:40:55 +0800313 return -EINVAL;
314
315 /*
Liu Ying17809992016-08-26 15:30:44 +0800316 * We support resizing active plane or changing its format by
317 * forcing CRTC mode change in plane's ->atomic_check callback
318 * and disabling all affected active planes in CRTC's ->atomic_disable
319 * callback. The planes will be reenabled in plane's ->atomic_update
320 * callback.
Liu Ying33f14232016-07-08 17:40:55 +0800321 */
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200322 if (old_fb &&
323 (drm_rect_width(&state->dst) != drm_rect_width(&old_state->dst) ||
324 drm_rect_height(&state->dst) != drm_rect_height(&old_state->dst) ||
325 fb->format != old_fb->format))
Liu Ying17809992016-08-26 15:30:44 +0800326 crtc_state->mode_changed = true;
Liu Ying33f14232016-07-08 17:40:55 +0800327
Philipp Zabel0bfd56f2016-07-22 12:01:11 +0200328 eba = drm_plane_state_to_eba(state, 0);
Liu Ying33f14232016-07-08 17:40:55 +0800329
330 if (eba & 0x7)
331 return -EINVAL;
332
333 if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
334 return -EINVAL;
335
336 if (old_fb && fb->pitches[0] != old_fb->pitches[0])
Liu Ying17809992016-08-26 15:30:44 +0800337 crtc_state->mode_changed = true;
Liu Ying33f14232016-07-08 17:40:55 +0800338
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200339 switch (fb->format->format) {
Liu Ying33f14232016-07-08 17:40:55 +0800340 case DRM_FORMAT_YUV420:
341 case DRM_FORMAT_YVU420:
Philipp Zabeleae13c92016-10-18 12:31:40 +0200342 case DRM_FORMAT_YUV422:
343 case DRM_FORMAT_YVU422:
344 case DRM_FORMAT_YUV444:
345 case DRM_FORMAT_YVU444:
Liu Ying33f14232016-07-08 17:40:55 +0800346 /*
347 * Multiplanar formats have to meet the following restrictions:
348 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
349 * - EBA, UBO and VBO are a multiple of 8
350 * - UBO and VBO are unsigned and not larger than 0xfffff8
351 * - Only EBA may be changed while scanout is active
352 * - The strides of U and V planes must be identical.
353 */
Liu Ying33f14232016-07-08 17:40:55 +0800354 vbo = drm_plane_state_to_vbo(state);
355
Philipp Zabeleae13c92016-10-18 12:31:40 +0200356 if (vbo & 0x7 || vbo > 0xfffff8)
Liu Ying33f14232016-07-08 17:40:55 +0800357 return -EINVAL;
358
Ville Syrjälädbd4d572016-11-18 21:53:10 +0200359 if (old_fb && (fb->format == old_fb->format)) {
Liu Ying33f14232016-07-08 17:40:55 +0800360 old_vbo = drm_plane_state_to_vbo(old_state);
Philipp Zabeleae13c92016-10-18 12:31:40 +0200361 if (vbo != old_vbo)
Philipp Zabel181c9bf2016-10-18 12:13:15 +0200362 crtc_state->mode_changed = true;
Liu Ying33f14232016-07-08 17:40:55 +0800363 }
364
365 if (fb->pitches[1] != fb->pitches[2])
366 return -EINVAL;
367
Philipp Zabeleae13c92016-10-18 12:31:40 +0200368 /* fall-through */
369 case DRM_FORMAT_NV12:
370 case DRM_FORMAT_NV16:
371 ubo = drm_plane_state_to_ubo(state);
372
373 if (ubo & 0x7 || ubo > 0xfffff8)
374 return -EINVAL;
375
Ville Syrjälädbd4d572016-11-18 21:53:10 +0200376 if (old_fb && (fb->format == old_fb->format)) {
Philipp Zabeleae13c92016-10-18 12:31:40 +0200377 old_ubo = drm_plane_state_to_ubo(old_state);
378 if (ubo != old_ubo)
379 crtc_state->mode_changed = true;
380 }
381
Liu Ying33f14232016-07-08 17:40:55 +0800382 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
383 return -EINVAL;
384
385 if (old_fb && old_fb->pitches[1] != fb->pitches[1])
Liu Ying17809992016-08-26 15:30:44 +0800386 crtc_state->mode_changed = true;
Philipp Zabel5fb57ab2016-10-18 12:30:36 +0200387
388 /*
389 * The x/y offsets must be even in case of horizontal/vertical
390 * chroma subsampling.
391 */
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200392 hsub = drm_format_horz_chroma_subsampling(fb->format->format);
393 vsub = drm_format_vert_chroma_subsampling(fb->format->format);
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200394 if (((state->src.x1 >> 16) & (hsub - 1)) ||
395 ((state->src.y1 >> 16) & (vsub - 1)))
Philipp Zabel5fb57ab2016-10-18 12:30:36 +0200396 return -EINVAL;
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200397 break;
398 case DRM_FORMAT_RGB565_A8:
399 case DRM_FORMAT_BGR565_A8:
400 case DRM_FORMAT_RGB888_A8:
401 case DRM_FORMAT_BGR888_A8:
402 case DRM_FORMAT_RGBX8888_A8:
403 case DRM_FORMAT_BGRX8888_A8:
404 alpha_eba = drm_plane_state_to_eba(state, 1);
405 if (alpha_eba & 0x7)
406 return -EINVAL;
407
408 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
409 return -EINVAL;
410
411 if (old_fb && old_fb->pitches[1] != fb->pitches[1])
412 crtc_state->mode_changed = true;
413 break;
Liu Ying33f14232016-07-08 17:40:55 +0800414 }
415
416 return 0;
417}
418
419static void ipu_plane_atomic_disable(struct drm_plane *plane,
420 struct drm_plane_state *old_state)
421{
Philipp Zabeleb8c8882017-02-24 18:31:05 +0100422 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
423
424 if (ipu_plane->dp)
425 ipu_dp_disable_channel(ipu_plane->dp, true);
426 ipu_plane->disabling = true;
Liu Ying33f14232016-07-08 17:40:55 +0800427}
428
429static void ipu_plane_atomic_update(struct drm_plane *plane,
430 struct drm_plane_state *old_state)
431{
432 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
433 struct drm_plane_state *state = plane->state;
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200434 struct drm_crtc_state *crtc_state = state->crtc->state;
435 struct drm_framebuffer *fb = state->fb;
Philipp Zabel2e9a7122016-10-20 15:37:52 +0200436 struct drm_rect *dst = &state->dst;
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200437 unsigned long eba, ubo, vbo;
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200438 unsigned long alpha_eba = 0;
Liu Ying33f14232016-07-08 17:40:55 +0800439 enum ipu_color_space ics;
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200440 int active;
Liu Ying33f14232016-07-08 17:40:55 +0800441
Philipp Zabel2e9a7122016-10-20 15:37:52 +0200442 if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
443 ipu_dp_set_window_pos(ipu_plane->dp, dst->x1, dst->y1);
444
Philipp Zabel0bfd56f2016-07-22 12:01:11 +0200445 eba = drm_plane_state_to_eba(state, 0);
Liu Ying5f4df0c2016-08-26 15:30:43 +0800446
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200447 if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
448 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
449 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
450 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200451 if (ipu_plane_separate_alpha(ipu_plane)) {
452 active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
453 ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
454 alpha_eba);
455 ipu_idmac_select_buffer(ipu_plane->alpha_ch, !active);
456 }
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200457 return;
Liu Ying33f14232016-07-08 17:40:55 +0800458 }
459
460 switch (ipu_plane->dp_flow) {
461 case IPU_DP_FLOW_SYNC_BG:
462 ipu_dp_setup_channel(ipu_plane->dp,
463 IPUV3_COLORSPACE_RGB,
464 IPUV3_COLORSPACE_RGB);
465 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
466 break;
467 case IPU_DP_FLOW_SYNC_FG:
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200468 ics = ipu_drm_fourcc_to_colorspace(state->fb->format->format);
Liu Ying33f14232016-07-08 17:40:55 +0800469 ipu_dp_setup_channel(ipu_plane->dp, ics,
470 IPUV3_COLORSPACE_UNKNOWN);
Liu Ying33f14232016-07-08 17:40:55 +0800471 /* Enable local alpha on partial plane */
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200472 switch (state->fb->format->format) {
Liu Ying33f14232016-07-08 17:40:55 +0800473 case DRM_FORMAT_ARGB1555:
474 case DRM_FORMAT_ABGR1555:
475 case DRM_FORMAT_RGBA5551:
476 case DRM_FORMAT_BGRA5551:
477 case DRM_FORMAT_ARGB4444:
478 case DRM_FORMAT_ARGB8888:
479 case DRM_FORMAT_ABGR8888:
480 case DRM_FORMAT_RGBA8888:
481 case DRM_FORMAT_BGRA8888:
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200482 case DRM_FORMAT_RGB565_A8:
483 case DRM_FORMAT_BGR565_A8:
484 case DRM_FORMAT_RGB888_A8:
485 case DRM_FORMAT_BGR888_A8:
486 case DRM_FORMAT_RGBX8888_A8:
487 case DRM_FORMAT_BGRX8888_A8:
Liu Ying33f14232016-07-08 17:40:55 +0800488 ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
489 break;
490 default:
Philipp Zabel86126742016-10-18 17:09:30 +0200491 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
Liu Ying33f14232016-07-08 17:40:55 +0800492 break;
493 }
494 }
495
Philipp Zabel2e9a7122016-10-20 15:37:52 +0200496 ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
Liu Ying33f14232016-07-08 17:40:55 +0800497
498 ipu_cpmem_zero(ipu_plane->ipu_ch);
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200499 ipu_cpmem_set_resolution(ipu_plane->ipu_ch,
500 drm_rect_width(&state->src) >> 16,
501 drm_rect_height(&state->src) >> 16);
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200502 ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->format->format);
Liu Ying33f14232016-07-08 17:40:55 +0800503 ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
504 ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
505 ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200506 switch (fb->format->format) {
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200507 case DRM_FORMAT_YUV420:
508 case DRM_FORMAT_YVU420:
Philipp Zabeleae13c92016-10-18 12:31:40 +0200509 case DRM_FORMAT_YUV422:
510 case DRM_FORMAT_YVU422:
511 case DRM_FORMAT_YUV444:
512 case DRM_FORMAT_YVU444:
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200513 ubo = drm_plane_state_to_ubo(state);
514 vbo = drm_plane_state_to_vbo(state);
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200515 if (fb->format->format == DRM_FORMAT_YVU420 ||
516 fb->format->format == DRM_FORMAT_YVU422 ||
517 fb->format->format == DRM_FORMAT_YVU444)
Philipp Zabeleae13c92016-10-18 12:31:40 +0200518 swap(ubo, vbo);
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200519
Philipp Zabeleae13c92016-10-18 12:31:40 +0200520 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
521 fb->pitches[1], ubo, vbo);
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200522
523 dev_dbg(ipu_plane->base.dev->dev,
524 "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200525 state->src.x1 >> 16, state->src.y1 >> 16);
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200526 break;
Philipp Zabeleae13c92016-10-18 12:31:40 +0200527 case DRM_FORMAT_NV12:
528 case DRM_FORMAT_NV16:
529 ubo = drm_plane_state_to_ubo(state);
530
531 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
532 fb->pitches[1], ubo, ubo);
533
534 dev_dbg(ipu_plane->base.dev->dev,
535 "phy = %lu %lu, x = %d, y = %d", eba, ubo,
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200536 state->src.x1 >> 16, state->src.y1 >> 16);
Philipp Zabeleae13c92016-10-18 12:31:40 +0200537 break;
Philipp Zabelf6b50ef2016-07-22 12:02:45 +0200538 case DRM_FORMAT_RGB565_A8:
539 case DRM_FORMAT_BGR565_A8:
540 case DRM_FORMAT_RGB888_A8:
541 case DRM_FORMAT_BGR888_A8:
542 case DRM_FORMAT_RGBX8888_A8:
543 case DRM_FORMAT_BGRX8888_A8:
544 alpha_eba = drm_plane_state_to_eba(state, 1);
545
546 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d",
547 eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16);
548
549 ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16);
550
551 ipu_cpmem_zero(ipu_plane->alpha_ch);
552 ipu_cpmem_set_resolution(ipu_plane->alpha_ch,
553 drm_rect_width(&state->src) >> 16,
554 drm_rect_height(&state->src) >> 16);
555 ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
556 ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
557 ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1);
558 ipu_cpmem_set_stride(ipu_plane->alpha_ch,
559 state->fb->pitches[1]);
560 ipu_cpmem_set_burstsize(ipu_plane->alpha_ch, 16);
561 ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 0, alpha_eba);
562 ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 1, alpha_eba);
563 break;
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200564 default:
565 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
Philipp Zabel03ee3da2016-10-19 10:50:26 +0200566 eba, state->src.x1 >> 16, state->src.y1 >> 16);
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200567 break;
568 }
569 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
570 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
Liu Ying33f14232016-07-08 17:40:55 +0800571 ipu_plane_enable(ipu_plane);
572}
573
574static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
Marek Vasut782ea2a2016-11-14 11:07:32 +0100575 .prepare_fb = drm_fb_cma_prepare_fb,
Liu Ying33f14232016-07-08 17:40:55 +0800576 .atomic_check = ipu_plane_atomic_check,
577 .atomic_disable = ipu_plane_atomic_disable,
578 .atomic_update = ipu_plane_atomic_update,
579};
580
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200581struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
582 int dma, int dp, unsigned int possible_crtcs,
Philipp Zabel43895592015-11-06 11:08:02 +0100583 enum drm_plane_type type)
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200584{
585 struct ipu_plane *ipu_plane;
586 int ret;
587
588 DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
589 dma, dp, possible_crtcs);
590
591 ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
592 if (!ipu_plane) {
593 DRM_ERROR("failed to allocate plane\n");
594 return ERR_PTR(-ENOMEM);
595 }
596
597 ipu_plane->ipu = ipu;
598 ipu_plane->dma = dma;
599 ipu_plane->dp_flow = dp;
600
Philipp Zabel43895592015-11-06 11:08:02 +0100601 ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
602 &ipu_plane_funcs, ipu_plane_formats,
Ville Syrjäläb0b3b792015-12-09 16:19:55 +0200603 ARRAY_SIZE(ipu_plane_formats), type,
604 NULL);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200605 if (ret) {
606 DRM_ERROR("failed to initialize plane\n");
607 kfree(ipu_plane);
608 return ERR_PTR(ret);
609 }
610
Liu Ying33f14232016-07-08 17:40:55 +0800611 drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
612
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200613 return ipu_plane;
614}