1 /*
2  * Copyright (C) 2015 Free Electrons
3  * Copyright (C) 2015 NextThing Co
4  *
5  * Maxime Ripard <maxime.ripard@free-electrons.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  */
12 
13 #include <drm/drm_atomic_helper.h>
14 #include <drm/drm_crtc.h>
15 #include <drm/drm_plane_helper.h>
16 #include <drm/drmP.h>
17 
18 #include "sun4i_backend.h"
19 #include "sun4i_drv.h"
20 #include "sun4i_layer.h"
21 
22 #define SUN4I_NUM_LAYERS	2
23 
24 static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
25 					    struct drm_plane_state *state)
26 {
27 	return 0;
28 }
29 
30 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
31 					       struct drm_plane_state *old_state)
32 {
33 	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
34 	struct sun4i_drv *drv = layer->drv;
35 	struct sun4i_backend *backend = drv->backend;
36 
37 	sun4i_backend_layer_enable(backend, layer->id, false);
38 }
39 
40 static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
41 					      struct drm_plane_state *old_state)
42 {
43 	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
44 	struct sun4i_drv *drv = layer->drv;
45 	struct sun4i_backend *backend = drv->backend;
46 
47 	sun4i_backend_update_layer_coord(backend, layer->id, plane);
48 	sun4i_backend_update_layer_formats(backend, layer->id, plane);
49 	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
50 	sun4i_backend_layer_enable(backend, layer->id, true);
51 }
52 
53 static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
54 	.atomic_check	= sun4i_backend_layer_atomic_check,
55 	.atomic_disable	= sun4i_backend_layer_atomic_disable,
56 	.atomic_update	= sun4i_backend_layer_atomic_update,
57 };
58 
59 static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
60 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
61 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
62 	.destroy		= drm_plane_cleanup,
63 	.disable_plane		= drm_atomic_helper_disable_plane,
64 	.reset			= drm_atomic_helper_plane_reset,
65 	.update_plane		= drm_atomic_helper_update_plane,
66 };
67 
68 static const uint32_t sun4i_backend_layer_formats[] = {
69 	DRM_FORMAT_ARGB8888,
70 	DRM_FORMAT_XRGB8888,
71 	DRM_FORMAT_RGB888,
72 };
73 
74 static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
75 						enum drm_plane_type type)
76 {
77 	struct sun4i_drv *drv = drm->dev_private;
78 	struct sun4i_layer *layer;
79 	int ret;
80 
81 	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
82 	if (!layer)
83 		return ERR_PTR(-ENOMEM);
84 
85 	ret = drm_universal_plane_init(drm, &layer->plane, BIT(0),
86 				       &sun4i_backend_layer_funcs,
87 				       sun4i_backend_layer_formats,
88 				       ARRAY_SIZE(sun4i_backend_layer_formats),
89 				       type,
90 				       NULL);
91 	if (ret) {
92 		dev_err(drm->dev, "Couldn't initialize layer\n");
93 		return ERR_PTR(ret);
94 	}
95 
96 	drm_plane_helper_add(&layer->plane,
97 			     &sun4i_backend_layer_helper_funcs);
98 	layer->drv = drv;
99 
100 	if (type == DRM_PLANE_TYPE_PRIMARY)
101 		drv->primary = &layer->plane;
102 
103 	return layer;
104 }
105 
106 struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
107 {
108 	struct sun4i_drv *drv = drm->dev_private;
109 	struct sun4i_layer **layers;
110 	int i;
111 
112 	layers = devm_kcalloc(drm->dev, SUN4I_NUM_LAYERS, sizeof(**layers),
113 			      GFP_KERNEL);
114 	if (!layers)
115 		return ERR_PTR(-ENOMEM);
116 
117 	/*
118 	 * The hardware is a bit unusual here.
119 	 *
120 	 * Even though it supports 4 layers, it does the composition
121 	 * in two separate steps.
122 	 *
123 	 * The first one is assigning a layer to one of its two
124 	 * pipes. If more that 1 layer is assigned to the same pipe,
125 	 * and if pixels overlaps, the pipe will take the pixel from
126 	 * the layer with the highest priority.
127 	 *
128 	 * The second step is the actual alpha blending, that takes
129 	 * the two pipes as input, and uses the eventual alpha
130 	 * component to do the transparency between the two.
131 	 *
132 	 * This two steps scenario makes us unable to guarantee a
133 	 * robust alpha blending between the 4 layers in all
134 	 * situations. So we just expose two layers, one per pipe. On
135 	 * SoCs that support it, sprites could fill the need for more
136 	 * layers.
137 	 */
138 	for (i = 0; i < SUN4I_NUM_LAYERS; i++) {
139 		enum drm_plane_type type = (i == 0)
140 					 ? DRM_PLANE_TYPE_PRIMARY
141 					 : DRM_PLANE_TYPE_OVERLAY;
142 		struct sun4i_layer *layer = layers[i];
143 
144 		layer = sun4i_layer_init_one(drm, type);
145 		if (IS_ERR(layer)) {
146 			dev_err(drm->dev, "Couldn't initialize %s plane\n",
147 				i ? "overlay" : "primary");
148 			return ERR_CAST(layer);
149 		};
150 
151 		DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
152 				 i ? "overlay" : "primary", i);
153 		regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
154 				   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
155 				   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(i));
156 
157 		layer->id = i;
158 	};
159 
160 	return layers;
161 }
162