99
1010#include <drm/drm_atomic.h>
1111#include <drm/drm_atomic_helper.h>
12- #include <drm/drm_fourcc.h>
1312#include <drm/drm_fb_dma_helper.h>
13+ #include <drm/drm_fourcc.h>
1414#include <drm/drm_framebuffer.h>
1515#include <drm/drm_gem.h>
1616#include <drm/drm_gem_dma_helper.h>
1717#include <drm/drm_plane.h>
1818
19+ #include <linux/align.h>
20+ #include <linux/log2.h>
21+
22+ #ifndef DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED
23+ #define DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED fourcc_mod_code(APPLE, 3)
24+ #endif
25+
1926#define FRAC_16_16 (mult , div ) (((mult) << 16) / (div))
2027
28+ struct apple_interchange_layout {
29+ u32 tiles_width ;
30+ u32 tiles_height ;
31+ u32 tile_size_B ;
32+ u32 meta_offset ;
33+ u32 meta_size ;
34+ };
35+
36+ static struct apple_interchange_layout
37+ get_apple_interchange_layout (u32 width , u32 height , u32 bpp )
38+ {
39+ const u32 cacheline = 0x80 ;
40+
41+ u32 tw = DIV_ROUND_UP (width , 16 );
42+ u32 th = DIV_ROUND_UP (height , 16 );
43+ u32 tsize_B = 16 * 16 * (bpp / 8 );
44+
45+ u32 meta_offset = ALIGN (tw * th * tsize_B , cacheline );
46+
47+ /*
48+ * The metadata buffer contains 8 bytes per 16x16 compression tile.
49+ * Addressing is fully twiddled, so both width and height are padded to
50+ * powers-of-two.
51+ */
52+ unsigned w_tl = DIV_ROUND_UP (roundup_pow_of_two (width ), 16 );
53+ unsigned h_tl = DIV_ROUND_UP (roundup_pow_of_two (height ), 16 );
54+ unsigned B_per_tl = 8 ;
55+
56+ u32 meta_size = ALIGN (w_tl * h_tl * B_per_tl , cacheline );
57+
58+ return (struct apple_interchange_layout ){
59+ .tiles_width = tw ,
60+ .tiles_height = th ,
61+ .tile_size_B = tsize_B ,
62+ .meta_offset = meta_offset ,
63+ .meta_size = meta_size ,
64+ };
65+ }
66+
2167static int apple_plane_atomic_check (struct drm_plane * plane ,
2268 struct drm_atomic_state * state )
2369{
@@ -105,6 +151,38 @@ static int apple_plane_atomic_check(struct drm_plane *plane,
105151 return - EINVAL ;
106152 }
107153
154+ /*
155+ * The calculated size of the compression meta data must fit into the size
156+ * of the gem object
157+ */
158+ for (u32 i = 0 ; i < new_plane_state -> fb -> format -> num_planes ; i ++ ) {
159+ struct drm_framebuffer * fb = new_plane_state -> fb ;
160+
161+ if (fb -> modifier != DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED )
162+ continue ;
163+
164+ u32 width =
165+ drm_format_info_plane_width (fb -> format , fb -> width , i );
166+ u32 height =
167+ drm_format_info_plane_height (fb -> format , fb -> height , i );
168+ u32 bpp = drm_format_info_bpp (fb -> format , i );
169+ struct apple_interchange_layout l =
170+ get_apple_interchange_layout (width , height , bpp );
171+
172+ u32 required_size =
173+ fb -> offsets [0 ] + l .meta_offset + l .meta_size ;
174+
175+ struct drm_gem_dma_object * obj = drm_fb_dma_get_gem_obj (fb , i );
176+ if (obj && required_size > obj -> base .size ) {
177+ dev_err_ratelimited (
178+ state -> dev -> dev ,
179+ "dcp: atomic_check, required size of %u bytes is less than gem size of %zu\n" ,
180+ required_size , obj -> base .size );
181+
182+ return - EINVAL ;
183+ }
184+ }
185+
108186 return 0 ;
109187}
110188
@@ -248,7 +326,6 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
248326 .stride = fb -> pitches [0 ],
249327 .width = fb -> width ,
250328 .height = fb -> height ,
251- .buf_size = fb -> height * fb -> pitches [0 ],
252329 // .surface_id = req->swap.surf_ids[l],
253330
254331 /* Only used for compressed or multiplanar surfaces */
@@ -257,6 +334,7 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
257334 .pel_h = 1 ,
258335 .has_comp = 1 ,
259336 .has_planes = 1 ,
337+ .has_compr_info = 1 ,
260338 };
261339
262340 /* Populate plane information for planar formats */
@@ -279,8 +357,33 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
279357 .tile_h = bh ,
280358 };
281359
282- if (i > 0 )
283- surf -> buf_size += surf -> planes [i ].size ;
360+ if (fb -> modifier == DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED ) {
361+ u32 bpp = drm_format_info_bpp (fmt , i );
362+ struct apple_interchange_layout l =
363+ get_apple_interchange_layout (width , height , bpp );
364+
365+ surf -> planes [i ].tile_w = 16 ;
366+ surf -> planes [i ].tile_h = 16 ;
367+ surf -> planes [i ].stride = l .tiles_width * l .tile_size_B ;
368+ surf -> planes [i ].size = l .meta_offset + l .meta_size ;
369+ surf -> planes [i ].tile_size = l .tile_size_B ;
370+ surf -> planes [i ].address_format = DCP_ADDRESS_FORMAT_INTERCHANGE_TILED ;
371+
372+ surf -> compression_info [i ] = (struct dcp_compression_info ){
373+ .tile_w = 16 ,
374+ .tile_h = 16 ,
375+ .data_offset = 0 ,
376+ .meta_offset = l .meta_offset ,
377+ .tile_meta_bytes = 8 ,
378+ .tiles_w = l .tiles_width ,
379+ .tiles_h = l .tiles_height ,
380+ .tile_bytes = l .tile_size_B ,
381+ .row_stride = l .tiles_width * l .tile_size_B ,
382+ .compresson_type = DCP_COMPRESSION_TYPE_INTERCHANGE_TILED ,
383+ };
384+ }
385+
386+ surf -> buf_size += surf -> planes [i ].size ;
284387 }
285388
286389 /* the obvious helper call drm_fb_dma_get_gem_addr() adjusts
@@ -337,6 +440,28 @@ apple_plane_duplicate_state(struct drm_plane *plane)
337440 return & apple_plane_state -> base ;
338441}
339442
443+ static bool apple_plane_format_mod_supported (struct drm_plane * plane ,
444+ uint32_t format , uint64_t modifier )
445+ {
446+ if (modifier != DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED ) {
447+ return true;
448+ }
449+
450+ // interchange is only supported with rgba formats for now.
451+ switch (format ) {
452+ case DRM_FORMAT_XRGB2101010 :
453+ case DRM_FORMAT_ARGB2101010 :
454+ case DRM_FORMAT_XRGB8888 :
455+ case DRM_FORMAT_ARGB8888 :
456+ case DRM_FORMAT_XBGR8888 :
457+ case DRM_FORMAT_ABGR8888 :
458+ return true;
459+
460+ default :
461+ return false;
462+ }
463+ }
464+
340465// void apple_plane_destroy_state(struct drm_plane *plane,
341466// struct drm_plane_state *state)
342467// {
@@ -350,6 +475,7 @@ static const struct drm_plane_funcs apple_plane_funcs = {
350475 .atomic_duplicate_state = apple_plane_duplicate_state ,
351476 // .atomic_destroy_state = apple_plane_destroy_state,
352477 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state ,
478+ .format_mod_supported = apple_plane_format_mod_supported ,
353479};
354480
355481/*
@@ -426,6 +552,7 @@ static const u32 dcp_overlay_formats_12_x[] = {
426552};
427553
428554u64 apple_format_modifiers [] = {
555+ DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED ,
429556 DRM_FORMAT_MOD_LINEAR ,
430557 DRM_FORMAT_MOD_INVALID
431558};
0 commit comments