diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/bridge/dw-hdmi.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/dw_hdmi-imx.c | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 120 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm.h | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 192 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-tve.c | 97 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-crtc.c | 400 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 548 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.h | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/parallel-display.c | 149 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-dc.c | 9 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-di.c | 3 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-dmfc.c | 213 |
13 files changed, 781 insertions, 1038 deletions
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 70b1f7d4270b..77ab47341658 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c | |||
@@ -1495,14 +1495,6 @@ static void dw_hdmi_connector_force(struct drm_connector *connector) | |||
1495 | } | 1495 | } |
1496 | 1496 | ||
1497 | static const struct drm_connector_funcs dw_hdmi_connector_funcs = { | 1497 | static const struct drm_connector_funcs dw_hdmi_connector_funcs = { |
1498 | .dpms = drm_helper_connector_dpms, | ||
1499 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
1500 | .detect = dw_hdmi_connector_detect, | ||
1501 | .destroy = dw_hdmi_connector_destroy, | ||
1502 | .force = dw_hdmi_connector_force, | ||
1503 | }; | ||
1504 | |||
1505 | static const struct drm_connector_funcs dw_hdmi_atomic_connector_funcs = { | ||
1506 | .dpms = drm_atomic_helper_connector_dpms, | 1498 | .dpms = drm_atomic_helper_connector_dpms, |
1507 | .fill_modes = drm_helper_probe_single_connector_modes, | 1499 | .fill_modes = drm_helper_probe_single_connector_modes, |
1508 | .detect = dw_hdmi_connector_detect, | 1500 | .detect = dw_hdmi_connector_detect, |
@@ -1634,14 +1626,9 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi) | |||
1634 | drm_connector_helper_add(&hdmi->connector, | 1626 | drm_connector_helper_add(&hdmi->connector, |
1635 | &dw_hdmi_connector_helper_funcs); | 1627 | &dw_hdmi_connector_helper_funcs); |
1636 | 1628 | ||
1637 | if (drm_core_check_feature(drm, DRIVER_ATOMIC)) | 1629 | drm_connector_init(drm, &hdmi->connector, |
1638 | drm_connector_init(drm, &hdmi->connector, | 1630 | &dw_hdmi_connector_funcs, |
1639 | &dw_hdmi_atomic_connector_funcs, | 1631 | DRM_MODE_CONNECTOR_HDMIA); |
1640 | DRM_MODE_CONNECTOR_HDMIA); | ||
1641 | else | ||
1642 | drm_connector_init(drm, &hdmi->connector, | ||
1643 | &dw_hdmi_connector_funcs, | ||
1644 | DRM_MODE_CONNECTOR_HDMIA); | ||
1645 | 1632 | ||
1646 | drm_mode_connector_attach_encoder(&hdmi->connector, encoder); | 1633 | drm_mode_connector_attach_encoder(&hdmi->connector, encoder); |
1647 | 1634 | ||
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index a24631fdf4ad..359cd2765552 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c | |||
@@ -28,6 +28,11 @@ struct imx_hdmi { | |||
28 | struct regmap *regmap; | 28 | struct regmap *regmap; |
29 | }; | 29 | }; |
30 | 30 | ||
31 | static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e) | ||
32 | { | ||
33 | return container_of(e, struct imx_hdmi, encoder); | ||
34 | } | ||
35 | |||
31 | static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = { | 36 | static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = { |
32 | { | 37 | { |
33 | 45250000, { | 38 | 45250000, { |
@@ -109,15 +114,9 @@ static void dw_hdmi_imx_encoder_disable(struct drm_encoder *encoder) | |||
109 | { | 114 | { |
110 | } | 115 | } |
111 | 116 | ||
112 | static void dw_hdmi_imx_encoder_mode_set(struct drm_encoder *encoder, | 117 | static void dw_hdmi_imx_encoder_enable(struct drm_encoder *encoder) |
113 | struct drm_display_mode *mode, | ||
114 | struct drm_display_mode *adj_mode) | ||
115 | { | 118 | { |
116 | } | 119 | struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder); |
117 | |||
118 | static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder) | ||
119 | { | ||
120 | struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); | ||
121 | int mux = drm_of_encoder_active_port_id(hdmi->dev->of_node, encoder); | 120 | int mux = drm_of_encoder_active_port_id(hdmi->dev->of_node, encoder); |
122 | 121 | ||
123 | regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, | 122 | regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, |
@@ -125,16 +124,23 @@ static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder) | |||
125 | mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); | 124 | mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); |
126 | } | 125 | } |
127 | 126 | ||
128 | static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder) | 127 | static int dw_hdmi_imx_atomic_check(struct drm_encoder *encoder, |
128 | struct drm_crtc_state *crtc_state, | ||
129 | struct drm_connector_state *conn_state) | ||
129 | { | 130 | { |
130 | imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_RGB888_1X24); | 131 | struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); |
132 | |||
133 | imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||
134 | imx_crtc_state->di_hsync_pin = 2; | ||
135 | imx_crtc_state->di_vsync_pin = 3; | ||
136 | |||
137 | return 0; | ||
131 | } | 138 | } |
132 | 139 | ||
133 | static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { | 140 | static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { |
134 | .mode_set = dw_hdmi_imx_encoder_mode_set, | 141 | .enable = dw_hdmi_imx_encoder_enable, |
135 | .prepare = dw_hdmi_imx_encoder_prepare, | ||
136 | .commit = dw_hdmi_imx_encoder_commit, | ||
137 | .disable = dw_hdmi_imx_encoder_disable, | 142 | .disable = dw_hdmi_imx_encoder_disable, |
143 | .atomic_check = dw_hdmi_imx_atomic_check, | ||
138 | }; | 144 | }; |
139 | 145 | ||
140 | static const struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = { | 146 | static const struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = { |
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 7746418a4c08..9f7dafce3a4c 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
@@ -15,10 +15,14 @@ | |||
15 | */ | 15 | */ |
16 | #include <linux/component.h> | 16 | #include <linux/component.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/dma-buf.h> | ||
18 | #include <linux/fb.h> | 19 | #include <linux/fb.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/reservation.h> | ||
21 | #include <drm/drmP.h> | 23 | #include <drm/drmP.h> |
24 | #include <drm/drm_atomic.h> | ||
25 | #include <drm/drm_atomic_helper.h> | ||
22 | #include <drm/drm_fb_helper.h> | 26 | #include <drm/drm_fb_helper.h> |
23 | #include <drm/drm_crtc_helper.h> | 27 | #include <drm/drm_crtc_helper.h> |
24 | #include <drm/drm_gem_cma_helper.h> | 28 | #include <drm/drm_gem_cma_helper.h> |
@@ -41,6 +45,7 @@ struct imx_drm_device { | |||
41 | struct imx_drm_crtc *crtc[MAX_CRTC]; | 45 | struct imx_drm_crtc *crtc[MAX_CRTC]; |
42 | unsigned int pipes; | 46 | unsigned int pipes; |
43 | struct drm_fbdev_cma *fbhelper; | 47 | struct drm_fbdev_cma *fbhelper; |
48 | struct drm_atomic_state *state; | ||
44 | }; | 49 | }; |
45 | 50 | ||
46 | struct imx_drm_crtc { | 51 | struct imx_drm_crtc { |
@@ -85,45 +90,6 @@ static int imx_drm_driver_unload(struct drm_device *drm) | |||
85 | return 0; | 90 | return 0; |
86 | } | 91 | } |
87 | 92 | ||
88 | static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) | ||
89 | { | ||
90 | struct imx_drm_device *imxdrm = crtc->dev->dev_private; | ||
91 | unsigned i; | ||
92 | |||
93 | for (i = 0; i < MAX_CRTC; i++) | ||
94 | if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc) | ||
95 | return imxdrm->crtc[i]; | ||
96 | |||
97 | return NULL; | ||
98 | } | ||
99 | |||
100 | int imx_drm_set_bus_config(struct drm_encoder *encoder, u32 bus_format, | ||
101 | int hsync_pin, int vsync_pin, u32 bus_flags) | ||
102 | { | ||
103 | struct imx_drm_crtc_helper_funcs *helper; | ||
104 | struct imx_drm_crtc *imx_crtc; | ||
105 | |||
106 | imx_crtc = imx_drm_find_crtc(encoder->crtc); | ||
107 | if (!imx_crtc) | ||
108 | return -EINVAL; | ||
109 | |||
110 | helper = &imx_crtc->imx_drm_helper_funcs; | ||
111 | if (helper->set_interface_pix_fmt) | ||
112 | return helper->set_interface_pix_fmt(encoder->crtc, | ||
113 | bus_format, hsync_pin, vsync_pin, | ||
114 | bus_flags); | ||
115 | return 0; | ||
116 | } | ||
117 | EXPORT_SYMBOL_GPL(imx_drm_set_bus_config); | ||
118 | |||
119 | int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format) | ||
120 | { | ||
121 | return imx_drm_set_bus_config(encoder, bus_format, 2, 3, | ||
122 | DRM_BUS_FLAG_DE_HIGH | | ||
123 | DRM_BUS_FLAG_PIXDATA_NEGEDGE); | ||
124 | } | ||
125 | EXPORT_SYMBOL_GPL(imx_drm_set_bus_format); | ||
126 | |||
127 | int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) | 93 | int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) |
128 | { | 94 | { |
129 | return drm_crtc_vblank_get(imx_drm_crtc->crtc); | 95 | return drm_crtc_vblank_get(imx_drm_crtc->crtc); |
@@ -208,6 +174,63 @@ static void imx_drm_output_poll_changed(struct drm_device *drm) | |||
208 | static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { | 174 | static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { |
209 | .fb_create = drm_fb_cma_create, | 175 | .fb_create = drm_fb_cma_create, |
210 | .output_poll_changed = imx_drm_output_poll_changed, | 176 | .output_poll_changed = imx_drm_output_poll_changed, |
177 | .atomic_check = drm_atomic_helper_check, | ||
178 | .atomic_commit = drm_atomic_helper_commit, | ||
179 | }; | ||
180 | |||
181 | static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) | ||
182 | { | ||
183 | struct drm_device *dev = state->dev; | ||
184 | struct drm_crtc *crtc; | ||
185 | struct drm_crtc_state *crtc_state; | ||
186 | struct drm_plane_state *plane_state; | ||
187 | struct drm_gem_cma_object *cma_obj; | ||
188 | struct fence *excl; | ||
189 | unsigned shared_count; | ||
190 | struct fence **shared; | ||
191 | unsigned int i, j; | ||
192 | int ret; | ||
193 | |||
194 | /* Wait for fences. */ | ||
195 | for_each_crtc_in_state(state, crtc, crtc_state, i) { | ||
196 | plane_state = crtc->primary->state; | ||
197 | if (plane_state->fb) { | ||
198 | cma_obj = drm_fb_cma_get_gem_obj(plane_state->fb, 0); | ||
199 | if (cma_obj->base.dma_buf) { | ||
200 | ret = reservation_object_get_fences_rcu( | ||
201 | cma_obj->base.dma_buf->resv, &excl, | ||
202 | &shared_count, &shared); | ||
203 | if (unlikely(ret)) | ||
204 | DRM_ERROR("failed to get fences " | ||
205 | "for buffer\n"); | ||
206 | |||
207 | if (excl) { | ||
208 | fence_wait(excl, false); | ||
209 | fence_put(excl); | ||
210 | } | ||
211 | for (j = 0; j < shared_count; i++) { | ||
212 | fence_wait(shared[j], false); | ||
213 | fence_put(shared[j]); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
219 | drm_atomic_helper_commit_modeset_disables(dev, state); | ||
220 | |||
221 | drm_atomic_helper_commit_planes(dev, state, true); | ||
222 | |||
223 | drm_atomic_helper_commit_modeset_enables(dev, state); | ||
224 | |||
225 | drm_atomic_helper_commit_hw_done(state); | ||
226 | |||
227 | drm_atomic_helper_wait_for_vblanks(dev, state); | ||
228 | |||
229 | drm_atomic_helper_cleanup_planes(dev, state); | ||
230 | } | ||
231 | |||
232 | static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = { | ||
233 | .atomic_commit_tail = imx_drm_atomic_commit_tail, | ||
211 | }; | 234 | }; |
212 | 235 | ||
213 | /* | 236 | /* |
@@ -249,6 +272,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) | |||
249 | drm->mode_config.max_width = 4096; | 272 | drm->mode_config.max_width = 4096; |
250 | drm->mode_config.max_height = 4096; | 273 | drm->mode_config.max_height = 4096; |
251 | drm->mode_config.funcs = &imx_drm_mode_config_funcs; | 274 | drm->mode_config.funcs = &imx_drm_mode_config_funcs; |
275 | drm->mode_config.helper_private = &imx_drm_mode_config_helpers; | ||
252 | 276 | ||
253 | drm_mode_config_init(drm); | 277 | drm_mode_config_init(drm); |
254 | 278 | ||
@@ -279,6 +303,8 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) | |||
279 | } | 303 | } |
280 | } | 304 | } |
281 | 305 | ||
306 | drm_mode_config_reset(drm); | ||
307 | |||
282 | /* | 308 | /* |
283 | * All components are now initialised, so setup the fb helper. | 309 | * All components are now initialised, so setup the fb helper. |
284 | * The fb helper takes copies of key hardware information, so the | 310 | * The fb helper takes copies of key hardware information, so the |
@@ -289,7 +315,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) | |||
289 | dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); | 315 | dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); |
290 | legacyfb_depth = 16; | 316 | legacyfb_depth = 16; |
291 | } | 317 | } |
292 | drm_helper_disable_unused_functions(drm); | ||
293 | imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, | 318 | imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, |
294 | drm->mode_config.num_crtc, MAX_CRTC); | 319 | drm->mode_config.num_crtc, MAX_CRTC); |
295 | if (IS_ERR(imxdrm->fbhelper)) { | 320 | if (IS_ERR(imxdrm->fbhelper)) { |
@@ -403,7 +428,8 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = { | |||
403 | }; | 428 | }; |
404 | 429 | ||
405 | static struct drm_driver imx_drm_driver = { | 430 | static struct drm_driver imx_drm_driver = { |
406 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, | 431 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | |
432 | DRIVER_ATOMIC, | ||
407 | .load = imx_drm_driver_load, | 433 | .load = imx_drm_driver_load, |
408 | .unload = imx_drm_driver_unload, | 434 | .unload = imx_drm_driver_unload, |
409 | .lastclose = imx_drm_driver_lastclose, | 435 | .lastclose = imx_drm_driver_lastclose, |
@@ -491,6 +517,7 @@ static int imx_drm_platform_remove(struct platform_device *pdev) | |||
491 | static int imx_drm_suspend(struct device *dev) | 517 | static int imx_drm_suspend(struct device *dev) |
492 | { | 518 | { |
493 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 519 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
520 | struct imx_drm_device *imxdrm; | ||
494 | 521 | ||
495 | /* The drm_dev is NULL before .load hook is called */ | 522 | /* The drm_dev is NULL before .load hook is called */ |
496 | if (drm_dev == NULL) | 523 | if (drm_dev == NULL) |
@@ -498,17 +525,26 @@ static int imx_drm_suspend(struct device *dev) | |||
498 | 525 | ||
499 | drm_kms_helper_poll_disable(drm_dev); | 526 | drm_kms_helper_poll_disable(drm_dev); |
500 | 527 | ||
528 | imxdrm = drm_dev->dev_private; | ||
529 | imxdrm->state = drm_atomic_helper_suspend(drm_dev); | ||
530 | if (IS_ERR(imxdrm->state)) { | ||
531 | drm_kms_helper_poll_enable(drm_dev); | ||
532 | return PTR_ERR(imxdrm->state); | ||
533 | } | ||
534 | |||
501 | return 0; | 535 | return 0; |
502 | } | 536 | } |
503 | 537 | ||
504 | static int imx_drm_resume(struct device *dev) | 538 | static int imx_drm_resume(struct device *dev) |
505 | { | 539 | { |
506 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 540 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
541 | struct imx_drm_device *imx_drm; | ||
507 | 542 | ||
508 | if (drm_dev == NULL) | 543 | if (drm_dev == NULL) |
509 | return 0; | 544 | return 0; |
510 | 545 | ||
511 | drm_helper_resume_force_mode(drm_dev); | 546 | imx_drm = drm_dev->dev_private; |
547 | drm_atomic_helper_resume(drm_dev, imx_drm->state); | ||
512 | drm_kms_helper_poll_enable(drm_dev); | 548 | drm_kms_helper_poll_enable(drm_dev); |
513 | 549 | ||
514 | return 0; | 550 | return 0; |
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index 74320a1723b7..07d33e45f90f 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h | |||
@@ -15,12 +15,22 @@ struct platform_device; | |||
15 | 15 | ||
16 | unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc); | 16 | unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc); |
17 | 17 | ||
18 | struct imx_crtc_state { | ||
19 | struct drm_crtc_state base; | ||
20 | u32 bus_format; | ||
21 | u32 bus_flags; | ||
22 | int di_hsync_pin; | ||
23 | int di_vsync_pin; | ||
24 | }; | ||
25 | |||
26 | static inline struct imx_crtc_state *to_imx_crtc_state(struct drm_crtc_state *s) | ||
27 | { | ||
28 | return container_of(s, struct imx_crtc_state, base); | ||
29 | } | ||
30 | |||
18 | struct imx_drm_crtc_helper_funcs { | 31 | struct imx_drm_crtc_helper_funcs { |
19 | int (*enable_vblank)(struct drm_crtc *crtc); | 32 | int (*enable_vblank)(struct drm_crtc *crtc); |
20 | void (*disable_vblank)(struct drm_crtc *crtc); | 33 | void (*disable_vblank)(struct drm_crtc *crtc); |
21 | int (*set_interface_pix_fmt)(struct drm_crtc *crtc, | ||
22 | u32 bus_format, int hsync_pin, int vsync_pin, | ||
23 | u32 bus_flags); | ||
24 | const struct drm_crtc_helper_funcs *crtc_helper_funcs; | 34 | const struct drm_crtc_helper_funcs *crtc_helper_funcs; |
25 | const struct drm_crtc_funcs *crtc_funcs; | 35 | const struct drm_crtc_funcs *crtc_funcs; |
26 | }; | 36 | }; |
@@ -42,11 +52,6 @@ void imx_drm_mode_config_init(struct drm_device *drm); | |||
42 | 52 | ||
43 | struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); | 53 | struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); |
44 | 54 | ||
45 | int imx_drm_set_bus_config(struct drm_encoder *encoder, u32 bus_format, | ||
46 | int hsync_pin, int vsync_pin, u32 bus_flags); | ||
47 | int imx_drm_set_bus_format(struct drm_encoder *encoder, | ||
48 | u32 bus_format); | ||
49 | |||
50 | int imx_drm_encoder_parse_of(struct drm_device *drm, | 55 | int imx_drm_encoder_parse_of(struct drm_device *drm, |
51 | struct drm_encoder *encoder, struct device_node *np); | 56 | struct drm_encoder *encoder, struct device_node *np); |
52 | 57 | ||
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index beff793bb717..5d2831dfb8b9 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/component.h> | 18 | #include <linux/component.h> |
19 | #include <drm/drmP.h> | 19 | #include <drm/drmP.h> |
20 | #include <drm/drm_atomic.h> | ||
21 | #include <drm/drm_atomic_helper.h> | ||
20 | #include <drm/drm_fb_helper.h> | 22 | #include <drm/drm_fb_helper.h> |
21 | #include <drm/drm_crtc_helper.h> | 23 | #include <drm/drm_crtc_helper.h> |
22 | #include <drm/drm_of.h> | 24 | #include <drm/drm_of.h> |
@@ -49,9 +51,6 @@ | |||
49 | #define LDB_DI1_VS_POL_ACT_LOW (1 << 10) | 51 | #define LDB_DI1_VS_POL_ACT_LOW (1 << 10) |
50 | #define LDB_BGREF_RMODE_INT (1 << 15) | 52 | #define LDB_BGREF_RMODE_INT (1 << 15) |
51 | 53 | ||
52 | #define con_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, connector) | ||
53 | #define enc_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, encoder) | ||
54 | |||
55 | struct imx_ldb; | 54 | struct imx_ldb; |
56 | 55 | ||
57 | struct imx_ldb_channel { | 56 | struct imx_ldb_channel { |
@@ -66,9 +65,19 @@ struct imx_ldb_channel { | |||
66 | int edid_len; | 65 | int edid_len; |
67 | struct drm_display_mode mode; | 66 | struct drm_display_mode mode; |
68 | int mode_valid; | 67 | int mode_valid; |
69 | int bus_format; | 68 | u32 bus_format; |
70 | }; | 69 | }; |
71 | 70 | ||
71 | static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c) | ||
72 | { | ||
73 | return container_of(c, struct imx_ldb_channel, connector); | ||
74 | } | ||
75 | |||
76 | static inline struct imx_ldb_channel *enc_to_imx_ldb_ch(struct drm_encoder *e) | ||
77 | { | ||
78 | return container_of(e, struct imx_ldb_channel, encoder); | ||
79 | } | ||
80 | |||
72 | struct bus_mux { | 81 | struct bus_mux { |
73 | int reg; | 82 | int reg; |
74 | int shift; | 83 | int shift; |
@@ -93,6 +102,32 @@ static enum drm_connector_status imx_ldb_connector_detect( | |||
93 | return connector_status_connected; | 102 | return connector_status_connected; |
94 | } | 103 | } |
95 | 104 | ||
105 | static void imx_ldb_ch_set_bus_format(struct imx_ldb_channel *imx_ldb_ch, | ||
106 | u32 bus_format) | ||
107 | { | ||
108 | struct imx_ldb *ldb = imx_ldb_ch->ldb; | ||
109 | int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; | ||
110 | |||
111 | switch (bus_format) { | ||
112 | case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: | ||
113 | break; | ||
114 | case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: | ||
115 | if (imx_ldb_ch->chno == 0 || dual) | ||
116 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; | ||
117 | if (imx_ldb_ch->chno == 1 || dual) | ||
118 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; | ||
119 | break; | ||
120 | case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: | ||
121 | if (imx_ldb_ch->chno == 0 || dual) | ||
122 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | | ||
123 | LDB_BIT_MAP_CH0_JEIDA; | ||
124 | if (imx_ldb_ch->chno == 1 || dual) | ||
125 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | | ||
126 | LDB_BIT_MAP_CH1_JEIDA; | ||
127 | break; | ||
128 | } | ||
129 | } | ||
130 | |||
96 | static int imx_ldb_connector_get_modes(struct drm_connector *connector) | 131 | static int imx_ldb_connector_get_modes(struct drm_connector *connector) |
97 | { | 132 | { |
98 | struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); | 133 | struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); |
@@ -100,11 +135,7 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) | |||
100 | 135 | ||
101 | if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && | 136 | if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && |
102 | imx_ldb_ch->panel->funcs->get_modes) { | 137 | imx_ldb_ch->panel->funcs->get_modes) { |
103 | struct drm_display_info *di = &connector->display_info; | ||
104 | |||
105 | num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); | 138 | num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); |
106 | if (!imx_ldb_ch->bus_format && di->num_bus_formats) | ||
107 | imx_ldb_ch->bus_format = di->bus_formats[0]; | ||
108 | if (num_modes > 0) | 139 | if (num_modes > 0) |
109 | return num_modes; | 140 | return num_modes; |
110 | } | 141 | } |
@@ -141,10 +172,6 @@ static struct drm_encoder *imx_ldb_connector_best_encoder( | |||
141 | return &imx_ldb_ch->encoder; | 172 | return &imx_ldb_ch->encoder; |
142 | } | 173 | } |
143 | 174 | ||
144 | static void imx_ldb_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
145 | { | ||
146 | } | ||
147 | |||
148 | static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, | 175 | static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, |
149 | unsigned long serial_clk, unsigned long di_clk) | 176 | unsigned long serial_clk, unsigned long di_clk) |
150 | { | 177 | { |
@@ -173,43 +200,7 @@ static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, | |||
173 | chno); | 200 | chno); |
174 | } | 201 | } |
175 | 202 | ||
176 | static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) | 203 | static void imx_ldb_encoder_enable(struct drm_encoder *encoder) |
177 | { | ||
178 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); | ||
179 | struct imx_ldb *ldb = imx_ldb_ch->ldb; | ||
180 | int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; | ||
181 | u32 bus_format; | ||
182 | |||
183 | switch (imx_ldb_ch->bus_format) { | ||
184 | default: | ||
185 | dev_warn(ldb->dev, | ||
186 | "could not determine data mapping, default to 18-bit \"spwg\"\n"); | ||
187 | /* fallthrough */ | ||
188 | case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: | ||
189 | bus_format = MEDIA_BUS_FMT_RGB666_1X18; | ||
190 | break; | ||
191 | case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: | ||
192 | bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||
193 | if (imx_ldb_ch->chno == 0 || dual) | ||
194 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; | ||
195 | if (imx_ldb_ch->chno == 1 || dual) | ||
196 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; | ||
197 | break; | ||
198 | case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: | ||
199 | bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||
200 | if (imx_ldb_ch->chno == 0 || dual) | ||
201 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | | ||
202 | LDB_BIT_MAP_CH0_JEIDA; | ||
203 | if (imx_ldb_ch->chno == 1 || dual) | ||
204 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | | ||
205 | LDB_BIT_MAP_CH1_JEIDA; | ||
206 | break; | ||
207 | } | ||
208 | |||
209 | imx_drm_set_bus_format(encoder, bus_format); | ||
210 | } | ||
211 | |||
212 | static void imx_ldb_encoder_commit(struct drm_encoder *encoder) | ||
213 | { | 204 | { |
214 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); | 205 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); |
215 | struct imx_ldb *ldb = imx_ldb_ch->ldb; | 206 | struct imx_ldb *ldb = imx_ldb_ch->ldb; |
@@ -219,8 +210,13 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) | |||
219 | drm_panel_prepare(imx_ldb_ch->panel); | 210 | drm_panel_prepare(imx_ldb_ch->panel); |
220 | 211 | ||
221 | if (dual) { | 212 | if (dual) { |
213 | clk_set_parent(ldb->clk_sel[mux], ldb->clk[0]); | ||
214 | clk_set_parent(ldb->clk_sel[mux], ldb->clk[1]); | ||
215 | |||
222 | clk_prepare_enable(ldb->clk[0]); | 216 | clk_prepare_enable(ldb->clk[0]); |
223 | clk_prepare_enable(ldb->clk[1]); | 217 | clk_prepare_enable(ldb->clk[1]); |
218 | } else { | ||
219 | clk_set_parent(ldb->clk_sel[mux], ldb->clk[imx_ldb_ch->chno]); | ||
224 | } | 220 | } |
225 | 221 | ||
226 | if (imx_ldb_ch == &ldb->channel[0] || dual) { | 222 | if (imx_ldb_ch == &ldb->channel[0] || dual) { |
@@ -265,6 +261,7 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, | |||
265 | unsigned long serial_clk; | 261 | unsigned long serial_clk; |
266 | unsigned long di_clk = mode->clock * 1000; | 262 | unsigned long di_clk = mode->clock * 1000; |
267 | int mux = drm_of_encoder_active_port_id(imx_ldb_ch->child, encoder); | 263 | int mux = drm_of_encoder_active_port_id(imx_ldb_ch->child, encoder); |
264 | u32 bus_format = imx_ldb_ch->bus_format; | ||
268 | 265 | ||
269 | if (mode->clock > 170000) { | 266 | if (mode->clock > 170000) { |
270 | dev_warn(ldb->dev, | 267 | dev_warn(ldb->dev, |
@@ -286,18 +283,36 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, | |||
286 | } | 283 | } |
287 | 284 | ||
288 | /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */ | 285 | /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */ |
289 | if (imx_ldb_ch == &ldb->channel[0]) { | 286 | if (imx_ldb_ch == &ldb->channel[0] || dual) { |
290 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 287 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
291 | ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW; | 288 | ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW; |
292 | else if (mode->flags & DRM_MODE_FLAG_PVSYNC) | 289 | else if (mode->flags & DRM_MODE_FLAG_PVSYNC) |
293 | ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW; | 290 | ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW; |
294 | } | 291 | } |
295 | if (imx_ldb_ch == &ldb->channel[1]) { | 292 | if (imx_ldb_ch == &ldb->channel[1] || dual) { |
296 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 293 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
297 | ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW; | 294 | ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW; |
298 | else if (mode->flags & DRM_MODE_FLAG_PVSYNC) | 295 | else if (mode->flags & DRM_MODE_FLAG_PVSYNC) |
299 | ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW; | 296 | ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW; |
300 | } | 297 | } |
298 | |||
299 | if (!bus_format) { | ||
300 | struct drm_connector_state *conn_state; | ||
301 | struct drm_connector *connector; | ||
302 | int i; | ||
303 | |||
304 | for_each_connector_in_state(encoder->crtc->state->state, | ||
305 | connector, conn_state, i) { | ||
306 | struct drm_display_info *di = &connector->display_info; | ||
307 | |||
308 | if (conn_state->crtc == encoder->crtc && | ||
309 | di->num_bus_formats) { | ||
310 | bus_format = di->bus_formats[0]; | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | imx_ldb_ch_set_bus_format(imx_ldb_ch, bus_format); | ||
301 | } | 316 | } |
302 | 317 | ||
303 | static void imx_ldb_encoder_disable(struct drm_encoder *encoder) | 318 | static void imx_ldb_encoder_disable(struct drm_encoder *encoder) |
@@ -357,11 +372,45 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) | |||
357 | drm_panel_unprepare(imx_ldb_ch->panel); | 372 | drm_panel_unprepare(imx_ldb_ch->panel); |
358 | } | 373 | } |
359 | 374 | ||
375 | static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder, | ||
376 | struct drm_crtc_state *crtc_state, | ||
377 | struct drm_connector_state *conn_state) | ||
378 | { | ||
379 | struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); | ||
380 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); | ||
381 | struct drm_display_info *di = &conn_state->connector->display_info; | ||
382 | u32 bus_format = imx_ldb_ch->bus_format; | ||
383 | |||
384 | /* Bus format description in DT overrides connector display info. */ | ||
385 | if (!bus_format && di->num_bus_formats) | ||
386 | bus_format = di->bus_formats[0]; | ||
387 | switch (bus_format) { | ||
388 | case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: | ||
389 | imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18; | ||
390 | break; | ||
391 | case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: | ||
392 | case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: | ||
393 | imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||
394 | break; | ||
395 | default: | ||
396 | return -EINVAL; | ||
397 | } | ||
398 | |||
399 | imx_crtc_state->di_hsync_pin = 2; | ||
400 | imx_crtc_state->di_vsync_pin = 3; | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | |||
360 | static const struct drm_connector_funcs imx_ldb_connector_funcs = { | 406 | static const struct drm_connector_funcs imx_ldb_connector_funcs = { |
361 | .dpms = drm_helper_connector_dpms, | 407 | .dpms = drm_atomic_helper_connector_dpms, |
362 | .fill_modes = drm_helper_probe_single_connector_modes, | 408 | .fill_modes = drm_helper_probe_single_connector_modes, |
363 | .detect = imx_ldb_connector_detect, | 409 | .detect = imx_ldb_connector_detect, |
364 | .destroy = imx_drm_connector_destroy, | 410 | .destroy = imx_drm_connector_destroy, |
411 | .reset = drm_atomic_helper_connector_reset, | ||
412 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
413 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
365 | }; | 414 | }; |
366 | 415 | ||
367 | static const struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = { | 416 | static const struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = { |
@@ -374,11 +423,10 @@ static const struct drm_encoder_funcs imx_ldb_encoder_funcs = { | |||
374 | }; | 423 | }; |
375 | 424 | ||
376 | static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { | 425 | static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { |
377 | .dpms = imx_ldb_encoder_dpms, | ||
378 | .prepare = imx_ldb_encoder_prepare, | ||
379 | .commit = imx_ldb_encoder_commit, | ||
380 | .mode_set = imx_ldb_encoder_mode_set, | 426 | .mode_set = imx_ldb_encoder_mode_set, |
427 | .enable = imx_ldb_encoder_enable, | ||
381 | .disable = imx_ldb_encoder_disable, | 428 | .disable = imx_ldb_encoder_disable, |
429 | .atomic_check = imx_ldb_encoder_atomic_check, | ||
382 | }; | 430 | }; |
383 | 431 | ||
384 | static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno) | 432 | static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno) |
@@ -400,10 +448,10 @@ static int imx_ldb_register(struct drm_device *drm, | |||
400 | struct imx_ldb_channel *imx_ldb_ch) | 448 | struct imx_ldb_channel *imx_ldb_ch) |
401 | { | 449 | { |
402 | struct imx_ldb *ldb = imx_ldb_ch->ldb; | 450 | struct imx_ldb *ldb = imx_ldb_ch->ldb; |
451 | struct drm_encoder *encoder = &imx_ldb_ch->encoder; | ||
403 | int ret; | 452 | int ret; |
404 | 453 | ||
405 | ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder, | 454 | ret = imx_drm_encoder_parse_of(drm, encoder, imx_ldb_ch->child); |
406 | imx_ldb_ch->child); | ||
407 | if (ret) | 455 | if (ret) |
408 | return ret; | 456 | return ret; |
409 | 457 | ||
@@ -417,9 +465,8 @@ static int imx_ldb_register(struct drm_device *drm, | |||
417 | return ret; | 465 | return ret; |
418 | } | 466 | } |
419 | 467 | ||
420 | drm_encoder_helper_add(&imx_ldb_ch->encoder, | 468 | drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs); |
421 | &imx_ldb_encoder_helper_funcs); | 469 | drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs, |
422 | drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs, | ||
423 | DRM_MODE_ENCODER_LVDS, NULL); | 470 | DRM_MODE_ENCODER_LVDS, NULL); |
424 | 471 | ||
425 | drm_connector_helper_add(&imx_ldb_ch->connector, | 472 | drm_connector_helper_add(&imx_ldb_ch->connector, |
@@ -427,11 +474,14 @@ static int imx_ldb_register(struct drm_device *drm, | |||
427 | drm_connector_init(drm, &imx_ldb_ch->connector, | 474 | drm_connector_init(drm, &imx_ldb_ch->connector, |
428 | &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); | 475 | &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); |
429 | 476 | ||
430 | if (imx_ldb_ch->panel) | 477 | if (imx_ldb_ch->panel) { |
431 | drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector); | 478 | ret = drm_panel_attach(imx_ldb_ch->panel, |
479 | &imx_ldb_ch->connector); | ||
480 | if (ret) | ||
481 | return ret; | ||
482 | } | ||
432 | 483 | ||
433 | drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, | 484 | drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, encoder); |
434 | &imx_ldb_ch->encoder); | ||
435 | 485 | ||
436 | return 0; | 486 | return 0; |
437 | } | 487 | } |
@@ -560,6 +610,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
560 | struct imx_ldb_channel *channel; | 610 | struct imx_ldb_channel *channel; |
561 | struct device_node *ddc_node; | 611 | struct device_node *ddc_node; |
562 | struct device_node *ep; | 612 | struct device_node *ep; |
613 | int bus_format; | ||
563 | 614 | ||
564 | ret = of_property_read_u32(child, "reg", &i); | 615 | ret = of_property_read_u32(child, "reg", &i); |
565 | if (ret || i < 0 || i > 1) | 616 | if (ret || i < 0 || i > 1) |
@@ -632,21 +683,22 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
632 | } | 683 | } |
633 | } | 684 | } |
634 | 685 | ||
635 | channel->bus_format = of_get_bus_format(dev, child); | 686 | bus_format = of_get_bus_format(dev, child); |
636 | if (channel->bus_format == -EINVAL) { | 687 | if (bus_format == -EINVAL) { |
637 | /* | 688 | /* |
638 | * If no bus format was specified in the device tree, | 689 | * If no bus format was specified in the device tree, |
639 | * we can still get it from the connected panel later. | 690 | * we can still get it from the connected panel later. |
640 | */ | 691 | */ |
641 | if (channel->panel && channel->panel->funcs && | 692 | if (channel->panel && channel->panel->funcs && |
642 | channel->panel->funcs->get_modes) | 693 | channel->panel->funcs->get_modes) |
643 | channel->bus_format = 0; | 694 | bus_format = 0; |
644 | } | 695 | } |
645 | if (channel->bus_format < 0) { | 696 | if (bus_format < 0) { |
646 | dev_err(dev, "could not determine data mapping: %d\n", | 697 | dev_err(dev, "could not determine data mapping: %d\n", |
647 | channel->bus_format); | 698 | bus_format); |
648 | return channel->bus_format; | 699 | return bus_format; |
649 | } | 700 | } |
701 | channel->bus_format = bus_format; | ||
650 | 702 | ||
651 | ret = imx_ldb_register(drm, channel); | 703 | ret = imx_ldb_register(drm, channel); |
652 | if (ret) | 704 | if (ret) |
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index baf788121287..5e875944ffa2 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/videodev2.h> | 24 | #include <linux/videodev2.h> |
25 | #include <drm/drmP.h> | 25 | #include <drm/drmP.h> |
26 | #include <drm/drm_atomic_helper.h> | ||
26 | #include <drm/drm_fb_helper.h> | 27 | #include <drm/drm_fb_helper.h> |
27 | #include <drm/drm_crtc_helper.h> | 28 | #include <drm/drm_crtc_helper.h> |
28 | #include <video/imx-ipu-v3.h> | 29 | #include <video/imx-ipu-v3.h> |
@@ -97,9 +98,6 @@ | |||
97 | /* TVE_TST_MODE_REG */ | 98 | /* TVE_TST_MODE_REG */ |
98 | #define TVE_TVDAC_TEST_MODE_MASK (0x7 << 0) | 99 | #define TVE_TVDAC_TEST_MODE_MASK (0x7 << 0) |
99 | 100 | ||
100 | #define con_to_tve(x) container_of(x, struct imx_tve, connector) | ||
101 | #define enc_to_tve(x) container_of(x, struct imx_tve, encoder) | ||
102 | |||
103 | enum { | 101 | enum { |
104 | TVE_MODE_TVOUT, | 102 | TVE_MODE_TVOUT, |
105 | TVE_MODE_VGA, | 103 | TVE_MODE_VGA, |
@@ -112,6 +110,8 @@ struct imx_tve { | |||
112 | spinlock_t lock; /* register lock */ | 110 | spinlock_t lock; /* register lock */ |
113 | bool enabled; | 111 | bool enabled; |
114 | int mode; | 112 | int mode; |
113 | int di_hsync_pin; | ||
114 | int di_vsync_pin; | ||
115 | 115 | ||
116 | struct regmap *regmap; | 116 | struct regmap *regmap; |
117 | struct regulator *dac_reg; | 117 | struct regulator *dac_reg; |
@@ -120,10 +120,18 @@ struct imx_tve { | |||
120 | struct clk *di_sel_clk; | 120 | struct clk *di_sel_clk; |
121 | struct clk_hw clk_hw_di; | 121 | struct clk_hw clk_hw_di; |
122 | struct clk *di_clk; | 122 | struct clk *di_clk; |
123 | int vsync_pin; | ||
124 | int hsync_pin; | ||
125 | }; | 123 | }; |
126 | 124 | ||
125 | static inline struct imx_tve *con_to_tve(struct drm_connector *c) | ||
126 | { | ||
127 | return container_of(c, struct imx_tve, connector); | ||
128 | } | ||
129 | |||
130 | static inline struct imx_tve *enc_to_tve(struct drm_encoder *e) | ||
131 | { | ||
132 | return container_of(e, struct imx_tve, encoder); | ||
133 | } | ||
134 | |||
127 | static void tve_lock(void *__tve) | 135 | static void tve_lock(void *__tve) |
128 | __acquires(&tve->lock) | 136 | __acquires(&tve->lock) |
129 | { | 137 | { |
@@ -148,8 +156,7 @@ static void tve_enable(struct imx_tve *tve) | |||
148 | tve->enabled = true; | 156 | tve->enabled = true; |
149 | clk_prepare_enable(tve->clk); | 157 | clk_prepare_enable(tve->clk); |
150 | ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, | 158 | ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, |
151 | TVE_IPU_CLK_EN | TVE_EN, | 159 | TVE_EN, TVE_EN); |
152 | TVE_IPU_CLK_EN | TVE_EN); | ||
153 | } | 160 | } |
154 | 161 | ||
155 | /* clear interrupt status register */ | 162 | /* clear interrupt status register */ |
@@ -172,7 +179,7 @@ static void tve_disable(struct imx_tve *tve) | |||
172 | if (tve->enabled) { | 179 | if (tve->enabled) { |
173 | tve->enabled = false; | 180 | tve->enabled = false; |
174 | ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, | 181 | ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, |
175 | TVE_IPU_CLK_EN | TVE_EN, 0); | 182 | TVE_EN, 0); |
176 | clk_disable_unprepare(tve->clk); | 183 | clk_disable_unprepare(tve->clk); |
177 | } | 184 | } |
178 | } | 185 | } |
@@ -275,36 +282,6 @@ static struct drm_encoder *imx_tve_connector_best_encoder( | |||
275 | return &tve->encoder; | 282 | return &tve->encoder; |
276 | } | 283 | } |
277 | 284 | ||
278 | static void imx_tve_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
279 | { | ||
280 | struct imx_tve *tve = enc_to_tve(encoder); | ||
281 | int ret; | ||
282 | |||
283 | ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, | ||
284 | TVE_TV_OUT_MODE_MASK, TVE_TV_OUT_DISABLE); | ||
285 | if (ret < 0) | ||
286 | dev_err(tve->dev, "failed to disable TVOUT: %d\n", ret); | ||
287 | } | ||
288 | |||
289 | static void imx_tve_encoder_prepare(struct drm_encoder *encoder) | ||
290 | { | ||
291 | struct imx_tve *tve = enc_to_tve(encoder); | ||
292 | |||
293 | tve_disable(tve); | ||
294 | |||
295 | switch (tve->mode) { | ||
296 | case TVE_MODE_VGA: | ||
297 | imx_drm_set_bus_config(encoder, MEDIA_BUS_FMT_GBR888_1X24, | ||
298 | tve->hsync_pin, tve->vsync_pin, | ||
299 | DRM_BUS_FLAG_DE_HIGH | | ||
300 | DRM_BUS_FLAG_PIXDATA_NEGEDGE); | ||
301 | break; | ||
302 | case TVE_MODE_TVOUT: | ||
303 | imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24); | ||
304 | break; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, | 285 | static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, |
309 | struct drm_display_mode *orig_mode, | 286 | struct drm_display_mode *orig_mode, |
310 | struct drm_display_mode *mode) | 287 | struct drm_display_mode *mode) |
@@ -333,6 +310,9 @@ static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, | |||
333 | ret); | 310 | ret); |
334 | } | 311 | } |
335 | 312 | ||
313 | regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, | ||
314 | TVE_IPU_CLK_EN, TVE_IPU_CLK_EN); | ||
315 | |||
336 | if (tve->mode == TVE_MODE_VGA) | 316 | if (tve->mode == TVE_MODE_VGA) |
337 | ret = tve_setup_vga(tve); | 317 | ret = tve_setup_vga(tve); |
338 | else | 318 | else |
@@ -341,7 +321,7 @@ static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, | |||
341 | dev_err(tve->dev, "failed to set configuration: %d\n", ret); | 321 | dev_err(tve->dev, "failed to set configuration: %d\n", ret); |
342 | } | 322 | } |
343 | 323 | ||
344 | static void imx_tve_encoder_commit(struct drm_encoder *encoder) | 324 | static void imx_tve_encoder_enable(struct drm_encoder *encoder) |
345 | { | 325 | { |
346 | struct imx_tve *tve = enc_to_tve(encoder); | 326 | struct imx_tve *tve = enc_to_tve(encoder); |
347 | 327 | ||
@@ -355,11 +335,28 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder) | |||
355 | tve_disable(tve); | 335 | tve_disable(tve); |
356 | } | 336 | } |
357 | 337 | ||
338 | static int imx_tve_atomic_check(struct drm_encoder *encoder, | ||
339 | struct drm_crtc_state *crtc_state, | ||
340 | struct drm_connector_state *conn_state) | ||
341 | { | ||
342 | struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); | ||
343 | struct imx_tve *tve = enc_to_tve(encoder); | ||
344 | |||
345 | imx_crtc_state->bus_format = MEDIA_BUS_FMT_GBR888_1X24; | ||
346 | imx_crtc_state->di_hsync_pin = tve->di_hsync_pin; | ||
347 | imx_crtc_state->di_vsync_pin = tve->di_vsync_pin; | ||
348 | |||
349 | return 0; | ||
350 | } | ||
351 | |||
358 | static const struct drm_connector_funcs imx_tve_connector_funcs = { | 352 | static const struct drm_connector_funcs imx_tve_connector_funcs = { |
359 | .dpms = drm_helper_connector_dpms, | 353 | .dpms = drm_atomic_helper_connector_dpms, |
360 | .fill_modes = drm_helper_probe_single_connector_modes, | 354 | .fill_modes = drm_helper_probe_single_connector_modes, |
361 | .detect = imx_tve_connector_detect, | 355 | .detect = imx_tve_connector_detect, |
362 | .destroy = imx_drm_connector_destroy, | 356 | .destroy = imx_drm_connector_destroy, |
357 | .reset = drm_atomic_helper_connector_reset, | ||
358 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
359 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
363 | }; | 360 | }; |
364 | 361 | ||
365 | static const struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { | 362 | static const struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { |
@@ -373,11 +370,10 @@ static const struct drm_encoder_funcs imx_tve_encoder_funcs = { | |||
373 | }; | 370 | }; |
374 | 371 | ||
375 | static const struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = { | 372 | static const struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = { |
376 | .dpms = imx_tve_encoder_dpms, | ||
377 | .prepare = imx_tve_encoder_prepare, | ||
378 | .mode_set = imx_tve_encoder_mode_set, | 373 | .mode_set = imx_tve_encoder_mode_set, |
379 | .commit = imx_tve_encoder_commit, | 374 | .enable = imx_tve_encoder_enable, |
380 | .disable = imx_tve_encoder_disable, | 375 | .disable = imx_tve_encoder_disable, |
376 | .atomic_check = imx_tve_atomic_check, | ||
381 | }; | 377 | }; |
382 | 378 | ||
383 | static irqreturn_t imx_tve_irq_handler(int irq, void *data) | 379 | static irqreturn_t imx_tve_irq_handler(int irq, void *data) |
@@ -495,8 +491,7 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) | |||
495 | encoder_type = tve->mode == TVE_MODE_VGA ? | 491 | encoder_type = tve->mode == TVE_MODE_VGA ? |
496 | DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC; | 492 | DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC; |
497 | 493 | ||
498 | ret = imx_drm_encoder_parse_of(drm, &tve->encoder, | 494 | ret = imx_drm_encoder_parse_of(drm, &tve->encoder, tve->dev->of_node); |
499 | tve->dev->of_node); | ||
500 | if (ret) | 495 | if (ret) |
501 | return ret; | 496 | return ret; |
502 | 497 | ||
@@ -587,15 +582,15 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) | |||
587 | 582 | ||
588 | if (tve->mode == TVE_MODE_VGA) { | 583 | if (tve->mode == TVE_MODE_VGA) { |
589 | ret = of_property_read_u32(np, "fsl,hsync-pin", | 584 | ret = of_property_read_u32(np, "fsl,hsync-pin", |
590 | &tve->hsync_pin); | 585 | &tve->di_hsync_pin); |
591 | 586 | ||
592 | if (ret < 0) { | 587 | if (ret < 0) { |
593 | dev_err(dev, "failed to get vsync pin\n"); | 588 | dev_err(dev, "failed to get hsync pin\n"); |
594 | return ret; | 589 | return ret; |
595 | } | 590 | } |
596 | 591 | ||
597 | ret |= of_property_read_u32(np, "fsl,vsync-pin", | 592 | ret = of_property_read_u32(np, "fsl,vsync-pin", |
598 | &tve->vsync_pin); | 593 | &tve->di_vsync_pin); |
599 | 594 | ||
600 | if (ret < 0) { | 595 | if (ret < 0) { |
601 | dev_err(dev, "failed to get vsync pin\n"); | 596 | dev_err(dev, "failed to get vsync pin\n"); |
@@ -633,7 +628,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) | |||
633 | 628 | ||
634 | tve->dac_reg = devm_regulator_get(dev, "dac"); | 629 | tve->dac_reg = devm_regulator_get(dev, "dac"); |
635 | if (!IS_ERR(tve->dac_reg)) { | 630 | if (!IS_ERR(tve->dac_reg)) { |
636 | regulator_set_voltage(tve->dac_reg, 2750000, 2750000); | 631 | ret = regulator_set_voltage(tve->dac_reg, 2750000, 2750000); |
632 | if (ret) | ||
633 | return ret; | ||
637 | ret = regulator_enable(tve->dac_reg); | 634 | ret = regulator_enable(tve->dac_reg); |
638 | if (ret) | 635 | if (ret) |
639 | return ret; | 636 | return ret; |
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index fc040417e1e8..08e188bc10fc 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c | |||
@@ -18,12 +18,12 @@ | |||
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <drm/drmP.h> | 20 | #include <drm/drmP.h> |
21 | #include <drm/drm_atomic.h> | ||
22 | #include <drm/drm_atomic_helper.h> | ||
21 | #include <drm/drm_crtc_helper.h> | 23 | #include <drm/drm_crtc_helper.h> |
22 | #include <linux/fb.h> | 24 | #include <linux/fb.h> |
23 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
24 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
25 | #include <linux/reservation.h> | ||
26 | #include <linux/dma-buf.h> | ||
27 | #include <drm/drm_gem_cma_helper.h> | 27 | #include <drm/drm_gem_cma_helper.h> |
28 | #include <drm/drm_fb_cma_helper.h> | 28 | #include <drm/drm_fb_cma_helper.h> |
29 | 29 | ||
@@ -33,23 +33,6 @@ | |||
33 | 33 | ||
34 | #define DRIVER_DESC "i.MX IPUv3 Graphics" | 34 | #define DRIVER_DESC "i.MX IPUv3 Graphics" |
35 | 35 | ||
36 | enum ipu_flip_status { | ||
37 | IPU_FLIP_NONE, | ||
38 | IPU_FLIP_PENDING, | ||
39 | IPU_FLIP_SUBMITTED, | ||
40 | }; | ||
41 | |||
42 | struct ipu_flip_work { | ||
43 | struct work_struct unref_work; | ||
44 | struct drm_gem_object *bo; | ||
45 | struct drm_pending_vblank_event *page_flip_event; | ||
46 | struct work_struct fence_work; | ||
47 | struct ipu_crtc *crtc; | ||
48 | struct fence *excl; | ||
49 | unsigned shared_count; | ||
50 | struct fence **shared; | ||
51 | }; | ||
52 | |||
53 | struct ipu_crtc { | 36 | struct ipu_crtc { |
54 | struct device *dev; | 37 | struct device *dev; |
55 | struct drm_crtc base; | 38 | struct drm_crtc base; |
@@ -60,201 +43,166 @@ struct ipu_crtc { | |||
60 | 43 | ||
61 | struct ipu_dc *dc; | 44 | struct ipu_dc *dc; |
62 | struct ipu_di *di; | 45 | struct ipu_di *di; |
63 | int enabled; | ||
64 | enum ipu_flip_status flip_state; | ||
65 | struct workqueue_struct *flip_queue; | ||
66 | struct ipu_flip_work *flip_work; | ||
67 | int irq; | 46 | int irq; |
68 | u32 bus_format; | ||
69 | u32 bus_flags; | ||
70 | int di_hsync_pin; | ||
71 | int di_vsync_pin; | ||
72 | }; | 47 | }; |
73 | 48 | ||
74 | #define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base) | 49 | static inline struct ipu_crtc *to_ipu_crtc(struct drm_crtc *crtc) |
50 | { | ||
51 | return container_of(crtc, struct ipu_crtc, base); | ||
52 | } | ||
75 | 53 | ||
76 | static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) | 54 | static void ipu_crtc_enable(struct drm_crtc *crtc) |
77 | { | 55 | { |
56 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | ||
78 | struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); | 57 | struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); |
79 | 58 | ||
80 | if (ipu_crtc->enabled) | ||
81 | return; | ||
82 | |||
83 | ipu_dc_enable(ipu); | 59 | ipu_dc_enable(ipu); |
84 | ipu_plane_enable(ipu_crtc->plane[0]); | ||
85 | /* Start DC channel and DI after IDMAC */ | ||
86 | ipu_dc_enable_channel(ipu_crtc->dc); | 60 | ipu_dc_enable_channel(ipu_crtc->dc); |
87 | ipu_di_enable(ipu_crtc->di); | 61 | ipu_di_enable(ipu_crtc->di); |
88 | drm_crtc_vblank_on(&ipu_crtc->base); | ||
89 | |||
90 | ipu_crtc->enabled = 1; | ||
91 | } | 62 | } |
92 | 63 | ||
93 | static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) | 64 | static void ipu_crtc_disable(struct drm_crtc *crtc) |
94 | { | 65 | { |
66 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | ||
95 | struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); | 67 | struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); |
96 | 68 | ||
97 | if (!ipu_crtc->enabled) | ||
98 | return; | ||
99 | |||
100 | /* Stop DC channel and DI before IDMAC */ | ||
101 | ipu_dc_disable_channel(ipu_crtc->dc); | 69 | ipu_dc_disable_channel(ipu_crtc->dc); |
102 | ipu_di_disable(ipu_crtc->di); | 70 | ipu_di_disable(ipu_crtc->di); |
103 | ipu_plane_disable(ipu_crtc->plane[0]); | ||
104 | ipu_dc_disable(ipu); | 71 | ipu_dc_disable(ipu); |
105 | drm_crtc_vblank_off(&ipu_crtc->base); | ||
106 | 72 | ||
107 | ipu_crtc->enabled = 0; | 73 | spin_lock_irq(&crtc->dev->event_lock); |
74 | if (crtc->state->event) { | ||
75 | drm_crtc_send_vblank_event(crtc, crtc->state->event); | ||
76 | crtc->state->event = NULL; | ||
77 | } | ||
78 | spin_unlock_irq(&crtc->dev->event_lock); | ||
108 | } | 79 | } |
109 | 80 | ||
110 | static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode) | 81 | static void imx_drm_crtc_reset(struct drm_crtc *crtc) |
111 | { | 82 | { |
112 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | 83 | struct imx_crtc_state *state; |
113 | 84 | ||
114 | dev_dbg(ipu_crtc->dev, "%s mode: %d\n", __func__, mode); | 85 | if (crtc->state) { |
115 | 86 | if (crtc->state->mode_blob) | |
116 | switch (mode) { | 87 | drm_property_unreference_blob(crtc->state->mode_blob); |
117 | case DRM_MODE_DPMS_ON: | 88 | |
118 | ipu_fb_enable(ipu_crtc); | 89 | state = to_imx_crtc_state(crtc->state); |
119 | break; | 90 | memset(state, 0, sizeof(*state)); |
120 | case DRM_MODE_DPMS_STANDBY: | 91 | } else { |
121 | case DRM_MODE_DPMS_SUSPEND: | 92 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
122 | case DRM_MODE_DPMS_OFF: | 93 | if (!state) |
123 | ipu_fb_disable(ipu_crtc); | 94 | return; |
124 | break; | 95 | crtc->state = &state->base; |
125 | } | 96 | } |
97 | |||
98 | state->base.crtc = crtc; | ||
126 | } | 99 | } |
127 | 100 | ||
128 | static void ipu_flip_unref_work_func(struct work_struct *__work) | 101 | static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc) |
129 | { | 102 | { |
130 | struct ipu_flip_work *work = | 103 | struct imx_crtc_state *state; |
131 | container_of(__work, struct ipu_flip_work, unref_work); | 104 | |
105 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
106 | if (!state) | ||
107 | return NULL; | ||
132 | 108 | ||
133 | drm_gem_object_unreference_unlocked(work->bo); | 109 | __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); |
134 | kfree(work); | 110 | |
111 | WARN_ON(state->base.crtc != crtc); | ||
112 | state->base.crtc = crtc; | ||
113 | |||
114 | return &state->base; | ||
135 | } | 115 | } |
136 | 116 | ||
137 | static void ipu_flip_fence_work_func(struct work_struct *__work) | 117 | static void imx_drm_crtc_destroy_state(struct drm_crtc *crtc, |
118 | struct drm_crtc_state *state) | ||
138 | { | 119 | { |
139 | struct ipu_flip_work *work = | 120 | __drm_atomic_helper_crtc_destroy_state(state); |
140 | container_of(__work, struct ipu_flip_work, fence_work); | 121 | kfree(to_imx_crtc_state(state)); |
141 | int i; | 122 | } |
142 | 123 | ||
143 | /* wait for all fences attached to the FB obj to signal */ | 124 | static const struct drm_crtc_funcs ipu_crtc_funcs = { |
144 | if (work->excl) { | 125 | .set_config = drm_atomic_helper_set_config, |
145 | fence_wait(work->excl, false); | 126 | .destroy = drm_crtc_cleanup, |
146 | fence_put(work->excl); | 127 | .page_flip = drm_atomic_helper_page_flip, |
147 | } | 128 | .reset = imx_drm_crtc_reset, |
148 | for (i = 0; i < work->shared_count; i++) { | 129 | .atomic_duplicate_state = imx_drm_crtc_duplicate_state, |
149 | fence_wait(work->shared[i], false); | 130 | .atomic_destroy_state = imx_drm_crtc_destroy_state, |
150 | fence_put(work->shared[i]); | 131 | }; |
151 | } | ||
152 | 132 | ||
153 | work->crtc->flip_state = IPU_FLIP_SUBMITTED; | 133 | static irqreturn_t ipu_irq_handler(int irq, void *dev_id) |
134 | { | ||
135 | struct ipu_crtc *ipu_crtc = dev_id; | ||
136 | |||
137 | imx_drm_handle_vblank(ipu_crtc->imx_crtc); | ||
138 | |||
139 | return IRQ_HANDLED; | ||
154 | } | 140 | } |
155 | 141 | ||
156 | static int ipu_page_flip(struct drm_crtc *crtc, | 142 | static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc, |
157 | struct drm_framebuffer *fb, | 143 | const struct drm_display_mode *mode, |
158 | struct drm_pending_vblank_event *event, | 144 | struct drm_display_mode *adjusted_mode) |
159 | uint32_t page_flip_flags) | ||
160 | { | 145 | { |
161 | struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); | ||
162 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | 146 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); |
163 | struct ipu_flip_work *flip_work; | 147 | struct videomode vm; |
164 | int ret; | 148 | int ret; |
165 | 149 | ||
166 | if (ipu_crtc->flip_state != IPU_FLIP_NONE) | 150 | drm_display_mode_to_videomode(adjusted_mode, &vm); |
167 | return -EBUSY; | ||
168 | |||
169 | ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc); | ||
170 | if (ret) { | ||
171 | dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n"); | ||
172 | list_del(&event->base.link); | ||
173 | |||
174 | return ret; | ||
175 | } | ||
176 | 151 | ||
177 | flip_work = kzalloc(sizeof *flip_work, GFP_KERNEL); | 152 | ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm); |
178 | if (!flip_work) { | 153 | if (ret) |
179 | ret = -ENOMEM; | 154 | return false; |
180 | goto put_vblank; | ||
181 | } | ||
182 | INIT_WORK(&flip_work->unref_work, ipu_flip_unref_work_func); | ||
183 | flip_work->page_flip_event = event; | ||
184 | 155 | ||
185 | /* get BO backing the old framebuffer and take a reference */ | 156 | if ((vm.vsync_len == 0) || (vm.hsync_len == 0)) |
186 | flip_work->bo = &drm_fb_cma_get_gem_obj(crtc->primary->fb, 0)->base; | 157 | return false; |
187 | drm_gem_object_reference(flip_work->bo); | ||
188 | 158 | ||
189 | ipu_crtc->flip_work = flip_work; | 159 | drm_display_mode_from_videomode(&vm, adjusted_mode); |
190 | /* | ||
191 | * If the object has a DMABUF attached, we need to wait on its fences | ||
192 | * if there are any. | ||
193 | */ | ||
194 | if (cma_obj->base.dma_buf) { | ||
195 | INIT_WORK(&flip_work->fence_work, ipu_flip_fence_work_func); | ||
196 | flip_work->crtc = ipu_crtc; | ||
197 | 160 | ||
198 | ret = reservation_object_get_fences_rcu( | 161 | return true; |
199 | cma_obj->base.dma_buf->resv, &flip_work->excl, | 162 | } |
200 | &flip_work->shared_count, &flip_work->shared); | ||
201 | 163 | ||
202 | if (unlikely(ret)) { | 164 | static int ipu_crtc_atomic_check(struct drm_crtc *crtc, |
203 | DRM_ERROR("failed to get fences for buffer\n"); | 165 | struct drm_crtc_state *state) |
204 | goto free_flip_work; | 166 | { |
205 | } | 167 | u32 primary_plane_mask = 1 << drm_plane_index(crtc->primary); |
206 | 168 | ||
207 | /* No need to queue the worker if the are no fences */ | 169 | if (state->active && (primary_plane_mask & state->plane_mask) == 0) |
208 | if (!flip_work->excl && !flip_work->shared_count) { | 170 | return -EINVAL; |
209 | ipu_crtc->flip_state = IPU_FLIP_SUBMITTED; | ||
210 | } else { | ||
211 | ipu_crtc->flip_state = IPU_FLIP_PENDING; | ||
212 | queue_work(ipu_crtc->flip_queue, | ||
213 | &flip_work->fence_work); | ||
214 | } | ||
215 | } else { | ||
216 | ipu_crtc->flip_state = IPU_FLIP_SUBMITTED; | ||
217 | } | ||
218 | 171 | ||
219 | return 0; | 172 | return 0; |
220 | |||
221 | free_flip_work: | ||
222 | drm_gem_object_unreference_unlocked(flip_work->bo); | ||
223 | kfree(flip_work); | ||
224 | ipu_crtc->flip_work = NULL; | ||
225 | put_vblank: | ||
226 | imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); | ||
227 | |||
228 | return ret; | ||
229 | } | 173 | } |
230 | 174 | ||
231 | static const struct drm_crtc_funcs ipu_crtc_funcs = { | 175 | static void ipu_crtc_atomic_begin(struct drm_crtc *crtc, |
232 | .set_config = drm_crtc_helper_set_config, | 176 | struct drm_crtc_state *old_crtc_state) |
233 | .destroy = drm_crtc_cleanup, | 177 | { |
234 | .page_flip = ipu_page_flip, | 178 | spin_lock_irq(&crtc->dev->event_lock); |
235 | }; | 179 | if (crtc->state->event) { |
180 | WARN_ON(drm_crtc_vblank_get(crtc)); | ||
181 | drm_crtc_arm_vblank_event(crtc, crtc->state->event); | ||
182 | crtc->state->event = NULL; | ||
183 | } | ||
184 | spin_unlock_irq(&crtc->dev->event_lock); | ||
185 | } | ||
236 | 186 | ||
237 | static int ipu_crtc_mode_set(struct drm_crtc *crtc, | 187 | static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) |
238 | struct drm_display_mode *orig_mode, | ||
239 | struct drm_display_mode *mode, | ||
240 | int x, int y, | ||
241 | struct drm_framebuffer *old_fb) | ||
242 | { | 188 | { |
243 | struct drm_device *dev = crtc->dev; | 189 | struct drm_device *dev = crtc->dev; |
244 | struct drm_encoder *encoder; | 190 | struct drm_encoder *encoder; |
245 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | 191 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); |
192 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; | ||
193 | struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state); | ||
246 | struct ipu_di_signal_cfg sig_cfg = {}; | 194 | struct ipu_di_signal_cfg sig_cfg = {}; |
247 | unsigned long encoder_types = 0; | 195 | unsigned long encoder_types = 0; |
248 | int ret; | ||
249 | 196 | ||
250 | dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, | 197 | dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, |
251 | mode->hdisplay); | 198 | mode->hdisplay); |
252 | dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, | 199 | dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, |
253 | mode->vdisplay); | 200 | mode->vdisplay); |
254 | 201 | ||
255 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) | 202 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
256 | if (encoder->crtc == crtc) | 203 | if (encoder->crtc == crtc) |
257 | encoder_types |= BIT(encoder->encoder_type); | 204 | encoder_types |= BIT(encoder->encoder_type); |
205 | } | ||
258 | 206 | ||
259 | dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n", | 207 | dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n", |
260 | __func__, encoder_types); | 208 | __func__, encoder_types); |
@@ -272,114 +220,30 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, | |||
272 | else | 220 | else |
273 | sig_cfg.clkflags = 0; | 221 | sig_cfg.clkflags = 0; |
274 | 222 | ||
275 | sig_cfg.enable_pol = !(ipu_crtc->bus_flags & DRM_BUS_FLAG_DE_LOW); | 223 | sig_cfg.enable_pol = !(imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_LOW); |
276 | /* Default to driving pixel data on negative clock edges */ | 224 | /* Default to driving pixel data on negative clock edges */ |
277 | sig_cfg.clk_pol = !!(ipu_crtc->bus_flags & | 225 | sig_cfg.clk_pol = !!(imx_crtc_state->bus_flags & |
278 | DRM_BUS_FLAG_PIXDATA_POSEDGE); | 226 | DRM_BUS_FLAG_PIXDATA_POSEDGE); |
279 | sig_cfg.bus_format = ipu_crtc->bus_format; | 227 | sig_cfg.bus_format = imx_crtc_state->bus_format; |
280 | sig_cfg.v_to_h_sync = 0; | 228 | sig_cfg.v_to_h_sync = 0; |
281 | sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; | 229 | sig_cfg.hsync_pin = imx_crtc_state->di_hsync_pin; |
282 | sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; | 230 | sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin; |
283 | 231 | ||
284 | drm_display_mode_to_videomode(mode, &sig_cfg.mode); | 232 | drm_display_mode_to_videomode(mode, &sig_cfg.mode); |
285 | 233 | ||
286 | ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, | 234 | ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, |
287 | mode->flags & DRM_MODE_FLAG_INTERLACE, | 235 | mode->flags & DRM_MODE_FLAG_INTERLACE, |
288 | ipu_crtc->bus_format, mode->hdisplay); | 236 | imx_crtc_state->bus_format, mode->hdisplay); |
289 | if (ret) { | 237 | ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); |
290 | dev_err(ipu_crtc->dev, | ||
291 | "initializing display controller failed with %d\n", | ||
292 | ret); | ||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); | ||
297 | if (ret) { | ||
298 | dev_err(ipu_crtc->dev, | ||
299 | "initializing panel failed with %d\n", ret); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, | ||
304 | crtc->primary->fb, | ||
305 | 0, 0, mode->hdisplay, mode->vdisplay, | ||
306 | x, y, mode->hdisplay, mode->vdisplay, | ||
307 | mode->flags & DRM_MODE_FLAG_INTERLACE); | ||
308 | } | ||
309 | |||
310 | static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) | ||
311 | { | ||
312 | unsigned long flags; | ||
313 | struct drm_device *drm = ipu_crtc->base.dev; | ||
314 | struct ipu_flip_work *work = ipu_crtc->flip_work; | ||
315 | |||
316 | spin_lock_irqsave(&drm->event_lock, flags); | ||
317 | if (work->page_flip_event) | ||
318 | drm_crtc_send_vblank_event(&ipu_crtc->base, | ||
319 | work->page_flip_event); | ||
320 | imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); | ||
321 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
322 | } | ||
323 | |||
324 | static irqreturn_t ipu_irq_handler(int irq, void *dev_id) | ||
325 | { | ||
326 | struct ipu_crtc *ipu_crtc = dev_id; | ||
327 | |||
328 | imx_drm_handle_vblank(ipu_crtc->imx_crtc); | ||
329 | |||
330 | if (ipu_crtc->flip_state == IPU_FLIP_SUBMITTED) { | ||
331 | struct ipu_plane *plane = ipu_crtc->plane[0]; | ||
332 | |||
333 | ipu_plane_set_base(plane, ipu_crtc->base.primary->fb, | ||
334 | plane->x, plane->y); | ||
335 | ipu_crtc_handle_pageflip(ipu_crtc); | ||
336 | queue_work(ipu_crtc->flip_queue, | ||
337 | &ipu_crtc->flip_work->unref_work); | ||
338 | ipu_crtc->flip_state = IPU_FLIP_NONE; | ||
339 | } | ||
340 | |||
341 | return IRQ_HANDLED; | ||
342 | } | ||
343 | |||
344 | static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc, | ||
345 | const struct drm_display_mode *mode, | ||
346 | struct drm_display_mode *adjusted_mode) | ||
347 | { | ||
348 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | ||
349 | struct videomode vm; | ||
350 | int ret; | ||
351 | |||
352 | drm_display_mode_to_videomode(adjusted_mode, &vm); | ||
353 | |||
354 | ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm); | ||
355 | if (ret) | ||
356 | return false; | ||
357 | |||
358 | drm_display_mode_from_videomode(&vm, adjusted_mode); | ||
359 | |||
360 | return true; | ||
361 | } | ||
362 | |||
363 | static void ipu_crtc_prepare(struct drm_crtc *crtc) | ||
364 | { | ||
365 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | ||
366 | |||
367 | ipu_fb_disable(ipu_crtc); | ||
368 | } | ||
369 | |||
370 | static void ipu_crtc_commit(struct drm_crtc *crtc) | ||
371 | { | ||
372 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | ||
373 | |||
374 | ipu_fb_enable(ipu_crtc); | ||
375 | } | 238 | } |
376 | 239 | ||
377 | static const struct drm_crtc_helper_funcs ipu_helper_funcs = { | 240 | static const struct drm_crtc_helper_funcs ipu_helper_funcs = { |
378 | .dpms = ipu_crtc_dpms, | ||
379 | .mode_fixup = ipu_crtc_mode_fixup, | 241 | .mode_fixup = ipu_crtc_mode_fixup, |
380 | .mode_set = ipu_crtc_mode_set, | 242 | .mode_set_nofb = ipu_crtc_mode_set_nofb, |
381 | .prepare = ipu_crtc_prepare, | 243 | .atomic_check = ipu_crtc_atomic_check, |
382 | .commit = ipu_crtc_commit, | 244 | .atomic_begin = ipu_crtc_atomic_begin, |
245 | .disable = ipu_crtc_disable, | ||
246 | .enable = ipu_crtc_enable, | ||
383 | }; | 247 | }; |
384 | 248 | ||
385 | static int ipu_enable_vblank(struct drm_crtc *crtc) | 249 | static int ipu_enable_vblank(struct drm_crtc *crtc) |
@@ -398,23 +262,9 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) | |||
398 | disable_irq_nosync(ipu_crtc->irq); | 262 | disable_irq_nosync(ipu_crtc->irq); |
399 | } | 263 | } |
400 | 264 | ||
401 | static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, | ||
402 | u32 bus_format, int hsync_pin, int vsync_pin, u32 bus_flags) | ||
403 | { | ||
404 | struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); | ||
405 | |||
406 | ipu_crtc->bus_format = bus_format; | ||
407 | ipu_crtc->bus_flags = bus_flags; | ||
408 | ipu_crtc->di_hsync_pin = hsync_pin; | ||
409 | ipu_crtc->di_vsync_pin = vsync_pin; | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = { | 265 | static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = { |
415 | .enable_vblank = ipu_enable_vblank, | 266 | .enable_vblank = ipu_enable_vblank, |
416 | .disable_vblank = ipu_disable_vblank, | 267 | .disable_vblank = ipu_disable_vblank, |
417 | .set_interface_pix_fmt = ipu_set_interface_pix_fmt, | ||
418 | .crtc_funcs = &ipu_crtc_funcs, | 268 | .crtc_funcs = &ipu_crtc_funcs, |
419 | .crtc_helper_funcs = &ipu_helper_funcs, | 269 | .crtc_helper_funcs = &ipu_helper_funcs, |
420 | }; | 270 | }; |
@@ -496,8 +346,16 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, | |||
496 | IPU_DP_FLOW_SYNC_FG, | 346 | IPU_DP_FLOW_SYNC_FG, |
497 | drm_crtc_mask(&ipu_crtc->base), | 347 | drm_crtc_mask(&ipu_crtc->base), |
498 | DRM_PLANE_TYPE_OVERLAY); | 348 | DRM_PLANE_TYPE_OVERLAY); |
499 | if (IS_ERR(ipu_crtc->plane[1])) | 349 | if (IS_ERR(ipu_crtc->plane[1])) { |
500 | ipu_crtc->plane[1] = NULL; | 350 | ipu_crtc->plane[1] = NULL; |
351 | } else { | ||
352 | ret = ipu_plane_get_resources(ipu_crtc->plane[1]); | ||
353 | if (ret) { | ||
354 | dev_err(ipu_crtc->dev, "getting plane 1 " | ||
355 | "resources failed with %d.\n", ret); | ||
356 | goto err_put_plane0_res; | ||
357 | } | ||
358 | } | ||
501 | } | 359 | } |
502 | 360 | ||
503 | ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]); | 361 | ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]); |
@@ -505,16 +363,17 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, | |||
505 | "imx_drm", ipu_crtc); | 363 | "imx_drm", ipu_crtc); |
506 | if (ret < 0) { | 364 | if (ret < 0) { |
507 | dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); | 365 | dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); |
508 | goto err_put_plane_res; | 366 | goto err_put_plane1_res; |
509 | } | 367 | } |
510 | /* Only enable IRQ when we actually need it to trigger work. */ | 368 | /* Only enable IRQ when we actually need it to trigger work. */ |
511 | disable_irq(ipu_crtc->irq); | 369 | disable_irq(ipu_crtc->irq); |
512 | 370 | ||
513 | ipu_crtc->flip_queue = create_singlethread_workqueue("ipu-crtc-flip"); | ||
514 | |||
515 | return 0; | 371 | return 0; |
516 | 372 | ||
517 | err_put_plane_res: | 373 | err_put_plane1_res: |
374 | if (ipu_crtc->plane[1]) | ||
375 | ipu_plane_put_resources(ipu_crtc->plane[1]); | ||
376 | err_put_plane0_res: | ||
518 | ipu_plane_put_resources(ipu_crtc->plane[0]); | 377 | ipu_plane_put_resources(ipu_crtc->plane[0]); |
519 | err_remove_crtc: | 378 | err_remove_crtc: |
520 | imx_drm_remove_crtc(ipu_crtc->imx_crtc); | 379 | imx_drm_remove_crtc(ipu_crtc->imx_crtc); |
@@ -553,9 +412,10 @@ static void ipu_drm_unbind(struct device *dev, struct device *master, | |||
553 | 412 | ||
554 | imx_drm_remove_crtc(ipu_crtc->imx_crtc); | 413 | imx_drm_remove_crtc(ipu_crtc->imx_crtc); |
555 | 414 | ||
556 | destroy_workqueue(ipu_crtc->flip_queue); | ||
557 | ipu_plane_put_resources(ipu_crtc->plane[0]); | ||
558 | ipu_put_resources(ipu_crtc); | 415 | ipu_put_resources(ipu_crtc); |
416 | if (ipu_crtc->plane[1]) | ||
417 | ipu_plane_put_resources(ipu_crtc->plane[1]); | ||
418 | ipu_plane_put_resources(ipu_crtc->plane[0]); | ||
559 | } | 419 | } |
560 | 420 | ||
561 | static const struct component_ops ipu_crtc_ops = { | 421 | static const struct component_ops ipu_crtc_ops = { |
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index a4bb44118d33..4ad67d015ec7 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c | |||
@@ -14,13 +14,19 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <drm/drmP.h> | 16 | #include <drm/drmP.h> |
17 | #include <drm/drm_atomic.h> | ||
18 | #include <drm/drm_atomic_helper.h> | ||
17 | #include <drm/drm_fb_cma_helper.h> | 19 | #include <drm/drm_fb_cma_helper.h> |
18 | #include <drm/drm_gem_cma_helper.h> | 20 | #include <drm/drm_gem_cma_helper.h> |
21 | #include <drm/drm_plane_helper.h> | ||
19 | 22 | ||
20 | #include "video/imx-ipu-v3.h" | 23 | #include "video/imx-ipu-v3.h" |
21 | #include "ipuv3-plane.h" | 24 | #include "ipuv3-plane.h" |
22 | 25 | ||
23 | #define to_ipu_plane(x) container_of(x, struct ipu_plane, base) | 26 | static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) |
27 | { | ||
28 | return container_of(p, struct ipu_plane, base); | ||
29 | } | ||
24 | 30 | ||
25 | static const uint32_t ipu_plane_formats[] = { | 31 | static const uint32_t ipu_plane_formats[] = { |
26 | DRM_FORMAT_ARGB1555, | 32 | DRM_FORMAT_ARGB1555, |
@@ -53,62 +59,67 @@ int ipu_plane_irq(struct ipu_plane *ipu_plane) | |||
53 | IPU_IRQ_EOF); | 59 | IPU_IRQ_EOF); |
54 | } | 60 | } |
55 | 61 | ||
56 | static int calc_vref(struct drm_display_mode *mode) | 62 | static inline unsigned long |
63 | drm_plane_state_to_eba(struct drm_plane_state *state) | ||
57 | { | 64 | { |
58 | unsigned long htotal, vtotal; | 65 | struct drm_framebuffer *fb = state->fb; |
66 | struct drm_gem_cma_object *cma_obj; | ||
59 | 67 | ||
60 | htotal = mode->htotal; | 68 | cma_obj = drm_fb_cma_get_gem_obj(fb, 0); |
61 | vtotal = mode->vtotal; | 69 | BUG_ON(!cma_obj); |
62 | 70 | ||
63 | if (!htotal || !vtotal) | 71 | return cma_obj->paddr + fb->offsets[0] + |
64 | return 60; | 72 | fb->pitches[0] * (state->src_y >> 16) + |
65 | 73 | (fb->bits_per_pixel >> 3) * (state->src_x >> 16); | |
66 | return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal); | ||
67 | } | 74 | } |
68 | 75 | ||
69 | static inline int calc_bandwidth(int width, int height, unsigned int vref) | 76 | static inline unsigned long |
77 | drm_plane_state_to_ubo(struct drm_plane_state *state) | ||
70 | { | 78 | { |
71 | return width * height * vref; | 79 | struct drm_framebuffer *fb = state->fb; |
72 | } | 80 | struct drm_gem_cma_object *cma_obj; |
81 | unsigned long eba = drm_plane_state_to_eba(state); | ||
73 | 82 | ||
74 | int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, | 83 | cma_obj = drm_fb_cma_get_gem_obj(fb, 1); |
75 | int x, int y) | 84 | BUG_ON(!cma_obj); |
76 | { | ||
77 | struct drm_gem_cma_object *cma_obj[3]; | ||
78 | unsigned long eba, ubo, vbo; | ||
79 | int active, i; | ||
80 | 85 | ||
81 | for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { | 86 | return cma_obj->paddr + fb->offsets[1] + |
82 | cma_obj[i] = drm_fb_cma_get_gem_obj(fb, i); | 87 | fb->pitches[1] * (state->src_y >> 16) / 2 + |
83 | if (!cma_obj[i]) { | 88 | (state->src_x >> 16) / 2 - eba; |
84 | DRM_DEBUG_KMS("plane %d entry is null.\n", i); | 89 | } |
85 | return -EFAULT; | ||
86 | } | ||
87 | } | ||
88 | 90 | ||
89 | eba = cma_obj[0]->paddr + fb->offsets[0] + | 91 | static inline unsigned long |
90 | fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x; | 92 | drm_plane_state_to_vbo(struct drm_plane_state *state) |
93 | { | ||
94 | struct drm_framebuffer *fb = state->fb; | ||
95 | struct drm_gem_cma_object *cma_obj; | ||
96 | unsigned long eba = drm_plane_state_to_eba(state); | ||
91 | 97 | ||
92 | if (eba & 0x7) { | 98 | cma_obj = drm_fb_cma_get_gem_obj(fb, 2); |
93 | DRM_DEBUG_KMS("base address must be a multiple of 8.\n"); | 99 | BUG_ON(!cma_obj); |
94 | return -EINVAL; | ||
95 | } | ||
96 | 100 | ||
97 | if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) { | 101 | return cma_obj->paddr + fb->offsets[2] + |
98 | DRM_DEBUG_KMS("pitches out of range.\n"); | 102 | fb->pitches[2] * (state->src_y >> 16) / 2 + |
99 | return -EINVAL; | 103 | (state->src_x >> 16) / 2 - eba; |
100 | } | 104 | } |
101 | 105 | ||
102 | if (ipu_plane->enabled && fb->pitches[0] != ipu_plane->stride[0]) { | 106 | static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane, |
103 | DRM_DEBUG_KMS("pitches must not change while plane is enabled.\n"); | 107 | struct drm_plane_state *old_state) |
104 | return -EINVAL; | 108 | { |
105 | } | 109 | struct drm_plane *plane = &ipu_plane->base; |
110 | struct drm_plane_state *state = plane->state; | ||
111 | struct drm_framebuffer *fb = state->fb; | ||
112 | unsigned long eba, ubo, vbo; | ||
113 | int active; | ||
106 | 114 | ||
107 | ipu_plane->stride[0] = fb->pitches[0]; | 115 | eba = drm_plane_state_to_eba(state); |
108 | 116 | ||
109 | switch (fb->pixel_format) { | 117 | switch (fb->pixel_format) { |
110 | case DRM_FORMAT_YUV420: | 118 | case DRM_FORMAT_YUV420: |
111 | case DRM_FORMAT_YVU420: | 119 | case DRM_FORMAT_YVU420: |
120 | if (old_state->fb) | ||
121 | break; | ||
122 | |||
112 | /* | 123 | /* |
113 | * Multiplanar formats have to meet the following restrictions: | 124 | * Multiplanar formats have to meet the following restrictions: |
114 | * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO | 125 | * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO |
@@ -117,59 +128,28 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, | |||
117 | * - Only EBA may be changed while scanout is active | 128 | * - Only EBA may be changed while scanout is active |
118 | * - The strides of U and V planes must be identical. | 129 | * - The strides of U and V planes must be identical. |
119 | */ | 130 | */ |
120 | ubo = cma_obj[1]->paddr + fb->offsets[1] + | 131 | ubo = drm_plane_state_to_ubo(state); |
121 | fb->pitches[1] * y / 2 + x / 2 - eba; | 132 | vbo = drm_plane_state_to_vbo(state); |
122 | vbo = cma_obj[2]->paddr + fb->offsets[2] + | ||
123 | fb->pitches[2] * y / 2 + x / 2 - eba; | ||
124 | 133 | ||
125 | if ((ubo & 0x7) || (vbo & 0x7)) { | 134 | if (fb->pixel_format == DRM_FORMAT_YUV420) |
126 | DRM_DEBUG_KMS("U/V buffer offsets must be a multiple of 8.\n"); | 135 | ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, |
127 | return -EINVAL; | 136 | fb->pitches[1], ubo, vbo); |
128 | } | 137 | else |
129 | 138 | ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, | |
130 | if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) { | 139 | fb->pitches[1], vbo, ubo); |
131 | DRM_DEBUG_KMS("U/V buffer offsets must be positive and not larger than 0xfffff8.\n"); | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | |||
135 | if (ipu_plane->enabled && ((ipu_plane->u_offset != ubo) || | ||
136 | (ipu_plane->v_offset != vbo))) { | ||
137 | DRM_DEBUG_KMS("U/V buffer offsets must not change while plane is enabled.\n"); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | if (fb->pitches[1] != fb->pitches[2]) { | ||
142 | DRM_DEBUG_KMS("U/V pitches must be identical.\n"); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) { | ||
147 | DRM_DEBUG_KMS("U/V pitches out of range.\n"); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | if (ipu_plane->enabled && | ||
152 | (ipu_plane->stride[1] != fb->pitches[1])) { | ||
153 | DRM_DEBUG_KMS("U/V pitches must not change while plane is enabled.\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | ipu_plane->u_offset = ubo; | ||
158 | ipu_plane->v_offset = vbo; | ||
159 | ipu_plane->stride[1] = fb->pitches[1]; | ||
160 | 140 | ||
161 | dev_dbg(ipu_plane->base.dev->dev, | 141 | dev_dbg(ipu_plane->base.dev->dev, |
162 | "phys = %pad %pad %pad, x = %d, y = %d", | 142 | "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo, |
163 | &cma_obj[0]->paddr, &cma_obj[1]->paddr, | 143 | state->src_x >> 16, state->src_y >> 16); |
164 | &cma_obj[2]->paddr, x, y); | ||
165 | break; | 144 | break; |
166 | default: | 145 | default: |
167 | dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", | 146 | dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d", |
168 | &cma_obj[0]->paddr, x, y); | 147 | eba, state->src_x >> 16, state->src_y >> 16); |
148 | |||
169 | break; | 149 | break; |
170 | } | 150 | } |
171 | 151 | ||
172 | if (ipu_plane->enabled) { | 152 | if (old_state->fb) { |
173 | active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); | 153 | active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); |
174 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); | 154 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); |
175 | ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); | 155 | ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); |
@@ -177,155 +157,6 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, | |||
177 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); | 157 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); |
178 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); | 158 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); |
179 | } | 159 | } |
180 | |||
181 | /* cache offsets for subsequent pageflips */ | ||
182 | ipu_plane->x = x; | ||
183 | ipu_plane->y = y; | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, | ||
189 | struct drm_display_mode *mode, | ||
190 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, | ||
191 | unsigned int crtc_w, unsigned int crtc_h, | ||
192 | uint32_t src_x, uint32_t src_y, | ||
193 | uint32_t src_w, uint32_t src_h, bool interlaced) | ||
194 | { | ||
195 | struct device *dev = ipu_plane->base.dev->dev; | ||
196 | int ret; | ||
197 | |||
198 | /* no scaling */ | ||
199 | if (src_w != crtc_w || src_h != crtc_h) | ||
200 | return -EINVAL; | ||
201 | |||
202 | /* clip to crtc bounds */ | ||
203 | if (crtc_x < 0) { | ||
204 | if (-crtc_x > crtc_w) | ||
205 | return -EINVAL; | ||
206 | src_x += -crtc_x; | ||
207 | src_w -= -crtc_x; | ||
208 | crtc_w -= -crtc_x; | ||
209 | crtc_x = 0; | ||
210 | } | ||
211 | if (crtc_y < 0) { | ||
212 | if (-crtc_y > crtc_h) | ||
213 | return -EINVAL; | ||
214 | src_y += -crtc_y; | ||
215 | src_h -= -crtc_y; | ||
216 | crtc_h -= -crtc_y; | ||
217 | crtc_y = 0; | ||
218 | } | ||
219 | if (crtc_x + crtc_w > mode->hdisplay) { | ||
220 | if (crtc_x > mode->hdisplay) | ||
221 | return -EINVAL; | ||
222 | crtc_w = mode->hdisplay - crtc_x; | ||
223 | src_w = crtc_w; | ||
224 | } | ||
225 | if (crtc_y + crtc_h > mode->vdisplay) { | ||
226 | if (crtc_y > mode->vdisplay) | ||
227 | return -EINVAL; | ||
228 | crtc_h = mode->vdisplay - crtc_y; | ||
229 | src_h = crtc_h; | ||
230 | } | ||
231 | /* full plane minimum width is 13 pixels */ | ||
232 | if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG)) | ||
233 | return -EINVAL; | ||
234 | if (crtc_h < 2) | ||
235 | return -EINVAL; | ||
236 | |||
237 | /* | ||
238 | * since we cannot touch active IDMAC channels, we do not support | ||
239 | * resizing the enabled plane or changing its format | ||
240 | */ | ||
241 | if (ipu_plane->enabled) { | ||
242 | if (src_w != ipu_plane->w || src_h != ipu_plane->h || | ||
243 | fb->pixel_format != ipu_plane->base.fb->pixel_format) | ||
244 | return -EINVAL; | ||
245 | |||
246 | return ipu_plane_set_base(ipu_plane, fb, src_x, src_y); | ||
247 | } | ||
248 | |||
249 | switch (ipu_plane->dp_flow) { | ||
250 | case IPU_DP_FLOW_SYNC_BG: | ||
251 | ret = ipu_dp_setup_channel(ipu_plane->dp, | ||
252 | IPUV3_COLORSPACE_RGB, | ||
253 | IPUV3_COLORSPACE_RGB); | ||
254 | if (ret) { | ||
255 | dev_err(dev, | ||
256 | "initializing display processor failed with %d\n", | ||
257 | ret); | ||
258 | return ret; | ||
259 | } | ||
260 | ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true); | ||
261 | break; | ||
262 | case IPU_DP_FLOW_SYNC_FG: | ||
263 | ipu_dp_setup_channel(ipu_plane->dp, | ||
264 | ipu_drm_fourcc_to_colorspace(fb->pixel_format), | ||
265 | IPUV3_COLORSPACE_UNKNOWN); | ||
266 | ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y); | ||
267 | /* Enable local alpha on partial plane */ | ||
268 | switch (fb->pixel_format) { | ||
269 | case DRM_FORMAT_ARGB1555: | ||
270 | case DRM_FORMAT_ABGR1555: | ||
271 | case DRM_FORMAT_RGBA5551: | ||
272 | case DRM_FORMAT_BGRA5551: | ||
273 | case DRM_FORMAT_ARGB4444: | ||
274 | case DRM_FORMAT_ARGB8888: | ||
275 | case DRM_FORMAT_ABGR8888: | ||
276 | case DRM_FORMAT_RGBA8888: | ||
277 | case DRM_FORMAT_BGRA8888: | ||
278 | ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false); | ||
279 | break; | ||
280 | default: | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc, | ||
286 | calc_bandwidth(crtc_w, crtc_h, | ||
287 | calc_vref(mode)), 64); | ||
288 | if (ret) { | ||
289 | dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret); | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | ipu_dmfc_config_wait4eot(ipu_plane->dmfc, crtc_w); | ||
294 | |||
295 | ipu_cpmem_zero(ipu_plane->ipu_ch); | ||
296 | ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h); | ||
297 | ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format); | ||
298 | if (ret < 0) { | ||
299 | dev_err(dev, "unsupported pixel format 0x%08x\n", | ||
300 | fb->pixel_format); | ||
301 | return ret; | ||
302 | } | ||
303 | ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); | ||
304 | ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); | ||
305 | ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]); | ||
306 | |||
307 | ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y); | ||
308 | if (ret < 0) | ||
309 | return ret; | ||
310 | if (interlaced) | ||
311 | ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]); | ||
312 | |||
313 | if (fb->pixel_format == DRM_FORMAT_YUV420) { | ||
314 | ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, | ||
315 | ipu_plane->stride[1], | ||
316 | ipu_plane->u_offset, | ||
317 | ipu_plane->v_offset); | ||
318 | } else if (fb->pixel_format == DRM_FORMAT_YVU420) { | ||
319 | ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, | ||
320 | ipu_plane->stride[1], | ||
321 | ipu_plane->v_offset, | ||
322 | ipu_plane->u_offset); | ||
323 | } | ||
324 | |||
325 | ipu_plane->w = src_w; | ||
326 | ipu_plane->h = src_h; | ||
327 | |||
328 | return 0; | ||
329 | } | 160 | } |
330 | 161 | ||
331 | void ipu_plane_put_resources(struct ipu_plane *ipu_plane) | 162 | void ipu_plane_put_resources(struct ipu_plane *ipu_plane) |
@@ -372,7 +203,7 @@ err_out: | |||
372 | return ret; | 203 | return ret; |
373 | } | 204 | } |
374 | 205 | ||
375 | void ipu_plane_enable(struct ipu_plane *ipu_plane) | 206 | static void ipu_plane_enable(struct ipu_plane *ipu_plane) |
376 | { | 207 | { |
377 | if (ipu_plane->dp) | 208 | if (ipu_plane->dp) |
378 | ipu_dp_enable(ipu_plane->ipu); | 209 | ipu_dp_enable(ipu_plane->ipu); |
@@ -380,14 +211,10 @@ void ipu_plane_enable(struct ipu_plane *ipu_plane) | |||
380 | ipu_idmac_enable_channel(ipu_plane->ipu_ch); | 211 | ipu_idmac_enable_channel(ipu_plane->ipu_ch); |
381 | if (ipu_plane->dp) | 212 | if (ipu_plane->dp) |
382 | ipu_dp_enable_channel(ipu_plane->dp); | 213 | ipu_dp_enable_channel(ipu_plane->dp); |
383 | |||
384 | ipu_plane->enabled = true; | ||
385 | } | 214 | } |
386 | 215 | ||
387 | void ipu_plane_disable(struct ipu_plane *ipu_plane) | 216 | static void ipu_plane_disable(struct ipu_plane *ipu_plane) |
388 | { | 217 | { |
389 | ipu_plane->enabled = false; | ||
390 | |||
391 | ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); | 218 | ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); |
392 | 219 | ||
393 | if (ipu_plane->dp) | 220 | if (ipu_plane->dp) |
@@ -398,74 +225,225 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane) | |||
398 | ipu_dp_disable(ipu_plane->ipu); | 225 | ipu_dp_disable(ipu_plane->ipu); |
399 | } | 226 | } |
400 | 227 | ||
401 | /* | 228 | static int ipu_disable_plane(struct drm_plane *plane) |
402 | * drm_plane API | ||
403 | */ | ||
404 | |||
405 | static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, | ||
406 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, | ||
407 | unsigned int crtc_w, unsigned int crtc_h, | ||
408 | uint32_t src_x, uint32_t src_y, | ||
409 | uint32_t src_w, uint32_t src_h) | ||
410 | { | 229 | { |
411 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); | 230 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); |
412 | int ret = 0; | ||
413 | |||
414 | DRM_DEBUG_KMS("plane - %p\n", plane); | ||
415 | |||
416 | if (!ipu_plane->enabled) | ||
417 | ret = ipu_plane_get_resources(ipu_plane); | ||
418 | if (ret < 0) | ||
419 | return ret; | ||
420 | |||
421 | ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb, | ||
422 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
423 | src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16, | ||
424 | false); | ||
425 | if (ret < 0) { | ||
426 | ipu_plane_put_resources(ipu_plane); | ||
427 | return ret; | ||
428 | } | ||
429 | 231 | ||
430 | if (crtc != plane->crtc) | 232 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); |
431 | dev_dbg(plane->dev->dev, "crtc change: %p -> %p\n", | ||
432 | plane->crtc, crtc); | ||
433 | 233 | ||
434 | if (!ipu_plane->enabled) | 234 | ipu_plane_disable(ipu_plane); |
435 | ipu_plane_enable(ipu_plane); | ||
436 | 235 | ||
437 | return 0; | 236 | return 0; |
438 | } | 237 | } |
439 | 238 | ||
440 | static int ipu_disable_plane(struct drm_plane *plane) | 239 | static void ipu_plane_destroy(struct drm_plane *plane) |
441 | { | 240 | { |
442 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); | 241 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); |
443 | 242 | ||
444 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 243 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); |
445 | 244 | ||
446 | if (ipu_plane->enabled) | 245 | ipu_disable_plane(plane); |
447 | ipu_plane_disable(ipu_plane); | 246 | drm_plane_cleanup(plane); |
247 | kfree(ipu_plane); | ||
248 | } | ||
448 | 249 | ||
449 | ipu_plane_put_resources(ipu_plane); | 250 | static const struct drm_plane_funcs ipu_plane_funcs = { |
251 | .update_plane = drm_atomic_helper_update_plane, | ||
252 | .disable_plane = drm_atomic_helper_disable_plane, | ||
253 | .destroy = ipu_plane_destroy, | ||
254 | .reset = drm_atomic_helper_plane_reset, | ||
255 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
256 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
257 | }; | ||
258 | |||
259 | static int ipu_plane_atomic_check(struct drm_plane *plane, | ||
260 | struct drm_plane_state *state) | ||
261 | { | ||
262 | struct drm_plane_state *old_state = plane->state; | ||
263 | struct drm_crtc_state *crtc_state; | ||
264 | struct device *dev = plane->dev->dev; | ||
265 | struct drm_framebuffer *fb = state->fb; | ||
266 | struct drm_framebuffer *old_fb = old_state->fb; | ||
267 | unsigned long eba, ubo, vbo, old_ubo, old_vbo; | ||
268 | |||
269 | /* Ok to disable */ | ||
270 | if (!fb) | ||
271 | return 0; | ||
272 | |||
273 | if (!state->crtc) | ||
274 | return -EINVAL; | ||
275 | |||
276 | crtc_state = | ||
277 | drm_atomic_get_existing_crtc_state(state->state, state->crtc); | ||
278 | if (WARN_ON(!crtc_state)) | ||
279 | return -EINVAL; | ||
280 | |||
281 | /* CRTC should be enabled */ | ||
282 | if (!crtc_state->enable) | ||
283 | return -EINVAL; | ||
284 | |||
285 | /* no scaling */ | ||
286 | if (state->src_w >> 16 != state->crtc_w || | ||
287 | state->src_h >> 16 != state->crtc_h) | ||
288 | return -EINVAL; | ||
289 | |||
290 | switch (plane->type) { | ||
291 | case DRM_PLANE_TYPE_PRIMARY: | ||
292 | /* full plane doesn't support partial off screen */ | ||
293 | if (state->crtc_x || state->crtc_y || | ||
294 | state->crtc_w != crtc_state->adjusted_mode.hdisplay || | ||
295 | state->crtc_h != crtc_state->adjusted_mode.vdisplay) | ||
296 | return -EINVAL; | ||
297 | |||
298 | /* full plane minimum width is 13 pixels */ | ||
299 | if (state->crtc_w < 13) | ||
300 | return -EINVAL; | ||
301 | break; | ||
302 | case DRM_PLANE_TYPE_OVERLAY: | ||
303 | if (state->crtc_x < 0 || state->crtc_y < 0) | ||
304 | return -EINVAL; | ||
305 | |||
306 | if (state->crtc_x + state->crtc_w > | ||
307 | crtc_state->adjusted_mode.hdisplay) | ||
308 | return -EINVAL; | ||
309 | if (state->crtc_y + state->crtc_h > | ||
310 | crtc_state->adjusted_mode.vdisplay) | ||
311 | return -EINVAL; | ||
312 | break; | ||
313 | default: | ||
314 | dev_warn(dev, "Unsupported plane type\n"); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | if (state->crtc_h < 2) | ||
319 | return -EINVAL; | ||
320 | |||
321 | /* | ||
322 | * since we cannot touch active IDMAC channels, we do not support | ||
323 | * resizing the enabled plane or changing its format | ||
324 | */ | ||
325 | if (old_fb && (state->src_w != old_state->src_w || | ||
326 | state->src_h != old_state->src_h || | ||
327 | fb->pixel_format != old_fb->pixel_format)) | ||
328 | return -EINVAL; | ||
329 | |||
330 | eba = drm_plane_state_to_eba(state); | ||
331 | |||
332 | if (eba & 0x7) | ||
333 | return -EINVAL; | ||
334 | |||
335 | if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) | ||
336 | return -EINVAL; | ||
337 | |||
338 | if (old_fb && fb->pitches[0] != old_fb->pitches[0]) | ||
339 | return -EINVAL; | ||
340 | |||
341 | switch (fb->pixel_format) { | ||
342 | case DRM_FORMAT_YUV420: | ||
343 | case DRM_FORMAT_YVU420: | ||
344 | /* | ||
345 | * Multiplanar formats have to meet the following restrictions: | ||
346 | * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO | ||
347 | * - EBA, UBO and VBO are a multiple of 8 | ||
348 | * - UBO and VBO are unsigned and not larger than 0xfffff8 | ||
349 | * - Only EBA may be changed while scanout is active | ||
350 | * - The strides of U and V planes must be identical. | ||
351 | */ | ||
352 | ubo = drm_plane_state_to_ubo(state); | ||
353 | vbo = drm_plane_state_to_vbo(state); | ||
354 | |||
355 | if ((ubo & 0x7) || (vbo & 0x7)) | ||
356 | return -EINVAL; | ||
357 | |||
358 | if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) | ||
359 | return -EINVAL; | ||
360 | |||
361 | if (old_fb) { | ||
362 | old_ubo = drm_plane_state_to_ubo(old_state); | ||
363 | old_vbo = drm_plane_state_to_vbo(old_state); | ||
364 | if (ubo != old_ubo || vbo != old_vbo) | ||
365 | return -EINVAL; | ||
366 | } | ||
367 | |||
368 | if (fb->pitches[1] != fb->pitches[2]) | ||
369 | return -EINVAL; | ||
370 | |||
371 | if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) | ||
372 | return -EINVAL; | ||
373 | |||
374 | if (old_fb && old_fb->pitches[1] != fb->pitches[1]) | ||
375 | return -EINVAL; | ||
376 | } | ||
450 | 377 | ||
451 | return 0; | 378 | return 0; |
452 | } | 379 | } |
453 | 380 | ||
454 | static void ipu_plane_destroy(struct drm_plane *plane) | 381 | static void ipu_plane_atomic_disable(struct drm_plane *plane, |
382 | struct drm_plane_state *old_state) | ||
383 | { | ||
384 | ipu_disable_plane(plane); | ||
385 | } | ||
386 | |||
387 | static void ipu_plane_atomic_update(struct drm_plane *plane, | ||
388 | struct drm_plane_state *old_state) | ||
455 | { | 389 | { |
456 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); | 390 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); |
391 | struct drm_plane_state *state = plane->state; | ||
392 | enum ipu_color_space ics; | ||
457 | 393 | ||
458 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 394 | if (old_state->fb) { |
395 | ipu_plane_atomic_set_base(ipu_plane, old_state); | ||
396 | return; | ||
397 | } | ||
459 | 398 | ||
460 | ipu_disable_plane(plane); | 399 | switch (ipu_plane->dp_flow) { |
461 | drm_plane_cleanup(plane); | 400 | case IPU_DP_FLOW_SYNC_BG: |
462 | kfree(ipu_plane); | 401 | ipu_dp_setup_channel(ipu_plane->dp, |
402 | IPUV3_COLORSPACE_RGB, | ||
403 | IPUV3_COLORSPACE_RGB); | ||
404 | ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true); | ||
405 | break; | ||
406 | case IPU_DP_FLOW_SYNC_FG: | ||
407 | ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format); | ||
408 | ipu_dp_setup_channel(ipu_plane->dp, ics, | ||
409 | IPUV3_COLORSPACE_UNKNOWN); | ||
410 | ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x, | ||
411 | state->crtc_y); | ||
412 | /* Enable local alpha on partial plane */ | ||
413 | switch (state->fb->pixel_format) { | ||
414 | case DRM_FORMAT_ARGB1555: | ||
415 | case DRM_FORMAT_ABGR1555: | ||
416 | case DRM_FORMAT_RGBA5551: | ||
417 | case DRM_FORMAT_BGRA5551: | ||
418 | case DRM_FORMAT_ARGB4444: | ||
419 | case DRM_FORMAT_ARGB8888: | ||
420 | case DRM_FORMAT_ABGR8888: | ||
421 | case DRM_FORMAT_RGBA8888: | ||
422 | case DRM_FORMAT_BGRA8888: | ||
423 | ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false); | ||
424 | break; | ||
425 | default: | ||
426 | break; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w); | ||
431 | |||
432 | ipu_cpmem_zero(ipu_plane->ipu_ch); | ||
433 | ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16, | ||
434 | state->src_h >> 16); | ||
435 | ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format); | ||
436 | ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); | ||
437 | ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); | ||
438 | ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]); | ||
439 | ipu_plane_atomic_set_base(ipu_plane, old_state); | ||
440 | ipu_plane_enable(ipu_plane); | ||
463 | } | 441 | } |
464 | 442 | ||
465 | static const struct drm_plane_funcs ipu_plane_funcs = { | 443 | static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { |
466 | .update_plane = ipu_update_plane, | 444 | .atomic_check = ipu_plane_atomic_check, |
467 | .disable_plane = ipu_disable_plane, | 445 | .atomic_disable = ipu_plane_atomic_disable, |
468 | .destroy = ipu_plane_destroy, | 446 | .atomic_update = ipu_plane_atomic_update, |
469 | }; | 447 | }; |
470 | 448 | ||
471 | struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, | 449 | struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, |
@@ -498,5 +476,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, | |||
498 | return ERR_PTR(ret); | 476 | return ERR_PTR(ret); |
499 | } | 477 | } |
500 | 478 | ||
479 | drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); | ||
480 | |||
501 | return ipu_plane; | 481 | return ipu_plane; |
502 | } | 482 | } |
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h index 4448fd4ad4eb..338b88a74eb6 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.h +++ b/drivers/gpu/drm/imx/ipuv3-plane.h | |||
@@ -23,17 +23,6 @@ struct ipu_plane { | |||
23 | 23 | ||
24 | int dma; | 24 | int dma; |
25 | int dp_flow; | 25 | int dp_flow; |
26 | |||
27 | int x; | ||
28 | int y; | ||
29 | int w; | ||
30 | int h; | ||
31 | |||
32 | unsigned int u_offset; | ||
33 | unsigned int v_offset; | ||
34 | unsigned int stride[2]; | ||
35 | |||
36 | bool enabled; | ||
37 | }; | 26 | }; |
38 | 27 | ||
39 | struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, | 28 | struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, |
@@ -48,11 +37,6 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, | |||
48 | uint32_t src_x, uint32_t src_y, uint32_t src_w, | 37 | uint32_t src_x, uint32_t src_y, uint32_t src_w, |
49 | uint32_t src_h, bool interlaced); | 38 | uint32_t src_h, bool interlaced); |
50 | 39 | ||
51 | void ipu_plane_enable(struct ipu_plane *plane); | ||
52 | void ipu_plane_disable(struct ipu_plane *plane); | ||
53 | int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb, | ||
54 | int x, int y); | ||
55 | |||
56 | int ipu_plane_get_resources(struct ipu_plane *plane); | 40 | int ipu_plane_get_resources(struct ipu_plane *plane); |
57 | void ipu_plane_put_resources(struct ipu_plane *plane); | 41 | void ipu_plane_put_resources(struct ipu_plane *plane); |
58 | 42 | ||
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 2d1fd02cd3d6..1dad297b01fd 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/component.h> | 16 | #include <linux/component.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <drm/drmP.h> | 18 | #include <drm/drmP.h> |
19 | #include <drm/drm_atomic_helper.h> | ||
19 | #include <drm/drm_fb_helper.h> | 20 | #include <drm/drm_fb_helper.h> |
20 | #include <drm/drm_crtc_helper.h> | 21 | #include <drm/drm_crtc_helper.h> |
21 | #include <drm/drm_panel.h> | 22 | #include <drm/drm_panel.h> |
@@ -25,9 +26,6 @@ | |||
25 | 26 | ||
26 | #include "imx-drm.h" | 27 | #include "imx-drm.h" |
27 | 28 | ||
28 | #define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector) | ||
29 | #define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder) | ||
30 | |||
31 | struct imx_parallel_display { | 29 | struct imx_parallel_display { |
32 | struct drm_connector connector; | 30 | struct drm_connector connector; |
33 | struct drm_encoder encoder; | 31 | struct drm_encoder encoder; |
@@ -37,8 +35,19 @@ struct imx_parallel_display { | |||
37 | u32 bus_format; | 35 | u32 bus_format; |
38 | struct drm_display_mode mode; | 36 | struct drm_display_mode mode; |
39 | struct drm_panel *panel; | 37 | struct drm_panel *panel; |
38 | struct drm_bridge *bridge; | ||
40 | }; | 39 | }; |
41 | 40 | ||
41 | static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c) | ||
42 | { | ||
43 | return container_of(c, struct imx_parallel_display, connector); | ||
44 | } | ||
45 | |||
46 | static inline struct imx_parallel_display *enc_to_imxpd(struct drm_encoder *e) | ||
47 | { | ||
48 | return container_of(e, struct imx_parallel_display, encoder); | ||
49 | } | ||
50 | |||
42 | static enum drm_connector_status imx_pd_connector_detect( | 51 | static enum drm_connector_status imx_pd_connector_detect( |
43 | struct drm_connector *connector, bool force) | 52 | struct drm_connector *connector, bool force) |
44 | { | 53 | { |
@@ -53,11 +62,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) | |||
53 | 62 | ||
54 | if (imxpd->panel && imxpd->panel->funcs && | 63 | if (imxpd->panel && imxpd->panel->funcs && |
55 | imxpd->panel->funcs->get_modes) { | 64 | imxpd->panel->funcs->get_modes) { |
56 | struct drm_display_info *di = &connector->display_info; | ||
57 | |||
58 | num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); | 65 | num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); |
59 | if (!imxpd->bus_format && di->num_bus_formats) | ||
60 | imxpd->bus_format = di->bus_formats[0]; | ||
61 | if (num_modes > 0) | 66 | if (num_modes > 0) |
62 | return num_modes; | 67 | return num_modes; |
63 | } | 68 | } |
@@ -69,10 +74,16 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) | |||
69 | 74 | ||
70 | if (np) { | 75 | if (np) { |
71 | struct drm_display_mode *mode = drm_mode_create(connector->dev); | 76 | struct drm_display_mode *mode = drm_mode_create(connector->dev); |
77 | int ret; | ||
72 | 78 | ||
73 | if (!mode) | 79 | if (!mode) |
74 | return -EINVAL; | 80 | return -EINVAL; |
75 | of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE); | 81 | |
82 | ret = of_get_drm_display_mode(np, &imxpd->mode, | ||
83 | OF_USE_NATIVE_MODE); | ||
84 | if (ret) | ||
85 | return ret; | ||
86 | |||
76 | drm_mode_copy(mode, &imxpd->mode); | 87 | drm_mode_copy(mode, &imxpd->mode); |
77 | mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, | 88 | mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, |
78 | drm_mode_probed_add(connector, mode); | 89 | drm_mode_probed_add(connector, mode); |
@@ -90,24 +101,7 @@ static struct drm_encoder *imx_pd_connector_best_encoder( | |||
90 | return &imxpd->encoder; | 101 | return &imxpd->encoder; |
91 | } | 102 | } |
92 | 103 | ||
93 | static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode) | 104 | static void imx_pd_encoder_enable(struct drm_encoder *encoder) |
94 | { | ||
95 | struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); | ||
96 | |||
97 | if (mode != DRM_MODE_DPMS_ON) | ||
98 | drm_panel_disable(imxpd->panel); | ||
99 | else | ||
100 | drm_panel_enable(imxpd->panel); | ||
101 | } | ||
102 | |||
103 | static void imx_pd_encoder_prepare(struct drm_encoder *encoder) | ||
104 | { | ||
105 | struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); | ||
106 | imx_drm_set_bus_config(encoder, imxpd->bus_format, 2, 3, | ||
107 | imxpd->connector.display_info.bus_flags); | ||
108 | } | ||
109 | |||
110 | static void imx_pd_encoder_commit(struct drm_encoder *encoder) | ||
111 | { | 105 | { |
112 | struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); | 106 | struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); |
113 | 107 | ||
@@ -115,12 +109,6 @@ static void imx_pd_encoder_commit(struct drm_encoder *encoder) | |||
115 | drm_panel_enable(imxpd->panel); | 109 | drm_panel_enable(imxpd->panel); |
116 | } | 110 | } |
117 | 111 | ||
118 | static void imx_pd_encoder_mode_set(struct drm_encoder *encoder, | ||
119 | struct drm_display_mode *orig_mode, | ||
120 | struct drm_display_mode *mode) | ||
121 | { | ||
122 | } | ||
123 | |||
124 | static void imx_pd_encoder_disable(struct drm_encoder *encoder) | 112 | static void imx_pd_encoder_disable(struct drm_encoder *encoder) |
125 | { | 113 | { |
126 | struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); | 114 | struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); |
@@ -129,11 +117,33 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder) | |||
129 | drm_panel_unprepare(imxpd->panel); | 117 | drm_panel_unprepare(imxpd->panel); |
130 | } | 118 | } |
131 | 119 | ||
120 | static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder, | ||
121 | struct drm_crtc_state *crtc_state, | ||
122 | struct drm_connector_state *conn_state) | ||
123 | { | ||
124 | struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); | ||
125 | struct drm_display_info *di = &conn_state->connector->display_info; | ||
126 | struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); | ||
127 | |||
128 | imx_crtc_state->bus_flags = di->bus_flags; | ||
129 | if (!imxpd->bus_format && di->num_bus_formats) | ||
130 | imx_crtc_state->bus_format = di->bus_formats[0]; | ||
131 | else | ||
132 | imx_crtc_state->bus_format = imxpd->bus_format; | ||
133 | imx_crtc_state->di_hsync_pin = 2; | ||
134 | imx_crtc_state->di_vsync_pin = 3; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
132 | static const struct drm_connector_funcs imx_pd_connector_funcs = { | 139 | static const struct drm_connector_funcs imx_pd_connector_funcs = { |
133 | .dpms = drm_helper_connector_dpms, | 140 | .dpms = drm_atomic_helper_connector_dpms, |
134 | .fill_modes = drm_helper_probe_single_connector_modes, | 141 | .fill_modes = drm_helper_probe_single_connector_modes, |
135 | .detect = imx_pd_connector_detect, | 142 | .detect = imx_pd_connector_detect, |
136 | .destroy = imx_drm_connector_destroy, | 143 | .destroy = imx_drm_connector_destroy, |
144 | .reset = drm_atomic_helper_connector_reset, | ||
145 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
146 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
137 | }; | 147 | }; |
138 | 148 | ||
139 | static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = { | 149 | static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = { |
@@ -146,20 +156,18 @@ static const struct drm_encoder_funcs imx_pd_encoder_funcs = { | |||
146 | }; | 156 | }; |
147 | 157 | ||
148 | static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { | 158 | static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { |
149 | .dpms = imx_pd_encoder_dpms, | 159 | .enable = imx_pd_encoder_enable, |
150 | .prepare = imx_pd_encoder_prepare, | ||
151 | .commit = imx_pd_encoder_commit, | ||
152 | .mode_set = imx_pd_encoder_mode_set, | ||
153 | .disable = imx_pd_encoder_disable, | 160 | .disable = imx_pd_encoder_disable, |
161 | .atomic_check = imx_pd_encoder_atomic_check, | ||
154 | }; | 162 | }; |
155 | 163 | ||
156 | static int imx_pd_register(struct drm_device *drm, | 164 | static int imx_pd_register(struct drm_device *drm, |
157 | struct imx_parallel_display *imxpd) | 165 | struct imx_parallel_display *imxpd) |
158 | { | 166 | { |
167 | struct drm_encoder *encoder = &imxpd->encoder; | ||
159 | int ret; | 168 | int ret; |
160 | 169 | ||
161 | ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder, | 170 | ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node); |
162 | imxpd->dev->of_node); | ||
163 | if (ret) | 171 | if (ret) |
164 | return ret; | 172 | return ret; |
165 | 173 | ||
@@ -170,19 +178,33 @@ static int imx_pd_register(struct drm_device *drm, | |||
170 | */ | 178 | */ |
171 | imxpd->connector.dpms = DRM_MODE_DPMS_OFF; | 179 | imxpd->connector.dpms = DRM_MODE_DPMS_OFF; |
172 | 180 | ||
173 | drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs); | 181 | drm_encoder_helper_add(encoder, &imx_pd_encoder_helper_funcs); |
174 | drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs, | 182 | drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs, |
175 | DRM_MODE_ENCODER_NONE, NULL); | 183 | DRM_MODE_ENCODER_NONE, NULL); |
176 | 184 | ||
177 | drm_connector_helper_add(&imxpd->connector, | 185 | if (!imxpd->bridge) { |
178 | &imx_pd_connector_helper_funcs); | 186 | drm_connector_helper_add(&imxpd->connector, |
179 | drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs, | 187 | &imx_pd_connector_helper_funcs); |
180 | DRM_MODE_CONNECTOR_VGA); | 188 | drm_connector_init(drm, &imxpd->connector, |
189 | &imx_pd_connector_funcs, | ||
190 | DRM_MODE_CONNECTOR_VGA); | ||
191 | } | ||
181 | 192 | ||
182 | if (imxpd->panel) | 193 | if (imxpd->panel) |
183 | drm_panel_attach(imxpd->panel, &imxpd->connector); | 194 | drm_panel_attach(imxpd->panel, &imxpd->connector); |
184 | 195 | ||
185 | drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder); | 196 | if (imxpd->bridge) { |
197 | imxpd->bridge->encoder = encoder; | ||
198 | encoder->bridge = imxpd->bridge; | ||
199 | ret = drm_bridge_attach(drm, imxpd->bridge); | ||
200 | if (ret < 0) { | ||
201 | dev_err(imxpd->dev, "failed to attach bridge: %d\n", | ||
202 | ret); | ||
203 | return ret; | ||
204 | } | ||
205 | } else { | ||
206 | drm_mode_connector_attach_encoder(&imxpd->connector, encoder); | ||
207 | } | ||
186 | 208 | ||
187 | return 0; | 209 | return 0; |
188 | } | 210 | } |
@@ -195,6 +217,7 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) | |||
195 | const u8 *edidp; | 217 | const u8 *edidp; |
196 | struct imx_parallel_display *imxpd; | 218 | struct imx_parallel_display *imxpd; |
197 | int ret; | 219 | int ret; |
220 | u32 bus_format = 0; | ||
198 | const char *fmt; | 221 | const char *fmt; |
199 | 222 | ||
200 | imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL); | 223 | imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL); |
@@ -208,14 +231,15 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) | |||
208 | ret = of_property_read_string(np, "interface-pix-fmt", &fmt); | 231 | ret = of_property_read_string(np, "interface-pix-fmt", &fmt); |
209 | if (!ret) { | 232 | if (!ret) { |
210 | if (!strcmp(fmt, "rgb24")) | 233 | if (!strcmp(fmt, "rgb24")) |
211 | imxpd->bus_format = MEDIA_BUS_FMT_RGB888_1X24; | 234 | bus_format = MEDIA_BUS_FMT_RGB888_1X24; |
212 | else if (!strcmp(fmt, "rgb565")) | 235 | else if (!strcmp(fmt, "rgb565")) |
213 | imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16; | 236 | bus_format = MEDIA_BUS_FMT_RGB565_1X16; |
214 | else if (!strcmp(fmt, "bgr666")) | 237 | else if (!strcmp(fmt, "bgr666")) |
215 | imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18; | 238 | bus_format = MEDIA_BUS_FMT_RGB666_1X18; |
216 | else if (!strcmp(fmt, "lvds666")) | 239 | else if (!strcmp(fmt, "lvds666")) |
217 | imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; | 240 | bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; |
218 | } | 241 | } |
242 | imxpd->bus_format = bus_format; | ||
219 | 243 | ||
220 | /* port@1 is the output port */ | 244 | /* port@1 is the output port */ |
221 | ep = of_graph_get_endpoint_by_regs(np, 1, -1); | 245 | ep = of_graph_get_endpoint_by_regs(np, 1, -1); |
@@ -223,13 +247,30 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) | |||
223 | struct device_node *remote; | 247 | struct device_node *remote; |
224 | 248 | ||
225 | remote = of_graph_get_remote_port_parent(ep); | 249 | remote = of_graph_get_remote_port_parent(ep); |
250 | if (!remote) { | ||
251 | dev_warn(dev, "endpoint %s not connected\n", | ||
252 | ep->full_name); | ||
253 | of_node_put(ep); | ||
254 | return -ENODEV; | ||
255 | } | ||
226 | of_node_put(ep); | 256 | of_node_put(ep); |
227 | if (remote) { | 257 | |
228 | imxpd->panel = of_drm_find_panel(remote); | 258 | imxpd->panel = of_drm_find_panel(remote); |
229 | of_node_put(remote); | 259 | if (imxpd->panel) { |
260 | dev_dbg(dev, "found panel %s\n", remote->full_name); | ||
261 | } else { | ||
262 | imxpd->bridge = of_drm_find_bridge(remote); | ||
263 | if (imxpd->bridge) | ||
264 | dev_dbg(dev, "found bridge %s\n", | ||
265 | remote->full_name); | ||
230 | } | 266 | } |
231 | if (!imxpd->panel) | 267 | if (!imxpd->panel && !imxpd->bridge) { |
268 | dev_dbg(dev, "waiting for panel or bridge %s\n", | ||
269 | remote->full_name); | ||
270 | of_node_put(remote); | ||
232 | return -EPROBE_DEFER; | 271 | return -EPROBE_DEFER; |
272 | } | ||
273 | of_node_put(remote); | ||
233 | } | 274 | } |
234 | 275 | ||
235 | imxpd->dev = dev; | 276 | imxpd->dev = dev; |
diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 2f29780e7c68..659475c1e44a 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c | |||
@@ -150,6 +150,9 @@ static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand, | |||
150 | static int ipu_bus_format_to_map(u32 fmt) | 150 | static int ipu_bus_format_to_map(u32 fmt) |
151 | { | 151 | { |
152 | switch (fmt) { | 152 | switch (fmt) { |
153 | default: | ||
154 | WARN_ON(1); | ||
155 | /* fall-through */ | ||
153 | case MEDIA_BUS_FMT_RGB888_1X24: | 156 | case MEDIA_BUS_FMT_RGB888_1X24: |
154 | return IPU_DC_MAP_RGB24; | 157 | return IPU_DC_MAP_RGB24; |
155 | case MEDIA_BUS_FMT_RGB565_1X16: | 158 | case MEDIA_BUS_FMT_RGB565_1X16: |
@@ -162,8 +165,6 @@ static int ipu_bus_format_to_map(u32 fmt) | |||
162 | return IPU_DC_MAP_LVDS666; | 165 | return IPU_DC_MAP_LVDS666; |
163 | case MEDIA_BUS_FMT_BGR888_1X24: | 166 | case MEDIA_BUS_FMT_BGR888_1X24: |
164 | return IPU_DC_MAP_BGR24; | 167 | return IPU_DC_MAP_BGR24; |
165 | default: | ||
166 | return -EINVAL; | ||
167 | } | 168 | } |
168 | } | 169 | } |
169 | 170 | ||
@@ -178,10 +179,6 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, | |||
178 | dc->di = ipu_di_get_num(di); | 179 | dc->di = ipu_di_get_num(di); |
179 | 180 | ||
180 | map = ipu_bus_format_to_map(bus_format); | 181 | map = ipu_bus_format_to_map(bus_format); |
181 | if (map < 0) { | ||
182 | dev_dbg(priv->dev, "IPU_DISP: No MAP\n"); | ||
183 | return map; | ||
184 | } | ||
185 | 182 | ||
186 | /* | 183 | /* |
187 | * In interlaced mode we need more counters to create the asymmetric | 184 | * In interlaced mode we need more counters to create the asymmetric |
diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index 359268e3a166..a8d87ddd8a17 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c | |||
@@ -572,9 +572,6 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) | |||
572 | dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n", | 572 | dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n", |
573 | di->id, sig->mode.hactive, sig->mode.vactive); | 573 | di->id, sig->mode.hactive, sig->mode.vactive); |
574 | 574 | ||
575 | if ((sig->mode.vsync_len == 0) || (sig->mode.hsync_len == 0)) | ||
576 | return -EINVAL; | ||
577 | |||
578 | dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n", | 575 | dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n", |
579 | clk_get_rate(di->clk_ipu), | 576 | clk_get_rate(di->clk_ipu), |
580 | clk_get_rate(di->clk_di), | 577 | clk_get_rate(di->clk_di), |
diff --git a/drivers/gpu/ipu-v3/ipu-dmfc.c b/drivers/gpu/ipu-v3/ipu-dmfc.c index 837b1ec22800..42705bb5aaa3 100644 --- a/drivers/gpu/ipu-v3/ipu-dmfc.c +++ b/drivers/gpu/ipu-v3/ipu-dmfc.c | |||
@@ -45,17 +45,6 @@ | |||
45 | #define DMFC_DP_CHAN_6B_24 16 | 45 | #define DMFC_DP_CHAN_6B_24 16 |
46 | #define DMFC_DP_CHAN_6F_29 24 | 46 | #define DMFC_DP_CHAN_6F_29 24 |
47 | 47 | ||
48 | #define DMFC_FIFO_SIZE_64 (3 << 3) | ||
49 | #define DMFC_FIFO_SIZE_128 (2 << 3) | ||
50 | #define DMFC_FIFO_SIZE_256 (1 << 3) | ||
51 | #define DMFC_FIFO_SIZE_512 (0 << 3) | ||
52 | |||
53 | #define DMFC_SEGMENT(x) ((x & 0x7) << 0) | ||
54 | #define DMFC_BURSTSIZE_128 (0 << 6) | ||
55 | #define DMFC_BURSTSIZE_64 (1 << 6) | ||
56 | #define DMFC_BURSTSIZE_32 (2 << 6) | ||
57 | #define DMFC_BURSTSIZE_16 (3 << 6) | ||
58 | |||
59 | struct dmfc_channel_data { | 48 | struct dmfc_channel_data { |
60 | int ipu_channel; | 49 | int ipu_channel; |
61 | unsigned long channel_reg; | 50 | unsigned long channel_reg; |
@@ -104,9 +93,6 @@ struct ipu_dmfc_priv; | |||
104 | 93 | ||
105 | struct dmfc_channel { | 94 | struct dmfc_channel { |
106 | unsigned slots; | 95 | unsigned slots; |
107 | unsigned slotmask; | ||
108 | unsigned segment; | ||
109 | int burstsize; | ||
110 | struct ipu_soc *ipu; | 96 | struct ipu_soc *ipu; |
111 | struct ipu_dmfc_priv *priv; | 97 | struct ipu_dmfc_priv *priv; |
112 | const struct dmfc_channel_data *data; | 98 | const struct dmfc_channel_data *data; |
@@ -117,7 +103,6 @@ struct ipu_dmfc_priv { | |||
117 | struct device *dev; | 103 | struct device *dev; |
118 | struct dmfc_channel channels[DMFC_NUM_CHANNELS]; | 104 | struct dmfc_channel channels[DMFC_NUM_CHANNELS]; |
119 | struct mutex mutex; | 105 | struct mutex mutex; |
120 | unsigned long bandwidth_per_slot; | ||
121 | void __iomem *base; | 106 | void __iomem *base; |
122 | int use_count; | 107 | int use_count; |
123 | }; | 108 | }; |
@@ -172,184 +157,6 @@ void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) | |||
172 | } | 157 | } |
173 | EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel); | 158 | EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel); |
174 | 159 | ||
175 | static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, | ||
176 | int segment, int burstsize) | ||
177 | { | ||
178 | struct ipu_dmfc_priv *priv = dmfc->priv; | ||
179 | u32 val, field; | ||
180 | |||
181 | dev_dbg(priv->dev, | ||
182 | "dmfc: using %d slots starting from segment %d for IPU channel %d\n", | ||
183 | slots, segment, dmfc->data->ipu_channel); | ||
184 | |||
185 | switch (slots) { | ||
186 | case 1: | ||
187 | field = DMFC_FIFO_SIZE_64; | ||
188 | break; | ||
189 | case 2: | ||
190 | field = DMFC_FIFO_SIZE_128; | ||
191 | break; | ||
192 | case 4: | ||
193 | field = DMFC_FIFO_SIZE_256; | ||
194 | break; | ||
195 | case 8: | ||
196 | field = DMFC_FIFO_SIZE_512; | ||
197 | break; | ||
198 | default: | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | switch (burstsize) { | ||
203 | case 16: | ||
204 | field |= DMFC_BURSTSIZE_16; | ||
205 | break; | ||
206 | case 32: | ||
207 | field |= DMFC_BURSTSIZE_32; | ||
208 | break; | ||
209 | case 64: | ||
210 | field |= DMFC_BURSTSIZE_64; | ||
211 | break; | ||
212 | case 128: | ||
213 | field |= DMFC_BURSTSIZE_128; | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | field |= DMFC_SEGMENT(segment); | ||
218 | |||
219 | val = readl(priv->base + dmfc->data->channel_reg); | ||
220 | |||
221 | val &= ~(0xff << dmfc->data->shift); | ||
222 | val |= field << dmfc->data->shift; | ||
223 | |||
224 | writel(val, priv->base + dmfc->data->channel_reg); | ||
225 | |||
226 | dmfc->slots = slots; | ||
227 | dmfc->segment = segment; | ||
228 | dmfc->burstsize = burstsize; | ||
229 | dmfc->slotmask = ((1 << slots) - 1) << segment; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv, | ||
235 | unsigned long bandwidth) | ||
236 | { | ||
237 | int slots = 1; | ||
238 | |||
239 | while (slots * priv->bandwidth_per_slot < bandwidth) | ||
240 | slots *= 2; | ||
241 | |||
242 | return slots; | ||
243 | } | ||
244 | |||
245 | static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots) | ||
246 | { | ||
247 | unsigned slotmask_need, slotmask_used = 0; | ||
248 | int i, segment = 0; | ||
249 | |||
250 | slotmask_need = (1 << slots) - 1; | ||
251 | |||
252 | for (i = 0; i < DMFC_NUM_CHANNELS; i++) | ||
253 | slotmask_used |= priv->channels[i].slotmask; | ||
254 | |||
255 | while (slotmask_need <= 0xff) { | ||
256 | if (!(slotmask_used & slotmask_need)) | ||
257 | return segment; | ||
258 | |||
259 | slotmask_need <<= 1; | ||
260 | segment++; | ||
261 | } | ||
262 | |||
263 | return -EBUSY; | ||
264 | } | ||
265 | |||
266 | void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc) | ||
267 | { | ||
268 | struct ipu_dmfc_priv *priv = dmfc->priv; | ||
269 | int i; | ||
270 | |||
271 | dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n", | ||
272 | dmfc->slots, dmfc->segment); | ||
273 | |||
274 | mutex_lock(&priv->mutex); | ||
275 | |||
276 | if (!dmfc->slots) | ||
277 | goto out; | ||
278 | |||
279 | dmfc->slotmask = 0; | ||
280 | dmfc->slots = 0; | ||
281 | dmfc->segment = 0; | ||
282 | |||
283 | for (i = 0; i < DMFC_NUM_CHANNELS; i++) | ||
284 | priv->channels[i].slotmask = 0; | ||
285 | |||
286 | for (i = 0; i < DMFC_NUM_CHANNELS; i++) { | ||
287 | if (priv->channels[i].slots > 0) { | ||
288 | priv->channels[i].segment = | ||
289 | dmfc_find_slots(priv, priv->channels[i].slots); | ||
290 | priv->channels[i].slotmask = | ||
291 | ((1 << priv->channels[i].slots) - 1) << | ||
292 | priv->channels[i].segment; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | for (i = 0; i < DMFC_NUM_CHANNELS; i++) { | ||
297 | if (priv->channels[i].slots > 0) | ||
298 | ipu_dmfc_setup_channel(&priv->channels[i], | ||
299 | priv->channels[i].slots, | ||
300 | priv->channels[i].segment, | ||
301 | priv->channels[i].burstsize); | ||
302 | } | ||
303 | out: | ||
304 | mutex_unlock(&priv->mutex); | ||
305 | } | ||
306 | EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth); | ||
307 | |||
308 | int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, | ||
309 | unsigned long bandwidth_pixel_per_second, int burstsize) | ||
310 | { | ||
311 | struct ipu_dmfc_priv *priv = dmfc->priv; | ||
312 | int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second); | ||
313 | int segment = -1, ret = 0; | ||
314 | |||
315 | dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n", | ||
316 | bandwidth_pixel_per_second / 1000000, | ||
317 | dmfc->data->ipu_channel); | ||
318 | |||
319 | ipu_dmfc_free_bandwidth(dmfc); | ||
320 | |||
321 | mutex_lock(&priv->mutex); | ||
322 | |||
323 | if (slots > 8) { | ||
324 | ret = -EBUSY; | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | /* For the MEM_BG channel, first try to allocate twice the slots */ | ||
329 | if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC) | ||
330 | segment = dmfc_find_slots(priv, slots * 2); | ||
331 | else if (slots < 2) | ||
332 | /* Always allocate at least 128*4 bytes (2 slots) */ | ||
333 | slots = 2; | ||
334 | |||
335 | if (segment >= 0) | ||
336 | slots *= 2; | ||
337 | else | ||
338 | segment = dmfc_find_slots(priv, slots); | ||
339 | if (segment < 0) { | ||
340 | ret = -EBUSY; | ||
341 | goto out; | ||
342 | } | ||
343 | |||
344 | ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize); | ||
345 | |||
346 | out: | ||
347 | mutex_unlock(&priv->mutex); | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth); | ||
352 | |||
353 | void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width) | 160 | void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width) |
354 | { | 161 | { |
355 | struct ipu_dmfc_priv *priv = dmfc->priv; | 162 | struct ipu_dmfc_priv *priv = dmfc->priv; |
@@ -384,7 +191,6 @@ EXPORT_SYMBOL_GPL(ipu_dmfc_get); | |||
384 | 191 | ||
385 | void ipu_dmfc_put(struct dmfc_channel *dmfc) | 192 | void ipu_dmfc_put(struct dmfc_channel *dmfc) |
386 | { | 193 | { |
387 | ipu_dmfc_free_bandwidth(dmfc); | ||
388 | } | 194 | } |
389 | EXPORT_SYMBOL_GPL(ipu_dmfc_put); | 195 | EXPORT_SYMBOL_GPL(ipu_dmfc_put); |
390 | 196 | ||
@@ -412,20 +218,15 @@ int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, | |||
412 | priv->channels[i].priv = priv; | 218 | priv->channels[i].priv = priv; |
413 | priv->channels[i].ipu = ipu; | 219 | priv->channels[i].ipu = ipu; |
414 | priv->channels[i].data = &dmfcdata[i]; | 220 | priv->channels[i].data = &dmfcdata[i]; |
415 | } | ||
416 | |||
417 | writel(0x0, priv->base + DMFC_WR_CHAN); | ||
418 | writel(0x0, priv->base + DMFC_DP_CHAN); | ||
419 | 221 | ||
420 | /* | 222 | if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC || |
421 | * We have a total bandwidth of clkrate * 4pixel divided | 223 | dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC || |
422 | * into 8 slots. | 224 | dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC) |
423 | */ | 225 | priv->channels[i].slots = 2; |
424 | priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8; | 226 | } |
425 | |||
426 | dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n", | ||
427 | priv->bandwidth_per_slot / 1000000); | ||
428 | 227 | ||
228 | writel(0x00000050, priv->base + DMFC_WR_CHAN); | ||
229 | writel(0x00005654, priv->base + DMFC_DP_CHAN); | ||
429 | writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF); | 230 | writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF); |
430 | writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF); | 231 | writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF); |
431 | writel(0x00000003, priv->base + DMFC_GENERAL1); | 232 | writel(0x00000003, priv->base + DMFC_GENERAL1); |