diff options
Diffstat (limited to 'drivers/gpu/drm/imx')
-rw-r--r-- | drivers/gpu/drm/imx/dw_hdmi-imx.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 123 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.h | 4 |
4 files changed, 119 insertions, 31 deletions
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 2a95d10e9d92..a24631fdf4ad 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c | |||
@@ -225,8 +225,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, | |||
225 | if (!iores) | 225 | if (!iores) |
226 | return -ENXIO; | 226 | return -ENXIO; |
227 | 227 | ||
228 | platform_set_drvdata(pdev, hdmi); | ||
229 | |||
230 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); | 228 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); |
231 | /* | 229 | /* |
232 | * If we failed to find the CRTC(s) which this encoder is | 230 | * If we failed to find the CRTC(s) which this encoder is |
@@ -245,7 +243,16 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, | |||
245 | drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs, | 243 | drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs, |
246 | DRM_MODE_ENCODER_TMDS, NULL); | 244 | DRM_MODE_ENCODER_TMDS, NULL); |
247 | 245 | ||
248 | return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); | 246 | ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); |
247 | |||
248 | /* | ||
249 | * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), | ||
250 | * which would have called the encoder cleanup. Do it manually. | ||
251 | */ | ||
252 | if (ret) | ||
253 | drm_encoder_cleanup(encoder); | ||
254 | |||
255 | return ret; | ||
249 | } | 256 | } |
250 | 257 | ||
251 | static void dw_hdmi_imx_unbind(struct device *dev, struct device *master, | 258 | static void dw_hdmi_imx_unbind(struct device *dev, struct device *master, |
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 9876e0f0c3e1..e26dcdec2aba 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
@@ -326,7 +326,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, | |||
326 | { | 326 | { |
327 | struct imx_drm_device *imxdrm = drm->dev_private; | 327 | struct imx_drm_device *imxdrm = drm->dev_private; |
328 | struct imx_drm_crtc *imx_drm_crtc; | 328 | struct imx_drm_crtc *imx_drm_crtc; |
329 | int ret; | ||
330 | 329 | ||
331 | /* | 330 | /* |
332 | * The vblank arrays are dimensioned by MAX_CRTC - we can't | 331 | * The vblank arrays are dimensioned by MAX_CRTC - we can't |
@@ -351,10 +350,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, | |||
351 | 350 | ||
352 | *new_crtc = imx_drm_crtc; | 351 | *new_crtc = imx_drm_crtc; |
353 | 352 | ||
354 | ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256); | ||
355 | if (ret) | ||
356 | goto err_register; | ||
357 | |||
358 | drm_crtc_helper_add(crtc, | 353 | drm_crtc_helper_add(crtc, |
359 | imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); | 354 | imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); |
360 | 355 | ||
@@ -362,11 +357,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, | |||
362 | imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL); | 357 | imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL); |
363 | 358 | ||
364 | return 0; | 359 | return 0; |
365 | |||
366 | err_register: | ||
367 | imxdrm->crtc[--imxdrm->pipes] = NULL; | ||
368 | kfree(imx_drm_crtc); | ||
369 | return ret; | ||
370 | } | 360 | } |
371 | EXPORT_SYMBOL_GPL(imx_drm_add_crtc); | 361 | EXPORT_SYMBOL_GPL(imx_drm_add_crtc); |
372 | 362 | ||
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 | ||
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h index 3a443b413c60..4448fd4ad4eb 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.h +++ b/drivers/gpu/drm/imx/ipuv3-plane.h | |||
@@ -29,6 +29,10 @@ struct ipu_plane { | |||
29 | int w; | 29 | int w; |
30 | int h; | 30 | int h; |
31 | 31 | ||
32 | unsigned int u_offset; | ||
33 | unsigned int v_offset; | ||
34 | unsigned int stride[2]; | ||
35 | |||
32 | bool enabled; | 36 | bool enabled; |
33 | }; | 37 | }; |
34 | 38 | ||