Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) STMicroelectronics SA 2014
  4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
  5 *          Fabien Dessenne <fabien.dessenne@st.com>
  6 *          for STMicroelectronics.
  7 */
  8
  9#include <linux/clk.h>
 10
 11#include <drm/drmP.h>
 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>
 16
 17#include "sti_compositor.h"
 18#include "sti_crtc.h"
 19#include "sti_drv.h"
 20#include "sti_vid.h"
 21#include "sti_vtg.h"
 22
 23static void sti_crtc_atomic_enable(struct drm_crtc *crtc,
 24				   struct drm_crtc_state *old_state)
 25{
 26	struct sti_mixer *mixer = to_sti_mixer(crtc);
 27
 28	DRM_DEBUG_DRIVER("\n");
 29
 30	mixer->status = STI_MIXER_READY;
 31
 32	drm_crtc_vblank_on(crtc);
 33}
 34
 35static void sti_crtc_atomic_disable(struct drm_crtc *crtc,
 36				    struct drm_crtc_state *old_state)
 37{
 38	struct sti_mixer *mixer = to_sti_mixer(crtc);
 39
 40	DRM_DEBUG_DRIVER("\n");
 41
 42	mixer->status = STI_MIXER_DISABLING;
 43}
 44
 45static int
 46sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
 47{
 48	struct sti_mixer *mixer = to_sti_mixer(crtc);
 49	struct device *dev = mixer->dev;
 50	struct sti_compositor *compo = dev_get_drvdata(dev);
 51	struct clk *compo_clk, *pix_clk;
 52	int rate = mode->clock * 1000;
 53
 54	DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n",
 55		      crtc->base.id, sti_mixer_to_str(mixer),
 56		      mode->base.id, mode->name);
 57
 58	DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
 59		      mode->vrefresh, mode->clock,
 60		      mode->hdisplay,
 61		      mode->hsync_start, mode->hsync_end,
 62		      mode->htotal,
 63		      mode->vdisplay,
 64		      mode->vsync_start, mode->vsync_end,
 65		      mode->vtotal, mode->type, mode->flags);
 66
 67	if (mixer->id == STI_MIXER_MAIN) {
 68		compo_clk = compo->clk_compo_main;
 69		pix_clk = compo->clk_pix_main;
 70	} else {
 71		compo_clk = compo->clk_compo_aux;
 72		pix_clk = compo->clk_pix_aux;
 73	}
 74
 75	/* Prepare and enable the compo IP clock */
 76	if (clk_prepare_enable(compo_clk)) {
 77		DRM_INFO("Failed to prepare/enable compositor clk\n");
 78		goto compo_error;
 79	}
 80
 81	/* Set rate and prepare/enable pixel clock */
 82	if (clk_set_rate(pix_clk, rate) < 0) {
 83		DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate);
 84		goto pix_error;
 85	}
 86	if (clk_prepare_enable(pix_clk)) {
 87		DRM_ERROR("Failed to prepare/enable pix clk\n");
 88		goto pix_error;
 89	}
 90
 91	sti_vtg_set_config(compo->vtg[mixer->id], &crtc->mode);
 92
 93	if (sti_mixer_active_video_area(mixer, &crtc->mode)) {
 94		DRM_ERROR("Can't set active video area\n");
 95		goto mixer_error;
 96	}
 97
 98	return 0;
 99
100mixer_error:
101	clk_disable_unprepare(pix_clk);
102pix_error:
103	clk_disable_unprepare(compo_clk);
104compo_error:
105	return -EINVAL;
106}
107
108static void sti_crtc_disable(struct drm_crtc *crtc)
109{
110	struct sti_mixer *mixer = to_sti_mixer(crtc);
111	struct device *dev = mixer->dev;
112	struct sti_compositor *compo = dev_get_drvdata(dev);
113
114	DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
115
116	/* Disable Background */
117	sti_mixer_set_background_status(mixer, false);
118
119	drm_crtc_vblank_off(crtc);
120
121	/* Disable pixel clock and compo IP clocks */
122	if (mixer->id == STI_MIXER_MAIN) {
123		clk_disable_unprepare(compo->clk_pix_main);
124		clk_disable_unprepare(compo->clk_compo_main);
125	} else {
126		clk_disable_unprepare(compo->clk_pix_aux);
127		clk_disable_unprepare(compo->clk_compo_aux);
128	}
129
130	mixer->status = STI_MIXER_DISABLED;
131}
132
133static void
134sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
135{
136	sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
137}
138
139static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
140				  struct drm_crtc_state *old_crtc_state)
141{
142	struct drm_device *drm_dev = crtc->dev;
143	struct sti_mixer *mixer = to_sti_mixer(crtc);
144	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
145	struct drm_plane *p;
146	struct drm_pending_vblank_event *event;
147	unsigned long flags;
148
149	DRM_DEBUG_DRIVER("\n");
150
151	/* perform plane actions */
152	list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
153		struct sti_plane *plane = to_sti_plane(p);
154
155		switch (plane->status) {
156		case STI_PLANE_UPDATED:
157			/* ignore update for other CRTC */
158			if (p->state->crtc != crtc)
159				continue;
160
161			/* update planes tag as updated */
162			DRM_DEBUG_DRIVER("update plane %s\n",
163					 sti_plane_to_str(plane));
164
165			if (sti_mixer_set_plane_depth(mixer, plane)) {
166				DRM_ERROR("Cannot set plane %s depth\n",
167					  sti_plane_to_str(plane));
168				break;
169			}
170
171			if (sti_mixer_set_plane_status(mixer, plane, true)) {
172				DRM_ERROR("Cannot enable plane %s at mixer\n",
173					  sti_plane_to_str(plane));
174				break;
175			}
176
177			/* if plane is HQVDP_0 then commit the vid[0] */
178			if (plane->desc == STI_HQVDP_0)
179				sti_vid_commit(compo->vid[0], p->state);
180
181			plane->status = STI_PLANE_READY;
182
183			break;
184		case STI_PLANE_DISABLING:
185			/* disabling sequence for planes tag as disabling */
186			DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
187					 sti_plane_to_str(plane));
188
189			if (sti_mixer_set_plane_status(mixer, plane, false)) {
190				DRM_ERROR("Cannot disable plane %s at mixer\n",
191					  sti_plane_to_str(plane));
192				continue;
193			}
194
195			if (plane->desc == STI_CURSOR)
196				/* tag plane status for disabled */
197				plane->status = STI_PLANE_DISABLED;
198			else
199				/* tag plane status for flushing */
200				plane->status = STI_PLANE_FLUSHING;
201
202			/* if plane is HQVDP_0 then disable the vid[0] */
203			if (plane->desc == STI_HQVDP_0)
204				sti_vid_disable(compo->vid[0]);
205
206			break;
207		default:
208			/* Other status case are not handled */
209			break;
210		}
211	}
212
213	event = crtc->state->event;
214	if (event) {
215		crtc->state->event = NULL;
216
217		spin_lock_irqsave(&crtc->dev->event_lock, flags);
218		if (drm_crtc_vblank_get(crtc) == 0)
219			drm_crtc_arm_vblank_event(crtc, event);
220		else
221			drm_crtc_send_vblank_event(crtc, event);
222		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
223	}
224}
225
226static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
227	.mode_set_nofb = sti_crtc_mode_set_nofb,
228	.atomic_flush = sti_crtc_atomic_flush,
229	.atomic_enable = sti_crtc_atomic_enable,
230	.atomic_disable = sti_crtc_atomic_disable,
231};
232
233static void sti_crtc_destroy(struct drm_crtc *crtc)
234{
235	DRM_DEBUG_KMS("\n");
236	drm_crtc_cleanup(crtc);
237}
238
239static int sti_crtc_set_property(struct drm_crtc *crtc,
240				 struct drm_property *property,
241				 uint64_t val)
242{
243	DRM_DEBUG_KMS("\n");
244	return 0;
245}
246
247int sti_crtc_vblank_cb(struct notifier_block *nb,
248		       unsigned long event, void *data)
249{
250	struct sti_compositor *compo;
251	struct drm_crtc *crtc = data;
252	struct sti_mixer *mixer;
253	struct sti_private *priv;
254	unsigned int pipe;
255
256	priv = crtc->dev->dev_private;
257	pipe = drm_crtc_index(crtc);
258	compo = container_of(nb, struct sti_compositor, vtg_vblank_nb[pipe]);
259	mixer = compo->mixer[pipe];
260
261	if ((event != VTG_TOP_FIELD_EVENT) &&
262	    (event != VTG_BOTTOM_FIELD_EVENT)) {
263		DRM_ERROR("unknown event: %lu\n", event);
264		return -EINVAL;
265	}
266
267	drm_crtc_handle_vblank(crtc);
268
269	if (mixer->status == STI_MIXER_DISABLING) {
270		struct drm_plane *p;
271
272		/* Disable mixer only if all overlay planes (GDP and VDP)
273		 * are disabled */
274		list_for_each_entry(p, &crtc->dev->mode_config.plane_list,
275				    head) {
276			struct sti_plane *plane = to_sti_plane(p);
277
278			if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
279				if (plane->status != STI_PLANE_DISABLED)
280					return 0;
281		}
282		sti_crtc_disable(crtc);
283	}
284
285	return 0;
286}
287
288int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
289{
290	struct sti_private *dev_priv = dev->dev_private;
291	struct sti_compositor *compo = dev_priv->compo;
292	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
293	struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
294	struct sti_vtg *vtg = compo->vtg[pipe];
295
296	DRM_DEBUG_DRIVER("\n");
297
298	if (sti_vtg_register_client(vtg, vtg_vblank_nb, crtc)) {
299		DRM_ERROR("Cannot register VTG notifier\n");
300		return -EINVAL;
301	}
302
303	return 0;
304}
305
306void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
307{
308	struct sti_private *priv = drm_dev->dev_private;
309	struct sti_compositor *compo = priv->compo;
310	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
311	struct sti_vtg *vtg = compo->vtg[pipe];
312
313	DRM_DEBUG_DRIVER("\n");
314
315	if (sti_vtg_unregister_client(vtg, vtg_vblank_nb))
316		DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
317}
318
319static int sti_crtc_late_register(struct drm_crtc *crtc)
320{
321	struct sti_mixer *mixer = to_sti_mixer(crtc);
322	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
323
324	if (drm_crtc_index(crtc) == 0)
325		return sti_compositor_debugfs_init(compo, crtc->dev->primary);
326
327	return 0;
328}
329
330static const struct drm_crtc_funcs sti_crtc_funcs = {
331	.set_config = drm_atomic_helper_set_config,
332	.page_flip = drm_atomic_helper_page_flip,
333	.destroy = sti_crtc_destroy,
334	.set_property = sti_crtc_set_property,
335	.reset = drm_atomic_helper_crtc_reset,
336	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
337	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
338	.late_register = sti_crtc_late_register,
339};
340
341bool sti_crtc_is_main(struct drm_crtc *crtc)
342{
343	struct sti_mixer *mixer = to_sti_mixer(crtc);
344
345	if (mixer->id == STI_MIXER_MAIN)
346		return true;
347
348	return false;
349}
350
351int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
352		  struct drm_plane *primary, struct drm_plane *cursor)
353{
354	struct drm_crtc *crtc = &mixer->drm_crtc;
355	int res;
356
357	res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
358					&sti_crtc_funcs, NULL);
359	if (res) {
360		DRM_ERROR("Can't initialze CRTC\n");
361		return -EINVAL;
362	}
363
364	drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs);
365
366	DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
367			 crtc->base.id, sti_mixer_to_str(mixer));
368
369	return 0;
370}