2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
12 #include <drm/drm_atomic.h>
13 #include <drm/drm_atomic_helper.h>
14 #include <drm/drm_crtc_helper.h>
15 #include <drm/drm_plane_helper.h>
17 #include "sti_compositor.h"
18 #include "sti_drm_drv.h"
19 #include "sti_drm_crtc.h"
22 static void sti_drm_crtc_dpms(struct drm_crtc
*crtc
, int mode
)
27 static void sti_drm_crtc_prepare(struct drm_crtc
*crtc
)
29 struct sti_mixer
*mixer
= to_sti_mixer(crtc
);
30 struct device
*dev
= mixer
->dev
;
31 struct sti_compositor
*compo
= dev_get_drvdata(dev
);
33 mixer
->enabled
= true;
35 /* Prepare and enable the compo IP clock */
36 if (mixer
->id
== STI_MIXER_MAIN
) {
37 if (clk_prepare_enable(compo
->clk_compo_main
))
38 DRM_INFO("Failed to prepare/enable compo_main clk\n");
40 if (clk_prepare_enable(compo
->clk_compo_aux
))
41 DRM_INFO("Failed to prepare/enable compo_aux clk\n");
44 sti_mixer_clear_all_layers(mixer
);
47 static void sti_drm_crtc_commit(struct drm_crtc
*crtc
)
49 struct sti_mixer
*mixer
= to_sti_mixer(crtc
);
50 struct device
*dev
= mixer
->dev
;
51 struct sti_compositor
*compo
= dev_get_drvdata(dev
);
52 struct sti_layer
*layer
;
54 if ((!mixer
|| !compo
)) {
55 DRM_ERROR("Can not find mixer or compositor)\n");
59 /* get GDP which is reserved to the CRTC FB */
60 layer
= to_sti_layer(crtc
->primary
);
62 sti_layer_commit(layer
);
64 DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n");
66 /* Enable layer on mixer */
67 if (sti_mixer_set_layer_status(mixer
, layer
, true))
68 DRM_ERROR("Can not enable layer at mixer\n");
70 drm_crtc_vblank_on(crtc
);
73 static bool sti_drm_crtc_mode_fixup(struct drm_crtc
*crtc
,
74 const struct drm_display_mode
*mode
,
75 struct drm_display_mode
*adjusted_mode
)
77 /* accept the provided drm_display_mode, do not fix it up */
82 sti_drm_crtc_mode_set(struct drm_crtc
*crtc
, struct drm_display_mode
*mode
)
84 struct sti_mixer
*mixer
= to_sti_mixer(crtc
);
85 struct device
*dev
= mixer
->dev
;
86 struct sti_compositor
*compo
= dev_get_drvdata(dev
);
88 int rate
= mode
->clock
* 1000;
91 DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n",
92 crtc
->base
.id
, sti_mixer_to_str(mixer
),
93 mode
->base
.id
, mode
->name
);
95 DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
96 mode
->vrefresh
, mode
->clock
,
98 mode
->hsync_start
, mode
->hsync_end
,
101 mode
->vsync_start
, mode
->vsync_end
,
102 mode
->vtotal
, mode
->type
, mode
->flags
);
104 /* Set rate and prepare/enable pixel clock */
105 if (mixer
->id
== STI_MIXER_MAIN
)
106 clk
= compo
->clk_pix_main
;
108 clk
= compo
->clk_pix_aux
;
110 res
= clk_set_rate(clk
, rate
);
112 DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate
);
115 if (clk_prepare_enable(clk
)) {
116 DRM_ERROR("Failed to prepare/enable pix clk\n");
120 sti_vtg_set_config(mixer
->id
== STI_MIXER_MAIN
?
121 compo
->vtg_main
: compo
->vtg_aux
, &crtc
->mode
);
123 res
= sti_mixer_active_video_area(mixer
, &crtc
->mode
);
125 DRM_ERROR("Can not set active video area\n");
132 static void sti_drm_crtc_disable(struct drm_crtc
*crtc
)
134 struct sti_mixer
*mixer
= to_sti_mixer(crtc
);
135 struct device
*dev
= mixer
->dev
;
136 struct sti_compositor
*compo
= dev_get_drvdata(dev
);
141 DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc
->base
.id
, sti_mixer_to_str(mixer
));
143 /* Disable Background */
144 sti_mixer_set_background_status(mixer
, false);
146 drm_crtc_vblank_off(crtc
);
148 /* Disable pixel clock and compo IP clocks */
149 if (mixer
->id
== STI_MIXER_MAIN
) {
150 clk_disable_unprepare(compo
->clk_pix_main
);
151 clk_disable_unprepare(compo
->clk_compo_main
);
153 clk_disable_unprepare(compo
->clk_pix_aux
);
154 clk_disable_unprepare(compo
->clk_compo_aux
);
157 mixer
->enabled
= false;
161 sti_drm_crtc_mode_set_nofb(struct drm_crtc
*crtc
)
163 sti_drm_crtc_prepare(crtc
);
164 sti_drm_crtc_mode_set(crtc
, &crtc
->state
->adjusted_mode
);
167 static void sti_drm_atomic_begin(struct drm_crtc
*crtc
)
169 struct sti_mixer
*mixer
= to_sti_mixer(crtc
);
171 if (crtc
->state
->event
) {
172 crtc
->state
->event
->pipe
= drm_crtc_index(crtc
);
174 WARN_ON(drm_crtc_vblank_get(crtc
) != 0);
176 mixer
->pending_event
= crtc
->state
->event
;
177 crtc
->state
->event
= NULL
;
181 static void sti_drm_atomic_flush(struct drm_crtc
*crtc
)
185 static struct drm_crtc_helper_funcs sti_crtc_helper_funcs
= {
186 .dpms
= sti_drm_crtc_dpms
,
187 .prepare
= sti_drm_crtc_prepare
,
188 .commit
= sti_drm_crtc_commit
,
189 .mode_fixup
= sti_drm_crtc_mode_fixup
,
190 .mode_set
= drm_helper_crtc_mode_set
,
191 .mode_set_nofb
= sti_drm_crtc_mode_set_nofb
,
192 .mode_set_base
= drm_helper_crtc_mode_set_base
,
193 .disable
= sti_drm_crtc_disable
,
194 .atomic_begin
= sti_drm_atomic_begin
,
195 .atomic_flush
= sti_drm_atomic_flush
,
198 static void sti_drm_crtc_destroy(struct drm_crtc
*crtc
)
201 drm_crtc_cleanup(crtc
);
204 static int sti_drm_crtc_set_property(struct drm_crtc
*crtc
,
205 struct drm_property
*property
,
212 int sti_drm_crtc_vblank_cb(struct notifier_block
*nb
,
213 unsigned long event
, void *data
)
215 struct drm_device
*drm_dev
;
216 struct sti_compositor
*compo
=
217 container_of(nb
, struct sti_compositor
, vtg_vblank_nb
);
220 struct sti_drm_private
*priv
;
222 drm_dev
= compo
->mixer
[*crtc
]->drm_crtc
.dev
;
223 priv
= drm_dev
->dev_private
;
225 if ((event
!= VTG_TOP_FIELD_EVENT
) &&
226 (event
!= VTG_BOTTOM_FIELD_EVENT
)) {
227 DRM_ERROR("unknown event: %lu\n", event
);
231 drm_handle_vblank(drm_dev
, *crtc
);
233 spin_lock_irqsave(&drm_dev
->event_lock
, flags
);
234 if (compo
->mixer
[*crtc
]->pending_event
) {
235 drm_send_vblank_event(drm_dev
, -1,
236 compo
->mixer
[*crtc
]->pending_event
);
237 drm_vblank_put(drm_dev
, *crtc
);
238 compo
->mixer
[*crtc
]->pending_event
= NULL
;
240 spin_unlock_irqrestore(&drm_dev
->event_lock
, flags
);
245 int sti_drm_crtc_enable_vblank(struct drm_device
*dev
, int crtc
)
247 struct sti_drm_private
*dev_priv
= dev
->dev_private
;
248 struct sti_compositor
*compo
= dev_priv
->compo
;
249 struct notifier_block
*vtg_vblank_nb
= &compo
->vtg_vblank_nb
;
251 if (sti_vtg_register_client(crtc
== STI_MIXER_MAIN
?
252 compo
->vtg_main
: compo
->vtg_aux
,
253 vtg_vblank_nb
, crtc
)) {
254 DRM_ERROR("Cannot register VTG notifier\n");
260 EXPORT_SYMBOL(sti_drm_crtc_enable_vblank
);
262 void sti_drm_crtc_disable_vblank(struct drm_device
*dev
, int crtc
)
264 struct sti_drm_private
*priv
= dev
->dev_private
;
265 struct sti_compositor
*compo
= priv
->compo
;
266 struct notifier_block
*vtg_vblank_nb
= &compo
->vtg_vblank_nb
;
268 DRM_DEBUG_DRIVER("\n");
270 if (sti_vtg_unregister_client(crtc
== STI_MIXER_MAIN
?
271 compo
->vtg_main
: compo
->vtg_aux
, vtg_vblank_nb
))
272 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
274 /* free the resources of the pending requests */
275 if (compo
->mixer
[crtc
]->pending_event
) {
276 drm_vblank_put(dev
, crtc
);
277 compo
->mixer
[crtc
]->pending_event
= NULL
;
280 EXPORT_SYMBOL(sti_drm_crtc_disable_vblank
);
282 static struct drm_crtc_funcs sti_crtc_funcs
= {
283 .set_config
= drm_atomic_helper_set_config
,
284 .page_flip
= drm_atomic_helper_page_flip
,
285 .destroy
= sti_drm_crtc_destroy
,
286 .set_property
= sti_drm_crtc_set_property
,
287 .reset
= drm_atomic_helper_crtc_reset
,
288 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
289 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
292 bool sti_drm_crtc_is_main(struct drm_crtc
*crtc
)
294 struct sti_mixer
*mixer
= to_sti_mixer(crtc
);
296 if (mixer
->id
== STI_MIXER_MAIN
)
301 EXPORT_SYMBOL(sti_drm_crtc_is_main
);
303 int sti_drm_crtc_init(struct drm_device
*drm_dev
, struct sti_mixer
*mixer
,
304 struct drm_plane
*primary
, struct drm_plane
*cursor
)
306 struct drm_crtc
*crtc
= &mixer
->drm_crtc
;
309 res
= drm_crtc_init_with_planes(drm_dev
, crtc
, primary
, cursor
,
312 DRM_ERROR("Can not initialze CRTC\n");
316 drm_crtc_helper_add(crtc
, &sti_crtc_helper_funcs
);
318 DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
319 crtc
->base
.id
, sti_mixer_to_str(mixer
));