diff options
author | Vincent Abriou <vincent.abriou@st.com> | 2015-08-03 08:22:16 -0400 |
---|---|---|
committer | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2015-08-03 08:26:05 -0400 |
commit | 29d1dc62e1618192a25bd2eae9617529b9930cfc (patch) | |
tree | 67e0151ceaad7b164d1f2b7accc7d6f21f377299 /drivers/gpu/drm | |
parent | 9e1f05b28009ca7de50fb92c227c8046f686e2c5 (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.c | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_crtc.c | 133 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_cursor.c | 211 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_cursor.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_gdp.c | 493 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_gdp.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_hqvdp.c | 429 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.h | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_plane.c | 253 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_plane.h | 66 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_vid.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_vid.h | 5 |
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 | ||
22 | static void sti_crtc_dpms(struct drm_crtc *crtc, int mode) | 23 | static void sti_crtc_enable(struct drm_crtc *crtc) |
23 | { | ||
24 | DRM_DEBUG_KMS("\n"); | ||
25 | } | ||
26 | |||
27 | static 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 | ||
47 | static void sti_crtc_commit(struct drm_crtc *crtc) | 45 | static 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 | ||
71 | static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, | 54 | static 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 | ||
158 | static void | 138 | static void |
159 | sti_crtc_mode_set_nofb(struct drm_crtc *crtc) | 139 | sti_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 | ||
179 | static void sti_crtc_atomic_flush(struct drm_crtc *crtc) | 159 | static 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 | ||
183 | static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { | 227 | static 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 | } |
260 | EXPORT_SYMBOL(sti_crtc_enable_vblank); | 317 | EXPORT_SYMBOL(sti_crtc_enable_vblank); |
261 | 318 | ||
262 | void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) | 319 | void 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 | */ |
54 | struct sti_cursor { | 60 | struct 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 | ||
71 | static const uint32_t *sti_cursor_get_formats(struct sti_plane *plane) | 77 | static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src) |
72 | { | ||
73 | return cursor_supported_formats; | ||
74 | } | ||
75 | |||
76 | static unsigned int sti_cursor_get_nb_formats(struct sti_plane *plane) | ||
77 | { | ||
78 | return ARRAY_SIZE(cursor_supported_formats); | ||
79 | } | ||
80 | |||
81 | static 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 | ||
103 | static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) | 97 | static 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 | |||
113 | static 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 | |||
170 | static 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 | ||
190 | static int sti_cursor_disable_plane(struct sti_plane *plane) | 214 | static 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 | ||
195 | static 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 | ||
211 | static const struct sti_plane_funcs cursor_plane_ops = { | 233 | static 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 | ||
219 | struct sti_plane *sti_cursor_create(struct device *dev, int desc, | 238 | struct 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 | |||
288 | err_plane: | ||
289 | dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr); | ||
290 | err_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 | ||
10 | struct sti_plane *sti_cursor_create(struct device *dev, int desc, | 10 | struct 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 | ||
59 | struct sti_gdp_node { | 62 | struct 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 | ||
127 | static const uint32_t *sti_gdp_get_formats(struct sti_plane *plane) | ||
128 | { | ||
129 | return gdp_supported_formats; | ||
130 | } | ||
131 | |||
132 | static unsigned int sti_gdp_get_nb_formats(struct sti_plane *plane) | ||
133 | { | ||
134 | return ARRAY_SIZE(gdp_supported_formats); | ||
135 | } | ||
136 | |||
137 | static int sti_gdp_fourcc2format(int fourcc) | 130 | static 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 | */ |
189 | static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane) | 182 | static 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 | ||
208 | end: | 200 | end: |
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 | */ |
221 | static | 213 | static |
222 | struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane) | 214 | struct 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 | ||
237 | end: | 228 | end: |
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 | */ | ||
254 | static 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 | */ | ||
372 | static 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 | */ |
431 | static int sti_gdp_disable(struct sti_plane *plane) | 241 | static 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 | ||
564 | static const struct sti_plane_funcs gdp_plane_ops = { | 383 | static 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 | |||
576 | end: | ||
577 | plane->status = STI_PLANE_UPDATED; | ||
578 | } | ||
579 | |||
580 | static 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 | |||
599 | static 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 | ||
572 | struct sti_plane *sti_gdp_create(struct device *dev, int desc, | 604 | struct 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 | |||
645 | err: | ||
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 | ||
14 | struct sti_plane *sti_gdp_create(struct device *dev, int desc, | 14 | struct 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 | ||
360 | static const uint32_t *sti_hqvdp_get_formats(struct sti_plane *plane) | ||
361 | { | ||
362 | return hqvdp_supported_formats; | ||
363 | } | ||
364 | |||
365 | static 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 | */ |
499 | static bool sti_hqvdp_check_hw_scaling(struct sti_plane *plane) | 497 | static 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 | */ | ||
523 | static 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 | */ | ||
640 | static 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 | */ |
677 | static int sti_hqvdp_disable(struct sti_plane *plane) | 519 | static 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 | ||
785 | static const struct sti_plane_funcs hqvdp_plane_ops = { | 631 | static 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 | |||
787 | static 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 | |||
806 | static 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 | ||
793 | struct sti_plane *sti_hqvdp_create(struct device *dev, int desc) | 811 | static 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 | ||
805 | static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) | 839 | static 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 | } |
61 | EXPORT_SYMBOL(sti_mixer_to_str); | ||
61 | 62 | ||
62 | static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id) | 63 | static 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 | ||
228 | void 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 | |||
237 | void sti_mixer_set_matrix(struct sti_mixer *mixer) | 229 | void 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 | ||
18 | enum 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 | */ |
28 | struct sti_mixer { | 34 | struct 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 | ||
37 | const char *sti_mixer_to_str(struct sti_mixer *mixer); | 43 | const 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 | ||
42 | int sti_mixer_set_plane_status(struct sti_mixer *mixer, | 48 | int sti_mixer_set_plane_status(struct sti_mixer *mixer, |
43 | struct sti_plane *plane, bool status); | 49 | struct sti_plane *plane, bool status); |
44 | void sti_mixer_clear_all_planes(struct sti_mixer *mixer); | ||
45 | int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane); | 50 | int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane); |
46 | int sti_mixer_active_video_area(struct sti_mixer *mixer, | 51 | int 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) */ |
21 | enum sti_plane_desc sti_plane_default_zorder[] = { | 18 | enum sti_plane_desc sti_plane_default_zorder[] = { |
@@ -47,115 +44,6 @@ const char *sti_plane_to_str(struct sti_plane *plane) | |||
47 | } | 44 | } |
48 | EXPORT_SYMBOL(sti_plane_to_str); | 45 | EXPORT_SYMBOL(sti_plane_to_str); |
49 | 46 | ||
50 | static 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 | |||
119 | static 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 | |||
132 | static 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 | |||
159 | static void sti_plane_destroy(struct drm_plane *drm_plane) | 47 | static 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 | ||
185 | static 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 | |||
195 | static int sti_plane_atomic_check(struct drm_plane *drm_plane, | ||
196 | struct drm_plane_state *state) | ||
197 | { | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static 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 | |||
247 | static 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 | |||
282 | static 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 | |||
288 | static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) | 73 | static 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 | ||
308 | struct drm_plane *sti_plane_init(struct drm_device *dev, | 93 | void 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 | } |
343 | EXPORT_SYMBOL(sti_plane_init); | 111 | EXPORT_SYMBOL(sti_plane_init_property); |
112 | |||
113 | struct 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 | }; | ||
122 | EXPORT_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 | |||
14 | extern 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 | ||
45 | enum 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 | */ |
62 | struct sti_plane { | 61 | struct 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 | */ | ||
91 | struct 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 | |||
99 | struct 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); | ||
103 | const char *sti_plane_to_str(struct sti_plane *plane); | 68 | const char *sti_plane_to_str(struct sti_plane *plane); |
104 | 69 | void 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 | ||
46 | int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane) | 46 | void 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 | ||
67 | int sti_vid_disable(struct sti_vid *vid) | 76 | void 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 | ||
79 | static void sti_vid_init(struct sti_vid *vid) | 86 | static 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 | ||
23 | int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane); | 23 | void sti_vid_commit(struct sti_vid *vid, |
24 | int sti_vid_disable(struct sti_vid *vid); | 24 | struct drm_plane_state *state); |
25 | void sti_vid_disable(struct sti_vid *vid); | ||
25 | struct sti_vid *sti_vid_create(struct device *dev, int id, | 26 | struct sti_vid *sti_vid_create(struct device *dev, int id, |
26 | void __iomem *baseaddr); | 27 | void __iomem *baseaddr); |
27 | 28 | ||