Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions drivers/gpu/drm/apple/iomfb_plane.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ enum dcp_xfer_func {
DCP_XFER_FUNC_HDR = 16,
};

enum dcp_address_format {
DCP_ADDRESS_FORMAT_INTERCHANGE_TILED = 5,
};

enum dcp_compression_type {
DCP_COMPRESSION_TYPE_INTERCHANGE_TILED = 3,
};

struct dcp_rect {
u32 x;
u32 y;
Expand All @@ -67,7 +75,26 @@ struct dcp_plane_info {
u16 tile_size;
u8 tile_w;
u8 tile_h;
u32 unk[13];
u8 unk1[0xd];
u8 address_format;
u8 unk2[0x26];
} __packed;

struct dcp_compression_info {
u32 tile_w;
u32 tile_h;
u32 meta_offset;
u32 data_offset;
u32 tile_meta_bytes;
u32 tiles_w;
u32 tiles_h;
u32 unk1;
u32 compresson_type;
u32 unk3;
u8 _pad1[3];
u32 tile_bytes;
u32 row_stride;
u8 pad2;
} __packed;

struct dcp_component_types {
Expand Down Expand Up @@ -100,7 +127,7 @@ struct dcp_surface {
u64 has_comp;
struct dcp_plane_info planes[DCP_SURF_MAX_PLANES];
u64 has_planes;
u32 compression_info[DCP_SURF_MAX_PLANES][13];
struct dcp_compression_info compression_info[DCP_SURF_MAX_PLANES];
u64 has_compr_info;
u32 unk_num;
u32 unk_denom;
Expand Down
135 changes: 131 additions & 4 deletions drivers/gpu/drm/apple/plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,61 @@

#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_plane.h>

#include <linux/align.h>
#include <linux/log2.h>

#ifndef DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED
#define DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED fourcc_mod_code(APPLE, 3)
#endif

#define FRAC_16_16(mult, div) (((mult) << 16) / (div))

struct apple_interchange_layout {
u32 tiles_width;
u32 tiles_height;
u32 tile_size_B;
u32 meta_offset;
u32 meta_size;
};

static struct apple_interchange_layout
get_apple_interchange_layout(u32 width, u32 height, u32 bpp)
{
const u32 cacheline = 0x80;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use a define


u32 tw = DIV_ROUND_UP(width, 16);
u32 th = DIV_ROUND_UP(height, 16);
u32 tsize_B = 16 * 16 * (bpp / 8);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should use DIV_ROUND_UP(bpp, 8), not that it matters right now.
That would still be for bit-packed formats. Not sure if dcp supports those or if we want to use them, probably not.
Single component formats with 10- or 12-bit per pixel are more common. Possible that drm_format_info_bpp() includes the padding though.


u32 meta_offset = ALIGN(tw * th * tsize_B, cacheline);

/*
* The metadata buffer contains 8 bytes per 16x16 compression tile.
* Addressing is fully twiddled, so both width and height are padded to
* powers-of-two.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comment from the drm_fourcc.h description would be more more appropriate:

/*
 *  ... The metadata section rounds the image dimensions to
 * powers-of-two and contains 8 bytes for each 16x16 compression subtile.
 * Subtiles are interleaved (Morton order).
 */

It's the most up to date description.

unsigned w_tl = DIV_ROUND_UP(roundup_pow_of_two(width), 16);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this the same as as roundup_pow_of_two(tw)?

unsigned h_tl = DIV_ROUND_UP(roundup_pow_of_two(height), 16);
unsigned B_per_tl = 8;

u32 meta_size = ALIGN(w_tl * h_tl * B_per_tl, cacheline);

return (struct apple_interchange_layout){
.tiles_width = tw,
.tiles_height = th,
.tile_size_B = tsize_B,
.meta_offset = meta_offset,
.meta_size = meta_size,
};
}

static int apple_plane_atomic_check(struct drm_plane *plane,
struct drm_atomic_state *state)
{
Expand Down Expand Up @@ -105,6 +151,38 @@ static int apple_plane_atomic_check(struct drm_plane *plane,
return -EINVAL;
}

/*
* The calculated size of the compression meta data must fit into the size
* of the gem object
*/
for (u32 i = 0; i < new_plane_state->fb->format->num_planes; i++) {
struct drm_framebuffer *fb = new_plane_state->fb;

if (fb->modifier != DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED)
continue;

u32 width =
drm_format_info_plane_width(fb->format, fb->width, i);
u32 height =
drm_format_info_plane_height(fb->format, fb->height, i);
u32 bpp = drm_format_info_bpp(fb->format, i);
struct apple_interchange_layout l =
get_apple_interchange_layout(width, height, bpp);

u32 required_size =
fb->offsets[0] + l.meta_offset + l.meta_size;

struct drm_gem_dma_object *obj = drm_fb_dma_get_gem_obj(fb, i);
if (obj && required_size > obj->base.size) {
dev_err_ratelimited(
state->dev->dev,
"dcp: atomic_check, required size of %u bytes is less than gem size of %zu\n",
required_size, obj->base.size);

return -EINVAL;
}
}

return 0;
}

Expand Down Expand Up @@ -248,7 +326,6 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
.stride = fb->pitches[0],
.width = fb->width,
.height = fb->height,
.buf_size = fb->height * fb->pitches[0],
// .surface_id = req->swap.surf_ids[l],

/* Only used for compressed or multiplanar surfaces */
Expand All @@ -257,6 +334,7 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
.pel_h = 1,
.has_comp = 1,
.has_planes = 1,
.has_compr_info = 1,
};

/* Populate plane information for planar formats */
Expand All @@ -279,8 +357,33 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
.tile_h = bh,
};

if (i > 0)
surf->buf_size += surf->planes[i].size;
if (fb->modifier == DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED) {
u32 bpp = drm_format_info_bpp(fmt, i);
struct apple_interchange_layout l =
get_apple_interchange_layout(width, height, bpp);

surf->planes[i].tile_w = 16;
surf->planes[i].tile_h = 16;
surf->planes[i].stride = l.tiles_width * l.tile_size_B;
surf->planes[i].size = l.meta_offset + l.meta_size;
surf->planes[i].tile_size = l.tile_size_B;
surf->planes[i].address_format = DCP_ADDRESS_FORMAT_INTERCHANGE_TILED;

surf->compression_info[i] = (struct dcp_compression_info){
.tile_w = 16,
.tile_h = 16,
.data_offset = 0,
.meta_offset = l.meta_offset,
.tile_meta_bytes = 8,
.tiles_w = l.tiles_width,
.tiles_h = l.tiles_height,
.tile_bytes = l.tile_size_B,
.row_stride = l.tiles_width * l.tile_size_B,
.compresson_type = DCP_COMPRESSION_TYPE_INTERCHANGE_TILED,
};
}

surf->buf_size += surf->planes[i].size;
}

/* the obvious helper call drm_fb_dma_get_gem_addr() adjusts
Expand Down Expand Up @@ -337,6 +440,28 @@ apple_plane_duplicate_state(struct drm_plane *plane)
return &apple_plane_state->base;
}

static bool apple_plane_format_mod_supported(struct drm_plane *plane,
uint32_t format, uint64_t modifier)
{
if (modifier != DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED) {
return true;
}

// interchange is only supported with rgba formats for now.
switch (format) {
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
return true;

default:
return false;
}
}

// void apple_plane_destroy_state(struct drm_plane *plane,
// struct drm_plane_state *state)
// {
Expand All @@ -350,6 +475,7 @@ static const struct drm_plane_funcs apple_plane_funcs = {
.atomic_duplicate_state = apple_plane_duplicate_state,
// .atomic_destroy_state = apple_plane_destroy_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.format_mod_supported = apple_plane_format_mod_supported,
};

/*
Expand Down Expand Up @@ -426,6 +552,7 @@ static const u32 dcp_overlay_formats_12_x[] = {
};

u64 apple_format_modifiers[] = {
DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
Expand Down