12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2109eee2fSJianwei Wang /*
3109eee2fSJianwei Wang  * Copyright 2015 Freescale Semiconductor, Inc.
4109eee2fSJianwei Wang  *
5109eee2fSJianwei Wang  * Freescale DCU drm device driver
6109eee2fSJianwei Wang  */
7109eee2fSJianwei Wang 
8109eee2fSJianwei Wang #include <linux/regmap.h>
9109eee2fSJianwei Wang 
107c11b99aSMaxime Ripard #include <drm/drm_atomic.h>
11109eee2fSJianwei Wang #include <drm/drm_atomic_helper.h>
12109eee2fSJianwei Wang #include <drm/drm_crtc.h>
136bcfe8eaSDanilo Krummrich #include <drm/drm_fb_dma_helper.h>
14b4b21c83SSam Ravnborg #include <drm/drm_fourcc.h>
15720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
164a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
17a4d847dfSThomas Zimmermann #include <drm/drm_plane_helper.h>
18fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
19109eee2fSJianwei Wang 
20109eee2fSJianwei Wang #include "fsl_dcu_drm_drv.h"
21109eee2fSJianwei Wang #include "fsl_dcu_drm_plane.h"
22109eee2fSJianwei Wang 
fsl_dcu_drm_plane_index(struct drm_plane * plane)23109eee2fSJianwei Wang static int fsl_dcu_drm_plane_index(struct drm_plane *plane)
24109eee2fSJianwei Wang {
25109eee2fSJianwei Wang 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
26109eee2fSJianwei Wang 	unsigned int total_layer = fsl_dev->soc->total_layer;
27109eee2fSJianwei Wang 	unsigned int index;
28109eee2fSJianwei Wang 
29109eee2fSJianwei Wang 	index = drm_plane_index(plane);
30109eee2fSJianwei Wang 	if (index < total_layer)
31109eee2fSJianwei Wang 		return total_layer - index - 1;
32109eee2fSJianwei Wang 
33109eee2fSJianwei Wang 	dev_err(fsl_dev->dev, "No more layer left\n");
34109eee2fSJianwei Wang 	return -EINVAL;
35109eee2fSJianwei Wang }
36109eee2fSJianwei Wang 
fsl_dcu_drm_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)37109eee2fSJianwei Wang static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
387c11b99aSMaxime Ripard 					  struct drm_atomic_state *state)
39109eee2fSJianwei Wang {
407c11b99aSMaxime Ripard 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
417c11b99aSMaxime Ripard 										 plane);
42ba5c1649SMaxime Ripard 	struct drm_framebuffer *fb = new_plane_state->fb;
43109eee2fSJianwei Wang 
44ba5c1649SMaxime Ripard 	if (!new_plane_state->fb || !new_plane_state->crtc)
45a36c9867SMeng Yi 		return 0;
46a36c9867SMeng Yi 
47438b74a5SVille Syrjälä 	switch (fb->format->format) {
48109eee2fSJianwei Wang 	case DRM_FORMAT_RGB565:
49109eee2fSJianwei Wang 	case DRM_FORMAT_RGB888:
5069855819SStefan Agner 	case DRM_FORMAT_XRGB8888:
51109eee2fSJianwei Wang 	case DRM_FORMAT_ARGB8888:
5269855819SStefan Agner 	case DRM_FORMAT_XRGB4444:
5369855819SStefan Agner 	case DRM_FORMAT_ARGB4444:
5469855819SStefan Agner 	case DRM_FORMAT_XRGB1555:
55109eee2fSJianwei Wang 	case DRM_FORMAT_ARGB1555:
56109eee2fSJianwei Wang 	case DRM_FORMAT_YUV422:
57109eee2fSJianwei Wang 		return 0;
58109eee2fSJianwei Wang 	default:
59109eee2fSJianwei Wang 		return -EINVAL;
60109eee2fSJianwei Wang 	}
61109eee2fSJianwei Wang }
62109eee2fSJianwei Wang 
fsl_dcu_drm_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)63109eee2fSJianwei Wang static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
64977697e2SMaxime Ripard 					     struct drm_atomic_state *state)
65109eee2fSJianwei Wang {
66109eee2fSJianwei Wang 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
6714d11b8dSAndrzej Hajda 	unsigned int value;
68e291d298SStefan Agner 	int index;
69109eee2fSJianwei Wang 
70109eee2fSJianwei Wang 	index = fsl_dcu_drm_plane_index(plane);
71109eee2fSJianwei Wang 	if (index < 0)
72109eee2fSJianwei Wang 		return;
73109eee2fSJianwei Wang 
74e291d298SStefan Agner 	regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value);
75109eee2fSJianwei Wang 	value &= ~DCU_LAYER_EN;
76e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value);
77109eee2fSJianwei Wang }
78109eee2fSJianwei Wang 
fsl_dcu_drm_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)79109eee2fSJianwei Wang static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
80977697e2SMaxime Ripard 					    struct drm_atomic_state *state)
81109eee2fSJianwei Wang 
82109eee2fSJianwei Wang {
83109eee2fSJianwei Wang 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
8437418bf1SMaxime Ripard 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
8537418bf1SMaxime Ripard 									   plane);
86109eee2fSJianwei Wang 	struct drm_framebuffer *fb = plane->state->fb;
874a83c26aSDanilo Krummrich 	struct drm_gem_dma_object *gem;
8869855819SStefan Agner 	unsigned int alpha = DCU_LAYER_AB_NONE, bpp;
89e291d298SStefan Agner 	int index;
90109eee2fSJianwei Wang 
91109eee2fSJianwei Wang 	if (!fb)
92109eee2fSJianwei Wang 		return;
93109eee2fSJianwei Wang 
94109eee2fSJianwei Wang 	index = fsl_dcu_drm_plane_index(plane);
95109eee2fSJianwei Wang 	if (index < 0)
96109eee2fSJianwei Wang 		return;
97109eee2fSJianwei Wang 
986bcfe8eaSDanilo Krummrich 	gem = drm_fb_dma_get_gem_obj(fb, 0);
99109eee2fSJianwei Wang 
100438b74a5SVille Syrjälä 	switch (fb->format->format) {
101109eee2fSJianwei Wang 	case DRM_FORMAT_RGB565:
102109eee2fSJianwei Wang 		bpp = FSL_DCU_RGB565;
103109eee2fSJianwei Wang 		break;
104109eee2fSJianwei Wang 	case DRM_FORMAT_RGB888:
105109eee2fSJianwei Wang 		bpp = FSL_DCU_RGB888;
106109eee2fSJianwei Wang 		break;
107109eee2fSJianwei Wang 	case DRM_FORMAT_ARGB8888:
10869855819SStefan Agner 		alpha = DCU_LAYER_AB_WHOLE_FRAME;
109df561f66SGustavo A. R. Silva 		fallthrough;
11069855819SStefan Agner 	case DRM_FORMAT_XRGB8888:
111109eee2fSJianwei Wang 		bpp = FSL_DCU_ARGB8888;
112109eee2fSJianwei Wang 		break;
11369855819SStefan Agner 	case DRM_FORMAT_ARGB4444:
11469855819SStefan Agner 		alpha = DCU_LAYER_AB_WHOLE_FRAME;
115df561f66SGustavo A. R. Silva 		fallthrough;
11669855819SStefan Agner 	case DRM_FORMAT_XRGB4444:
117109eee2fSJianwei Wang 		bpp = FSL_DCU_ARGB4444;
118109eee2fSJianwei Wang 		break;
119109eee2fSJianwei Wang 	case DRM_FORMAT_ARGB1555:
12069855819SStefan Agner 		alpha = DCU_LAYER_AB_WHOLE_FRAME;
121df561f66SGustavo A. R. Silva 		fallthrough;
12269855819SStefan Agner 	case DRM_FORMAT_XRGB1555:
123109eee2fSJianwei Wang 		bpp = FSL_DCU_ARGB1555;
124109eee2fSJianwei Wang 		break;
125109eee2fSJianwei Wang 	case DRM_FORMAT_YUV422:
126109eee2fSJianwei Wang 		bpp = FSL_DCU_YUV422;
127109eee2fSJianwei Wang 		break;
128109eee2fSJianwei Wang 	default:
129109eee2fSJianwei Wang 		return;
130109eee2fSJianwei Wang 	}
131109eee2fSJianwei Wang 
132e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1),
13341016fe1SMaxime Ripard 		     DCU_LAYER_HEIGHT(new_state->crtc_h) |
13441016fe1SMaxime Ripard 		     DCU_LAYER_WIDTH(new_state->crtc_w));
135e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2),
13641016fe1SMaxime Ripard 		     DCU_LAYER_POSY(new_state->crtc_y) |
13741016fe1SMaxime Ripard 		     DCU_LAYER_POSX(new_state->crtc_x));
138e291d298SStefan Agner 	regmap_write(fsl_dev->regmap,
139*8c30eeccSDanilo Krummrich 		     DCU_CTRLDESCLN(index, 3), gem->dma_addr);
140e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4),
141109eee2fSJianwei Wang 		     DCU_LAYER_EN |
14269855819SStefan Agner 		     DCU_LAYER_TRANS(0xff) |
143109eee2fSJianwei Wang 		     DCU_LAYER_BPP(bpp) |
14469855819SStefan Agner 		     alpha);
145e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5),
146109eee2fSJianwei Wang 		     DCU_LAYER_CKMAX_R(0xFF) |
147109eee2fSJianwei Wang 		     DCU_LAYER_CKMAX_G(0xFF) |
148109eee2fSJianwei Wang 		     DCU_LAYER_CKMAX_B(0xFF));
149e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6),
150109eee2fSJianwei Wang 		     DCU_LAYER_CKMIN_R(0) |
151109eee2fSJianwei Wang 		     DCU_LAYER_CKMIN_G(0) |
152109eee2fSJianwei Wang 		     DCU_LAYER_CKMIN_B(0));
153e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0);
154e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8),
155109eee2fSJianwei Wang 		     DCU_LAYER_FG_FCOLOR(0));
156e291d298SStefan Agner 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9),
157109eee2fSJianwei Wang 		     DCU_LAYER_BG_BCOLOR(0));
158e291d298SStefan Agner 
159109eee2fSJianwei Wang 	if (!strcmp(fsl_dev->soc->name, "ls1021a")) {
160e291d298SStefan Agner 		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10),
161109eee2fSJianwei Wang 			     DCU_LAYER_POST_SKIP(0) |
162109eee2fSJianwei Wang 			     DCU_LAYER_PRE_SKIP(0));
163109eee2fSJianwei Wang 	}
164109eee2fSJianwei Wang 
165e291d298SStefan Agner 	return;
166109eee2fSJianwei Wang }
167109eee2fSJianwei Wang 
168109eee2fSJianwei Wang static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
169109eee2fSJianwei Wang 	.atomic_check = fsl_dcu_drm_plane_atomic_check,
170109eee2fSJianwei Wang 	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
171109eee2fSJianwei Wang 	.atomic_update = fsl_dcu_drm_plane_atomic_update,
172109eee2fSJianwei Wang };
173109eee2fSJianwei Wang 
174109eee2fSJianwei Wang static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
175109eee2fSJianwei Wang 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
176109eee2fSJianwei Wang 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
177a4d847dfSThomas Zimmermann 	.destroy = drm_plane_helper_destroy,
178109eee2fSJianwei Wang 	.disable_plane = drm_atomic_helper_disable_plane,
179109eee2fSJianwei Wang 	.reset = drm_atomic_helper_plane_reset,
180109eee2fSJianwei Wang 	.update_plane = drm_atomic_helper_update_plane,
181109eee2fSJianwei Wang };
182109eee2fSJianwei Wang 
183109eee2fSJianwei Wang static const u32 fsl_dcu_drm_plane_formats[] = {
184109eee2fSJianwei Wang 	DRM_FORMAT_RGB565,
185109eee2fSJianwei Wang 	DRM_FORMAT_RGB888,
18669855819SStefan Agner 	DRM_FORMAT_XRGB8888,
187109eee2fSJianwei Wang 	DRM_FORMAT_ARGB8888,
18869855819SStefan Agner 	DRM_FORMAT_XRGB4444,
189109eee2fSJianwei Wang 	DRM_FORMAT_ARGB4444,
19069855819SStefan Agner 	DRM_FORMAT_XRGB1555,
191109eee2fSJianwei Wang 	DRM_FORMAT_ARGB1555,
192109eee2fSJianwei Wang 	DRM_FORMAT_YUV422,
193109eee2fSJianwei Wang };
194109eee2fSJianwei Wang 
fsl_dcu_drm_init_planes(struct drm_device * dev)1951277f802SStefan Agner void fsl_dcu_drm_init_planes(struct drm_device *dev)
1961277f802SStefan Agner {
1971277f802SStefan Agner 	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
1981277f802SStefan Agner 	int i, j;
1991277f802SStefan Agner 
2001277f802SStefan Agner 	for (i = 0; i < fsl_dev->soc->total_layer; i++) {
2011277f802SStefan Agner 		for (j = 1; j <= fsl_dev->soc->layer_regs; j++)
2021277f802SStefan Agner 			regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(i, j), 0);
2031277f802SStefan Agner 	}
2041277f802SStefan Agner }
2051277f802SStefan Agner 
fsl_dcu_drm_primary_create_plane(struct drm_device * dev)206109eee2fSJianwei Wang struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
207109eee2fSJianwei Wang {
208109eee2fSJianwei Wang 	struct drm_plane *primary;
209109eee2fSJianwei Wang 	int ret;
210109eee2fSJianwei Wang 
211109eee2fSJianwei Wang 	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
212109eee2fSJianwei Wang 	if (!primary) {
213109eee2fSJianwei Wang 		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
214109eee2fSJianwei Wang 		return NULL;
215109eee2fSJianwei Wang 	}
216109eee2fSJianwei Wang 
217109eee2fSJianwei Wang 	/* possible_crtc's will be filled in later by crtc_init */
218109eee2fSJianwei Wang 	ret = drm_universal_plane_init(dev, primary, 0,
219109eee2fSJianwei Wang 				       &fsl_dcu_drm_plane_funcs,
220109eee2fSJianwei Wang 				       fsl_dcu_drm_plane_formats,
221109eee2fSJianwei Wang 				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
222e6fc3b68SBen Widawsky 				       NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
223109eee2fSJianwei Wang 	if (ret) {
224109eee2fSJianwei Wang 		kfree(primary);
225109eee2fSJianwei Wang 		primary = NULL;
226109eee2fSJianwei Wang 	}
227109eee2fSJianwei Wang 	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
228109eee2fSJianwei Wang 
229109eee2fSJianwei Wang 	return primary;
230109eee2fSJianwei Wang }
231