Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * Copyright © 2014 Intel Corporation
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice (including the next
 12 * paragraph) shall be included in all copies or substantial portions of the
 13 * Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 21 * DEALINGS IN THE SOFTWARE.
 22 */
 23
 24/**
 25 * DOC: atomic plane helpers
 26 *
 27 * The functions here are used by the atomic plane helper functions to
 28 * implement legacy plane updates (i.e., drm_plane->update_plane() and
 29 * drm_plane->disable_plane()).  This allows plane updates to use the
 30 * atomic state infrastructure and perform plane updates as separate
 31 * prepare/check/commit/cleanup steps.
 32 */
 33
 34#include <drm/drm_atomic_helper.h>
 35#include <drm/drm_fourcc.h>
 36#include <drm/drm_plane_helper.h>
 37
 38#include "i915_trace.h"
 39#include "intel_atomic_plane.h"
 40#include "intel_display_types.h"
 41#include "intel_pm.h"
 42#include "intel_sprite.h"
 43
 44struct intel_plane *intel_plane_alloc(void)
 45{
 46	struct intel_plane_state *plane_state;
 47	struct intel_plane *plane;
 48
 49	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
 50	if (!plane)
 51		return ERR_PTR(-ENOMEM);
 52
 53	plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 54	if (!plane_state) {
 55		kfree(plane);
 56		return ERR_PTR(-ENOMEM);
 57	}
 58
 59	__drm_atomic_helper_plane_reset(&plane->base, &plane_state->base);
 60	plane_state->scaler_id = -1;
 61
 62	return plane;
 63}
 64
 65void intel_plane_free(struct intel_plane *plane)
 66{
 67	intel_plane_destroy_state(&plane->base, plane->base.state);
 68	kfree(plane);
 69}
 70
 71/**
 72 * intel_plane_duplicate_state - duplicate plane state
 73 * @plane: drm plane
 74 *
 75 * Allocates and returns a copy of the plane state (both common and
 76 * Intel-specific) for the specified plane.
 77 *
 78 * Returns: The newly allocated plane state, or NULL on failure.
 79 */
 80struct drm_plane_state *
 81intel_plane_duplicate_state(struct drm_plane *plane)
 82{
 83	struct drm_plane_state *state;
 84	struct intel_plane_state *intel_state;
 85
 86	intel_state = kmemdup(plane->state, sizeof(*intel_state), GFP_KERNEL);
 87
 88	if (!intel_state)
 89		return NULL;
 90
 91	state = &intel_state->base;
 92
 93	__drm_atomic_helper_plane_duplicate_state(plane, state);
 94
 95	intel_state->vma = NULL;
 96	intel_state->flags = 0;
 97
 98	return state;
 99}
100
101/**
102 * intel_plane_destroy_state - destroy plane state
103 * @plane: drm plane
104 * @state: state object to destroy
105 *
106 * Destroys the plane state (both common and Intel-specific) for the
107 * specified plane.
108 */
109void
110intel_plane_destroy_state(struct drm_plane *plane,
111			  struct drm_plane_state *state)
112{
113	WARN_ON(to_intel_plane_state(state)->vma);
114
115	drm_atomic_helper_plane_destroy_state(plane, state);
116}
117
118unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
119				   const struct intel_plane_state *plane_state)
120{
121	const struct drm_framebuffer *fb = plane_state->base.fb;
122	unsigned int cpp;
123
124	if (!plane_state->base.visible)
125		return 0;
126
127	cpp = fb->format->cpp[0];
128
129	/*
130	 * Based on HSD#:1408715493
131	 * NV12 cpp == 4, P010 cpp == 8
132	 *
133	 * FIXME what is the logic behind this?
134	 */
135	if (fb->format->is_yuv && fb->format->num_planes > 1)
136		cpp *= 4;
137
138	return cpp * crtc_state->pixel_rate;
139}
140
141int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
142					struct intel_crtc_state *new_crtc_state,
143					const struct intel_plane_state *old_plane_state,
144					struct intel_plane_state *new_plane_state)
145{
146	struct intel_plane *plane = to_intel_plane(new_plane_state->base.plane);
147	int ret;
148
149	new_crtc_state->active_planes &= ~BIT(plane->id);
150	new_crtc_state->nv12_planes &= ~BIT(plane->id);
151	new_crtc_state->c8_planes &= ~BIT(plane->id);
152	new_crtc_state->data_rate[plane->id] = 0;
153	new_plane_state->base.visible = false;
154
155	if (!new_plane_state->base.crtc && !old_plane_state->base.crtc)
156		return 0;
157
158	ret = plane->check_plane(new_crtc_state, new_plane_state);
159	if (ret)
160		return ret;
161
162	/* FIXME pre-g4x don't work like this */
163	if (new_plane_state->base.visible)
164		new_crtc_state->active_planes |= BIT(plane->id);
165
166	if (new_plane_state->base.visible &&
167	    is_planar_yuv_format(new_plane_state->base.fb->format->format))
168		new_crtc_state->nv12_planes |= BIT(plane->id);
169
170	if (new_plane_state->base.visible &&
171	    new_plane_state->base.fb->format->format == DRM_FORMAT_C8)
172		new_crtc_state->c8_planes |= BIT(plane->id);
173
174	if (new_plane_state->base.visible || old_plane_state->base.visible)
175		new_crtc_state->update_planes |= BIT(plane->id);
176
177	new_crtc_state->data_rate[plane->id] =
178		intel_plane_data_rate(new_crtc_state, new_plane_state);
179
180	return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state,
181					       old_plane_state, new_plane_state);
182}
183
184static struct intel_crtc *
185get_crtc_from_states(const struct intel_plane_state *old_plane_state,
186		     const struct intel_plane_state *new_plane_state)
187{
188	if (new_plane_state->base.crtc)
189		return to_intel_crtc(new_plane_state->base.crtc);
190
191	if (old_plane_state->base.crtc)
192		return to_intel_crtc(old_plane_state->base.crtc);
193
194	return NULL;
195}
196
197static int intel_plane_atomic_check(struct drm_plane *_plane,
198				    struct drm_plane_state *_new_plane_state)
199{
200	struct intel_plane *plane = to_intel_plane(_plane);
201	struct intel_atomic_state *state =
202		to_intel_atomic_state(_new_plane_state->state);
203	struct intel_plane_state *new_plane_state =
204		to_intel_plane_state(_new_plane_state);
205	const struct intel_plane_state *old_plane_state =
206		intel_atomic_get_old_plane_state(state, plane);
207	struct intel_crtc *crtc =
208		get_crtc_from_states(old_plane_state, new_plane_state);
209	const struct intel_crtc_state *old_crtc_state;
210	struct intel_crtc_state *new_crtc_state;
211
212	new_plane_state->base.visible = false;
213	if (!crtc)
214		return 0;
215
216	old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
217	new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
218
219	return intel_plane_atomic_check_with_state(old_crtc_state,
220						   new_crtc_state,
221						   old_plane_state,
222						   new_plane_state);
223}
224
225static struct intel_plane *
226skl_next_plane_to_commit(struct intel_atomic_state *state,
227			 struct intel_crtc *crtc,
228			 struct skl_ddb_entry entries_y[I915_MAX_PLANES],
229			 struct skl_ddb_entry entries_uv[I915_MAX_PLANES],
230			 unsigned int *update_mask)
231{
232	struct intel_crtc_state *crtc_state =
233		intel_atomic_get_new_crtc_state(state, crtc);
234	struct intel_plane_state *plane_state;
235	struct intel_plane *plane;
236	int i;
237
238	if (*update_mask == 0)
239		return NULL;
240
241	for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
242		enum plane_id plane_id = plane->id;
243
244		if (crtc->pipe != plane->pipe ||
245		    !(*update_mask & BIT(plane_id)))
246			continue;
247
248		if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
249						entries_y,
250						I915_MAX_PLANES, plane_id) ||
251		    skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id],
252						entries_uv,
253						I915_MAX_PLANES, plane_id))
254			continue;
255
256		*update_mask &= ~BIT(plane_id);
257		entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
258		entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id];
259
260		return plane;
261	}
262
263	/* should never happen */
264	WARN_ON(1);
265
266	return NULL;
267}
268
269void intel_update_plane(struct intel_plane *plane,
270			const struct intel_crtc_state *crtc_state,
271			const struct intel_plane_state *plane_state)
272{
273	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
274
275	trace_intel_update_plane(&plane->base, crtc);
276	plane->update_plane(plane, crtc_state, plane_state);
277}
278
279void intel_update_slave(struct intel_plane *plane,
280			const struct intel_crtc_state *crtc_state,
281			const struct intel_plane_state *plane_state)
282{
283	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
284
285	trace_intel_update_plane(&plane->base, crtc);
286	plane->update_slave(plane, crtc_state, plane_state);
287}
288
289void intel_disable_plane(struct intel_plane *plane,
290			 const struct intel_crtc_state *crtc_state)
291{
292	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
293
294	trace_intel_disable_plane(&plane->base, crtc);
295	plane->disable_plane(plane, crtc_state);
296}
297
298void skl_update_planes_on_crtc(struct intel_atomic_state *state,
299			       struct intel_crtc *crtc)
300{
301	struct intel_crtc_state *old_crtc_state =
302		intel_atomic_get_old_crtc_state(state, crtc);
303	struct intel_crtc_state *new_crtc_state =
304		intel_atomic_get_new_crtc_state(state, crtc);
305	struct skl_ddb_entry entries_y[I915_MAX_PLANES];
306	struct skl_ddb_entry entries_uv[I915_MAX_PLANES];
307	u32 update_mask = new_crtc_state->update_planes;
308	struct intel_plane *plane;
309
310	memcpy(entries_y, old_crtc_state->wm.skl.plane_ddb_y,
311	       sizeof(old_crtc_state->wm.skl.plane_ddb_y));
312	memcpy(entries_uv, old_crtc_state->wm.skl.plane_ddb_uv,
313	       sizeof(old_crtc_state->wm.skl.plane_ddb_uv));
314
315	while ((plane = skl_next_plane_to_commit(state, crtc,
316						 entries_y, entries_uv,
317						 &update_mask))) {
318		struct intel_plane_state *new_plane_state =
319			intel_atomic_get_new_plane_state(state, plane);
320
321		if (new_plane_state->base.visible) {
322			intel_update_plane(plane, new_crtc_state, new_plane_state);
323		} else if (new_plane_state->slave) {
324			struct intel_plane *master =
325				new_plane_state->linked_plane;
326
327			/*
328			 * We update the slave plane from this function because
329			 * programming it from the master plane's update_plane
330			 * callback runs into issues when the Y plane is
331			 * reassigned, disabled or used by a different plane.
332			 *
333			 * The slave plane is updated with the master plane's
334			 * plane_state.
335			 */
336			new_plane_state =
337				intel_atomic_get_new_plane_state(state, master);
338
339			intel_update_slave(plane, new_crtc_state, new_plane_state);
340		} else {
341			intel_disable_plane(plane, new_crtc_state);
342		}
343	}
344}
345
346void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
347				struct intel_crtc *crtc)
348{
349	struct intel_crtc_state *new_crtc_state =
350		intel_atomic_get_new_crtc_state(state, crtc);
351	u32 update_mask = new_crtc_state->update_planes;
352	struct intel_plane_state *new_plane_state;
353	struct intel_plane *plane;
354	int i;
355
356	for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
357		if (crtc->pipe != plane->pipe ||
358		    !(update_mask & BIT(plane->id)))
359			continue;
360
361		if (new_plane_state->base.visible)
362			intel_update_plane(plane, new_crtc_state, new_plane_state);
363		else
364			intel_disable_plane(plane, new_crtc_state);
365	}
366}
367
368const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
369	.prepare_fb = intel_prepare_plane_fb,
370	.cleanup_fb = intel_cleanup_plane_fb,
371	.atomic_check = intel_plane_atomic_check,
372};