aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/imx/ipuv3-plane.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/imx/ipuv3-plane.c')
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c123
1 files changed, 105 insertions, 18 deletions
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 588827844f30..681ec6eb77d9 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -72,22 +72,101 @@ static inline int calc_bandwidth(int width, int height, unsigned int vref)
72int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, 72int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
73 int x, int y) 73 int x, int y)
74{ 74{
75 struct drm_gem_cma_object *cma_obj; 75 struct drm_gem_cma_object *cma_obj[3];
76 unsigned long eba; 76 unsigned long eba, ubo, vbo;
77 int active; 77 int active, i;
78 78
79 cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 79 for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
80 if (!cma_obj) { 80 cma_obj[i] = drm_fb_cma_get_gem_obj(fb, i);
81 DRM_DEBUG_KMS("entry is null.\n"); 81 if (!cma_obj[i]) {
82 return -EFAULT; 82 DRM_DEBUG_KMS("plane %d entry is null.\n", i);
83 return -EFAULT;
84 }
83 } 85 }
84 86
85 dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", 87 eba = cma_obj[0]->paddr + fb->offsets[0] +
86 &cma_obj->paddr, x, y);
87
88 eba = cma_obj->paddr + fb->offsets[0] +
89 fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x; 88 fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
90 89
90 if (eba & 0x7) {
91 DRM_DEBUG_KMS("base address must be a multiple of 8.\n");
92 return -EINVAL;
93 }
94
95 if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) {
96 DRM_DEBUG_KMS("pitches out of range.\n");
97 return -EINVAL;
98 }
99
100 if (ipu_plane->enabled && fb->pitches[0] != ipu_plane->stride[0]) {
101 DRM_DEBUG_KMS("pitches must not change while plane is enabled.\n");
102 return -EINVAL;
103 }
104
105 ipu_plane->stride[0] = fb->pitches[0];
106
107 switch (fb->pixel_format) {
108 case DRM_FORMAT_YUV420:
109 case DRM_FORMAT_YVU420:
110 /*
111 * Multiplanar formats have to meet the following restrictions:
112 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
113 * - EBA, UBO and VBO are a multiple of 8
114 * - UBO and VBO are unsigned and not larger than 0xfffff8
115 * - Only EBA may be changed while scanout is active
116 * - The strides of U and V planes must be identical.
117 */
118 ubo = cma_obj[1]->paddr + fb->offsets[1] +
119 fb->pitches[1] * y / 2 + x / 2 - eba;
120 vbo = cma_obj[2]->paddr + fb->offsets[2] +
121 fb->pitches[2] * y / 2 + x / 2 - eba;
122
123 if ((ubo & 0x7) || (vbo & 0x7)) {
124 DRM_DEBUG_KMS("U/V buffer offsets must be a multiple of 8.\n");
125 return -EINVAL;
126 }
127
128 if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) {
129 DRM_DEBUG_KMS("U/V buffer offsets must be positive and not larger than 0xfffff8.\n");
130 return -EINVAL;
131 }
132
133 if (ipu_plane->enabled && ((ipu_plane->u_offset != ubo) ||
134 (ipu_plane->v_offset != vbo))) {
135 DRM_DEBUG_KMS("U/V buffer offsets must not change while plane is enabled.\n");
136 return -EINVAL;
137 }
138
139 if (fb->pitches[1] != fb->pitches[2]) {
140 DRM_DEBUG_KMS("U/V pitches must be identical.\n");
141 return -EINVAL;
142 }
143
144 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) {
145 DRM_DEBUG_KMS("U/V pitches out of range.\n");
146 return -EINVAL;
147 }
148
149 if (ipu_plane->enabled &&
150 (ipu_plane->stride[1] != fb->pitches[1])) {
151 DRM_DEBUG_KMS("U/V pitches must not change while plane is enabled.\n");
152 return -EINVAL;
153 }
154
155 ipu_plane->u_offset = ubo;
156 ipu_plane->v_offset = vbo;
157 ipu_plane->stride[1] = fb->pitches[1];
158
159 dev_dbg(ipu_plane->base.dev->dev,
160 "phys = %pad %pad %pad, x = %d, y = %d",
161 &cma_obj[0]->paddr, &cma_obj[1]->paddr,
162 &cma_obj[2]->paddr, x, y);
163 break;
164 default:
165 dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
166 &cma_obj[0]->paddr, x, y);
167 break;
168 }
169
91 if (ipu_plane->enabled) { 170 if (ipu_plane->enabled) {
92 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); 171 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
93 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); 172 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
@@ -201,12 +280,6 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
201 } 280 }
202 } 281 }
203 282
204 ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w);
205 if (ret) {
206 dev_err(dev, "initializing dmfc channel failed with %d\n", ret);
207 return ret;
208 }
209
210 ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc, 283 ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
211 calc_bandwidth(crtc_w, crtc_h, 284 calc_bandwidth(crtc_w, crtc_h,
212 calc_vref(mode)), 64); 285 calc_vref(mode)), 64);
@@ -215,6 +288,8 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
215 return ret; 288 return ret;
216 } 289 }
217 290
291 ipu_dmfc_config_wait4eot(ipu_plane->dmfc, crtc_w);
292
218 ipu_cpmem_zero(ipu_plane->ipu_ch); 293 ipu_cpmem_zero(ipu_plane->ipu_ch);
219 ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h); 294 ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
220 ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format); 295 ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
@@ -233,6 +308,18 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
233 if (interlaced) 308 if (interlaced)
234 ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]); 309 ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]);
235 310
311 if (fb->pixel_format == DRM_FORMAT_YUV420) {
312 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
313 ipu_plane->stride[1],
314 ipu_plane->u_offset,
315 ipu_plane->v_offset);
316 } else if (fb->pixel_format == DRM_FORMAT_YVU420) {
317 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
318 ipu_plane->stride[1],
319 ipu_plane->v_offset,
320 ipu_plane->u_offset);
321 }
322
236 ipu_plane->w = src_w; 323 ipu_plane->w = src_w;
237 ipu_plane->h = src_h; 324 ipu_plane->h = src_h;
238 325