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 value;
62 	int index, ret;
63 
64 	index = fsl_dcu_drm_plane_index(plane);
65 	if (index < 0)
66 		return;
67 
68 	ret = regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value);
69 	if (ret)
70 		dev_err(fsl_dev->dev, "read DCU_INT_MASK failed\n");
71 	value &= ~DCU_LAYER_EN;
72 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value);
73 	if (ret)
74 		dev_err(fsl_dev->dev, "set DCU register failed\n");
75 }
76 
77 static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
78 					    struct drm_plane_state *old_state)
79 
80 {
81 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
82 	struct drm_plane_state *state = plane->state;
83 	struct drm_framebuffer *fb = plane->state->fb;
84 	struct drm_gem_cma_object *gem;
85 	unsigned int alpha, bpp;
86 	int index, ret;
87 
88 	if (!fb)
89 		return;
90 
91 	index = fsl_dcu_drm_plane_index(plane);
92 	if (index < 0)
93 		return;
94 
95 	gem = drm_fb_cma_get_gem_obj(fb, 0);
96 
97 	switch (fb->pixel_format) {
98 	case DRM_FORMAT_RGB565:
99 		bpp = FSL_DCU_RGB565;
100 		alpha = 0xff;
101 		break;
102 	case DRM_FORMAT_RGB888:
103 		bpp = FSL_DCU_RGB888;
104 		alpha = 0xff;
105 		break;
106 	case DRM_FORMAT_ARGB8888:
107 		bpp = FSL_DCU_ARGB8888;
108 		alpha = 0xff;
109 		break;
110 	case DRM_FORMAT_BGRA4444:
111 		bpp = FSL_DCU_ARGB4444;
112 		alpha = 0xff;
113 		break;
114 	case DRM_FORMAT_ARGB1555:
115 		bpp = FSL_DCU_ARGB1555;
116 		alpha = 0xff;
117 		break;
118 	case DRM_FORMAT_YUV422:
119 		bpp = FSL_DCU_YUV422;
120 		alpha = 0xff;
121 		break;
122 	default:
123 		return;
124 	}
125 
126 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1),
127 			   DCU_LAYER_HEIGHT(state->crtc_h) |
128 			   DCU_LAYER_WIDTH(state->crtc_w));
129 	if (ret)
130 		goto set_failed;
131 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2),
132 			   DCU_LAYER_POSY(state->crtc_y) |
133 			   DCU_LAYER_POSX(state->crtc_x));
134 	if (ret)
135 		goto set_failed;
136 	ret = regmap_write(fsl_dev->regmap,
137 			   DCU_CTRLDESCLN(index, 3), gem->paddr);
138 	if (ret)
139 		goto set_failed;
140 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4),
141 			   DCU_LAYER_EN |
142 			   DCU_LAYER_TRANS(alpha) |
143 			   DCU_LAYER_BPP(bpp) |
144 			   DCU_LAYER_AB(0));
145 	if (ret)
146 		goto set_failed;
147 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5),
148 			   DCU_LAYER_CKMAX_R(0xFF) |
149 			   DCU_LAYER_CKMAX_G(0xFF) |
150 			   DCU_LAYER_CKMAX_B(0xFF));
151 	if (ret)
152 		goto set_failed;
153 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6),
154 			   DCU_LAYER_CKMIN_R(0) |
155 			   DCU_LAYER_CKMIN_G(0) |
156 			   DCU_LAYER_CKMIN_B(0));
157 	if (ret)
158 		goto set_failed;
159 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0);
160 	if (ret)
161 		goto set_failed;
162 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8),
163 			   DCU_LAYER_FG_FCOLOR(0));
164 	if (ret)
165 		goto set_failed;
166 	ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9),
167 			   DCU_LAYER_BG_BCOLOR(0));
168 	if (ret)
169 		goto set_failed;
170 	if (!strcmp(fsl_dev->soc->name, "ls1021a")) {
171 		ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10),
172 				   DCU_LAYER_POST_SKIP(0) |
173 				   DCU_LAYER_PRE_SKIP(0));
174 		if (ret)
175 			goto set_failed;
176 	}
177 	ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
178 				 DCU_MODE_DCU_MODE_MASK,
179 				 DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
180 	if (ret)
181 		goto set_failed;
182 	ret = regmap_write(fsl_dev->regmap,
183 			   DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
184 	if (ret)
185 		goto set_failed;
186 	return;
187 
188 set_failed:
189 	dev_err(fsl_dev->dev, "set DCU register failed\n");
190 }
191 
192 static void
193 fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
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 			     const struct drm_plane_state *new_state)
201 {
202 	return 0;
203 }
204 
205 static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
206 	.atomic_check = fsl_dcu_drm_plane_atomic_check,
207 	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
208 	.atomic_update = fsl_dcu_drm_plane_atomic_update,
209 	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
210 	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,
211 };
212 
213 static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
214 {
215 	drm_plane_cleanup(plane);
216 }
217 
218 static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
219 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
220 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
221 	.destroy = fsl_dcu_drm_plane_destroy,
222 	.disable_plane = drm_atomic_helper_disable_plane,
223 	.reset = drm_atomic_helper_plane_reset,
224 	.update_plane = drm_atomic_helper_update_plane,
225 };
226 
227 static const u32 fsl_dcu_drm_plane_formats[] = {
228 	DRM_FORMAT_RGB565,
229 	DRM_FORMAT_RGB888,
230 	DRM_FORMAT_ARGB8888,
231 	DRM_FORMAT_ARGB4444,
232 	DRM_FORMAT_ARGB1555,
233 	DRM_FORMAT_YUV422,
234 };
235 
236 struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
237 {
238 	struct drm_plane *primary;
239 	int ret;
240 
241 	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
242 	if (!primary) {
243 		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
244 		return NULL;
245 	}
246 
247 	/* possible_crtc's will be filled in later by crtc_init */
248 	ret = drm_universal_plane_init(dev, primary, 0,
249 				       &fsl_dcu_drm_plane_funcs,
250 				       fsl_dcu_drm_plane_formats,
251 				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
252 				       DRM_PLANE_TYPE_PRIMARY, NULL);
253 	if (ret) {
254 		kfree(primary);
255 		primary = NULL;
256 	}
257 	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
258 
259 	return primary;
260 }
261