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.
@@ -247,12 +353,28 @@ static const u32 dcp_primary_formats[] = {
247353 DRM_FORMAT_ARGB8888 ,
248354 DRM_FORMAT_XBGR8888 ,
249355 DRM_FORMAT_ABGR8888 ,
356+ DRM_FORMAT_NV12 ,
357+ DRM_FORMAT_NV16 ,
358+ DRM_FORMAT_NV24 ,
359+ DRM_FORMAT_P010 ,
360+ DRM_FORMAT_P210 ,
361+ #if defined(DRM_FORMAT_P410 )
362+ DRM_FORMAT_P410 ,
363+ #endif
250364};
251365
252366static const u32 dcp_overlay_formats [] = {
253367 DRM_FORMAT_ARGB2101010 ,
254368 DRM_FORMAT_ARGB8888 ,
255369 DRM_FORMAT_ABGR8888 ,
370+ DRM_FORMAT_NV12 ,
371+ DRM_FORMAT_NV16 ,
372+ DRM_FORMAT_NV24 ,
373+ DRM_FORMAT_P010 ,
374+ DRM_FORMAT_P210 ,
375+ #if defined(DRM_FORMAT_P410 )
376+ DRM_FORMAT_P410 ,
377+ #endif
256378};
257379
258380u64 apple_format_modifiers [] = {
@@ -291,6 +413,12 @@ struct drm_plane *apple_plane_init(struct drm_device *dev,
291413 if (IS_ERR (plane ))
292414 return ERR_PTR (PTR_ERR (plane ));
293415
416+ drm_plane_create_color_properties (& plane -> base ,
417+ (1 << DRM_COLOR_ENCODING_MAX ) - 1 ,
418+ (1 << DRM_COLOR_RANGE_MAX ) - 1 ,
419+ DRM_COLOR_YCBCR_BT709 ,
420+ DRM_COLOR_YCBCR_LIMITED_RANGE );
421+
294422 if (type == DRM_PLANE_TYPE_PRIMARY )
295423 drm_plane_helper_add (& plane -> base , & apple_primary_plane_helper_funcs );
296424 else
0 commit comments