diff options
Diffstat (limited to 'drivers/gpu/drm/imx/ipuv3-plane.c')
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 123 |
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) | |||
72 | int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, | 72 | int 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 | ||