1212#include <drm/drm_fourcc.h>
1313#include <drm/drm_fb_dma_helper.h>
1414#include <drm/drm_framebuffer.h>
15+ #include <drm/drm_gem.h>
1516#include <drm/drm_gem_dma_helper.h>
1617#include <drm/drm_plane.h>
1718
@@ -81,6 +82,29 @@ static int apple_plane_atomic_check(struct drm_plane *plane,
8182 return - EINVAL ;
8283 }
8384
85+ /*
86+ * Pitches have to be 64-byte aligned.
87+ */
88+ for (u32 i = 0 ; i < new_plane_state -> fb -> format -> num_planes ; i ++ )
89+ if (new_plane_state -> fb -> pitches [i ] & 63 )
90+ return - EINVAL ;
91+
92+ /*
93+ * FIXME: dcp can currently only use multi-planar buffers using the same
94+ * object for all planes. It has a mandatory iommu so it should
95+ * be no problem to map multiple objects "linearly" into DCP
96+ * virtual address space and calculate the offsets accordingly.
97+ * Or maybe it can accept multiple BOs via the per plane field
98+ * `base`.
99+ */
100+ if (new_plane_state -> fb -> format -> num_planes > 1 ) {
101+ const struct drm_gem_object * first = new_plane_state -> fb -> obj [0 ];
102+ for (u32 i = 1 ; i < new_plane_state -> fb -> format -> num_planes ; i ++ )
103+ if (new_plane_state -> fb -> obj [i ] != NULL &&
104+ new_plane_state -> fb -> obj [i ] != first )
105+ return - EINVAL ;
106+ }
107+
84108 return 0 ;
85109}
86110
@@ -105,8 +129,9 @@ static struct dcp_rect drm_to_dcp_rect_fp(const struct drm_rect *fp_rect)
105129 return drm_to_dcp_rect (& rect );
106130}
107131
108- static u32 drm_format_to_dcp (u32 drm )
132+ static u32 drm_format_to_dcp (u32 drm , enum drm_color_range range )
109133{
134+ bool fr = range == DRM_COLOR_YCBCR_FULL_RANGE ;
110135 switch (drm ) {
111136 case DRM_FORMAT_XRGB8888 :
112137 case DRM_FORMAT_ARGB8888 :
@@ -119,12 +144,67 @@ static u32 drm_format_to_dcp(u32 drm)
119144 case DRM_FORMAT_XRGB2101010 :
120145 case DRM_FORMAT_ARGB2101010 :
121146 return DCP_FORMAT_L10R ;
147+
148+ /* semi planar YCbCr formats, limited and full range */
149+ case DRM_FORMAT_NV12 :
150+ return fr ? DCP_FORMAT_420F : DCP_FORMAT_420V ;
151+ case DRM_FORMAT_NV16 :
152+ return fr ? DCP_FORMAT_422F : DCP_FORMAT_422V ;
153+ case DRM_FORMAT_NV24 :
154+ return fr ? DCP_FORMAT_444F : DCP_FORMAT_444V ;
155+
156+ /* semi planar 10-bit YCbCr formats, limited and full range */
157+ case DRM_FORMAT_P010 :
158+ return fr ? DCP_FORMAT_XF20 : DCP_FORMAT_X420 ;
159+ case DRM_FORMAT_P210 :
160+ return fr ? DCP_FORMAT_XF22 : DCP_FORMAT_X422 ;
161+ /*
162+ * TODO: missing DRM fourcc for P410
163+ */
164+ #if defined(DRM_FORMAT_P410 )
165+ case DRM_FORMAT_P410 :
166+ return fr ? DCP_FORMAT_XF44 : DCP_FORMAT_X444 ;
167+ #endif
122168 }
123169
124170 pr_warn ("DRM format %X not supported in DCP\n" , drm );
125171 return 0 ;
126172}
127173
174+ static enum dcp_xfer_func get_xfer_func (bool is_yuv , enum drm_color_encoding enc )
175+ {
176+ if (!is_yuv )
177+ return DCP_XFER_FUNC_SDR ;
178+
179+ switch (enc ) {
180+ case DRM_COLOR_YCBCR_BT601 :
181+ return DCP_XFER_FUNC_BT601 ;
182+ case DRM_COLOR_YCBCR_BT709 :
183+ case DRM_COLOR_YCBCR_BT2020 :
184+ return DCP_XFER_FUNC_BT1886 ;
185+ default :
186+ return DCP_XFER_FUNC_SDR ;
187+ }
188+ }
189+
190+ static enum dcp_colorspace get_colorspace (bool is_yuv ,
191+ enum drm_color_encoding enc )
192+ {
193+ if (!is_yuv )
194+ return DCP_COLORSPACE_NATIVE ;
195+
196+ switch (enc ) {
197+ case DRM_COLOR_YCBCR_BT601 :
198+ return DCP_COLORSPACE_BT601 ;
199+ case DRM_COLOR_YCBCR_BT709 :
200+ return DCP_COLORSPACE_BT709 ;
201+ case DRM_COLOR_YCBCR_BT2020 :
202+ return DCP_COLORSPACE_BG_BT2020 ;
203+ default :
204+ return DCP_COLORSPACE_NATIVE ;
205+ }
206+ }
207+
128208static void apple_plane_atomic_update (struct drm_plane * plane ,
129209 struct drm_atomic_state * state )
130210{
@@ -160,9 +240,11 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
160240
161241 new_state -> surf = (struct dcp_surface ){
162242 .is_premultiplied = is_premultiplied ,
163- .format = drm_format_to_dcp (fb -> format -> format ),
164- .xfer_func = DCP_XFER_FUNC_SDR ,
165- .colorspace = DCP_COLORSPACE_NATIVE ,
243+ .plane_cnt = fb -> format -> num_planes ,
244+ .plane_cnt2 = fb -> format -> num_planes ,
245+ .format = drm_format_to_dcp (fmt -> format , base -> color_range ),
246+ .xfer_func = get_xfer_func (fmt -> is_yuv , base -> color_encoding ),
247+ .colorspace = get_colorspace (fmt -> is_yuv , base -> color_encoding ),
166248 .stride = fb -> pitches [0 ],
167249 .width = fb -> width ,
168250 .height = fb -> height ,
@@ -177,6 +259,30 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
177259 .has_planes = 1 ,
178260 };
179261
262+ /* Populate plane information for planar formats */
263+ struct dcp_surface * surf = & new_state -> surf ;
264+ for (int i = 0 ; fb -> format -> num_planes && i < fb -> format -> num_planes ; i ++ ) {
265+ u32 width = drm_format_info_plane_width (fb -> format , fb -> width , i );
266+ u32 height = drm_format_info_plane_height (fb -> format , fb -> height , i );
267+ u32 bh = drm_format_info_block_height (fb -> format , i );
268+ u32 bw = drm_format_info_block_width (fb -> format , i );
269+
270+ surf -> planes [i ] = (struct dcp_plane_info ){
271+ .width = width ,
272+ .height = height ,
273+ .base = fb -> offsets [i ] - fb -> offsets [0 ],
274+ .offset = fb -> offsets [i ] - fb -> offsets [0 ],
275+ .stride = fb -> pitches [i ],
276+ .size = height * fb -> pitches [i ],
277+ .tile_size = bw * bh ,
278+ .tile_w = bw ,
279+ .tile_h = bh ,
280+ };
281+
282+ if (i > 0 )
283+ surf -> buf_size += surf -> planes [i ].size ;
284+ }
285+
180286 /* the obvious helper call drm_fb_dma_get_gem_addr() adjusts
181287 * the address for source x/y offsets. Since IOMFB has a direct
182288 * support source position prefer that.
@@ -264,12 +370,28 @@ static const u32 dcp_primary_formats[] = {
264370 DRM_FORMAT_ARGB8888 ,
265371 DRM_FORMAT_XBGR8888 ,
266372 DRM_FORMAT_ABGR8888 ,
373+ DRM_FORMAT_NV12 ,
374+ DRM_FORMAT_NV16 ,
375+ DRM_FORMAT_NV24 ,
376+ DRM_FORMAT_P010 ,
377+ DRM_FORMAT_P210 ,
378+ #if defined(DRM_FORMAT_P410 )
379+ DRM_FORMAT_P410 ,
380+ #endif
267381};
268382
269383static const u32 dcp_overlay_formats [] = {
270384 DRM_FORMAT_ARGB2101010 ,
271385 DRM_FORMAT_ARGB8888 ,
272386 DRM_FORMAT_ABGR8888 ,
387+ DRM_FORMAT_NV12 ,
388+ DRM_FORMAT_NV16 ,
389+ DRM_FORMAT_NV24 ,
390+ DRM_FORMAT_P010 ,
391+ DRM_FORMAT_P210 ,
392+ #if defined(DRM_FORMAT_P410 )
393+ DRM_FORMAT_P410 ,
394+ #endif
273395};
274396
275397u64 apple_format_modifiers [] = {
@@ -308,6 +430,12 @@ struct drm_plane *apple_plane_init(struct drm_device *dev,
308430 if (IS_ERR (plane ))
309431 return ERR_PTR (PTR_ERR (plane ));
310432
433+ drm_plane_create_color_properties (& plane -> base ,
434+ (1 << DRM_COLOR_ENCODING_MAX ) - 1 ,
435+ (1 << DRM_COLOR_RANGE_MAX ) - 1 ,
436+ DRM_COLOR_YCBCR_BT709 ,
437+ DRM_COLOR_YCBCR_LIMITED_RANGE );
438+
311439 if (type == DRM_PLANE_TYPE_PRIMARY )
312440 drm_plane_helper_add (& plane -> base , & apple_primary_plane_helper_funcs );
313441 else
0 commit comments