aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorVincent Abriou <vincent.abriou@st.com>2015-08-03 08:22:16 -0400
committerBenjamin Gaignard <benjamin.gaignard@linaro.org>2015-08-03 08:26:05 -0400
commit29d1dc62e1618192a25bd2eae9617529b9930cfc (patch)
tree67e0151ceaad7b164d1f2b7accc7d6f21f377299 /drivers/gpu/drm
parent9e1f05b28009ca7de50fb92c227c8046f686e2c5 (diff)
drm/sti: atomic crtc/plane update
Better fit STI hardware structure. Planes are no more responsible of updating mixer information such as z-order and status. It is now up to the CRTC atomic flush to do it. Plane actions (enable or disable) are performed atomically. Disabling of a plane is synchronize with the vsync event. Signed-off-by: Vincent Abriou <vincent.abriou@st.com> Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.c32
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c133
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c211
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.h6
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c493
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.h8
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c429
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.c10
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.h11
-rw-r--r--drivers/gpu/drm/sti/sti_plane.c253
-rw-r--r--drivers/gpu/drm/sti/sti_plane.h66
-rw-r--r--drivers/gpu/drm/sti/sti_vid.c29
-rw-r--r--drivers/gpu/drm/sti/sti_vid.h5
13 files changed, 809 insertions, 877 deletions
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index d62ed7f4cb2c..c652627b1bca 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -61,15 +61,13 @@ static int sti_compositor_bind(struct device *dev,
61{ 61{
62 struct sti_compositor *compo = dev_get_drvdata(dev); 62 struct sti_compositor *compo = dev_get_drvdata(dev);
63 struct drm_device *drm_dev = data; 63 struct drm_device *drm_dev = data;
64 unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0; 64 unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0;
65 struct sti_private *dev_priv = drm_dev->dev_private; 65 struct sti_private *dev_priv = drm_dev->dev_private;
66 struct drm_plane *cursor = NULL; 66 struct drm_plane *cursor = NULL;
67 struct drm_plane *primary = NULL; 67 struct drm_plane *primary = NULL;
68 struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc; 68 struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc;
69 unsigned int array_size = compo->data.nb_subdev; 69 unsigned int array_size = compo->data.nb_subdev;
70 70
71 struct sti_plane *plane;
72
73 dev_priv->compo = compo; 71 dev_priv->compo = compo;
74 72
75 /* Register mixer subdev and video subdev first */ 73 /* Register mixer subdev and video subdev first */
@@ -110,27 +108,25 @@ static int sti_compositor_bind(struct device *dev,
110 /* Nothing to do, already done at the first round */ 108 /* Nothing to do, already done at the first round */
111 break; 109 break;
112 case STI_CURSOR_SUBDEV: 110 case STI_CURSOR_SUBDEV:
113 plane = sti_cursor_create(compo->dev, desc[i].id, 111 cursor = sti_cursor_create(drm_dev, compo->dev,
114 compo->regs + desc[i].offset); 112 desc[i].id,
115 if (!plane) { 113 compo->regs + desc[i].offset,
114 1);
115 if (!cursor) {
116 DRM_ERROR("Can't create CURSOR plane\n"); 116 DRM_ERROR("Can't create CURSOR plane\n");
117 break; 117 break;
118 } 118 }
119 cursor = sti_plane_init(drm_dev, plane, 1,
120 DRM_PLANE_TYPE_CURSOR);
121 plane_id++;
122 break; 119 break;
123 case STI_GPD_SUBDEV: 120 case STI_GPD_SUBDEV:
124 plane = sti_gdp_create(compo->dev, desc[i].id, 121 primary = sti_gdp_create(drm_dev, compo->dev,
125 compo->regs + desc[i].offset); 122 desc[i].id,
126 if (!plane) { 123 compo->regs + desc[i].offset,
124 (1 << mixer_id) - 1,
125 plane_type);
126 if (!primary) {
127 DRM_ERROR("Can't create GDP plane\n"); 127 DRM_ERROR("Can't create GDP plane\n");
128 break; 128 break;
129 } 129 }
130 primary = sti_plane_init(drm_dev, plane,
131 (1 << mixer_id) - 1,
132 plane_type);
133 plane_id++;
134 break; 130 break;
135 default: 131 default:
136 DRM_ERROR("Unknown subdev compoment type\n"); 132 DRM_ERROR("Unknown subdev compoment type\n");
@@ -151,10 +147,6 @@ static int sti_compositor_bind(struct device *dev,
151 /* Allow usage of vblank without having to call drm_irq_install */ 147 /* Allow usage of vblank without having to call drm_irq_install */
152 drm_dev->irq_enabled = 1; 148 drm_dev->irq_enabled = 1;
153 149
154 DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n",
155 crtc_id, plane_id);
156 DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n");
157
158 return 0; 150 return 0;
159} 151}
160 152
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index 27b3ef207617..23fc2db50d17 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -17,20 +17,18 @@
17#include "sti_compositor.h" 17#include "sti_compositor.h"
18#include "sti_crtc.h" 18#include "sti_crtc.h"
19#include "sti_drv.h" 19#include "sti_drv.h"
20#include "sti_vid.h"
20#include "sti_vtg.h" 21#include "sti_vtg.h"
21 22
22static void sti_crtc_dpms(struct drm_crtc *crtc, int mode) 23static void sti_crtc_enable(struct drm_crtc *crtc)
23{
24 DRM_DEBUG_KMS("\n");
25}
26
27static void sti_crtc_prepare(struct drm_crtc *crtc)
28{ 24{
29 struct sti_mixer *mixer = to_sti_mixer(crtc); 25 struct sti_mixer *mixer = to_sti_mixer(crtc);
30 struct device *dev = mixer->dev; 26 struct device *dev = mixer->dev;
31 struct sti_compositor *compo = dev_get_drvdata(dev); 27 struct sti_compositor *compo = dev_get_drvdata(dev);
32 28
33 mixer->enabled = true; 29 DRM_DEBUG_DRIVER("\n");
30
31 mixer->status = STI_MIXER_READY;
34 32
35 /* Prepare and enable the compo IP clock */ 33 /* Prepare and enable the compo IP clock */
36 if (mixer->id == STI_MIXER_MAIN) { 34 if (mixer->id == STI_MIXER_MAIN) {
@@ -41,31 +39,16 @@ static void sti_crtc_prepare(struct drm_crtc *crtc)
41 DRM_INFO("Failed to prepare/enable compo_aux clk\n"); 39 DRM_INFO("Failed to prepare/enable compo_aux clk\n");
42 } 40 }
43 41
44 sti_mixer_clear_all_planes(mixer); 42 drm_crtc_vblank_on(crtc);
45} 43}
46 44
47static void sti_crtc_commit(struct drm_crtc *crtc) 45static void sti_crtc_disabling(struct drm_crtc *crtc)
48{ 46{
49 struct sti_mixer *mixer = to_sti_mixer(crtc); 47 struct sti_mixer *mixer = to_sti_mixer(crtc);
50 struct device *dev = mixer->dev;
51 struct sti_compositor *compo = dev_get_drvdata(dev);
52 struct sti_plane *plane;
53
54 if ((!mixer || !compo)) {
55 DRM_ERROR("Can't find mixer or compositor)\n");
56 return;
57 }
58
59 /* get GDP which is reserved to the CRTC FB */
60 plane = to_sti_plane(crtc->primary);
61 if (!plane)
62 DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n");
63 48
64 /* Enable plane on mixer */ 49 DRM_DEBUG_DRIVER("\n");
65 if (sti_mixer_set_plane_status(mixer, plane, true))
66 DRM_ERROR("Cannot enable plane at mixer\n");
67 50
68 drm_crtc_vblank_on(crtc); 51 mixer->status = STI_MIXER_DISABLING;
69} 52}
70 53
71static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, 54static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -133,9 +116,6 @@ static void sti_crtc_disable(struct drm_crtc *crtc)
133 struct device *dev = mixer->dev; 116 struct device *dev = mixer->dev;
134 struct sti_compositor *compo = dev_get_drvdata(dev); 117 struct sti_compositor *compo = dev_get_drvdata(dev);
135 118
136 if (!mixer->enabled)
137 return;
138
139 DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); 119 DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
140 120
141 /* Disable Background */ 121 /* Disable Background */
@@ -152,13 +132,13 @@ static void sti_crtc_disable(struct drm_crtc *crtc)
152 clk_disable_unprepare(compo->clk_compo_aux); 132 clk_disable_unprepare(compo->clk_compo_aux);
153 } 133 }
154 134
155 mixer->enabled = false; 135 mixer->status = STI_MIXER_DISABLED;
156} 136}
157 137
158static void 138static void
159sti_crtc_mode_set_nofb(struct drm_crtc *crtc) 139sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
160{ 140{
161 sti_crtc_prepare(crtc); 141 sti_crtc_enable(crtc);
162 sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); 142 sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
163} 143}
164 144
@@ -178,17 +158,79 @@ static void sti_crtc_atomic_begin(struct drm_crtc *crtc)
178 158
179static void sti_crtc_atomic_flush(struct drm_crtc *crtc) 159static void sti_crtc_atomic_flush(struct drm_crtc *crtc)
180{ 160{
161 struct drm_device *drm_dev = crtc->dev;
162 struct sti_mixer *mixer = to_sti_mixer(crtc);
163 struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
164 struct drm_plane *p;
165
166 DRM_DEBUG_DRIVER("\n");
167
168 /* perform plane actions */
169 list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
170 struct sti_plane *plane = to_sti_plane(p);
171
172 switch (plane->status) {
173 case STI_PLANE_UPDATED:
174 /* update planes tag as updated */
175 DRM_DEBUG_DRIVER("update plane %s\n",
176 sti_plane_to_str(plane));
177
178 if (sti_mixer_set_plane_depth(mixer, plane)) {
179 DRM_ERROR("Cannot set plane %s depth\n",
180 sti_plane_to_str(plane));
181 break;
182 }
183
184 if (sti_mixer_set_plane_status(mixer, plane, true)) {
185 DRM_ERROR("Cannot enable plane %s at mixer\n",
186 sti_plane_to_str(plane));
187 break;
188 }
189
190 /* if plane is HQVDP_0 then commit the vid[0] */
191 if (plane->desc == STI_HQVDP_0)
192 sti_vid_commit(compo->vid[0], p->state);
193
194 plane->status = STI_PLANE_READY;
195
196 break;
197 case STI_PLANE_DISABLING:
198 /* disabling sequence for planes tag as disabling */
199 DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
200 sti_plane_to_str(plane));
201
202 if (sti_mixer_set_plane_status(mixer, plane, false)) {
203 DRM_ERROR("Cannot disable plane %s at mixer\n",
204 sti_plane_to_str(plane));
205 continue;
206 }
207
208 if (plane->desc == STI_CURSOR)
209 /* tag plane status for disabled */
210 plane->status = STI_PLANE_DISABLED;
211 else
212 /* tag plane status for flushing */
213 plane->status = STI_PLANE_FLUSHING;
214
215 /* if plane is HQVDP_0 then disable the vid[0] */
216 if (plane->desc == STI_HQVDP_0)
217 sti_vid_disable(compo->vid[0]);
218
219 break;
220 default:
221 /* Other status case are not handled */
222 break;
223 }
224 }
181} 225}
182 226
183static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { 227static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
184 .dpms = sti_crtc_dpms, 228 .enable = sti_crtc_enable,
185 .prepare = sti_crtc_prepare, 229 .disable = sti_crtc_disabling,
186 .commit = sti_crtc_commit,
187 .mode_fixup = sti_crtc_mode_fixup, 230 .mode_fixup = sti_crtc_mode_fixup,
188 .mode_set = drm_helper_crtc_mode_set, 231 .mode_set = drm_helper_crtc_mode_set,
189 .mode_set_nofb = sti_crtc_mode_set_nofb, 232 .mode_set_nofb = sti_crtc_mode_set_nofb,
190 .mode_set_base = drm_helper_crtc_mode_set_base, 233 .mode_set_base = drm_helper_crtc_mode_set_base,
191 .disable = sti_crtc_disable,
192 .atomic_begin = sti_crtc_atomic_begin, 234 .atomic_begin = sti_crtc_atomic_begin,
193 .atomic_flush = sti_crtc_atomic_flush, 235 .atomic_flush = sti_crtc_atomic_flush,
194}; 236};
@@ -237,6 +279,21 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
237 } 279 }
238 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 280 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
239 281
282 if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) {
283 struct drm_plane *p;
284
285 /* Disable mixer only if all overlay planes (GDP and VDP)
286 * are disabled */
287 list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
288 struct sti_plane *plane = to_sti_plane(p);
289
290 if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
291 if (plane->status != STI_PLANE_DISABLED)
292 return 0;
293 }
294 sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
295 }
296
240 return 0; 297 return 0;
241} 298}
242 299
@@ -259,9 +316,9 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc)
259} 316}
260EXPORT_SYMBOL(sti_crtc_enable_vblank); 317EXPORT_SYMBOL(sti_crtc_enable_vblank);
261 318
262void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) 319void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc)
263{ 320{
264 struct sti_private *priv = dev->dev_private; 321 struct sti_private *priv = drm_dev->dev_private;
265 struct sti_compositor *compo = priv->compo; 322 struct sti_compositor *compo = priv->compo;
266 struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; 323 struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
267 324
@@ -273,7 +330,7 @@ void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)
273 330
274 /* free the resources of the pending requests */ 331 /* free the resources of the pending requests */
275 if (compo->mixer[crtc]->pending_event) { 332 if (compo->mixer[crtc]->pending_event) {
276 drm_vblank_put(dev, crtc); 333 drm_vblank_put(drm_dev, crtc);
277 compo->mixer[crtc]->pending_event = NULL; 334 compo->mixer[crtc]->pending_event = NULL;
278 } 335 }
279} 336}
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 2868909aa926..dd1032195051 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -7,6 +7,12 @@
7 */ 7 */
8#include <drm/drmP.h> 8#include <drm/drmP.h>
9 9
10#include <drm/drm_atomic_helper.h>
11#include <drm/drm_fb_cma_helper.h>
12#include <drm/drm_gem_cma_helper.h>
13#include <drm/drm_plane_helper.h>
14
15#include "sti_compositor.h"
10#include "sti_cursor.h" 16#include "sti_cursor.h"
11#include "sti_plane.h" 17#include "sti_plane.h"
12#include "sti_vtg.h" 18#include "sti_vtg.h"
@@ -42,14 +48,14 @@ struct dma_pixmap {
42/** 48/**
43 * STI Cursor structure 49 * STI Cursor structure
44 * 50 *
45 * @sti_plane: sti_plane structure 51 * @sti_plane: sti_plane structure
46 * @dev: driver device 52 * @dev: driver device
47 * @regs: cursor registers 53 * @regs: cursor registers
48 * @width: cursor width 54 * @width: cursor width
49 * @height: cursor height 55 * @height: cursor height
50 * @clut: color look up table 56 * @clut: color look up table
51 * @clut_paddr: color look up table physical address 57 * @clut_paddr: color look up table physical address
52 * @pixmap: pixmap dma buffer (clut8-format cursor) 58 * @pixmap: pixmap dma buffer (clut8-format cursor)
53 */ 59 */
54struct sti_cursor { 60struct sti_cursor {
55 struct sti_plane plane; 61 struct sti_plane plane;
@@ -68,20 +74,8 @@ static const uint32_t cursor_supported_formats[] = {
68 74
69#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane) 75#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)
70 76
71static const uint32_t *sti_cursor_get_formats(struct sti_plane *plane) 77static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src)
72{
73 return cursor_supported_formats;
74}
75
76static unsigned int sti_cursor_get_nb_formats(struct sti_plane *plane)
77{
78 return ARRAY_SIZE(cursor_supported_formats);
79}
80
81static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane)
82{ 78{
83 struct sti_cursor *cursor = to_sti_cursor(plane);
84 u32 *src = plane->vaddr;
85 u8 *dst = cursor->pixmap.base; 79 u8 *dst = cursor->pixmap.base;
86 unsigned int i, j; 80 unsigned int i, j;
87 u32 a, r, g, b; 81 u32 a, r, g, b;
@@ -100,32 +94,67 @@ static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane)
100 } 94 }
101} 95}
102 96
103static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) 97static void sti_cursor_init(struct sti_cursor *cursor)
98{
99 unsigned short *base = cursor->clut;
100 unsigned int a, r, g, b;
101
102 /* Assign CLUT values, ARGB444 format */
103 for (a = 0; a < 4; a++)
104 for (r = 0; r < 4; r++)
105 for (g = 0; g < 4; g++)
106 for (b = 0; b < 4; b++)
107 *base++ = (a * 5) << 12 |
108 (r * 5) << 8 |
109 (g * 5) << 4 |
110 (b * 5);
111}
112
113static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
114 struct drm_plane_state *oldstate)
104{ 115{
116 struct drm_plane_state *state = drm_plane->state;
117 struct sti_plane *plane = to_sti_plane(drm_plane);
105 struct sti_cursor *cursor = to_sti_cursor(plane); 118 struct sti_cursor *cursor = to_sti_cursor(plane);
106 struct drm_display_mode *mode = plane->mode; 119 struct drm_crtc *crtc = state->crtc;
120 struct sti_mixer *mixer = to_sti_mixer(crtc);
121 struct drm_framebuffer *fb = state->fb;
122 struct drm_display_mode *mode = &crtc->mode;
123 int dst_x = state->crtc_x;
124 int dst_y = state->crtc_y;
125 int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
126 int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
127 /* src_x are in 16.16 format */
128 int src_w = state->src_w >> 16;
129 int src_h = state->src_h >> 16;
130 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
131 struct drm_gem_cma_object *cma_obj;
107 u32 y, x; 132 u32 y, x;
108 u32 val; 133 u32 val;
109 134
110 DRM_DEBUG_DRIVER("\n"); 135 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
136 crtc->base.id, sti_mixer_to_str(mixer),
137 drm_plane->base.id, sti_plane_to_str(plane));
138 DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
111 139
112 dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); 140 dev_dbg(cursor->dev, "%s %s\n", __func__,
141 sti_plane_to_str(plane));
113 142
114 if (plane->src_w < STI_CURS_MIN_SIZE || 143 if (src_w < STI_CURS_MIN_SIZE ||
115 plane->src_h < STI_CURS_MIN_SIZE || 144 src_h < STI_CURS_MIN_SIZE ||
116 plane->src_w > STI_CURS_MAX_SIZE || 145 src_w > STI_CURS_MAX_SIZE ||
117 plane->src_h > STI_CURS_MAX_SIZE) { 146 src_h > STI_CURS_MAX_SIZE) {
118 DRM_ERROR("Invalid cursor size (%dx%d)\n", 147 DRM_ERROR("Invalid cursor size (%dx%d)\n",
119 plane->src_w, plane->src_h); 148 src_w, src_h);
120 return -EINVAL; 149 return;
121 } 150 }
122 151
123 /* If the cursor size has changed, re-allocated the pixmap */ 152 /* If the cursor size has changed, re-allocated the pixmap */
124 if (!cursor->pixmap.base || 153 if (!cursor->pixmap.base ||
125 (cursor->width != plane->src_w) || 154 (cursor->width != src_w) ||
126 (cursor->height != plane->src_h)) { 155 (cursor->height != src_h)) {
127 cursor->width = plane->src_w; 156 cursor->width = src_w;
128 cursor->height = plane->src_h; 157 cursor->height = src_h;
129 158
130 if (cursor->pixmap.base) 159 if (cursor->pixmap.base)
131 dma_free_writecombine(cursor->dev, 160 dma_free_writecombine(cursor->dev,
@@ -141,12 +170,18 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
141 GFP_KERNEL | GFP_DMA); 170 GFP_KERNEL | GFP_DMA);
142 if (!cursor->pixmap.base) { 171 if (!cursor->pixmap.base) {
143 DRM_ERROR("Failed to allocate memory for pixmap\n"); 172 DRM_ERROR("Failed to allocate memory for pixmap\n");
144 return -ENOMEM; 173 return;
145 } 174 }
146 } 175 }
147 176
177 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
178 if (!cma_obj) {
179 DRM_ERROR("Can't get CMA GEM object for fb\n");
180 return;
181 }
182
148 /* Convert ARGB8888 to CLUT8 */ 183 /* Convert ARGB8888 to CLUT8 */
149 sti_cursor_argb8888_to_clut8(plane); 184 sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);
150 185
151 /* AWS and AWE depend on the mode */ 186 /* AWS and AWE depend on the mode */
152 y = sti_vtg_get_line_number(*mode, 0); 187 y = sti_vtg_get_line_number(*mode, 0);
@@ -164,62 +199,50 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
164 writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL); 199 writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
165 } 200 }
166 201
167 return 0;
168}
169
170static int sti_cursor_commit_plane(struct sti_plane *plane)
171{
172 struct sti_cursor *cursor = to_sti_cursor(plane);
173 struct drm_display_mode *mode = plane->mode;
174 u32 ydo, xdo;
175
176 dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
177
178 /* Set memory location, size, and position */ 202 /* Set memory location, size, and position */
179 writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); 203 writel(cursor->pixmap.paddr, cursor->regs + CUR_PML);
180 writel(cursor->width, cursor->regs + CUR_PMP); 204 writel(cursor->width, cursor->regs + CUR_PMP);
181 writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE); 205 writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE);
182 206
183 ydo = sti_vtg_get_line_number(*mode, plane->dst_y); 207 y = sti_vtg_get_line_number(*mode, dst_y);
184 xdo = sti_vtg_get_pixel_number(*mode, plane->dst_y); 208 x = sti_vtg_get_pixel_number(*mode, dst_y);
185 writel((ydo << 16) | xdo, cursor->regs + CUR_VPO); 209 writel((y << 16) | x, cursor->regs + CUR_VPO);
186 210
187 return 0; 211 plane->status = STI_PLANE_UPDATED;
188} 212}
189 213
190static int sti_cursor_disable_plane(struct sti_plane *plane) 214static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
215 struct drm_plane_state *oldstate)
191{ 216{
192 return 0; 217 struct sti_plane *plane = to_sti_plane(drm_plane);
193} 218 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
194 219
195static void sti_cursor_init(struct sti_cursor *cursor) 220 if (!drm_plane->crtc) {
196{ 221 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
197 unsigned short *base = cursor->clut; 222 drm_plane->base.id);
198 unsigned int a, r, g, b; 223 return;
224 }
199 225
200 /* Assign CLUT values, ARGB444 format */ 226 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
201 for (a = 0; a < 4; a++) 227 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
202 for (r = 0; r < 4; r++) 228 drm_plane->base.id, sti_plane_to_str(plane));
203 for (g = 0; g < 4; g++) 229
204 for (b = 0; b < 4; b++) 230 plane->status = STI_PLANE_DISABLING;
205 *base++ = (a * 5) << 12 |
206 (r * 5) << 8 |
207 (g * 5) << 4 |
208 (b * 5);
209} 231}
210 232
211static const struct sti_plane_funcs cursor_plane_ops = { 233static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
212 .get_formats = sti_cursor_get_formats, 234 .atomic_update = sti_cursor_atomic_update,
213 .get_nb_formats = sti_cursor_get_nb_formats, 235 .atomic_disable = sti_cursor_atomic_disable,
214 .prepare = sti_cursor_prepare_plane,
215 .commit = sti_cursor_commit_plane,
216 .disable = sti_cursor_disable_plane,
217}; 236};
218 237
219struct sti_plane *sti_cursor_create(struct device *dev, int desc, 238struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
220 void __iomem *baseaddr) 239 struct device *dev, int desc,
240 void __iomem *baseaddr,
241 unsigned int possible_crtcs)
221{ 242{
222 struct sti_cursor *cursor; 243 struct sti_cursor *cursor;
244 size_t size;
245 int res;
223 246
224 cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL); 247 cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
225 if (!cursor) { 248 if (!cursor) {
@@ -228,23 +251,43 @@ struct sti_plane *sti_cursor_create(struct device *dev, int desc,
228 } 251 }
229 252
230 /* Allocate clut buffer */ 253 /* Allocate clut buffer */
231 cursor->clut = dma_alloc_writecombine(dev, 254 size = 0x100 * sizeof(unsigned short);
232 0x100 * sizeof(unsigned short), 255 cursor->clut = dma_alloc_writecombine(dev, size, &cursor->clut_paddr,
233 &cursor->clut_paddr, 256 GFP_KERNEL | GFP_DMA);
234 GFP_KERNEL | GFP_DMA);
235 257
236 if (!cursor->clut) { 258 if (!cursor->clut) {
237 DRM_ERROR("Failed to allocate memory for cursor clut\n"); 259 DRM_ERROR("Failed to allocate memory for cursor clut\n");
238 devm_kfree(dev, cursor); 260 goto err_clut;
239 return NULL;
240 } 261 }
241 262
242 cursor->dev = dev; 263 cursor->dev = dev;
243 cursor->regs = baseaddr; 264 cursor->regs = baseaddr;
244 cursor->plane.desc = desc; 265 cursor->plane.desc = desc;
245 cursor->plane.ops = &cursor_plane_ops; 266 cursor->plane.status = STI_PLANE_DISABLED;
246 267
247 sti_cursor_init(cursor); 268 sti_cursor_init(cursor);
248 269
249 return &cursor->plane; 270 res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane,
271 possible_crtcs,
272 &sti_plane_helpers_funcs,
273 cursor_supported_formats,
274 ARRAY_SIZE(cursor_supported_formats),
275 DRM_PLANE_TYPE_CURSOR);
276 if (res) {
277 DRM_ERROR("Failed to initialize universal plane\n");
278 goto err_plane;
279 }
280
281 drm_plane_helper_add(&cursor->plane.drm_plane,
282 &sti_cursor_helpers_funcs);
283
284 sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
285
286 return &cursor->plane.drm_plane;
287
288err_plane:
289 dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr);
290err_clut:
291 devm_kfree(dev, cursor);
292 return NULL;
250} 293}
diff --git a/drivers/gpu/drm/sti/sti_cursor.h b/drivers/gpu/drm/sti/sti_cursor.h
index db973b705d92..2ee5c10e8b33 100644
--- a/drivers/gpu/drm/sti/sti_cursor.h
+++ b/drivers/gpu/drm/sti/sti_cursor.h
@@ -7,7 +7,9 @@
7#ifndef _STI_CURSOR_H_ 7#ifndef _STI_CURSOR_H_
8#define _STI_CURSOR_H_ 8#define _STI_CURSOR_H_
9 9
10struct sti_plane *sti_cursor_create(struct device *dev, int desc, 10struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
11 void __iomem *baseaddr); 11 struct device *dev, int desc,
12 void __iomem *baseaddr,
13 unsigned int possible_crtcs);
12 14
13#endif 15#endif
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index e323310bfa73..9365670427ad 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -9,6 +9,9 @@
9#include <linux/clk.h> 9#include <linux/clk.h>
10#include <linux/dma-mapping.h> 10#include <linux/dma-mapping.h>
11 11
12#include <drm/drm_fb_cma_helper.h>
13#include <drm/drm_gem_cma_helper.h>
14
12#include "sti_compositor.h" 15#include "sti_compositor.h"
13#include "sti_gdp.h" 16#include "sti_gdp.h"
14#include "sti_plane.h" 17#include "sti_plane.h"
@@ -26,7 +29,7 @@
26#define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH) 29#define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH)
27#define GDP_ARGB8565 0x04 30#define GDP_ARGB8565 0x04
28#define GDP_ARGB8888 0x05 31#define GDP_ARGB8888 0x05
29#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) 32#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
30#define GDP_ARGB1555 0x06 33#define GDP_ARGB1555 0x06
31#define GDP_ARGB4444 0x07 34#define GDP_ARGB4444 0x07
32#define GDP_CLUT8 0x0B 35#define GDP_CLUT8 0x0B
@@ -53,8 +56,8 @@
53#define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0)) 56#define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0))
54#define GAM_GDP_SIZE_MAX 0x7FF 57#define GAM_GDP_SIZE_MAX 0x7FF
55 58
56#define GDP_NODE_NB_BANK 2 59#define GDP_NODE_NB_BANK 2
57#define GDP_NODE_PER_FIELD 2 60#define GDP_NODE_PER_FIELD 2
58 61
59struct sti_gdp_node { 62struct sti_gdp_node {
60 u32 gam_gdp_ctl; 63 u32 gam_gdp_ctl;
@@ -124,16 +127,6 @@ static const uint32_t gdp_supported_formats[] = {
124 DRM_FORMAT_C8, 127 DRM_FORMAT_C8,
125}; 128};
126 129
127static const uint32_t *sti_gdp_get_formats(struct sti_plane *plane)
128{
129 return gdp_supported_formats;
130}
131
132static unsigned int sti_gdp_get_nb_formats(struct sti_plane *plane)
133{
134 return ARRAY_SIZE(gdp_supported_formats);
135}
136
137static int sti_gdp_fourcc2format(int fourcc) 130static int sti_gdp_fourcc2format(int fourcc)
138{ 131{
139 switch (fourcc) { 132 switch (fourcc) {
@@ -179,17 +172,16 @@ static int sti_gdp_get_alpharange(int format)
179 172
180/** 173/**
181 * sti_gdp_get_free_nodes 174 * sti_gdp_get_free_nodes
182 * @plane: gdp plane 175 * @gdp: gdp pointer
183 * 176 *
184 * Look for a GDP node list that is not currently read by the HW. 177 * Look for a GDP node list that is not currently read by the HW.
185 * 178 *
186 * RETURNS: 179 * RETURNS:
187 * Pointer to the free GDP node list 180 * Pointer to the free GDP node list
188 */ 181 */
189static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane) 182static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_gdp *gdp)
190{ 183{
191 int hw_nvn; 184 int hw_nvn;
192 struct sti_gdp *gdp = to_sti_gdp(plane);
193 unsigned int i; 185 unsigned int i;
194 186
195 hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); 187 hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
@@ -203,7 +195,7 @@ static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane)
203 195
204 /* in hazardious cases restart with the first node */ 196 /* in hazardious cases restart with the first node */
205 DRM_ERROR("inconsistent NVN for %s: 0x%08X\n", 197 DRM_ERROR("inconsistent NVN for %s: 0x%08X\n",
206 sti_plane_to_str(plane), hw_nvn); 198 sti_plane_to_str(&gdp->plane), hw_nvn);
207 199
208end: 200end:
209 return &gdp->node_list[0]; 201 return &gdp->node_list[0];
@@ -211,7 +203,7 @@ end:
211 203
212/** 204/**
213 * sti_gdp_get_current_nodes 205 * sti_gdp_get_current_nodes
214 * @plane: GDP plane 206 * @gdp: gdp pointer
215 * 207 *
216 * Look for GDP nodes that are currently read by the HW. 208 * Look for GDP nodes that are currently read by the HW.
217 * 209 *
@@ -219,10 +211,9 @@ end:
219 * Pointer to the current GDP node list 211 * Pointer to the current GDP node list
220 */ 212 */
221static 213static
222struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane) 214struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_gdp *gdp)
223{ 215{
224 int hw_nvn; 216 int hw_nvn;
225 struct sti_gdp *gdp = to_sti_gdp(plane);
226 unsigned int i; 217 unsigned int i;
227 218
228 hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); 219 hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
@@ -236,205 +227,25 @@ struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane)
236 227
237end: 228end:
238 DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n", 229 DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n",
239 hw_nvn, sti_plane_to_str(plane)); 230 hw_nvn, sti_plane_to_str(&gdp->plane));
240 231
241 return NULL; 232 return NULL;
242} 233}
243 234
244/** 235/**
245 * sti_gdp_prepare
246 * @plane: gdp plane
247 * @first_prepare: true if it is the first time this function is called
248 *
249 * Update the free GDP node list according to the plane properties.
250 *
251 * RETURNS:
252 * 0 on success.
253 */
254static int sti_gdp_prepare(struct sti_plane *plane, bool first_prepare)
255{
256 struct sti_gdp_node_list *list;
257 struct sti_gdp_node *top_field, *btm_field;
258 struct drm_display_mode *mode = plane->mode;
259 struct sti_gdp *gdp = to_sti_gdp(plane);
260 struct device *dev = gdp->dev;
261 struct sti_compositor *compo = dev_get_drvdata(dev);
262 int format;
263 unsigned int depth, bpp;
264 int rate = mode->clock * 1000;
265 int res;
266 u32 ydo, xdo, yds, xds;
267
268 list = sti_gdp_get_free_nodes(plane);
269 top_field = list->top_field;
270 btm_field = list->btm_field;
271
272 dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
273 sti_plane_to_str(plane), top_field, btm_field);
274
275 /* Build the top field from plane params */
276 top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
277 top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
278 format = sti_gdp_fourcc2format(plane->format);
279 if (format == -1) {
280 DRM_ERROR("Format not supported by GDP %.4s\n",
281 (char *)&plane->format);
282 return 1;
283 }
284 top_field->gam_gdp_ctl |= format;
285 top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
286 top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
287
288 /* pixel memory location */
289 drm_fb_get_bpp_depth(plane->format, &depth, &bpp);
290 top_field->gam_gdp_pml = (u32)plane->paddr + plane->offsets[0];
291 top_field->gam_gdp_pml += plane->src_x * (bpp >> 3);
292 top_field->gam_gdp_pml += plane->src_y * plane->pitches[0];
293
294 /* input parameters */
295 top_field->gam_gdp_pmp = plane->pitches[0];
296 top_field->gam_gdp_size =
297 clamp_val(plane->src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
298 clamp_val(plane->src_w, 0, GAM_GDP_SIZE_MAX);
299
300 /* output parameters */
301 ydo = sti_vtg_get_line_number(*mode, plane->dst_y);
302 yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1);
303 xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x);
304 xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1);
305 top_field->gam_gdp_vpo = (ydo << 16) | xdo;
306 top_field->gam_gdp_vps = (yds << 16) | xds;
307
308 /* Same content and chained together */
309 memcpy(btm_field, top_field, sizeof(*btm_field));
310 top_field->gam_gdp_nvn = list->btm_field_paddr;
311 btm_field->gam_gdp_nvn = list->top_field_paddr;
312
313 /* Interlaced mode */
314 if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE)
315 btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
316 plane->pitches[0];
317
318 if (first_prepare) {
319 /* Register gdp callback */
320 if (sti_vtg_register_client(plane->mixer_id == STI_MIXER_MAIN ?
321 compo->vtg_main : compo->vtg_aux,
322 &gdp->vtg_field_nb, plane->mixer_id)) {
323 DRM_ERROR("Cannot register VTG notifier\n");
324 return 1;
325 }
326
327 /* Set and enable gdp clock */
328 if (gdp->clk_pix) {
329 struct clk *clkp;
330 /* According to the mixer used, the gdp pixel clock
331 * should have a different parent clock. */
332 if (plane->mixer_id == STI_MIXER_MAIN)
333 clkp = gdp->clk_main_parent;
334 else
335 clkp = gdp->clk_aux_parent;
336
337 if (clkp)
338 clk_set_parent(gdp->clk_pix, clkp);
339
340 res = clk_set_rate(gdp->clk_pix, rate);
341 if (res < 0) {
342 DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
343 rate);
344 return 1;
345 }
346
347 if (clk_prepare_enable(gdp->clk_pix)) {
348 DRM_ERROR("Failed to prepare/enable gdp\n");
349 return 1;
350 }
351 }
352 }
353
354 return 0;
355}
356
357/**
358 * sti_gdp_commit
359 * @plane: gdp plane
360 *
361 * Update the NVN field of the 'right' field of the current GDP node (being
362 * used by the HW) with the address of the updated ('free') top field GDP node.
363 * - In interlaced mode the 'right' field is the bottom field as we update
364 * frames starting from their top field
365 * - In progressive mode, we update both bottom and top fields which are
366 * equal nodes.
367 * At the next VSYNC, the updated node list will be used by the HW.
368 *
369 * RETURNS:
370 * 0 on success.
371 */
372static int sti_gdp_commit(struct sti_plane *plane)
373{
374 struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(plane);
375 struct sti_gdp_node *updated_top_node = updated_list->top_field;
376 struct sti_gdp_node *updated_btm_node = updated_list->btm_field;
377 struct sti_gdp *gdp = to_sti_gdp(plane);
378 u32 dma_updated_top = updated_list->top_field_paddr;
379 u32 dma_updated_btm = updated_list->btm_field_paddr;
380 struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(plane);
381
382 dev_dbg(gdp->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__,
383 sti_plane_to_str(plane),
384 updated_top_node, updated_btm_node);
385 dev_dbg(gdp->dev, "Current NVN:0x%X\n",
386 readl(gdp->regs + GAM_GDP_NVN_OFFSET));
387 dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n",
388 (unsigned long)plane->paddr,
389 readl(gdp->regs + GAM_GDP_PML_OFFSET));
390
391 if (curr_list == NULL) {
392 /* First update or invalid node should directly write in the
393 * hw register */
394 DRM_DEBUG_DRIVER("%s first update (or invalid node)",
395 sti_plane_to_str(plane));
396
397 writel(gdp->is_curr_top == true ?
398 dma_updated_btm : dma_updated_top,
399 gdp->regs + GAM_GDP_NVN_OFFSET);
400 return 0;
401 }
402
403 if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) {
404 if (gdp->is_curr_top == true) {
405 /* Do not update in the middle of the frame, but
406 * postpone the update after the bottom field has
407 * been displayed */
408 curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
409 } else {
410 /* Direct update to avoid one frame delay */
411 writel(dma_updated_top,
412 gdp->regs + GAM_GDP_NVN_OFFSET);
413 }
414 } else {
415 /* Direct update for progressive to avoid one frame delay */
416 writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET);
417 }
418
419 return 0;
420}
421
422/**
423 * sti_gdp_disable 236 * sti_gdp_disable
424 * @plane: gdp plane 237 * @gdp: gdp pointer
425 * 238 *
426 * Disable a GDP. 239 * Disable a GDP.
427 *
428 * RETURNS:
429 * 0 on success.
430 */ 240 */
431static int sti_gdp_disable(struct sti_plane *plane) 241static void sti_gdp_disable(struct sti_gdp *gdp)
432{ 242{
433 unsigned int i; 243 struct drm_plane *drm_plane = &gdp->plane.drm_plane;
434 struct sti_gdp *gdp = to_sti_gdp(plane); 244 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
435 struct sti_compositor *compo = dev_get_drvdata(gdp->dev); 245 struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
246 unsigned int i;
436 247
437 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); 248 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane));
438 249
439 /* Set the nodes as 'to be ignored on mixer' */ 250 /* Set the nodes as 'to be ignored on mixer' */
440 for (i = 0; i < GDP_NODE_NB_BANK; i++) { 251 for (i = 0; i < GDP_NODE_NB_BANK; i++) {
@@ -442,14 +253,14 @@ static int sti_gdp_disable(struct sti_plane *plane)
442 gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; 253 gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
443 } 254 }
444 255
445 if (sti_vtg_unregister_client(plane->mixer_id == STI_MIXER_MAIN ? 256 if (sti_vtg_unregister_client(mixer->id == STI_MIXER_MAIN ?
446 compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb)) 257 compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb))
447 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); 258 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
448 259
449 if (gdp->clk_pix) 260 if (gdp->clk_pix)
450 clk_disable_unprepare(gdp->clk_pix); 261 clk_disable_unprepare(gdp->clk_pix);
451 262
452 return 0; 263 gdp->plane.status = STI_PLANE_DISABLED;
453} 264}
454 265
455/** 266/**
@@ -468,6 +279,14 @@ int sti_gdp_field_cb(struct notifier_block *nb,
468{ 279{
469 struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb); 280 struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb);
470 281
282 if (gdp->plane.status == STI_PLANE_FLUSHING) {
283 /* disable need to be synchronize on vsync event */
284 DRM_DEBUG_DRIVER("Vsync event received => disable %s\n",
285 sti_plane_to_str(&gdp->plane));
286
287 sti_gdp_disable(gdp);
288 }
289
471 switch (event) { 290 switch (event) {
472 case VTG_TOP_FIELD_EVENT: 291 case VTG_TOP_FIELD_EVENT:
473 gdp->is_curr_top = true; 292 gdp->is_curr_top = true;
@@ -561,18 +380,235 @@ static void sti_gdp_init(struct sti_gdp *gdp)
561 } 380 }
562} 381}
563 382
564static const struct sti_plane_funcs gdp_plane_ops = { 383static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
565 .get_formats = sti_gdp_get_formats, 384 struct drm_plane_state *oldstate)
566 .get_nb_formats = sti_gdp_get_nb_formats, 385{
567 .prepare = sti_gdp_prepare, 386 struct drm_plane_state *state = drm_plane->state;
568 .commit = sti_gdp_commit, 387 struct sti_plane *plane = to_sti_plane(drm_plane);
569 .disable = sti_gdp_disable, 388 struct sti_gdp *gdp = to_sti_gdp(plane);
389 struct drm_crtc *crtc = state->crtc;
390 struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
391 struct drm_framebuffer *fb = state->fb;
392 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
393 struct sti_mixer *mixer;
394 struct drm_display_mode *mode;
395 int dst_x, dst_y, dst_w, dst_h;
396 int src_x, src_y, src_w, src_h;
397 struct drm_gem_cma_object *cma_obj;
398 struct sti_gdp_node_list *list;
399 struct sti_gdp_node_list *curr_list;
400 struct sti_gdp_node *top_field, *btm_field;
401 u32 dma_updated_top;
402 u32 dma_updated_btm;
403 int format;
404 unsigned int depth, bpp;
405 u32 ydo, xdo, yds, xds;
406 int res;
407
408 /* Manage the case where crtc is null (disabled) */
409 if (!crtc)
410 return;
411
412 mixer = to_sti_mixer(crtc);
413 mode = &crtc->mode;
414 dst_x = state->crtc_x;
415 dst_y = state->crtc_y;
416 dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
417 dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
418 /* src_x are in 16.16 format */
419 src_x = state->src_x >> 16;
420 src_y = state->src_y >> 16;
421 src_w = state->src_w >> 16;
422 src_h = state->src_h >> 16;
423
424 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
425 crtc->base.id, sti_mixer_to_str(mixer),
426 drm_plane->base.id, sti_plane_to_str(plane));
427 DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
428 sti_plane_to_str(plane),
429 dst_w, dst_h, dst_x, dst_y,
430 src_w, src_h, src_x, src_y);
431
432 list = sti_gdp_get_free_nodes(gdp);
433 top_field = list->top_field;
434 btm_field = list->btm_field;
435
436 dev_dbg(gdp->dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
437 sti_plane_to_str(plane), top_field, btm_field);
438
439 /* build the top field */
440 top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
441 top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
442 format = sti_gdp_fourcc2format(fb->pixel_format);
443 if (format == -1) {
444 DRM_ERROR("Format not supported by GDP %.4s\n",
445 (char *)&fb->pixel_format);
446 return;
447 }
448 top_field->gam_gdp_ctl |= format;
449 top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
450 top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
451
452 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
453 if (!cma_obj) {
454 DRM_ERROR("Can't get CMA GEM object for fb\n");
455 return;
456 }
457
458 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
459 (char *)&fb->pixel_format,
460 (unsigned long)cma_obj->paddr);
461
462 /* pixel memory location */
463 drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
464 top_field->gam_gdp_pml = (u32)cma_obj->paddr + fb->offsets[0];
465 top_field->gam_gdp_pml += src_x * (bpp >> 3);
466 top_field->gam_gdp_pml += src_y * fb->pitches[0];
467
468 /* input parameters */
469 top_field->gam_gdp_pmp = fb->pitches[0];
470 top_field->gam_gdp_size = clamp_val(src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
471 clamp_val(src_w, 0, GAM_GDP_SIZE_MAX);
472
473 /* output parameters */
474 ydo = sti_vtg_get_line_number(*mode, dst_y);
475 yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
476 xdo = sti_vtg_get_pixel_number(*mode, dst_x);
477 xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
478 top_field->gam_gdp_vpo = (ydo << 16) | xdo;
479 top_field->gam_gdp_vps = (yds << 16) | xds;
480
481 /* Same content and chained together */
482 memcpy(btm_field, top_field, sizeof(*btm_field));
483 top_field->gam_gdp_nvn = list->btm_field_paddr;
484 btm_field->gam_gdp_nvn = list->top_field_paddr;
485
486 /* Interlaced mode */
487 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
488 btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
489 fb->pitches[0];
490
491 if (first_prepare) {
492 /* Register gdp callback */
493 if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ?
494 compo->vtg_main : compo->vtg_aux,
495 &gdp->vtg_field_nb, mixer->id)) {
496 DRM_ERROR("Cannot register VTG notifier\n");
497 return;
498 }
499
500 /* Set and enable gdp clock */
501 if (gdp->clk_pix) {
502 struct clk *clkp;
503 int rate = mode->clock * 1000;
504
505 /* According to the mixer used, the gdp pixel clock
506 * should have a different parent clock. */
507 if (mixer->id == STI_MIXER_MAIN)
508 clkp = gdp->clk_main_parent;
509 else
510 clkp = gdp->clk_aux_parent;
511
512 if (clkp)
513 clk_set_parent(gdp->clk_pix, clkp);
514
515 res = clk_set_rate(gdp->clk_pix, rate);
516 if (res < 0) {
517 DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
518 rate);
519 return;
520 }
521
522 if (clk_prepare_enable(gdp->clk_pix)) {
523 DRM_ERROR("Failed to prepare/enable gdp\n");
524 return;
525 }
526 }
527 }
528
529 /* Update the NVN field of the 'right' field of the current GDP node
530 * (being used by the HW) with the address of the updated ('free') top
531 * field GDP node.
532 * - In interlaced mode the 'right' field is the bottom field as we
533 * update frames starting from their top field
534 * - In progressive mode, we update both bottom and top fields which
535 * are equal nodes.
536 * At the next VSYNC, the updated node list will be used by the HW.
537 */
538 curr_list = sti_gdp_get_current_nodes(gdp);
539 dma_updated_top = list->top_field_paddr;
540 dma_updated_btm = list->btm_field_paddr;
541
542 dev_dbg(gdp->dev, "Current NVN:0x%X\n",
543 readl(gdp->regs + GAM_GDP_NVN_OFFSET));
544 dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n",
545 (unsigned long)cma_obj->paddr,
546 readl(gdp->regs + GAM_GDP_PML_OFFSET));
547
548 if (!curr_list) {
549 /* First update or invalid node should directly write in the
550 * hw register */
551 DRM_DEBUG_DRIVER("%s first update (or invalid node)",
552 sti_plane_to_str(plane));
553
554 writel(gdp->is_curr_top ?
555 dma_updated_btm : dma_updated_top,
556 gdp->regs + GAM_GDP_NVN_OFFSET);
557 goto end;
558 }
559
560 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
561 if (gdp->is_curr_top) {
562 /* Do not update in the middle of the frame, but
563 * postpone the update after the bottom field has
564 * been displayed */
565 curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
566 } else {
567 /* Direct update to avoid one frame delay */
568 writel(dma_updated_top,
569 gdp->regs + GAM_GDP_NVN_OFFSET);
570 }
571 } else {
572 /* Direct update for progressive to avoid one frame delay */
573 writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET);
574 }
575
576end:
577 plane->status = STI_PLANE_UPDATED;
578}
579
580static void sti_gdp_atomic_disable(struct drm_plane *drm_plane,
581 struct drm_plane_state *oldstate)
582{
583 struct sti_plane *plane = to_sti_plane(drm_plane);
584 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
585
586 if (!drm_plane->crtc) {
587 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
588 drm_plane->base.id);
589 return;
590 }
591
592 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
593 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
594 drm_plane->base.id, sti_plane_to_str(plane));
595
596 plane->status = STI_PLANE_DISABLING;
597}
598
599static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
600 .atomic_update = sti_gdp_atomic_update,
601 .atomic_disable = sti_gdp_atomic_disable,
570}; 602};
571 603
572struct sti_plane *sti_gdp_create(struct device *dev, int desc, 604struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
573 void __iomem *baseaddr) 605 struct device *dev, int desc,
606 void __iomem *baseaddr,
607 unsigned int possible_crtcs,
608 enum drm_plane_type type)
574{ 609{
575 struct sti_gdp *gdp; 610 struct sti_gdp *gdp;
611 int res;
576 612
577 gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL); 613 gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL);
578 if (!gdp) { 614 if (!gdp) {
@@ -583,11 +619,30 @@ struct sti_plane *sti_gdp_create(struct device *dev, int desc,
583 gdp->dev = dev; 619 gdp->dev = dev;
584 gdp->regs = baseaddr; 620 gdp->regs = baseaddr;
585 gdp->plane.desc = desc; 621 gdp->plane.desc = desc;
586 gdp->plane.ops = &gdp_plane_ops; 622 gdp->plane.status = STI_PLANE_DISABLED;
587 623
588 gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb; 624 gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb;
589 625
590 sti_gdp_init(gdp); 626 sti_gdp_init(gdp);
591 627
592 return &gdp->plane; 628 res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane,
629 possible_crtcs,
630 &sti_plane_helpers_funcs,
631 gdp_supported_formats,
632 ARRAY_SIZE(gdp_supported_formats),
633 type);
634 if (res) {
635 DRM_ERROR("Failed to initialize universal plane\n");
636 goto err;
637 }
638
639 drm_plane_helper_add(&gdp->plane.drm_plane, &sti_gdp_helpers_funcs);
640
641 sti_plane_init_property(&gdp->plane, type);
642
643 return &gdp->plane.drm_plane;
644
645err:
646 devm_kfree(dev, gdp);
647 return NULL;
593} 648}
diff --git a/drivers/gpu/drm/sti/sti_gdp.h b/drivers/gpu/drm/sti/sti_gdp.h
index 01818ea72125..73947a4a8004 100644
--- a/drivers/gpu/drm/sti/sti_gdp.h
+++ b/drivers/gpu/drm/sti/sti_gdp.h
@@ -11,7 +11,9 @@
11 11
12#include <linux/types.h> 12#include <linux/types.h>
13 13
14struct sti_plane *sti_gdp_create(struct device *dev, int desc, 14struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
15 void __iomem *baseaddr); 15 struct device *dev, int desc,
16 16 void __iomem *baseaddr,
17 unsigned int possible_crtcs,
18 enum drm_plane_type type);
17#endif 19#endif
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index b91a009f0d5d..7c8f9b8bfae1 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -12,7 +12,10 @@
12#include <linux/reset.h> 12#include <linux/reset.h>
13 13
14#include <drm/drmP.h> 14#include <drm/drmP.h>
15#include <drm/drm_fb_cma_helper.h>
16#include <drm/drm_gem_cma_helper.h>
15 17
18#include "sti_compositor.h"
16#include "sti_hqvdp_lut.h" 19#include "sti_hqvdp_lut.h"
17#include "sti_plane.h" 20#include "sti_plane.h"
18#include "sti_vtg.h" 21#include "sti_vtg.h"
@@ -357,16 +360,6 @@ static const uint32_t hqvdp_supported_formats[] = {
357 DRM_FORMAT_NV12, 360 DRM_FORMAT_NV12,
358}; 361};
359 362
360static const uint32_t *sti_hqvdp_get_formats(struct sti_plane *plane)
361{
362 return hqvdp_supported_formats;
363}
364
365static unsigned int sti_hqvdp_get_nb_formats(struct sti_plane *plane)
366{
367 return ARRAY_SIZE(hqvdp_supported_formats);
368}
369
370/** 363/**
371 * sti_hqvdp_get_free_cmd 364 * sti_hqvdp_get_free_cmd
372 * @hqvdp: hqvdp structure 365 * @hqvdp: hqvdp structure
@@ -482,7 +475,12 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale,
482 475
483/** 476/**
484 * sti_hqvdp_check_hw_scaling 477 * sti_hqvdp_check_hw_scaling
485 * @plane: hqvdp plane 478 * @hqvdp: hqvdp pointer
479 * @mode: display mode with timing constraints
480 * @src_w: source width
481 * @src_h: source height
482 * @dst_w: destination width
483 * @dst_h: destination height
486 * 484 *
487 * Check if the HW is able to perform the scaling request 485 * Check if the HW is able to perform the scaling request
488 * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where: 486 * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where:
@@ -496,194 +494,36 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale,
496 * RETURNS: 494 * RETURNS:
497 * True if the HW can scale. 495 * True if the HW can scale.
498 */ 496 */
499static bool sti_hqvdp_check_hw_scaling(struct sti_plane *plane) 497static bool sti_hqvdp_check_hw_scaling(struct sti_hqvdp *hqvdp,
498 struct drm_display_mode *mode,
499 int src_w, int src_h,
500 int dst_w, int dst_h)
500{ 501{
501 struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
502 unsigned long lfw; 502 unsigned long lfw;
503 unsigned int inv_zy; 503 unsigned int inv_zy;
504 504
505 lfw = plane->mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000); 505 lfw = mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000);
506 lfw /= max(plane->src_w, plane->dst_w) * plane->mode->clock / 1000; 506 lfw /= max(src_w, dst_w) * mode->clock / 1000;
507 507
508 inv_zy = DIV_ROUND_UP(plane->src_h, plane->dst_h); 508 inv_zy = DIV_ROUND_UP(src_h, dst_h);
509 509
510 return (inv_zy <= lfw) ? true : false; 510 return (inv_zy <= lfw) ? true : false;
511} 511}
512 512
513/** 513/**
514 * sti_hqvdp_prepare
515 * @plane: hqvdp plane
516 * @first_prepare: true if it is the first time this function is called
517 *
518 * Prepares a command for the firmware
519 *
520 * RETURNS:
521 * 0 on success.
522 */
523static int sti_hqvdp_prepare(struct sti_plane *plane, bool first_prepare)
524{
525 struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
526 struct sti_hqvdp_cmd *cmd;
527 int scale_h, scale_v;
528 int cmd_offset;
529
530 dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
531
532 cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
533 if (cmd_offset == -1) {
534 DRM_ERROR("No available hqvdp_cmd now\n");
535 return -EBUSY;
536 }
537 cmd = hqvdp->hqvdp_cmd + cmd_offset;
538
539 if (!sti_hqvdp_check_hw_scaling(plane)) {
540 DRM_ERROR("Scaling beyond HW capabilities\n");
541 return -EINVAL;
542 }
543
544 /* Static parameters, defaulting to progressive mode */
545 cmd->top.config = TOP_CONFIG_PROGRESSIVE;
546 cmd->top.mem_format = TOP_MEM_FORMAT_DFLT;
547 cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT;
548 cmd->csdi.config = CSDI_CONFIG_PROG;
549
550 /* VC1RE, FMD bypassed : keep everything set to 0
551 * IQI/P2I bypassed */
552 cmd->iqi.config = IQI_CONFIG_DFLT;
553 cmd->iqi.con_bri = IQI_CON_BRI_DFLT;
554 cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT;
555 cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
556
557 /* Buffer planes address */
558 cmd->top.current_luma = (u32)plane->paddr + plane->offsets[0];
559 cmd->top.current_chroma = (u32)plane->paddr + plane->offsets[1];
560
561 /* Pitches */
562 cmd->top.luma_processed_pitch = cmd->top.luma_src_pitch =
563 plane->pitches[0];
564 cmd->top.chroma_processed_pitch = cmd->top.chroma_src_pitch =
565 plane->pitches[1];
566
567 /* Input / output size
568 * Align to upper even value */
569 plane->dst_w = ALIGN(plane->dst_w, 2);
570 plane->dst_h = ALIGN(plane->dst_h, 2);
571
572 if ((plane->src_w > MAX_WIDTH) || (plane->src_w < MIN_WIDTH) ||
573 (plane->src_h > MAX_HEIGHT) || (plane->src_h < MIN_HEIGHT) ||
574 (plane->dst_w > MAX_WIDTH) || (plane->dst_w < MIN_WIDTH) ||
575 (plane->dst_h > MAX_HEIGHT) || (plane->dst_h < MIN_HEIGHT)) {
576 DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n",
577 plane->src_w, plane->src_h,
578 plane->dst_w, plane->dst_h);
579 return -EINVAL;
580 }
581 cmd->top.input_viewport_size = cmd->top.input_frame_size =
582 plane->src_h << 16 | plane->src_w;
583 cmd->hvsrc.output_picture_size = plane->dst_h << 16 | plane->dst_w;
584 cmd->top.input_viewport_ori = plane->src_y << 16 | plane->src_x;
585
586 /* Handle interlaced */
587 if (plane->fb->flags & DRM_MODE_FB_INTERLACED) {
588 /* Top field to display */
589 cmd->top.config = TOP_CONFIG_INTER_TOP;
590
591 /* Update pitches and vert size */
592 cmd->top.input_frame_size = (plane->src_h / 2) << 16 |
593 plane->src_w;
594 cmd->top.luma_processed_pitch *= 2;
595 cmd->top.luma_src_pitch *= 2;
596 cmd->top.chroma_processed_pitch *= 2;
597 cmd->top.chroma_src_pitch *= 2;
598
599 /* Enable directional deinterlacing processing */
600 cmd->csdi.config = CSDI_CONFIG_INTER_DIR;
601 cmd->csdi.config2 = CSDI_CONFIG2_DFLT;
602 cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT;
603 }
604
605 /* Update hvsrc lut coef */
606 scale_h = SCALE_FACTOR * plane->dst_w / plane->src_w;
607 sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc);
608
609 scale_v = SCALE_FACTOR * plane->dst_h / plane->src_h;
610 sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
611
612 if (first_prepare) {
613 /* Prevent VTG shutdown */
614 if (clk_prepare_enable(hqvdp->clk_pix_main)) {
615 DRM_ERROR("Failed to prepare/enable pix main clk\n");
616 return -ENXIO;
617 }
618
619 /* Register VTG Vsync callback to handle bottom fields */
620 if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) &&
621 sti_vtg_register_client(hqvdp->vtg, &hqvdp->vtg_nb,
622 plane->mixer_id)) {
623 DRM_ERROR("Cannot register VTG notifier\n");
624 return -ENXIO;
625 }
626 }
627
628 return 0;
629}
630
631/**
632 * sti_hqvdp_commit
633 * @plane: hqvdp plane
634 *
635 * Enables the HQVDP plane
636 *
637 * RETURNS:
638 * 0 on success.
639 */
640static int sti_hqvdp_commit(struct sti_plane *plane)
641{
642 struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
643 int cmd_offset;
644
645 dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
646
647 cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
648 if (cmd_offset == -1) {
649 DRM_ERROR("No available hqvdp_cmd now\n");
650 return -EBUSY;
651 }
652
653 writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
654 hqvdp->regs + HQVDP_MBX_NEXT_CMD);
655
656 hqvdp->curr_field_count++;
657
658 /* Interlaced : get ready to display the bottom field at next Vsync */
659 if (plane->fb->flags & DRM_MODE_FB_INTERLACED)
660 hqvdp->btm_field_pending = true;
661
662 dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
663 __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);
664
665 return 0;
666}
667
668/**
669 * sti_hqvdp_disable 514 * sti_hqvdp_disable
670 * @plane: hqvdp plane 515 * @hqvdp: hqvdp pointer
671 * 516 *
672 * Disables the HQVDP plane 517 * Disables the HQVDP plane
673 *
674 * RETURNS:
675 * 0 on success.
676 */ 518 */
677static int sti_hqvdp_disable(struct sti_plane *plane) 519static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp)
678{ 520{
679 struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
680 int i; 521 int i;
681 522
682 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); 523 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&hqvdp->plane));
683 524
684 /* Unregister VTG Vsync callback */ 525 /* Unregister VTG Vsync callback */
685 if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) && 526 if (sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb))
686 sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb))
687 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); 527 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
688 528
689 /* Set next cmd to NULL */ 529 /* Set next cmd to NULL */
@@ -699,12 +539,10 @@ static int sti_hqvdp_disable(struct sti_plane *plane)
699 /* VTG can stop now */ 539 /* VTG can stop now */
700 clk_disable_unprepare(hqvdp->clk_pix_main); 540 clk_disable_unprepare(hqvdp->clk_pix_main);
701 541
702 if (i == POLL_MAX_ATTEMPT) { 542 if (i == POLL_MAX_ATTEMPT)
703 DRM_ERROR("XP70 could not revert to idle\n"); 543 DRM_ERROR("XP70 could not revert to idle\n");
704 return -ENXIO;
705 }
706 544
707 return 0; 545 hqvdp->plane.status = STI_PLANE_DISABLED;
708} 546}
709 547
710/** 548/**
@@ -729,6 +567,14 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
729 return 0; 567 return 0;
730 } 568 }
731 569
570 if (hqvdp->plane.status == STI_PLANE_FLUSHING) {
571 /* disable need to be synchronize on vsync event */
572 DRM_DEBUG_DRIVER("Vsync event received => disable %s\n",
573 sti_plane_to_str(&hqvdp->plane));
574
575 sti_hqvdp_disable(hqvdp);
576 }
577
732 if (hqvdp->btm_field_pending) { 578 if (hqvdp->btm_field_pending) {
733 /* Create the btm field command from the current one */ 579 /* Create the btm field command from the current one */
734 btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); 580 btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
@@ -782,24 +628,212 @@ static void sti_hqvdp_init(struct sti_hqvdp *hqvdp)
782 memset(hqvdp->hqvdp_cmd, 0, size); 628 memset(hqvdp->hqvdp_cmd, 0, size);
783} 629}
784 630
785static const struct sti_plane_funcs hqvdp_plane_ops = { 631static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
786 .get_formats = sti_hqvdp_get_formats, 632 struct drm_plane_state *oldstate)
787 .get_nb_formats = sti_hqvdp_get_nb_formats, 633{
788 .prepare = sti_hqvdp_prepare, 634 struct drm_plane_state *state = drm_plane->state;
789 .commit = sti_hqvdp_commit, 635 struct sti_plane *plane = to_sti_plane(drm_plane);
790 .disable = sti_hqvdp_disable, 636 struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
637 struct drm_crtc *crtc = state->crtc;
638 struct sti_mixer *mixer = to_sti_mixer(crtc);
639 struct drm_framebuffer *fb = state->fb;
640 struct drm_display_mode *mode = &crtc->mode;
641 int dst_x = state->crtc_x;
642 int dst_y = state->crtc_y;
643 int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
644 int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
645 /* src_x are in 16.16 format */
646 int src_x = state->src_x >> 16;
647 int src_y = state->src_y >> 16;
648 int src_w = state->src_w >> 16;
649 int src_h = state->src_h >> 16;
650 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
651 struct drm_gem_cma_object *cma_obj;
652 struct sti_hqvdp_cmd *cmd;
653 int scale_h, scale_v;
654 int cmd_offset;
655
656 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
657 crtc->base.id, sti_mixer_to_str(mixer),
658 drm_plane->base.id, sti_plane_to_str(plane));
659 DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
660 sti_plane_to_str(plane),
661 dst_w, dst_h, dst_x, dst_y,
662 src_w, src_h, src_x, src_y);
663
664 cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
665 if (cmd_offset == -1) {
666 DRM_ERROR("No available hqvdp_cmd now\n");
667 return;
668 }
669 cmd = hqvdp->hqvdp_cmd + cmd_offset;
670
671 if (!sti_hqvdp_check_hw_scaling(hqvdp, mode,
672 src_w, src_h,
673 dst_w, dst_h)) {
674 DRM_ERROR("Scaling beyond HW capabilities\n");
675 return;
676 }
677
678 /* Static parameters, defaulting to progressive mode */
679 cmd->top.config = TOP_CONFIG_PROGRESSIVE;
680 cmd->top.mem_format = TOP_MEM_FORMAT_DFLT;
681 cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT;
682 cmd->csdi.config = CSDI_CONFIG_PROG;
683
684 /* VC1RE, FMD bypassed : keep everything set to 0
685 * IQI/P2I bypassed */
686 cmd->iqi.config = IQI_CONFIG_DFLT;
687 cmd->iqi.con_bri = IQI_CON_BRI_DFLT;
688 cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT;
689 cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
690
691 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
692 if (!cma_obj) {
693 DRM_ERROR("Can't get CMA GEM object for fb\n");
694 return;
695 }
696
697 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
698 (char *)&fb->pixel_format,
699 (unsigned long)cma_obj->paddr);
700
701 /* Buffer planes address */
702 cmd->top.current_luma = (u32)cma_obj->paddr + fb->offsets[0];
703 cmd->top.current_chroma = (u32)cma_obj->paddr + fb->offsets[1];
704
705 /* Pitches */
706 cmd->top.luma_processed_pitch = fb->pitches[0];
707 cmd->top.luma_src_pitch = fb->pitches[0];
708 cmd->top.chroma_processed_pitch = fb->pitches[1];
709 cmd->top.chroma_src_pitch = fb->pitches[1];
710
711 /* Input / output size
712 * Align to upper even value */
713 dst_w = ALIGN(dst_w, 2);
714 dst_h = ALIGN(dst_h, 2);
715
716 if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) ||
717 (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) ||
718 (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) ||
719 (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) {
720 DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n",
721 src_w, src_h,
722 dst_w, dst_h);
723 return;
724 }
725
726 cmd->top.input_viewport_size = src_h << 16 | src_w;
727 cmd->top.input_frame_size = src_h << 16 | src_w;
728 cmd->hvsrc.output_picture_size = dst_h << 16 | dst_w;
729 cmd->top.input_viewport_ori = src_y << 16 | src_x;
730
731 /* Handle interlaced */
732 if (fb->flags & DRM_MODE_FB_INTERLACED) {
733 /* Top field to display */
734 cmd->top.config = TOP_CONFIG_INTER_TOP;
735
736 /* Update pitches and vert size */
737 cmd->top.input_frame_size = (src_h / 2) << 16 | src_w;
738 cmd->top.luma_processed_pitch *= 2;
739 cmd->top.luma_src_pitch *= 2;
740 cmd->top.chroma_processed_pitch *= 2;
741 cmd->top.chroma_src_pitch *= 2;
742
743 /* Enable directional deinterlacing processing */
744 cmd->csdi.config = CSDI_CONFIG_INTER_DIR;
745 cmd->csdi.config2 = CSDI_CONFIG2_DFLT;
746 cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT;
747 }
748
749 /* Update hvsrc lut coef */
750 scale_h = SCALE_FACTOR * dst_w / src_w;
751 sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc);
752
753 scale_v = SCALE_FACTOR * dst_h / src_h;
754 sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
755
756 if (first_prepare) {
757 /* Prevent VTG shutdown */
758 if (clk_prepare_enable(hqvdp->clk_pix_main)) {
759 DRM_ERROR("Failed to prepare/enable pix main clk\n");
760 return;
761 }
762
763 /* Register VTG Vsync callback to handle bottom fields */
764 if (sti_vtg_register_client(hqvdp->vtg,
765 &hqvdp->vtg_nb,
766 mixer->id)) {
767 DRM_ERROR("Cannot register VTG notifier\n");
768 return;
769 }
770 }
771
772 writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
773 hqvdp->regs + HQVDP_MBX_NEXT_CMD);
774
775 hqvdp->curr_field_count++;
776
777 /* Interlaced : get ready to display the bottom field at next Vsync */
778 if (fb->flags & DRM_MODE_FB_INTERLACED)
779 hqvdp->btm_field_pending = true;
780
781 dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
782 __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);
783
784 plane->status = STI_PLANE_UPDATED;
785}
786
787static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane,
788 struct drm_plane_state *oldstate)
789{
790 struct sti_plane *plane = to_sti_plane(drm_plane);
791 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
792
793 if (!drm_plane->crtc) {
794 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
795 drm_plane->base.id);
796 return;
797 }
798
799 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
800 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
801 drm_plane->base.id, sti_plane_to_str(plane));
802
803 plane->status = STI_PLANE_DISABLING;
804}
805
806static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = {
807 .atomic_update = sti_hqvdp_atomic_update,
808 .atomic_disable = sti_hqvdp_atomic_disable,
791}; 809};
792 810
793struct sti_plane *sti_hqvdp_create(struct device *dev, int desc) 811static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
812 struct device *dev, int desc)
794{ 813{
795 struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); 814 struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
815 int res;
796 816
797 hqvdp->plane.desc = desc; 817 hqvdp->plane.desc = desc;
798 hqvdp->plane.ops = &hqvdp_plane_ops; 818 hqvdp->plane.status = STI_PLANE_DISABLED;
799 819
800 sti_hqvdp_init(hqvdp); 820 sti_hqvdp_init(hqvdp);
801 821
802 return &hqvdp->plane; 822 res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1,
823 &sti_plane_helpers_funcs,
824 hqvdp_supported_formats,
825 ARRAY_SIZE(hqvdp_supported_formats),
826 DRM_PLANE_TYPE_OVERLAY);
827 if (res) {
828 DRM_ERROR("Failed to initialize universal plane\n");
829 return NULL;
830 }
831
832 drm_plane_helper_add(&hqvdp->plane.drm_plane, &sti_hqvdp_helpers_funcs);
833
834 sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY);
835
836 return &hqvdp->plane.drm_plane;
803} 837}
804 838
805static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) 839static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp)
@@ -948,7 +982,7 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
948{ 982{
949 struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); 983 struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
950 struct drm_device *drm_dev = data; 984 struct drm_device *drm_dev = data;
951 struct sti_plane *plane; 985 struct drm_plane *plane;
952 int err; 986 int err;
953 987
954 DRM_DEBUG_DRIVER("\n"); 988 DRM_DEBUG_DRIVER("\n");
@@ -965,11 +999,8 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
965 } 999 }
966 1000
967 /* Create HQVDP plane once xp70 is initialized */ 1001 /* Create HQVDP plane once xp70 is initialized */
968 plane = sti_hqvdp_create(hqvdp->dev, STI_HQVDP_0); 1002 plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0);
969 if (plane) 1003 if (!plane)
970 sti_plane_init(hqvdp->drm_dev, plane, 1,
971 DRM_PLANE_TYPE_OVERLAY);
972 else
973 DRM_ERROR("Can't create HQVDP plane\n"); 1004 DRM_ERROR("Can't create HQVDP plane\n");
974 1005
975 return 0; 1006 return 0;
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c
index d5a96561c8ce..0182e9365004 100644
--- a/drivers/gpu/drm/sti/sti_mixer.c
+++ b/drivers/gpu/drm/sti/sti_mixer.c
@@ -58,6 +58,7 @@ const char *sti_mixer_to_str(struct sti_mixer *mixer)
58 return "<UNKNOWN MIXER>"; 58 return "<UNKNOWN MIXER>";
59 } 59 }
60} 60}
61EXPORT_SYMBOL(sti_mixer_to_str);
61 62
62static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id) 63static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
63{ 64{
@@ -225,15 +226,6 @@ int sti_mixer_set_plane_status(struct sti_mixer *mixer,
225 return 0; 226 return 0;
226} 227}
227 228
228void sti_mixer_clear_all_planes(struct sti_mixer *mixer)
229{
230 u32 val;
231
232 DRM_DEBUG_DRIVER("%s clear all planes\n", sti_mixer_to_str(mixer));
233 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL) & 0xFFFF0000;
234 sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
235}
236
237void sti_mixer_set_matrix(struct sti_mixer *mixer) 229void sti_mixer_set_matrix(struct sti_mixer *mixer)
238{ 230{
239 unsigned int i; 231 unsigned int i;
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h
index 2f69b007e7c8..efb1a9a5ba86 100644
--- a/drivers/gpu/drm/sti/sti_mixer.h
+++ b/drivers/gpu/drm/sti/sti_mixer.h
@@ -15,6 +15,12 @@
15 15
16#define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc) 16#define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc)
17 17
18enum sti_mixer_status {
19 STI_MIXER_READY,
20 STI_MIXER_DISABLING,
21 STI_MIXER_DISABLED,
22};
23
18/** 24/**
19 * STI Mixer subdevice structure 25 * STI Mixer subdevice structure
20 * 26 *
@@ -23,7 +29,7 @@
23 * @id: id of the mixer 29 * @id: id of the mixer
24 * @drm_crtc: crtc object link to the mixer 30 * @drm_crtc: crtc object link to the mixer
25 * @pending_event: set if a flip event is pending on crtc 31 * @pending_event: set if a flip event is pending on crtc
26 * @enabled: to know if the mixer is active or not 32 * @status: to know the status of the mixer
27 */ 33 */
28struct sti_mixer { 34struct sti_mixer {
29 struct device *dev; 35 struct device *dev;
@@ -31,7 +37,7 @@ struct sti_mixer {
31 int id; 37 int id;
32 struct drm_crtc drm_crtc; 38 struct drm_crtc drm_crtc;
33 struct drm_pending_vblank_event *pending_event; 39 struct drm_pending_vblank_event *pending_event;
34 bool enabled; 40 enum sti_mixer_status status;
35}; 41};
36 42
37const char *sti_mixer_to_str(struct sti_mixer *mixer); 43const char *sti_mixer_to_str(struct sti_mixer *mixer);
@@ -41,7 +47,6 @@ struct sti_mixer *sti_mixer_create(struct device *dev, int id,
41 47
42int sti_mixer_set_plane_status(struct sti_mixer *mixer, 48int sti_mixer_set_plane_status(struct sti_mixer *mixer,
43 struct sti_plane *plane, bool status); 49 struct sti_plane *plane, bool status);
44void sti_mixer_clear_all_planes(struct sti_mixer *mixer);
45int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane); 50int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane);
46int sti_mixer_active_video_area(struct sti_mixer *mixer, 51int sti_mixer_active_video_area(struct sti_mixer *mixer,
47 struct drm_display_mode *mode); 52 struct drm_display_mode *mode);
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
index 6a38521ca9b4..d5c5e91f2956 100644
--- a/drivers/gpu/drm/sti/sti_plane.c
+++ b/drivers/gpu/drm/sti/sti_plane.c
@@ -7,15 +7,12 @@
7 */ 7 */
8 8
9#include <drm/drmP.h> 9#include <drm/drmP.h>
10#include <drm/drm_atomic_helper.h>
11#include <drm/drm_gem_cma_helper.h>
12#include <drm/drm_fb_cma_helper.h> 10#include <drm/drm_fb_cma_helper.h>
13#include <drm/drm_plane_helper.h> 11#include <drm/drm_gem_cma_helper.h>
14 12
15#include "sti_compositor.h" 13#include "sti_compositor.h"
16#include "sti_drv.h" 14#include "sti_drv.h"
17#include "sti_plane.h" 15#include "sti_plane.h"
18#include "sti_vtg.h"
19 16
20/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ 17/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */
21enum sti_plane_desc sti_plane_default_zorder[] = { 18enum sti_plane_desc sti_plane_default_zorder[] = {
@@ -47,115 +44,6 @@ const char *sti_plane_to_str(struct sti_plane *plane)
47} 44}
48EXPORT_SYMBOL(sti_plane_to_str); 45EXPORT_SYMBOL(sti_plane_to_str);
49 46
50static int sti_plane_prepare(struct sti_plane *plane,
51 struct drm_crtc *crtc,
52 struct drm_framebuffer *fb,
53 struct drm_display_mode *mode, int mixer_id,
54 int dest_x, int dest_y, int dest_w, int dest_h,
55 int src_x, int src_y, int src_w, int src_h)
56{
57 struct drm_gem_cma_object *cma_obj;
58 unsigned int i;
59 int res;
60
61 if (!plane || !fb || !mode) {
62 DRM_ERROR("Null fb, plane or mode\n");
63 return 1;
64 }
65
66 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
67 if (!cma_obj) {
68 DRM_ERROR("Can't get CMA GEM object for fb\n");
69 return 1;
70 }
71
72 plane->fb = fb;
73 plane->mode = mode;
74 plane->mixer_id = mixer_id;
75 plane->dst_x = dest_x;
76 plane->dst_y = dest_y;
77 plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x);
78 plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y);
79 plane->src_x = src_x;
80 plane->src_y = src_y;
81 plane->src_w = src_w;
82 plane->src_h = src_h;
83 plane->format = fb->pixel_format;
84 plane->vaddr = cma_obj->vaddr;
85 plane->paddr = cma_obj->paddr;
86 for (i = 0; i < 4; i++) {
87 plane->pitches[i] = fb->pitches[i];
88 plane->offsets[i] = fb->offsets[i];
89 }
90
91 DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n",
92 sti_plane_to_str(plane),
93 plane->mixer_id);
94 DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
95 sti_plane_to_str(plane),
96 plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y,
97 plane->src_w, plane->src_h, plane->src_x,
98 plane->src_y);
99
100 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
101 (char *)&plane->format, (unsigned long)plane->paddr);
102
103 if (!plane->ops->prepare) {
104 DRM_ERROR("Cannot prepare\n");
105 return 1;
106 }
107
108 res = plane->ops->prepare(plane, !plane->enabled);
109 if (res) {
110 DRM_ERROR("Plane prepare failed\n");
111 return res;
112 }
113
114 plane->enabled = true;
115
116 return 0;
117}
118
119static int sti_plane_commit(struct sti_plane *plane)
120{
121 if (!plane)
122 return 1;
123
124 if (!plane->ops->commit) {
125 DRM_ERROR("Cannot commit\n");
126 return 1;
127 }
128
129 return plane->ops->commit(plane);
130}
131
132static int sti_plane_disable(struct sti_plane *plane)
133{
134 int res;
135
136 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane));
137 if (!plane)
138 return 1;
139
140 if (!plane->enabled)
141 return 0;
142
143 if (!plane->ops->disable) {
144 DRM_ERROR("Cannot disable\n");
145 return 1;
146 }
147
148 res = plane->ops->disable(plane);
149 if (res) {
150 DRM_ERROR("Plane disable failed\n");
151 return res;
152 }
153
154 plane->enabled = false;
155
156 return 0;
157}
158
159static void sti_plane_destroy(struct drm_plane *drm_plane) 47static void sti_plane_destroy(struct drm_plane *drm_plane)
160{ 48{
161 DRM_DEBUG_DRIVER("\n"); 49 DRM_DEBUG_DRIVER("\n");
@@ -182,109 +70,6 @@ static int sti_plane_set_property(struct drm_plane *drm_plane,
182 return -EINVAL; 70 return -EINVAL;
183} 71}
184 72
185static struct drm_plane_funcs sti_plane_funcs = {
186 .update_plane = drm_atomic_helper_update_plane,
187 .disable_plane = drm_atomic_helper_disable_plane,
188 .destroy = sti_plane_destroy,
189 .set_property = sti_plane_set_property,
190 .reset = drm_atomic_helper_plane_reset,
191 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
192 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
193};
194
195static int sti_plane_atomic_check(struct drm_plane *drm_plane,
196 struct drm_plane_state *state)
197{
198 return 0;
199}
200
201static void sti_plane_atomic_update(struct drm_plane *drm_plane,
202 struct drm_plane_state *oldstate)
203{
204 struct drm_plane_state *state = drm_plane->state;
205 struct sti_plane *plane = to_sti_plane(drm_plane);
206 struct sti_mixer *mixer = to_sti_mixer(state->crtc);
207 int res;
208
209 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
210 state->crtc->base.id, sti_mixer_to_str(mixer),
211 drm_plane->base.id, sti_plane_to_str(plane));
212 DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n",
213 state->crtc_w, state->crtc_h,
214 state->crtc_x, state->crtc_y);
215
216 res = sti_mixer_set_plane_depth(mixer, plane);
217 if (res) {
218 DRM_ERROR("Cannot set plane depth\n");
219 return;
220 }
221
222 /* src_x are in 16.16 format */
223 res = sti_plane_prepare(plane, state->crtc, state->fb,
224 &state->crtc->mode, mixer->id,
225 state->crtc_x, state->crtc_y,
226 state->crtc_w, state->crtc_h,
227 state->src_x >> 16, state->src_y >> 16,
228 state->src_w >> 16, state->src_h >> 16);
229 if (res) {
230 DRM_ERROR("Plane prepare failed\n");
231 return;
232 }
233
234 res = sti_plane_commit(plane);
235 if (res) {
236 DRM_ERROR("Plane commit failed\n");
237 return;
238 }
239
240 res = sti_mixer_set_plane_status(mixer, plane, true);
241 if (res) {
242 DRM_ERROR("Cannot enable plane at mixer\n");
243 return;
244 }
245}
246
247static void sti_plane_atomic_disable(struct drm_plane *drm_plane,
248 struct drm_plane_state *oldstate)
249{
250 struct sti_plane *plane = to_sti_plane(drm_plane);
251 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
252 int res;
253
254 if (!drm_plane->crtc) {
255 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
256 drm_plane->base.id);
257 return;
258 }
259
260 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
261 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
262 drm_plane->base.id, sti_plane_to_str(plane));
263
264 /* Disable plane at mixer level */
265 res = sti_mixer_set_plane_status(mixer, plane, false);
266 if (res) {
267 DRM_ERROR("Cannot disable plane at mixer\n");
268 return;
269 }
270
271 /* Wait a while to be sure that a Vsync event is received */
272 msleep(WAIT_NEXT_VSYNC_MS);
273
274 /* Then disable plane itself */
275 res = sti_plane_disable(plane);
276 if (res) {
277 DRM_ERROR("Plane disable failed\n");
278 return;
279 }
280}
281
282static const struct drm_plane_helper_funcs sti_plane_helpers_funcs = {
283 .atomic_check = sti_plane_atomic_check,
284 .atomic_update = sti_plane_atomic_update,
285 .atomic_disable = sti_plane_atomic_disable,
286};
287
288static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) 73static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane)
289{ 74{
290 struct drm_device *dev = drm_plane->dev; 75 struct drm_device *dev = drm_plane->dev;
@@ -305,25 +90,10 @@ static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane)
305 drm_object_attach_property(&drm_plane->base, prop, plane->zorder); 90 drm_object_attach_property(&drm_plane->base, prop, plane->zorder);
306} 91}
307 92
308struct drm_plane *sti_plane_init(struct drm_device *dev, 93void sti_plane_init_property(struct sti_plane *plane,
309 struct sti_plane *plane, 94 enum drm_plane_type type)
310 unsigned int possible_crtcs,
311 enum drm_plane_type type)
312{ 95{
313 int err, i; 96 unsigned int i;
314
315 err = drm_universal_plane_init(dev, &plane->drm_plane,
316 possible_crtcs,
317 &sti_plane_funcs,
318 plane->ops->get_formats(plane),
319 plane->ops->get_nb_formats(plane),
320 type);
321 if (err) {
322 DRM_ERROR("Failed to initialize universal plane\n");
323 return NULL;
324 }
325
326 drm_plane_helper_add(&plane->drm_plane, &sti_plane_helpers_funcs);
327 97
328 for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) 98 for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++)
329 if (sti_plane_default_zorder[i] == plane->desc) 99 if (sti_plane_default_zorder[i] == plane->desc)
@@ -337,7 +107,16 @@ struct drm_plane *sti_plane_init(struct drm_device *dev,
337 DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", 107 DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n",
338 plane->drm_plane.base.id, 108 plane->drm_plane.base.id,
339 sti_plane_to_str(plane), plane->zorder); 109 sti_plane_to_str(plane), plane->zorder);
340
341 return &plane->drm_plane;
342} 110}
343EXPORT_SYMBOL(sti_plane_init); 111EXPORT_SYMBOL(sti_plane_init_property);
112
113struct drm_plane_funcs sti_plane_helpers_funcs = {
114 .update_plane = drm_atomic_helper_update_plane,
115 .disable_plane = drm_atomic_helper_disable_plane,
116 .destroy = sti_plane_destroy,
117 .set_property = sti_plane_set_property,
118 .reset = drm_atomic_helper_plane_reset,
119 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
120 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
121};
122EXPORT_SYMBOL(sti_plane_helpers_funcs);
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h
index bd527543bb1c..86f1e6fc81b9 100644
--- a/drivers/gpu/drm/sti/sti_plane.h
+++ b/drivers/gpu/drm/sti/sti_plane.h
@@ -8,6 +8,10 @@
8#define _STI_PLANE_H_ 8#define _STI_PLANE_H_
9 9
10#include <drm/drmP.h> 10#include <drm/drmP.h>
11#include <drm/drm_atomic_helper.h>
12#include <drm/drm_plane_helper.h>
13
14extern struct drm_plane_funcs sti_plane_helpers_funcs;
11 15
12#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) 16#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane)
13 17
@@ -38,68 +42,30 @@ enum sti_plane_desc {
38 STI_BACK = STI_BCK 42 STI_BACK = STI_BCK
39}; 43};
40 44
45enum sti_plane_status {
46 STI_PLANE_READY,
47 STI_PLANE_UPDATED,
48 STI_PLANE_DISABLING,
49 STI_PLANE_FLUSHING,
50 STI_PLANE_DISABLED,
51};
52
41/** 53/**
42 * STI plane structure 54 * STI plane structure
43 * 55 *
44 * @plane: drm plane it is bound to (if any) 56 * @plane: drm plane it is bound to (if any)
45 * @fb: drm fb it is bound to
46 * @mode: display mode
47 * @desc: plane type & id 57 * @desc: plane type & id
48 * @ops: plane functions 58 * @status: to know the status of the plane
49 * @zorder: plane z-order 59 * @zorder: plane z-order
50 * @mixer_id: id of the mixer used to display the plane
51 * @enabled: to know if the plane is active or not
52 * @src_x src_y: coordinates of the input (fb) area
53 * @src_w src_h: size of the input (fb) area
54 * @dst_x dst_y: coordinates of the output (crtc) area
55 * @dst_w dst_h: size of the output (crtc) area
56 * @format: format
57 * @pitches: pitch of 'planes' (eg: Y, U, V)
58 * @offsets: offset of 'planes'
59 * @vaddr: virtual address of the input buffer
60 * @paddr: physical address of the input buffer
61 */ 60 */
62struct sti_plane { 61struct sti_plane {
63 struct drm_plane drm_plane; 62 struct drm_plane drm_plane;
64 struct drm_framebuffer *fb;
65 struct drm_display_mode *mode;
66 enum sti_plane_desc desc; 63 enum sti_plane_desc desc;
67 const struct sti_plane_funcs *ops; 64 enum sti_plane_status status;
68 int zorder; 65 int zorder;
69 int mixer_id;
70 bool enabled;
71 int src_x, src_y;
72 int src_w, src_h;
73 int dst_x, dst_y;
74 int dst_w, dst_h;
75 uint32_t format;
76 unsigned int pitches[4];
77 unsigned int offsets[4];
78 void *vaddr;
79 dma_addr_t paddr;
80}; 66};
81 67
82/**
83 * STI plane functions structure
84 *
85 * @get_formats: get plane supported formats
86 * @get_nb_formats: get number of format supported
87 * @prepare: prepare plane before rendering
88 * @commit: set plane for rendering
89 * @disable: disable plane
90 */
91struct sti_plane_funcs {
92 const uint32_t* (*get_formats)(struct sti_plane *plane);
93 unsigned int (*get_nb_formats)(struct sti_plane *plane);
94 int (*prepare)(struct sti_plane *plane, bool first_prepare);
95 int (*commit)(struct sti_plane *plane);
96 int (*disable)(struct sti_plane *plane);
97};
98
99struct drm_plane *sti_plane_init(struct drm_device *dev,
100 struct sti_plane *sti_plane,
101 unsigned int possible_crtcs,
102 enum drm_plane_type type);
103const char *sti_plane_to_str(struct sti_plane *plane); 68const char *sti_plane_to_str(struct sti_plane *plane);
104 69void sti_plane_init_property(struct sti_plane *plane,
70 enum drm_plane_type type);
105#endif 71#endif
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c
index 1e7e1d776adb..a8254cc362a1 100644
--- a/drivers/gpu/drm/sti/sti_vid.c
+++ b/drivers/gpu/drm/sti/sti_vid.c
@@ -43,28 +43,37 @@
43#define VID_MPR2_BT709 0x07150545 43#define VID_MPR2_BT709 0x07150545
44#define VID_MPR3_BT709 0x00000AE8 44#define VID_MPR3_BT709 0x00000AE8
45 45
46int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane) 46void sti_vid_commit(struct sti_vid *vid,
47 struct drm_plane_state *state)
47{ 48{
48 struct drm_display_mode *mode = plane->mode; 49 struct drm_crtc *crtc = state->crtc;
50 struct drm_display_mode *mode = &crtc->mode;
51 int dst_x = state->crtc_x;
52 int dst_y = state->crtc_y;
53 int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
54 int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
49 u32 val, ydo, xdo, yds, xds; 55 u32 val, ydo, xdo, yds, xds;
50 56
57 /* Input / output size
58 * Align to upper even value */
59 dst_w = ALIGN(dst_w, 2);
60 dst_h = ALIGN(dst_h, 2);
61
51 /* Unmask */ 62 /* Unmask */
52 val = readl(vid->regs + VID_CTL); 63 val = readl(vid->regs + VID_CTL);
53 val &= ~VID_CTL_IGNORE; 64 val &= ~VID_CTL_IGNORE;
54 writel(val, vid->regs + VID_CTL); 65 writel(val, vid->regs + VID_CTL);
55 66
56 ydo = sti_vtg_get_line_number(*mode, plane->dst_y); 67 ydo = sti_vtg_get_line_number(*mode, dst_y);
57 yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1); 68 yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
58 xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x); 69 xdo = sti_vtg_get_pixel_number(*mode, dst_x);
59 xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1); 70 xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
60 71
61 writel((ydo << 16) | xdo, vid->regs + VID_VPO); 72 writel((ydo << 16) | xdo, vid->regs + VID_VPO);
62 writel((yds << 16) | xds, vid->regs + VID_VPS); 73 writel((yds << 16) | xds, vid->regs + VID_VPS);
63
64 return 0;
65} 74}
66 75
67int sti_vid_disable(struct sti_vid *vid) 76void sti_vid_disable(struct sti_vid *vid)
68{ 77{
69 u32 val; 78 u32 val;
70 79
@@ -72,8 +81,6 @@ int sti_vid_disable(struct sti_vid *vid)
72 val = readl(vid->regs + VID_CTL); 81 val = readl(vid->regs + VID_CTL);
73 val |= VID_CTL_IGNORE; 82 val |= VID_CTL_IGNORE;
74 writel(val, vid->regs + VID_CTL); 83 writel(val, vid->regs + VID_CTL);
75
76 return 0;
77} 84}
78 85
79static void sti_vid_init(struct sti_vid *vid) 86static void sti_vid_init(struct sti_vid *vid)
diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h
index cc680a23cc5d..5dea4791f1d6 100644
--- a/drivers/gpu/drm/sti/sti_vid.h
+++ b/drivers/gpu/drm/sti/sti_vid.h
@@ -20,8 +20,9 @@ struct sti_vid {
20 int id; 20 int id;
21}; 21};
22 22
23int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane); 23void sti_vid_commit(struct sti_vid *vid,
24int sti_vid_disable(struct sti_vid *vid); 24 struct drm_plane_state *state);
25void sti_vid_disable(struct sti_vid *vid);
25struct sti_vid *sti_vid_create(struct device *dev, int id, 26struct sti_vid *sti_vid_create(struct device *dev, int id,
26 void __iomem *baseaddr); 27 void __iomem *baseaddr);
27 28