88#include <drm/drm_atomic_helper.h>
99#include <drm/drm_gem_atomic_helper.h>
1010#include <drm/drm_plane_helper.h>
11+ #include <drm/drm_fourcc.h>
1112
1213#include "omap_dmm_tiler.h"
1314#include "omap_drv.h"
2122struct omap_plane_state {
2223 /* Must be first. */
2324 struct drm_plane_state base ;
25+
26+ struct omap_hw_overlay * overlay ;
2427};
2528
2629#define to_omap_plane (x ) container_of(x, struct omap_plane, base)
2730
2831struct omap_plane {
2932 struct drm_plane base ;
3033 enum omap_plane_id id ;
31-
32- struct omap_hw_overlay * overlay ;
3334};
3435
3536static int omap_plane_prepare_fb (struct drm_plane * plane ,
@@ -54,13 +55,29 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
5455 struct drm_atomic_state * state )
5556{
5657 struct omap_drm_private * priv = plane -> dev -> dev_private ;
57- struct omap_plane * omap_plane = to_omap_plane (plane );
5858 struct drm_plane_state * new_state = drm_atomic_get_new_plane_state (state ,
5959 plane );
60- enum omap_plane_id ovl_id = omap_plane -> overlay -> id ;
60+ struct drm_plane_state * old_state = drm_atomic_get_old_plane_state (state ,
61+ plane );
62+ struct omap_plane_state * new_omap_state ;
63+ struct omap_plane_state * old_omap_state ;
6164 struct omap_overlay_info info ;
65+ enum omap_plane_id ovl_id ;
6266 int ret ;
6367
68+ new_omap_state = to_omap_plane_state (new_state );
69+ old_omap_state = to_omap_plane_state (old_state );
70+
71+ /* Cleanup previously held overlay if needed */
72+ if (old_omap_state -> overlay )
73+ omap_overlay_update_state (priv , old_omap_state -> overlay );
74+
75+ if (!new_omap_state -> overlay ) {
76+ DBG ("[PLANE:%d:%s] no overlay attached" , plane -> base .id , plane -> name );
77+ return ;
78+ }
79+
80+ ovl_id = new_omap_state -> overlay -> id ;
6481 DBG ("%s, crtc=%p fb=%p" , plane -> name , new_state -> crtc ,
6582 new_state -> fb );
6683
@@ -79,9 +96,9 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
7996 /* update scanout: */
8097 omap_framebuffer_update_scanout (new_state -> fb , new_state , & info );
8198
82- DBG ("%dx%d -> %dx%d (%d)" , info . width , info . height ,
83- info .out_width , info .out_height ,
84- info .screen_width );
99+ DBG ("%s: % dx%d -> %dx%d (%d)" ,
100+ new_omap_state -> overlay -> name , info .width , info .height ,
101+ info .out_width , info . out_height , info . screen_width );
85102 DBG ("%d,%d %pad %pad" , info .pos_x , info .pos_y ,
86103 & info .paddr , & info .p_uv_addr );
87104
@@ -102,16 +119,26 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
102119static void omap_plane_atomic_disable (struct drm_plane * plane ,
103120 struct drm_atomic_state * state )
104121{
105- struct drm_plane_state * new_state = drm_atomic_get_new_plane_state (state ,
106- plane );
107122 struct omap_drm_private * priv = plane -> dev -> dev_private ;
108123 struct omap_plane * omap_plane = to_omap_plane (plane );
109- enum omap_plane_id ovl_id = omap_plane -> overlay -> id ;
124+ struct drm_plane_state * new_state = drm_atomic_get_new_plane_state (state ,
125+ plane );
126+ struct drm_plane_state * old_state = drm_atomic_get_old_plane_state (state ,
127+ plane );
128+ struct omap_plane_state * new_omap_state ;
129+ struct omap_plane_state * old_omap_state ;
130+
131+ new_omap_state = to_omap_plane_state (new_state );
132+ old_omap_state = to_omap_plane_state (old_state );
133+
134+ if (!old_omap_state -> overlay )
135+ return ;
110136
111137 new_state -> rotation = DRM_MODE_ROTATE_0 ;
112138 new_state -> zpos = plane -> type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane -> id ;
113139
114- dispc_ovl_enable (priv -> dispc , ovl_id , false);
140+ omap_overlay_update_state (priv , old_omap_state -> overlay );
141+ new_omap_state -> overlay = NULL ;
115142}
116143
117144#define FRAC_16_16 (mult , div ) (((mult) << 16) / (div))
@@ -121,32 +148,37 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
121148{
122149 struct drm_plane_state * new_plane_state = drm_atomic_get_new_plane_state (state ,
123150 plane );
151+ struct drm_plane_state * old_plane_state = drm_atomic_get_old_plane_state (state ,
152+ plane );
124153 struct omap_drm_private * priv = plane -> dev -> dev_private ;
154+ struct omap_plane_state * omap_state = to_omap_plane_state (new_plane_state );
155+ struct omap_global_state * omap_overlay_global_state ;
125156 struct drm_crtc_state * crtc_state ;
157+ bool new_hw_overlay = false;
126158 u32 max_width , max_height ;
159+ struct drm_crtc * crtc ;
127160 u16 width , height ;
161+ u32 caps = 0 ;
162+ u32 fourcc ;
128163 int ret ;
129164
130- if (!new_plane_state -> fb )
131- return 0 ;
165+ omap_overlay_global_state = omap_get_global_state (state );
166+ if (IS_ERR (omap_overlay_global_state ))
167+ return PTR_ERR (omap_overlay_global_state );
132168
133169 dispc_ovl_get_max_size (priv -> dispc , & width , & height );
134170 max_width = width << 16 ;
135171 max_height = height << 16 ;
136172
137- /* crtc should only be NULL when disabling (i.e., ! new_plane_state->fb) */
138- if (WARN_ON (! new_plane_state -> crtc ) )
173+ crtc = new_plane_state -> crtc ? new_plane_state -> crtc : plane -> state -> crtc ;
174+ if (! crtc )
139175 return 0 ;
140176
141- crtc_state = drm_atomic_get_existing_crtc_state (state ,
142- new_plane_state -> crtc );
177+ crtc_state = drm_atomic_get_existing_crtc_state (state , crtc );
143178 /* we should have a crtc state if the plane is attached to a crtc */
144179 if (WARN_ON (!crtc_state ))
145180 return 0 ;
146181
147- if (!crtc_state -> enable )
148- return 0 ;
149-
150182 /*
151183 * Note: these are just sanity checks to filter out totally bad scaling
152184 * factors. The real limits must be calculated case by case, and
@@ -159,6 +191,15 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
159191 if (ret )
160192 return ret ;
161193
194+ DBG ("%s: visible %d -> %d" , plane -> name ,
195+ old_plane_state -> visible , new_plane_state -> visible );
196+
197+ if (!new_plane_state -> visible ) {
198+ omap_overlay_release (state , omap_state -> overlay );
199+ omap_state -> overlay = NULL ;
200+ return 0 ;
201+ }
202+
162203 if (new_plane_state -> crtc_x < 0 || new_plane_state -> crtc_y < 0 )
163204 return - EINVAL ;
164205
@@ -179,6 +220,43 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
179220 !omap_framebuffer_supports_rotation (new_plane_state -> fb ))
180221 return - EINVAL ;
181222
223+ if ((new_plane_state -> src_w >> 16 ) != new_plane_state -> crtc_w ||
224+ (new_plane_state -> src_h >> 16 ) != new_plane_state -> crtc_h )
225+ caps |= OMAP_DSS_OVL_CAP_SCALE ;
226+
227+ fourcc = new_plane_state -> fb -> format -> format ;
228+
229+ /*
230+ * (re)allocate hw overlay if we don't have one or
231+ * there is a caps mismatch
232+ */
233+ if (!omap_state -> overlay || (caps & ~omap_state -> overlay -> caps )) {
234+ new_hw_overlay = true;
235+ } else {
236+ /* check supported format */
237+ if (!dispc_ovl_color_mode_supported (priv -> dispc , omap_state -> overlay -> id ,
238+ fourcc ))
239+ new_hw_overlay = true;
240+ }
241+
242+ if (new_hw_overlay ) {
243+ struct omap_hw_overlay * old_ovl = omap_state -> overlay ;
244+ struct omap_hw_overlay * new_ovl = NULL ;
245+
246+ omap_overlay_release (state , old_ovl );
247+
248+ ret = omap_overlay_assign (state , plane , caps , fourcc , & new_ovl );
249+ if (ret ) {
250+ DBG ("%s: failed to assign hw_overlay" , plane -> name );
251+ omap_state -> overlay = NULL ;
252+ return ret ;
253+ }
254+
255+ omap_state -> overlay = new_ovl ;
256+ }
257+
258+ DBG ("plane: %s overlay_id: %d" , plane -> name , omap_state -> overlay -> id );
259+
182260 return 0 ;
183261}
184262
@@ -252,17 +330,21 @@ static void omap_plane_reset(struct drm_plane *plane)
252330static struct drm_plane_state *
253331omap_plane_atomic_duplicate_state (struct drm_plane * plane )
254332{
255- struct omap_plane_state * state ;
333+ struct omap_plane_state * state , * current_state ;
256334
257335 if (WARN_ON (!plane -> state ))
258336 return NULL ;
259337
338+ current_state = to_omap_plane_state (plane -> state );
339+
260340 state = kmalloc (sizeof (* state ), GFP_KERNEL );
261341 if (!state )
262342 return NULL ;
263343
264344 __drm_atomic_helper_plane_duplicate_state (plane , & state -> base );
265345
346+ state -> overlay = current_state -> overlay ;
347+
266348 return & state -> base ;
267349}
268350
@@ -344,12 +426,11 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
344426 return ERR_PTR (- ENOMEM );
345427
346428 omap_plane -> id = idx ;
347- omap_plane -> overlay = priv -> overlays [idx ];
348429
349430 DBG ("%d: type=%d" , omap_plane -> id , type );
350431 DBG (" crtc_mask: 0x%04x" , possible_crtcs );
351432
352- formats = dispc_ovl_get_color_modes (priv -> dispc , omap_plane -> overlay -> id );
433+ formats = dispc_ovl_get_color_modes (priv -> dispc , omap_plane -> id );
353434 for (nformats = 0 ; formats [nformats ]; ++ nformats )
354435 ;
355436
0 commit comments