1/*
2 * Copyright (C) 2014-2015 The Linux Foundation. All rights reserved.
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "mdp5_kms.h"
20
21struct mdp5_plane {
22	struct drm_plane base;
23	const char *name;
24
25	enum mdp5_pipe pipe;
26
27	spinlock_t pipe_lock;	/* protect REG_MDP5_PIPE_* registers */
28	uint32_t reg_offset;
29	uint32_t caps;
30
31	uint32_t flush_mask;	/* used to commit pipe registers */
32
33	uint32_t nformats;
34	uint32_t formats[32];
35};
36#define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
37
38static int mdp5_plane_mode_set(struct drm_plane *plane,
39		struct drm_crtc *crtc, struct drm_framebuffer *fb,
40		int crtc_x, int crtc_y,
41		unsigned int crtc_w, unsigned int crtc_h,
42		uint32_t src_x, uint32_t src_y,
43		uint32_t src_w, uint32_t src_h);
44
45static void set_scanout_locked(struct drm_plane *plane,
46		struct drm_framebuffer *fb);
47
48static struct mdp5_kms *get_kms(struct drm_plane *plane)
49{
50	struct msm_drm_private *priv = plane->dev->dev_private;
51	return to_mdp5_kms(to_mdp_kms(priv->kms));
52}
53
54static bool plane_enabled(struct drm_plane_state *state)
55{
56	return state->fb && state->crtc;
57}
58
59static void mdp5_plane_destroy(struct drm_plane *plane)
60{
61	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
62
63	drm_plane_helper_disable(plane);
64	drm_plane_cleanup(plane);
65
66	kfree(mdp5_plane);
67}
68
69static void mdp5_plane_install_rotation_property(struct drm_device *dev,
70		struct drm_plane *plane)
71{
72	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
73
74	if (!(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP) &&
75		!(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP))
76		return;
77
78	if (!dev->mode_config.rotation_property)
79		dev->mode_config.rotation_property =
80			drm_mode_create_rotation_property(dev,
81			BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
82
83	if (dev->mode_config.rotation_property)
84		drm_object_attach_property(&plane->base,
85			dev->mode_config.rotation_property,
86			0);
87}
88
89/* helper to install properties which are common to planes and crtcs */
90static void mdp5_plane_install_properties(struct drm_plane *plane,
91		struct drm_mode_object *obj)
92{
93	struct drm_device *dev = plane->dev;
94	struct msm_drm_private *dev_priv = dev->dev_private;
95	struct drm_property *prop;
96
97#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
98		prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
99		if (!prop) { \
100			prop = drm_property_##fnc(dev, 0, #name, \
101				##__VA_ARGS__); \
102			if (!prop) { \
103				dev_warn(dev->dev, \
104					"Create property %s failed\n", \
105					#name); \
106				return; \
107			} \
108			dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
109		} \
110		drm_object_attach_property(&plane->base, prop, init_val); \
111	} while (0)
112
113#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
114		INSTALL_PROPERTY(name, NAME, init_val, \
115				create_range, min, max)
116
117#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
118		INSTALL_PROPERTY(name, NAME, init_val, \
119				create_enum, name##_prop_enum_list, \
120				ARRAY_SIZE(name##_prop_enum_list))
121
122	INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
123
124	mdp5_plane_install_rotation_property(dev, plane);
125
126#undef INSTALL_RANGE_PROPERTY
127#undef INSTALL_ENUM_PROPERTY
128#undef INSTALL_PROPERTY
129}
130
131static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
132		struct drm_plane_state *state, struct drm_property *property,
133		uint64_t val)
134{
135	struct drm_device *dev = plane->dev;
136	struct mdp5_plane_state *pstate;
137	struct msm_drm_private *dev_priv = dev->dev_private;
138	int ret = 0;
139
140	pstate = to_mdp5_plane_state(state);
141
142#define SET_PROPERTY(name, NAME, type) do { \
143		if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
144			pstate->name = (type)val; \
145			DBG("Set property %s %d", #name, (type)val); \
146			goto done; \
147		} \
148	} while (0)
149
150	SET_PROPERTY(zpos, ZPOS, uint8_t);
151
152	dev_err(dev->dev, "Invalid property\n");
153	ret = -EINVAL;
154done:
155	return ret;
156#undef SET_PROPERTY
157}
158
159static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
160		const struct drm_plane_state *state,
161		struct drm_property *property, uint64_t *val)
162{
163	struct drm_device *dev = plane->dev;
164	struct mdp5_plane_state *pstate;
165	struct msm_drm_private *dev_priv = dev->dev_private;
166	int ret = 0;
167
168	pstate = to_mdp5_plane_state(state);
169
170#define GET_PROPERTY(name, NAME, type) do { \
171		if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
172			*val = pstate->name; \
173			DBG("Get property %s %lld", #name, *val); \
174			goto done; \
175		} \
176	} while (0)
177
178	GET_PROPERTY(zpos, ZPOS, uint8_t);
179
180	dev_err(dev->dev, "Invalid property\n");
181	ret = -EINVAL;
182done:
183	return ret;
184#undef SET_PROPERTY
185}
186
187static void mdp5_plane_reset(struct drm_plane *plane)
188{
189	struct mdp5_plane_state *mdp5_state;
190
191	if (plane->state && plane->state->fb)
192		drm_framebuffer_unreference(plane->state->fb);
193
194	kfree(to_mdp5_plane_state(plane->state));
195	mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
196
197	/* assign default blend parameters */
198	mdp5_state->alpha = 255;
199	mdp5_state->premultiplied = 0;
200
201	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
202		mdp5_state->zpos = STAGE_BASE;
203	else
204		mdp5_state->zpos = STAGE0 + drm_plane_index(plane);
205
206	mdp5_state->base.plane = plane;
207
208	plane->state = &mdp5_state->base;
209}
210
211static struct drm_plane_state *
212mdp5_plane_duplicate_state(struct drm_plane *plane)
213{
214	struct mdp5_plane_state *mdp5_state;
215
216	if (WARN_ON(!plane->state))
217		return NULL;
218
219	mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
220			sizeof(*mdp5_state), GFP_KERNEL);
221
222	if (mdp5_state && mdp5_state->base.fb)
223		drm_framebuffer_reference(mdp5_state->base.fb);
224
225	mdp5_state->mode_changed = false;
226	mdp5_state->pending = false;
227
228	return &mdp5_state->base;
229}
230
231static void mdp5_plane_destroy_state(struct drm_plane *plane,
232		struct drm_plane_state *state)
233{
234	if (state->fb)
235		drm_framebuffer_unreference(state->fb);
236
237	kfree(to_mdp5_plane_state(state));
238}
239
240static const struct drm_plane_funcs mdp5_plane_funcs = {
241		.update_plane = drm_atomic_helper_update_plane,
242		.disable_plane = drm_atomic_helper_disable_plane,
243		.destroy = mdp5_plane_destroy,
244		.set_property = drm_atomic_helper_plane_set_property,
245		.atomic_set_property = mdp5_plane_atomic_set_property,
246		.atomic_get_property = mdp5_plane_atomic_get_property,
247		.reset = mdp5_plane_reset,
248		.atomic_duplicate_state = mdp5_plane_duplicate_state,
249		.atomic_destroy_state = mdp5_plane_destroy_state,
250};
251
252static int mdp5_plane_prepare_fb(struct drm_plane *plane,
253		const struct drm_plane_state *new_state)
254{
255	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
256	struct mdp5_kms *mdp5_kms = get_kms(plane);
257	struct drm_framebuffer *fb = new_state->fb;
258
259	if (!new_state->fb)
260		return 0;
261
262	DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id);
263	return msm_framebuffer_prepare(fb, mdp5_kms->id);
264}
265
266static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
267		const struct drm_plane_state *old_state)
268{
269	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
270	struct mdp5_kms *mdp5_kms = get_kms(plane);
271	struct drm_framebuffer *fb = old_state->fb;
272
273	if (!fb)
274		return;
275
276	DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id);
277	msm_framebuffer_cleanup(fb, mdp5_kms->id);
278}
279
280static int mdp5_plane_atomic_check(struct drm_plane *plane,
281		struct drm_plane_state *state)
282{
283	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
284	struct drm_plane_state *old_state = plane->state;
285	const struct mdp_format *format;
286	bool vflip, hflip;
287
288	DBG("%s: check (%d -> %d)", mdp5_plane->name,
289			plane_enabled(old_state), plane_enabled(state));
290
291	if (plane_enabled(state)) {
292		format = to_mdp_format(msm_framebuffer_format(state->fb));
293		if (MDP_FORMAT_IS_YUV(format) &&
294			!pipe_supports_yuv(mdp5_plane->caps)) {
295			dev_err(plane->dev->dev,
296				"Pipe doesn't support YUV\n");
297
298			return -EINVAL;
299		}
300
301		if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) &&
302			(((state->src_w >> 16) != state->crtc_w) ||
303			((state->src_h >> 16) != state->crtc_h))) {
304			dev_err(plane->dev->dev,
305				"Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
306				state->src_w >> 16, state->src_h >> 16,
307				state->crtc_w, state->crtc_h);
308
309			return -EINVAL;
310		}
311
312		hflip = !!(state->rotation & BIT(DRM_REFLECT_X));
313		vflip = !!(state->rotation & BIT(DRM_REFLECT_Y));
314		if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) ||
315			(hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) {
316			dev_err(plane->dev->dev,
317				"Pipe doesn't support flip\n");
318
319			return -EINVAL;
320		}
321	}
322
323	if (plane_enabled(state) && plane_enabled(old_state)) {
324		/* we cannot change SMP block configuration during scanout: */
325		bool full_modeset = false;
326		if (state->fb->pixel_format != old_state->fb->pixel_format) {
327			DBG("%s: pixel_format change!", mdp5_plane->name);
328			full_modeset = true;
329		}
330		if (state->src_w != old_state->src_w) {
331			DBG("%s: src_w change!", mdp5_plane->name);
332			full_modeset = true;
333		}
334		if (to_mdp5_plane_state(old_state)->pending) {
335			DBG("%s: still pending!", mdp5_plane->name);
336			full_modeset = true;
337		}
338		if (full_modeset) {
339			struct drm_crtc_state *crtc_state =
340					drm_atomic_get_crtc_state(state->state, state->crtc);
341			crtc_state->mode_changed = true;
342			to_mdp5_plane_state(state)->mode_changed = true;
343		}
344	} else {
345		to_mdp5_plane_state(state)->mode_changed = true;
346	}
347
348	return 0;
349}
350
351static void mdp5_plane_atomic_update(struct drm_plane *plane,
352				     struct drm_plane_state *old_state)
353{
354	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
355	struct drm_plane_state *state = plane->state;
356
357	DBG("%s: update", mdp5_plane->name);
358
359	if (!plane_enabled(state)) {
360		to_mdp5_plane_state(state)->pending = true;
361	} else if (to_mdp5_plane_state(state)->mode_changed) {
362		int ret;
363		to_mdp5_plane_state(state)->pending = true;
364		ret = mdp5_plane_mode_set(plane,
365				state->crtc, state->fb,
366				state->crtc_x, state->crtc_y,
367				state->crtc_w, state->crtc_h,
368				state->src_x,  state->src_y,
369				state->src_w, state->src_h);
370		/* atomic_check should have ensured that this doesn't fail */
371		WARN_ON(ret < 0);
372	} else {
373		unsigned long flags;
374		spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
375		set_scanout_locked(plane, state->fb);
376		spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags);
377	}
378}
379
380static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
381		.prepare_fb = mdp5_plane_prepare_fb,
382		.cleanup_fb = mdp5_plane_cleanup_fb,
383		.atomic_check = mdp5_plane_atomic_check,
384		.atomic_update = mdp5_plane_atomic_update,
385};
386
387static void set_scanout_locked(struct drm_plane *plane,
388		struct drm_framebuffer *fb)
389{
390	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
391	struct mdp5_kms *mdp5_kms = get_kms(plane);
392	enum mdp5_pipe pipe = mdp5_plane->pipe;
393
394	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
395			MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
396			MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
397
398	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
399			MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
400			MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
401
402	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe),
403			msm_framebuffer_iova(fb, mdp5_kms->id, 0));
404	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe),
405			msm_framebuffer_iova(fb, mdp5_kms->id, 1));
406	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
407			msm_framebuffer_iova(fb, mdp5_kms->id, 2));
408	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
409			msm_framebuffer_iova(fb, mdp5_kms->id, 3));
410
411	plane->fb = fb;
412}
413
414/* Note: mdp5_plane->pipe_lock must be locked */
415static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe)
416{
417	uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) &
418			 ~MDP5_PIPE_OP_MODE_CSC_1_EN;
419
420	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value);
421}
422
423/* Note: mdp5_plane->pipe_lock must be locked */
424static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
425		struct csc_cfg *csc)
426{
427	uint32_t  i, mode = 0; /* RGB, no CSC */
428	uint32_t *matrix;
429
430	if (unlikely(!csc))
431		return;
432
433	if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type))
434		mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV);
435	if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type))
436		mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV);
437	mode |= MDP5_PIPE_OP_MODE_CSC_1_EN;
438	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode);
439
440	matrix = csc->matrix;
441	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe),
442			MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) |
443			MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1]));
444	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe),
445			MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) |
446			MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3]));
447	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe),
448			MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) |
449			MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5]));
450	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe),
451			MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) |
452			MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7]));
453	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe),
454			MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8]));
455
456	for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) {
457		uint32_t *pre_clamp = csc->pre_clamp;
458		uint32_t *post_clamp = csc->post_clamp;
459
460		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i),
461			MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) |
462			MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i]));
463
464		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i),
465			MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) |
466			MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i]));
467
468		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i),
469			MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i]));
470
471		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i),
472			MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i]));
473	}
474}
475
476#define PHASE_STEP_SHIFT	21
477#define DOWN_SCALE_RATIO_MAX	32	/* 2^(26-21) */
478
479static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
480{
481	uint32_t unit;
482
483	if (src == 0 || dst == 0)
484		return -EINVAL;
485
486	/*
487	 * PHASE_STEP_X/Y is coded on 26 bits (25:0),
488	 * where 2^21 represents the unity "1" in fixed-point hardware design.
489	 * This leaves 5 bits for the integer part (downscale case):
490	 *	-> maximum downscale ratio = 0b1_1111 = 31
491	 */
492	if (src > (dst * DOWN_SCALE_RATIO_MAX))
493		return -EOVERFLOW;
494
495	unit = 1 << PHASE_STEP_SHIFT;
496	*out_phase = mult_frac(unit, src, dst);
497
498	return 0;
499}
500
501static int calc_scalex_steps(struct drm_plane *plane,
502		uint32_t pixel_format, uint32_t src, uint32_t dest,
503		uint32_t phasex_steps[COMP_MAX])
504{
505	struct mdp5_kms *mdp5_kms = get_kms(plane);
506	struct device *dev = mdp5_kms->dev->dev;
507	uint32_t phasex_step;
508	unsigned int hsub;
509	int ret;
510
511	ret = calc_phase_step(src, dest, &phasex_step);
512	if (ret) {
513		dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
514		return ret;
515	}
516
517	hsub = drm_format_horz_chroma_subsampling(pixel_format);
518
519	phasex_steps[COMP_0]   = phasex_step;
520	phasex_steps[COMP_3]   = phasex_step;
521	phasex_steps[COMP_1_2] = phasex_step / hsub;
522
523	return 0;
524}
525
526static int calc_scaley_steps(struct drm_plane *plane,
527		uint32_t pixel_format, uint32_t src, uint32_t dest,
528		uint32_t phasey_steps[COMP_MAX])
529{
530	struct mdp5_kms *mdp5_kms = get_kms(plane);
531	struct device *dev = mdp5_kms->dev->dev;
532	uint32_t phasey_step;
533	unsigned int vsub;
534	int ret;
535
536	ret = calc_phase_step(src, dest, &phasey_step);
537	if (ret) {
538		dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
539		return ret;
540	}
541
542	vsub = drm_format_vert_chroma_subsampling(pixel_format);
543
544	phasey_steps[COMP_0]   = phasey_step;
545	phasey_steps[COMP_3]   = phasey_step;
546	phasey_steps[COMP_1_2] = phasey_step / vsub;
547
548	return 0;
549}
550
551static uint32_t get_scale_config(const struct mdp_format *format,
552		uint32_t src, uint32_t dst, bool horz)
553{
554	bool scaling = format->is_yuv ? true : (src != dst);
555	uint32_t sub, pix_fmt = format->base.pixel_format;
556	uint32_t ya_filter, uv_filter;
557	bool yuv = format->is_yuv;
558
559	if (!scaling)
560		return 0;
561
562	if (yuv) {
563		sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) :
564			     drm_format_vert_chroma_subsampling(pix_fmt);
565		uv_filter = ((src / sub) <= dst) ?
566				   SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
567	}
568	ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
569
570	if (horz)
571		return  MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
572			MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) |
573			MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) |
574			COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter));
575	else
576		return  MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
577			MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) |
578			MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) |
579			COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter));
580}
581
582static void calc_pixel_ext(const struct mdp_format *format,
583		uint32_t src, uint32_t dst, uint32_t phase_step[2],
584		int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX],
585		bool horz)
586{
587	bool scaling = format->is_yuv ? true : (src != dst);
588	int i;
589
590	/*
591	 * Note:
592	 * We assume here that:
593	 *     1. PCMN filter is used for downscale
594	 *     2. bilinear filter is used for upscale
595	 *     3. we are in a single pipe configuration
596	 */
597
598	for (i = 0; i < COMP_MAX; i++) {
599		pix_ext_edge1[i] = 0;
600		pix_ext_edge2[i] = scaling ? 1 : 0;
601	}
602}
603
604static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
605	const struct mdp_format *format,
606	uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX],
607	uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX])
608{
609	uint32_t pix_fmt = format->base.pixel_format;
610	uint32_t lr, tb, req;
611	int i;
612
613	for (i = 0; i < COMP_MAX; i++) {
614		uint32_t roi_w = src_w;
615		uint32_t roi_h = src_h;
616
617		if (format->is_yuv && i == COMP_1_2) {
618			roi_w /= drm_format_horz_chroma_subsampling(pix_fmt);
619			roi_h /= drm_format_vert_chroma_subsampling(pix_fmt);
620		}
621
622		lr  = (pe_left[i] >= 0) ?
623			MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) :
624			MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]);
625
626		lr |= (pe_right[i] >= 0) ?
627			MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) :
628			MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]);
629
630		tb  = (pe_top[i] >= 0) ?
631			MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) :
632			MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]);
633
634		tb |= (pe_bottom[i] >= 0) ?
635			MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) :
636			MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]);
637
638		req  = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w +
639				pe_left[i] + pe_right[i]);
640
641		req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h +
642				pe_top[i] + pe_bottom[i]);
643
644		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr);
645		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb);
646		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req);
647
648		DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i,
649			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT),
650			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT),
651			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF),
652			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF),
653			FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT));
654
655		DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i,
656			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT),
657			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT),
658			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF),
659			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF),
660			FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM));
661	}
662}
663
664
665static int mdp5_plane_mode_set(struct drm_plane *plane,
666		struct drm_crtc *crtc, struct drm_framebuffer *fb,
667		int crtc_x, int crtc_y,
668		unsigned int crtc_w, unsigned int crtc_h,
669		uint32_t src_x, uint32_t src_y,
670		uint32_t src_w, uint32_t src_h)
671{
672	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
673	struct drm_plane_state *pstate = plane->state;
674	struct mdp5_kms *mdp5_kms = get_kms(plane);
675	enum mdp5_pipe pipe = mdp5_plane->pipe;
676	const struct mdp_format *format;
677	uint32_t nplanes, config = 0;
678	uint32_t phasex_step[COMP_MAX] = {0,}, phasey_step[COMP_MAX] = {0,};
679	bool pe = mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT;
680	int pe_left[COMP_MAX], pe_right[COMP_MAX];
681	int pe_top[COMP_MAX], pe_bottom[COMP_MAX];
682	uint32_t hdecm = 0, vdecm = 0;
683	uint32_t pix_format;
684	bool vflip, hflip;
685	unsigned long flags;
686	int ret;
687
688	nplanes = drm_format_num_planes(fb->pixel_format);
689
690	/* bad formats should already be rejected: */
691	if (WARN_ON(nplanes > pipe2nclients(pipe)))
692		return -EINVAL;
693
694	format = to_mdp_format(msm_framebuffer_format(fb));
695	pix_format = format->base.pixel_format;
696
697	/* src values are in Q16 fixed point, convert to integer: */
698	src_x = src_x >> 16;
699	src_y = src_y >> 16;
700	src_w = src_w >> 16;
701	src_h = src_h >> 16;
702
703	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name,
704			fb->base.id, src_x, src_y, src_w, src_h,
705			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
706
707	/* Request some memory from the SMP: */
708	if (mdp5_kms->smp) {
709		ret = mdp5_smp_request(mdp5_kms->smp,
710				mdp5_plane->pipe, format, src_w, false);
711		if (ret)
712			return ret;
713	}
714
715	/*
716	 * Currently we update the hw for allocations/requests immediately,
717	 * but once atomic modeset/pageflip is in place, the allocation
718	 * would move into atomic->check_plane_state(), while updating the
719	 * hw would remain here:
720	 */
721	if (mdp5_kms->smp)
722		mdp5_smp_configure(mdp5_kms->smp, pipe);
723
724	ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, phasex_step);
725	if (ret)
726		return ret;
727
728	ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, phasey_step);
729	if (ret)
730		return ret;
731
732	if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT) {
733		calc_pixel_ext(format, src_w, crtc_w, phasex_step,
734					 pe_left, pe_right, true);
735		calc_pixel_ext(format, src_h, crtc_h, phasey_step,
736					pe_top, pe_bottom, false);
737	}
738
739	/* TODO calc hdecm, vdecm */
740
741	/* SCALE is used to both scale and up-sample chroma components */
742	config |= get_scale_config(format, src_w, crtc_w, true);
743	config |= get_scale_config(format, src_h, crtc_h, false);
744	DBG("scale config = %x", config);
745
746	hflip = !!(pstate->rotation & BIT(DRM_REFLECT_X));
747	vflip = !!(pstate->rotation & BIT(DRM_REFLECT_Y));
748
749	spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
750
751	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
752			MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb->width) |
753			MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb->height));
754
755	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
756			MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
757			MDP5_PIPE_SRC_SIZE_HEIGHT(src_h));
758
759	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe),
760			MDP5_PIPE_SRC_XY_X(src_x) |
761			MDP5_PIPE_SRC_XY_Y(src_y));
762
763	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe),
764			MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) |
765			MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h));
766
767	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe),
768			MDP5_PIPE_OUT_XY_X(crtc_x) |
769			MDP5_PIPE_OUT_XY_Y(crtc_y));
770
771	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
772			MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
773			MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
774			MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
775			MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
776			COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
777			MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
778			MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
779			COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
780			MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) |
781			MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
782
783	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
784			MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
785			MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
786			MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
787			MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
788
789	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
790			(hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) |
791			(vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) |
792			COND(pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) |
793			MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
794
795	/* not using secure mode: */
796	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
797
798	if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT)
799		mdp5_write_pixel_ext(mdp5_kms, pipe, format,
800				src_w, pe_left, pe_right,
801				src_h, pe_top, pe_bottom);
802
803	if (mdp5_plane->caps & MDP_PIPE_CAP_SCALE) {
804		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
805				phasex_step[COMP_0]);
806		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
807				phasey_step[COMP_0]);
808		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
809				phasex_step[COMP_1_2]);
810		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
811				phasey_step[COMP_1_2]);
812		mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
813				MDP5_PIPE_DECIMATION_VERT(vdecm) |
814				MDP5_PIPE_DECIMATION_HORZ(hdecm));
815		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config);
816	}
817
818	if (mdp5_plane->caps & MDP_PIPE_CAP_CSC) {
819		if (MDP_FORMAT_IS_YUV(format))
820			csc_enable(mdp5_kms, pipe,
821					mdp_get_default_csc_cfg(CSC_YUV2RGB));
822		else
823			csc_disable(mdp5_kms, pipe);
824	}
825
826	set_scanout_locked(plane, fb);
827
828	spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags);
829
830	return ret;
831}
832
833void mdp5_plane_complete_flip(struct drm_plane *plane)
834{
835	struct mdp5_kms *mdp5_kms = get_kms(plane);
836	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
837	enum mdp5_pipe pipe = mdp5_plane->pipe;
838
839	DBG("%s: complete flip", mdp5_plane->name);
840
841	if (mdp5_kms->smp)
842		mdp5_smp_commit(mdp5_kms->smp, pipe);
843
844	to_mdp5_plane_state(plane->state)->pending = false;
845}
846
847enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
848{
849	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
850	return mdp5_plane->pipe;
851}
852
853uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
854{
855	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
856
857	return mdp5_plane->flush_mask;
858}
859
860/* called after vsync in thread context */
861void mdp5_plane_complete_commit(struct drm_plane *plane,
862	struct drm_plane_state *state)
863{
864	struct mdp5_kms *mdp5_kms = get_kms(plane);
865	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
866	enum mdp5_pipe pipe = mdp5_plane->pipe;
867
868	if (!plane_enabled(plane->state) && mdp5_kms->smp) {
869		DBG("%s: free SMP", mdp5_plane->name);
870		mdp5_smp_release(mdp5_kms->smp, pipe);
871	}
872}
873
874/* initialize plane */
875struct drm_plane *mdp5_plane_init(struct drm_device *dev,
876		enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset,
877		uint32_t caps)
878{
879	struct drm_plane *plane = NULL;
880	struct mdp5_plane *mdp5_plane;
881	int ret;
882	enum drm_plane_type type;
883
884	mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
885	if (!mdp5_plane) {
886		ret = -ENOMEM;
887		goto fail;
888	}
889
890	plane = &mdp5_plane->base;
891
892	mdp5_plane->pipe = pipe;
893	mdp5_plane->name = pipe2name(pipe);
894	mdp5_plane->caps = caps;
895
896	mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
897		ARRAY_SIZE(mdp5_plane->formats),
898		!pipe_supports_yuv(mdp5_plane->caps));
899
900	mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
901	mdp5_plane->reg_offset = reg_offset;
902	spin_lock_init(&mdp5_plane->pipe_lock);
903
904	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
905	ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
906				 mdp5_plane->formats, mdp5_plane->nformats,
907				 type);
908	if (ret)
909		goto fail;
910
911	drm_plane_helper_add(plane, &mdp5_plane_helper_funcs);
912
913	mdp5_plane_install_properties(plane, &plane->base);
914
915	return plane;
916
917fail:
918	if (plane)
919		mdp5_plane_destroy(plane);
920
921	return ERR_PTR(ret);
922}
923