xref: /openbmc/linux/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c (revision 5c3a87e363c09242541620a777d5b73e89b6c245)
1 /*
2  * Copyright 2015 Freescale Semiconductor, Inc.
3  *
4  * Freescale DCU drm device driver
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11 
12 #include <linux/regmap.h>
13 
14 #include <drm/drmP.h>
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_crtc.h>
17 #include <drm/drm_crtc_helper.h>
18 #include <drm/drm_fb_cma_helper.h>
19 #include <drm/drm_gem_cma_helper.h>
20 #include <drm/drm_plane_helper.h>
21 
22 #include "fsl_dcu_drm_drv.h"
23 #include "fsl_dcu_drm_plane.h"
24 
25 static int fsl_dcu_drm_plane_index(struct drm_plane *plane)
26 {
27 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
28 	unsigned int total_layer = fsl_dev->soc->total_layer;
29 	unsigned int index;
30 
31 	index = drm_plane_index(plane);
32 	if (index < total_layer)
33 		return total_layer - index - 1;
34 
35 	dev_err(fsl_dev->dev, "No more layer left\n");
36 	return -EINVAL;
37 }
38 
39 static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
40 					  struct drm_plane_state *state)
41 {
42 	struct drm_framebuffer *fb = state->fb;
43 
44 	switch (fb->pixel_format) {
45 	case DRM_FORMAT_RGB565:
46 	case DRM_FORMAT_RGB888:
47 	case DRM_FORMAT_ARGB8888:
48 	case DRM_FORMAT_BGRA4444:
49 	case DRM_FORMAT_ARGB1555:
50 	case DRM_FORMAT_YUV422:
51 		return 0;
52 	default:
53 		return -EINVAL;
54 	}
55 }
56 
57 static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
58 					     struct drm_plane_state *old_state)
59 {
60 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
61 	unsigned int index, value, ret;
62 
63 	index = fsl_dcu_drm_plane_index(plane);
64 	if (index < 0)
65 		return;
66 
67 	ret = regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value);
68 	if (ret)
69 		dev_err(fsl_dev->dev, "read DCU_INT_MASK failed\n");
70 	value &= ~DCU_LAYER_EN;
71 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value);
72 	if (ret)
73 		dev_err(fsl_dev->dev, "set DCU register failed\n");
74 }
75 
76 static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
77 					    struct drm_plane_state *old_state)
78 
79 {
80 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
81 	struct drm_plane_state *state = plane->state;
82 	struct drm_framebuffer *fb = plane->state->fb;
83 	struct drm_gem_cma_object *gem;
84 	unsigned int alpha, bpp;
85 	int index, ret;
86 
87 	if (!fb)
88 		return;
89 
90 	index = fsl_dcu_drm_plane_index(plane);
91 	if (index < 0)
92 		return;
93 
94 	gem = drm_fb_cma_get_gem_obj(fb, 0);
95 
96 	switch (fb->pixel_format) {
97 	case DRM_FORMAT_RGB565:
98 		bpp = FSL_DCU_RGB565;
99 		alpha = 0xff;
100 		break;
101 	case DRM_FORMAT_RGB888:
102 		bpp = FSL_DCU_RGB888;
103 		alpha = 0xff;
104 		break;
105 	case DRM_FORMAT_ARGB8888:
106 		bpp = FSL_DCU_ARGB8888;
107 		alpha = 0xff;
108 		break;
109 	case DRM_FORMAT_BGRA4444:
110 		bpp = FSL_DCU_ARGB4444;
111 		alpha = 0xff;
112 		break;
113 	case DRM_FORMAT_ARGB1555:
114 		bpp = FSL_DCU_ARGB1555;
115 		alpha = 0xff;
116 		break;
117 	case DRM_FORMAT_YUV422:
118 		bpp = FSL_DCU_YUV422;
119 		alpha = 0xff;
120 		break;
121 	default:
122 		return;
123 	}
124 
125 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1),
126 			   DCU_LAYER_HEIGHT(state->crtc_h) |
127 			   DCU_LAYER_WIDTH(state->crtc_w));
128 	if (ret)
129 		goto set_failed;
130 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2),
131 			   DCU_LAYER_POSY(state->crtc_y) |
132 			   DCU_LAYER_POSX(state->crtc_x));
133 	if (ret)
134 		goto set_failed;
135 	ret = regmap_write(fsl_dev->regmap,
136 			   DCU_CTRLDESCLN(index, 3), gem->paddr);
137 	if (ret)
138 		goto set_failed;
139 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4),
140 			   DCU_LAYER_EN |
141 			   DCU_LAYER_TRANS(alpha) |
142 			   DCU_LAYER_BPP(bpp) |
143 			   DCU_LAYER_AB(0));
144 	if (ret)
145 		goto set_failed;
146 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5),
147 			   DCU_LAYER_CKMAX_R(0xFF) |
148 			   DCU_LAYER_CKMAX_G(0xFF) |
149 			   DCU_LAYER_CKMAX_B(0xFF));
150 	if (ret)
151 		goto set_failed;
152 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6),
153 			   DCU_LAYER_CKMIN_R(0) |
154 			   DCU_LAYER_CKMIN_G(0) |
155 			   DCU_LAYER_CKMIN_B(0));
156 	if (ret)
157 		goto set_failed;
158 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0);
159 	if (ret)
160 		goto set_failed;
161 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8),
162 			   DCU_LAYER_FG_FCOLOR(0));
163 	if (ret)
164 		goto set_failed;
165 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9),
166 			   DCU_LAYER_BG_BCOLOR(0));
167 	if (ret)
168 		goto set_failed;
169 	if (!strcmp(fsl_dev->soc->name, "ls1021a")) {
170 		ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10),
171 				   DCU_LAYER_POST_SKIP(0) |
172 				   DCU_LAYER_PRE_SKIP(0));
173 		if (ret)
174 			goto set_failed;
175 	}
176 	ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
177 				 DCU_MODE_DCU_MODE_MASK,
178 				 DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
179 	if (ret)
180 		goto set_failed;
181 	ret = regmap_write(fsl_dev->regmap,
182 			   DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
183 	if (ret)
184 		goto set_failed;
185 	return;
186 
187 set_failed:
188 	dev_err(fsl_dev->dev, "set DCU register failed\n");
189 }
190 
191 static void
192 fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
193 			     struct drm_framebuffer *fb,
194 			     const struct drm_plane_state *new_state)
195 {
196 }
197 
198 static int
199 fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
200 			     struct drm_framebuffer *fb,
201 			     const struct drm_plane_state *new_state)
202 {
203 	return 0;
204 }
205 
206 static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
207 	.atomic_check = fsl_dcu_drm_plane_atomic_check,
208 	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
209 	.atomic_update = fsl_dcu_drm_plane_atomic_update,
210 	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
211 	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,
212 };
213 
214 static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
215 {
216 	drm_plane_cleanup(plane);
217 }
218 
219 static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
220 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
221 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
222 	.destroy = fsl_dcu_drm_plane_destroy,
223 	.disable_plane = drm_atomic_helper_disable_plane,
224 	.reset = drm_atomic_helper_plane_reset,
225 	.update_plane = drm_atomic_helper_update_plane,
226 };
227 
228 static const u32 fsl_dcu_drm_plane_formats[] = {
229 	DRM_FORMAT_RGB565,
230 	DRM_FORMAT_RGB888,
231 	DRM_FORMAT_ARGB8888,
232 	DRM_FORMAT_ARGB4444,
233 	DRM_FORMAT_ARGB1555,
234 	DRM_FORMAT_YUV422,
235 };
236 
237 struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
238 {
239 	struct drm_plane *primary;
240 	int ret;
241 
242 	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
243 	if (!primary) {
244 		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
245 		return NULL;
246 	}
247 
248 	/* possible_crtc's will be filled in later by crtc_init */
249 	ret = drm_universal_plane_init(dev, primary, 0,
250 				       &fsl_dcu_drm_plane_funcs,
251 				       fsl_dcu_drm_plane_formats,
252 				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
253 				       DRM_PLANE_TYPE_PRIMARY);
254 	if (ret) {
255 		kfree(primary);
256 		primary = NULL;
257 	}
258 	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
259 
260 	return primary;
261 }
262