1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2015 Freescale Semiconductor, Inc.
4  *
5  * Freescale DCU drm device driver
6  */
7 
8 #include <linux/regmap.h>
9 
10 #include <drm/drm_atomic.h>
11 #include <drm/drm_atomic_helper.h>
12 #include <drm/drm_crtc.h>
13 #include <drm/drm_fb_dma_helper.h>
14 #include <drm/drm_fourcc.h>
15 #include <drm/drm_framebuffer.h>
16 #include <drm/drm_gem_dma_helper.h>
17 #include <drm/drm_plane_helper.h>
18 #include <drm/drm_probe_helper.h>
19 
20 #include "fsl_dcu_drm_drv.h"
21 #include "fsl_dcu_drm_plane.h"
22 
23 static int fsl_dcu_drm_plane_index(struct drm_plane *plane)
24 {
25 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
26 	unsigned int total_layer = fsl_dev->soc->total_layer;
27 	unsigned int index;
28 
29 	index = drm_plane_index(plane);
30 	if (index < total_layer)
31 		return total_layer - index - 1;
32 
33 	dev_err(fsl_dev->dev, "No more layer left\n");
34 	return -EINVAL;
35 }
36 
37 static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
38 					  struct drm_atomic_state *state)
39 {
40 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
41 										 plane);
42 	struct drm_framebuffer *fb = new_plane_state->fb;
43 
44 	if (!new_plane_state->fb || !new_plane_state->crtc)
45 		return 0;
46 
47 	switch (fb->format->format) {
48 	case DRM_FORMAT_RGB565:
49 	case DRM_FORMAT_RGB888:
50 	case DRM_FORMAT_XRGB8888:
51 	case DRM_FORMAT_ARGB8888:
52 	case DRM_FORMAT_XRGB4444:
53 	case DRM_FORMAT_ARGB4444:
54 	case DRM_FORMAT_XRGB1555:
55 	case DRM_FORMAT_ARGB1555:
56 	case DRM_FORMAT_YUV422:
57 		return 0;
58 	default:
59 		return -EINVAL;
60 	}
61 }
62 
63 static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
64 					     struct drm_atomic_state *state)
65 {
66 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
67 	unsigned int value;
68 	int index;
69 
70 	index = fsl_dcu_drm_plane_index(plane);
71 	if (index < 0)
72 		return;
73 
74 	regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value);
75 	value &= ~DCU_LAYER_EN;
76 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value);
77 }
78 
79 static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
80 					    struct drm_atomic_state *state)
81 
82 {
83 	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
84 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
85 									   plane);
86 	struct drm_framebuffer *fb = plane->state->fb;
87 	struct drm_gem_dma_object *gem;
88 	unsigned int alpha = DCU_LAYER_AB_NONE, bpp;
89 	int index;
90 
91 	if (!fb)
92 		return;
93 
94 	index = fsl_dcu_drm_plane_index(plane);
95 	if (index < 0)
96 		return;
97 
98 	gem = drm_fb_dma_get_gem_obj(fb, 0);
99 
100 	switch (fb->format->format) {
101 	case DRM_FORMAT_RGB565:
102 		bpp = FSL_DCU_RGB565;
103 		break;
104 	case DRM_FORMAT_RGB888:
105 		bpp = FSL_DCU_RGB888;
106 		break;
107 	case DRM_FORMAT_ARGB8888:
108 		alpha = DCU_LAYER_AB_WHOLE_FRAME;
109 		fallthrough;
110 	case DRM_FORMAT_XRGB8888:
111 		bpp = FSL_DCU_ARGB8888;
112 		break;
113 	case DRM_FORMAT_ARGB4444:
114 		alpha = DCU_LAYER_AB_WHOLE_FRAME;
115 		fallthrough;
116 	case DRM_FORMAT_XRGB4444:
117 		bpp = FSL_DCU_ARGB4444;
118 		break;
119 	case DRM_FORMAT_ARGB1555:
120 		alpha = DCU_LAYER_AB_WHOLE_FRAME;
121 		fallthrough;
122 	case DRM_FORMAT_XRGB1555:
123 		bpp = FSL_DCU_ARGB1555;
124 		break;
125 	case DRM_FORMAT_YUV422:
126 		bpp = FSL_DCU_YUV422;
127 		break;
128 	default:
129 		return;
130 	}
131 
132 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1),
133 		     DCU_LAYER_HEIGHT(new_state->crtc_h) |
134 		     DCU_LAYER_WIDTH(new_state->crtc_w));
135 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2),
136 		     DCU_LAYER_POSY(new_state->crtc_y) |
137 		     DCU_LAYER_POSX(new_state->crtc_x));
138 	regmap_write(fsl_dev->regmap,
139 		     DCU_CTRLDESCLN(index, 3), gem->dma_addr);
140 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4),
141 		     DCU_LAYER_EN |
142 		     DCU_LAYER_TRANS(0xff) |
143 		     DCU_LAYER_BPP(bpp) |
144 		     alpha);
145 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5),
146 		     DCU_LAYER_CKMAX_R(0xFF) |
147 		     DCU_LAYER_CKMAX_G(0xFF) |
148 		     DCU_LAYER_CKMAX_B(0xFF));
149 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6),
150 		     DCU_LAYER_CKMIN_R(0) |
151 		     DCU_LAYER_CKMIN_G(0) |
152 		     DCU_LAYER_CKMIN_B(0));
153 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0);
154 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8),
155 		     DCU_LAYER_FG_FCOLOR(0));
156 	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9),
157 		     DCU_LAYER_BG_BCOLOR(0));
158 
159 	if (!strcmp(fsl_dev->soc->name, "ls1021a")) {
160 		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10),
161 			     DCU_LAYER_POST_SKIP(0) |
162 			     DCU_LAYER_PRE_SKIP(0));
163 	}
164 
165 	return;
166 }
167 
168 static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
169 	.atomic_check = fsl_dcu_drm_plane_atomic_check,
170 	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
171 	.atomic_update = fsl_dcu_drm_plane_atomic_update,
172 };
173 
174 static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
175 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
176 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
177 	.destroy = drm_plane_helper_destroy,
178 	.disable_plane = drm_atomic_helper_disable_plane,
179 	.reset = drm_atomic_helper_plane_reset,
180 	.update_plane = drm_atomic_helper_update_plane,
181 };
182 
183 static const u32 fsl_dcu_drm_plane_formats[] = {
184 	DRM_FORMAT_RGB565,
185 	DRM_FORMAT_RGB888,
186 	DRM_FORMAT_XRGB8888,
187 	DRM_FORMAT_ARGB8888,
188 	DRM_FORMAT_XRGB4444,
189 	DRM_FORMAT_ARGB4444,
190 	DRM_FORMAT_XRGB1555,
191 	DRM_FORMAT_ARGB1555,
192 	DRM_FORMAT_YUV422,
193 };
194 
195 void fsl_dcu_drm_init_planes(struct drm_device *dev)
196 {
197 	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
198 	int i, j;
199 
200 	for (i = 0; i < fsl_dev->soc->total_layer; i++) {
201 		for (j = 1; j <= fsl_dev->soc->layer_regs; j++)
202 			regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(i, j), 0);
203 	}
204 }
205 
206 struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
207 {
208 	struct drm_plane *primary;
209 	int ret;
210 
211 	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
212 	if (!primary) {
213 		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
214 		return NULL;
215 	}
216 
217 	/* possible_crtc's will be filled in later by crtc_init */
218 	ret = drm_universal_plane_init(dev, primary, 0,
219 				       &fsl_dcu_drm_plane_funcs,
220 				       fsl_dcu_drm_plane_formats,
221 				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
222 				       NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
223 	if (ret) {
224 		kfree(primary);
225 		primary = NULL;
226 	}
227 	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
228 
229 	return primary;
230 }
231