diff --git a/Documentation/devicetree/bindings/media/apple,avd.yaml b/Documentation/devicetree/bindings/media/apple,avd.yaml new file mode 100644 index 00000000000000..46a0cfc226efec --- /dev/null +++ b/Documentation/devicetree/bindings/media/apple,avd.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/apple,avd.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple AVD (Apple Video Decoder) + +description: + AVD is a video decode block present on all apple silicon devices. + +maintainers: + - Sofus + +properties: + compatible: + oneOf: + - items: + - enum: + - apple,t6030-avd + - apple,t6031-avd + - const: apple,t8122-avd + - enum: + - apple,t8103-avd + - apple,t6000-avd + - apple,t8112-avd + - apple,t6020-avd + - apple,t8122-avd + + reg: + items: + - description: cm3 code + - description: cm3 sram + - description: mbox registers + - description: decode ctrl registers + + reg-names: + items: + - const: code + - const: sram + - const: mbox + - const: ctrl + + iommus: + minItems: 1 + maxItems: 3 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + interrupts: + minItems: 2 + items: + - description: mailbox 0 + - description: mailbox 1 + - description: mailbox 2 + - description: mailbox 3 + - description: flag 0 + - description: flag 1 + +required: + - compatible + - reg + - interrupts + - reg-names + - iommus + - power-domains + - resets + +additionalProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + avd: avd@288000000 { + compatible = "apple,t8122-avd"; + interrupt-parent = <&aic>; + interrupts = , + ; + power-domains = <&ps_avd_sys>; + resets = <&ps_avd_sys>; + reg = <0x2 0x89080000 0x0 0x12000>, + <0x2 0x89092000 0x0 0x12000>, + <0x2 0x890a4000 0x0 0x4000>, + <0x2 0x89100000 0x0 0x10000>; + reg-names = "code", "sram", "mbox", "ctrl"; + iommus = <&avd_dart 0>; + }; + }; diff --git a/drivers/media/platform/apple/avd/avd-av1.c b/drivers/media/platform/apple/avd/avd-av1.c index c399825d5ad157..1d8c6d2f2b798a 100644 --- a/drivers/media/platform/apple/avd/avd-av1.c +++ b/drivers/media/platform/apple/avd/avd-av1.c @@ -182,26 +182,19 @@ #define AV1_REF_SCALE_X(v) FIELD_PREP(GENMASK(31, 16), v) #define AV1_REF_SCALE_Y(v) FIELD_PREP(GENMASK(15, 0), v) -/* not sure what this is? mv data or something? */ -#define AVD_AV1_REF_BUF_SIZE 0xf000 +#define AVD_CDFS_SIZE (sizeof(struct avd_av1_cdfs)) -#define AVD_AV1_CDFS_OFFSET(dst_len) ((dst_len) - sizeof(struct avd_av1_cdfs)) - -#define AVD_AV1_REF_OFFSET(dst_len) \ - (AVD_AV1_CDFS_OFFSET(dst_len) - AVD_AV1_REF_BUF_SIZE) -#define AVD_AV1_RVRA_OFFSET(dst_len, rvra_size) \ - (AVD_AV1_CDFS_OFFSET(dst_len) - (rvra_size)) +#define AVD_AV1_TLB_OFFSET(dst, tlb) \ + ((dst) - ALIGN(tlb, AVD_ALIGN)) +#define AVD_AV1_CDFS_OFFSET(dst, tlb) \ + (AVD_AV1_TLB_OFFSET(dst, tlb) - ALIGN(AVD_CDFS_SIZE, AVD_ALIGN)) struct avd_av1_run { struct avd_run base; struct { - dma_addr_t y; - dma_addr_t uv; - dma_addr_t sl; - dma_addr_t rvra; dma_addr_t probs_out; - dma_addr_t mv; /* no sure */ + dma_addr_t priv_tlb; } addresses; const struct v4l2_ctrl_av1_sequence *seq; @@ -215,10 +208,14 @@ struct avd_av1_ctx { struct { struct avd_buf inst; struct avd_buf pipe_state; - struct avd_buf const_unk[12]; - struct avd_buf ref; + struct avd_buf unk[2]; struct avd_buf probs; } bufs; + struct { + struct avd_buf tile_col[4]; + struct avd_buf tile_row[4]; + struct avd_buf ref; + } scratch; }; /* @@ -331,7 +328,7 @@ static void set_refs(struct avd_ctx *ctx, struct avd_av1_run *run) dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf); push(0, "ref_cnst0"); - pusha(av1_ctx->bufs.ref.addr, "unk_ref_buf", 0); + pusha(av1_ctx->scratch.ref.addr, "unk_ref_buf", 0); for (i = 0; i < 4; i++) push(0, "ref_cnst1"); @@ -347,8 +344,7 @@ static void set_refs(struct avd_ctx *ctx, struct avd_av1_run *run) [frame->ref_frame_idx[i]]); } addr = vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf, 0) + - AVD_AV1_RVRA_OFFSET(ref->base.vb.planes[0].length, - ref->rvra.size); + ref->comp.start_offset; if (!intrabc) { int shift = @@ -406,7 +402,7 @@ static void set_refs(struct avd_ctx *ctx, struct avd_av1_run *run) push(AV1_REF_SCALE_X(x_scale) | AV1_REF_SCALE_Y(y_scale), "ref_scale"); - push_rvra(avd, ctx, addr, ref->rvra.offsets); + push_comp(avd, ctx, addr, ref->comp.offsets); } } @@ -621,7 +617,7 @@ static void set_header(struct avd_ctx *ctx, struct avd_av1_run *run) AVD_OP_EXEC_FLAG_START_REV4(avd->variant->revision == 4) | AVD_OP_EXEC_FIFO_IDX(ctx->fifo_idx), "vp_start"); - push(AVD_OP_HDR | AVD_OP_HDR_FLAG0 | + push(AVD_OP_HDR | AVD_OP_HDR_FLAG_DECOMP(ctx->decomp) | AVD_OP_HDR_FLAG_INTRA(intra_only && !intrabc) | AVD_OP_HDR_CONST | AVD_OP_HDR_FLAG_PIPE_STATE(1), "op_hdr"); @@ -793,13 +789,13 @@ static void set_header(struct avd_ctx *ctx, struct avd_av1_run *run) pusha(run->addresses.probs_out, "probs_out", 0); pusha(av1_ctx->bufs.probs.addr, "probs", 1); - pusha(av1_ctx->bufs.const_unk[0].addr, "const_buf", 0); + pusha(av1_ctx->scratch.tile_col[0].addr, "col", 0); /* TODO */ pusha((dma_addr_t)0, "", 0); pusha((dma_addr_t)0, "", 1); - pusha(run->addresses.mv, "cur_ref_addr", 0); + pusha(run->addresses.priv_tlb, "cur_ref_addr", 0); for (i = 0; i < 3; i++) { if (selected_refs[i] < V4L2_AV1_REF_LAST_FRAME) { @@ -810,10 +806,12 @@ static void set_header(struct avd_ctx *ctx, struct avd_av1_run *run) ref = avd_get_ref_buf( ctx, &dst->base.vb, frame->reference_frame_ts[ref_idx]); - ref_addr = vb2_dma_contig_plane_dma_addr( - &ref->base.vb.vb2_buf, 0) + - AVD_AV1_REF_OFFSET( - ref->base.vb.planes[0].length); + ref_addr = + vb2_dma_contig_plane_dma_addr( + &ref->base.vb.vb2_buf, 0) + + AVD_AV1_TLB_OFFSET( + ref->base.vb.vb2_buf.planes[0].length, + ref->av1.priv_tlb_size); pusha(ref_addr, "ref", ref_idx); } @@ -917,20 +915,30 @@ static void set_header(struct avd_ctx *ctx, struct avd_av1_run *run) push(0, ""); push(0, ""); pusha(av1_ctx->bufs.pipe_state.addr, "pipe_state", 0); - for (i = 0; i < 10; i++) - pusha(av1_ctx->bufs.const_unk[i + 2].addr, "const_unk", i + 2); + pusha(av1_ctx->scratch.tile_col[1].addr, "col", 1); + pusha(av1_ctx->scratch.tile_col[2].addr, "col", 2); + pusha(av1_ctx->scratch.tile_col[3].addr, "col", 3); + + pusha(av1_ctx->scratch.tile_row[0].addr, "row", 0); + pusha(av1_ctx->scratch.tile_row[1].addr, "row", 1); + pusha(0, "unk", 0); + pusha(av1_ctx->bufs.unk[0].addr, "unk", 0); + pusha(av1_ctx->scratch.tile_row[2].addr, "row", 2); + pusha(av1_ctx->bufs.unk[1].addr, "unk", 1); + pusha(av1_ctx->scratch.tile_row[3].addr, "row", 3); push(0, "mark_section"); - push_rvra(avd, ctx, run->addresses.rvra, ctx->rvra.offsets); + push_comp(avd, ctx, run->base.comp_out, ctx->comp.offsets); push(0, ""); push(0, "mark_section"); + /* ignored if decomp is disabled */ bytesperline = ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline; - pusha(run->addresses.y, "y", 0); + pusha(run->base.y_out, "y", 0); push(bytesperline, "bytesperline_y"); - pusha(run->addresses.uv, "uv", 0); + pusha(run->base.uv_out, "uv", 0); push(bytesperline, "bytesperline_uv"); push(0, "mark_section"); @@ -967,11 +975,11 @@ static void set_tiles(struct avd_ctx *ctx, struct avd_av1_run *run) push(AVD_OP_CODED_DATA | AVD_OP_CODED_DATA_ADDR( - (run->addresses.sl + + (run->base.coded_in + tile_group->tile_offset) >> 32), "tile_start"); - push((u32)((run->addresses.sl + + push((u32)((run->base.coded_in + tile_group->tile_offset) & 0xffffffff), "tile_addr"); @@ -1039,7 +1047,8 @@ static void avd_av1_set_prob(struct avd_ctx *ctx, struct avd_av1_run *run) memcpy(av1_ctx->bufs.probs.cpu, vb2_plane_vaddr(&ref->base.vb.vb2_buf, 0) + AVD_AV1_CDFS_OFFSET( - ref->base.vb.vb2_buf.planes[0].length), + ref->base.vb.vb2_buf.planes[0].length, + ref->av1.priv_tlb_size), sizeof(struct avd_av1_cdfs)); } @@ -1048,11 +1057,20 @@ static void avd_av1_set_prob(struct avd_ctx *ctx, struct avd_av1_run *run) * enabled */ memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) + - AVD_AV1_CDFS_OFFSET( - dst->base.vb.vb2_buf.planes[0].length), + AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length, + dst->av1.priv_tlb_size), av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs)); } +static int avd_priv_tlb_size(int h, int w) +{ + /* + * in reality its dependent on quality + * 64 with lower quality + */ + return ALIGN(w, 128) * ALIGN(h, 128) / 16; +} + static void update_dec_buf_info(struct avd_decoded_buffer *buf, const struct v4l2_ctrl_av1_sequence *seq, const struct v4l2_ctrl_av1_frame *frame) @@ -1065,6 +1083,10 @@ static void update_dec_buf_info(struct avd_decoded_buffer *buf, buf->av1.frame_type = frame->frame_type; buf->av1.intrabc = frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC; + buf->av1.priv_tlb_size = + avd_priv_tlb_size(frame->frame_width_minus_1 + 1, + frame->frame_height_minus_1 + 1); + for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME; i++) buf->av1.order_hints[i] = frame->order_hints[i]; @@ -1075,7 +1097,7 @@ static void update_dec_buf_info(struct avd_decoded_buffer *buf, static int avd_av1_run_preamble(struct avd_ctx *ctx, struct avd_av1_run *run) { struct v4l2_ctrl *ctrl; - u32 dst_len; + int dst_len, tlb_len; avd_run_preamble(ctx, &run->base); @@ -1101,26 +1123,113 @@ static int avd_av1_run_preamble(struct avd_ctx *ctx, struct avd_av1_run *run) return -EINVAL; run->grain = ctrl->p_cur.p; - run->addresses.sl = - vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0); - dst_len = run->base.bufs.dst->vb2_buf.planes[0].length; + tlb_len = avd_priv_tlb_size(run->frame->frame_width_minus_1 + 1, + run->frame->frame_height_minus_1 + 1); - run->addresses.y = - vb2_dma_contig_plane_dma_addr(&run->base.bufs.dst->vb2_buf, 0); + run->addresses.priv_tlb = + run->base.y_out + AVD_AV1_TLB_OFFSET(dst_len, tlb_len); - run->addresses.uv = - run->addresses.y + - ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline * - ALIGN(ctx->decoded_fmt.fmt.pix_mp.height, 16); + run->addresses.probs_out = + run->base.y_out + AVD_AV1_CDFS_OFFSET(dst_len, tlb_len); + return 0; +} - run->addresses.rvra = - run->addresses.y + AVD_AV1_RVRA_OFFSET(dst_len, ctx->rvra.size); +static int avd_av1_alloc_scratch(struct avd_ctx *ctx, struct avd_av1_run *run) +{ + struct avd_dev *avd = ctx->dev; + struct avd_av1_ctx *av1_ctx = ctx->priv; + const struct v4l2_ctrl_av1_frame *frame = run->frame; + const struct v4l2_ctrl_av1_sequence *seq = run->seq; + const struct v4l2_av1_tile_info *tile_info = &frame->tile_info; + int ret, max_sb_col = 0, max_sb_row = 0, i, sb_cols = 0, sb; + int sb_shift = + seq->flags & V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK ? 1 : + 0; + int w = frame->frame_width_minus_1 + 1; + int bit_depth = seq->bit_depth; + + for (i = 0; i < tile_info->tile_cols; i++) { + sb = tile_info->width_in_sbs_minus_1[i] + 1; + max_sb_col = sb > max_sb_col ? sb : max_sb_col; + sb_cols += ALIGN((sb << sb_shift) * 44, 128); + } - run->addresses.mv = run->addresses.y + AVD_AV1_REF_OFFSET(dst_len); + max_sb_col <<= sb_shift; - run->addresses.probs_out = - run->addresses.y + AVD_AV1_CDFS_OFFSET(dst_len); + ret = avd_buf_alloc(avd, &av1_ctx->scratch.ref, max_sb_col * 80); + if (ret) + return ret; + + /* first frame this is always much smaller */ + ret = avd_buf_alloc(avd, &av1_ctx->scratch.tile_col[0], + (max_sb_col * 400)); + if (ret) + return ret; + + /* first frame this is always 0 */ + ret = avd_buf_alloc(avd, &av1_ctx->scratch.tile_col[3], sb_cols); + if (ret) + return ret; + + /* i think this is the metadata buffer to the one below */ + ret = avd_buf_alloc(avd, &av1_ctx->scratch.tile_col[1], + (max_sb_col * bit_depth * 22)); + if (ret) + return ret; + + ret = avd_buf_alloc(avd, &av1_ctx->scratch.tile_col[2], + ALIGN(ALIGN(w, 8) * bit_depth * 2 + + tile_info->tile_cols * bit_depth * 16, + 128)); + if (ret) + return ret; + + /* this is not a mistake, but im not sure why */ + if (tile_info->tile_cols > 1) { + for (i = 0; i < tile_info->tile_rows; i++) { + sb = tile_info->height_in_sbs_minus_1[i] + 1; + max_sb_row = sb > max_sb_row ? sb : max_sb_row; + } + + max_sb_row = max_sb_row << sb_shift; + + /* + * metadata buffer maybe? At least for row[0], they all seem to have + * some kinda alignment to 24 so could be for them all + */ + ret = avd_buf_alloc(avd, &av1_ctx->scratch.tile_row[1], + (max_sb_row * 72)); + if (ret) + return ret; + + /* + * they all share the pattern of max_sb_row * something where + * something is a block of luma and chroma aligned to + * something. Depending on the height, the last + * (or second last??) block has a different size from the + * rest. + * + * I counted blocks as luma or chroma with padding until it + * changes to the other + */ + ret = avd_buf_alloc(avd, &av1_ctx->scratch.tile_row[0], + (max_sb_row * 72 + 1) * 2 * bit_depth); + if (ret) + return ret; + + ret = avd_buf_alloc(avd, &av1_ctx->scratch.tile_row[2], + max_sb_row * bit_depth * (53 + 52)); + if (ret) + return ret; + + ret = avd_buf_alloc( + avd, &av1_ctx->scratch.tile_row[3], + max_sb_row * bit_depth * + (192 + 96 + (bit_depth > 8 ? 12 : 0))); + if (ret) + return ret; + } return 0; } @@ -1146,6 +1255,7 @@ static int avd_av1_run(struct avd_ctx *ctx) dev_err(avd->dev, "no free slots: %d", ret); return ret; } + dst = vb2_to_avd_decoded_buf(&run.base.bufs.dst->vb2_buf); update_dec_buf_info(dst, run.seq, run.frame); @@ -1155,6 +1265,7 @@ static int avd_av1_run(struct avd_ctx *ctx) ctx->fifo_idx, ctx->vp_slot); avd_av1_set_prob(ctx, &run); + avd_av1_alloc_scratch(ctx, &run); set_header(ctx, &run); set_tiles(ctx, &run); @@ -1164,11 +1275,26 @@ static int avd_av1_run(struct avd_ctx *ctx) return 0; } +static void avd_av1_dealloc_scratch(struct avd_ctx *ctx) +{ + struct avd_dev *avd = ctx->dev; + struct avd_av1_ctx *av1_ctx = ctx->priv; + int i; + + for (i = 0; i < 4; i++) + avd_buf_free(avd, &av1_ctx->scratch.tile_col[i]); + + for (i = 0; i < 4; i++) + avd_buf_free(avd, &av1_ctx->scratch.tile_row[i]); + + avd_buf_free(avd, &av1_ctx->scratch.ref); +} + static int avd_av1_alloc_bufs(struct avd_ctx *ctx) { struct avd_dev *avd = ctx->dev; struct avd_av1_ctx *av1_ctx = ctx->priv; - int ret, i; + int ret; ret = avd_buf_alloc(avd, &av1_ctx->bufs.inst, fifo_size()); if (ret) @@ -1179,21 +1305,18 @@ static int avd_av1_alloc_bufs(struct avd_ctx *ctx) if (ret) return ret; - ret = avd_buf_alloc(avd, &av1_ctx->bufs.ref, 0x10000); + ret = avd_buf_alloc(avd, &av1_ctx->bufs.probs, + sizeof(struct avd_av1_cdfs)); if (ret) return ret; - ret = avd_buf_alloc(avd, &av1_ctx->bufs.probs, - sizeof(struct avd_av1_cdfs)); + ret = avd_buf_alloc(avd, &av1_ctx->bufs.unk[0], 1024); if (ret) return ret; - for (i = 0; i < 12; i++) { - ret = avd_buf_alloc(avd, &av1_ctx->bufs.const_unk[i], - 0x10000 * 4); - if (ret) - return ret; - } + ret = avd_buf_alloc(avd, &av1_ctx->bufs.unk[1], 1024); + if (ret) + return ret; return 0; } @@ -1225,13 +1348,14 @@ static void avd_av1_stop(struct avd_ctx *ctx) struct avd_av1_ctx *av1_ctx = ctx->priv; struct avd_dev *avd = ctx->dev; + avd_av1_dealloc_scratch(ctx); + avd_buf_free(avd, &av1_ctx->bufs.pipe_state); avd_buf_free(avd, &av1_ctx->bufs.inst); - avd_buf_free(avd, &av1_ctx->bufs.ref); avd_buf_free(avd, &av1_ctx->bufs.probs); - for (int i = 0; i < 12; i++) - avd_buf_free(avd, &av1_ctx->bufs.const_unk[i]); + for (int i = 0; i < 2; i++) + avd_buf_free(avd, &av1_ctx->bufs.unk[i]); kfree(av1_ctx); } @@ -1298,8 +1422,27 @@ static void avd_av1_submit(struct avd_ctx *ctx) static void avd_av1_adjust_decoded_fmt(struct avd_ctx *ctx, struct v4l2_pix_format_mplane *pix_mp) { - pix_mp->plane_fmt[0].sizeimage += sizeof(struct avd_av1_cdfs); - pix_mp->plane_fmt[0].sizeimage += AVD_AV1_REF_BUF_SIZE; + pix_mp->plane_fmt[0].sizeimage += ALIGN(AVD_CDFS_SIZE, AVD_ALIGN); + pix_mp->plane_fmt[0].sizeimage += ALIGN( + avd_priv_tlb_size(pix_mp->width, pix_mp->height), AVD_ALIGN); +} + +static int avd_av1_validate_sequence(struct avd_ctx *ctx, + struct v4l2_ctrl_av1_sequence *seq) +{ + if (seq->flags & V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME) + return -EINVAL; /* 4:0:0 (not supported?) */ + + return 0; +} + +static int avd_av1_try_ctrl(struct avd_ctx *ctx, struct v4l2_ctrl *ctrl) +{ + if (ctrl->id == V4L2_CID_STATELESS_AV1_SEQUENCE) + return avd_av1_validate_sequence(ctx, + ctrl->p_new.p_av1_sequence); + /* width should also be > 8 */ + return 0; } const struct avd_coded_fmt_ops avd_av1_fmt_ops = { @@ -1308,5 +1451,6 @@ const struct avd_coded_fmt_ops avd_av1_fmt_ops = { .stop = avd_av1_stop, .run = avd_av1_run, .submit = avd_av1_submit, + .try_ctrl = avd_av1_try_ctrl, .get_image_fmt = avd_av1_get_image_fmt, }; diff --git a/drivers/media/platform/apple/avd/avd-drv.c b/drivers/media/platform/apple/avd/avd-drv.c index fafa1a742faf7f..487d478b00f397 100644 --- a/drivers/media/platform/apple/avd/avd-drv.c +++ b/drivers/media/platform/apple/avd/avd-drv.c @@ -21,41 +21,50 @@ #include "avd.h" #include "avd-regs.h" -void fill_rvra(struct avd_rvra *rvra, enum avd_image_fmt image_fmt, - u32 width, u32 height) +static void calc_tile_meta(u32 w, u32 h, u32 bpb, u32 tile_dim, + u32 meta_hdr_bytes, u32 *tile, u32 *meta) { - u32 size0, size1, size2; - u32 hs = round_up(height, 32); + u32 tiles_width, tiles_height, meta_tile_w, meta_tile_h, tile_bytes; + tiles_width = DIV_ROUND_UP(w, tile_dim); + tiles_height = DIV_ROUND_UP(h, tile_dim); + tile_bytes = tile_dim * tile_dim * DIV_ROUND_UP(bpb, 8); + *tile = ALIGN(tiles_width * tiles_height * tile_bytes, 16); - size0 = (width * hs) + ((width * hs) / 4); - size2 = size0; + meta_tile_w = roundup_pow_of_two(tiles_width); + meta_tile_h = roundup_pow_of_two(tiles_height); + + *meta = ALIGN(meta_tile_w * meta_tile_h * meta_hdr_bytes, 16); +} + +void fill_comp(struct avd_comp *comp, enum avd_image_fmt image_fmt, u32 width, + u32 height) +{ + u32 y_meta, y, uv_meta, uv; + int bit_depth; switch (image_fmt) { - case AVD_IMG_FMT_420_8BIT: case AVD_IMG_FMT_420_10BIT: - size2 /= 2; + case AVD_IMG_FMT_422_10BIT: + bit_depth = 10; break; default: + bit_depth = 8; break; } - size1 = max((roundup_pow_of_two(width) * roundup_pow_of_two(height)) / 32, - 0x100u); - /* TODO: how big? */ - - rvra->size = round_up(size0 + size1 + size2, 0x4000); - rvra->size += - (width < 1000 ? 0 : width < 1800 ? 2 : width < 3800 ? 3 : 9) * 0x4000; - /* TODO */ - rvra->size += - (height < 1000 ? 0 : height < 1800 ? 2 : height < 3800 ? 3 : 9) * 0x4000; - /* TODO */ - rvra->size += 0x10000; - - rvra->offsets[1] = 0; - rvra->offsets[0] = size0; - rvra->offsets[3] = size0 + size1; - rvra->offsets[2] = size0 + size1 + size2; + /* y has 32x32 tiles and 32 bytes of metadata per tile */ + calc_tile_meta(width, height, bit_depth, 32, 32, &y, &y_meta); + /* uv has 16x16 tiles and 8 bytes of metadata per tile */ + calc_tile_meta(width / 2, height / 2, bit_depth * 2, 16, 8, &uv, + &uv_meta); + + /* output like DCP driver expects */ + comp->offsets[0] = y; + comp->offsets[1] = 0; + comp->offsets[2] = y + y_meta + uv; + comp->offsets[3] = y + y_meta; + + comp->size = y_meta + y + uv_meta + uv; } @@ -76,19 +85,24 @@ int alloc_slots(struct avd_dev *avd, struct avd_ctx *ctx, enum avd_codec codec) ctx->vp_slot = free; ctx->fifo_idx = find_first_zero_bit(&avd->inst_fifo_slots, - avd->variant->fifo_slots); + avd->variant->fifo_slots); if (WARN_ON(ctx->fifo_idx >= avd->variant->fifo_slots)) { clear_bit(free, &avd->vp_slots); return -ENOMEM; } - set_bit(ctx->fifo_idx, &avd->inst_fifo_slots); + set_bit(ctx->fifo_idx, &avd->inst_fifo_slots); return 0; } int avd_buf_alloc(struct avd_dev *avd, struct avd_buf *buf, size_t size) { + if (!buf->cpu && size < buf->size) + return 0; + else if (buf->cpu) + avd_buf_free(avd, buf); + buf->size = size; buf->cpu = dma_alloc_coherent(avd->dev, buf->size, &buf->addr, GFP_KERNEL); @@ -709,7 +723,7 @@ static void avd_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(avd->dev); } -static int avd_runtime_resume(struct device *dev) +static __maybe_unused int avd_runtime_resume(struct device *dev) { int ret; struct avd_dev *avd = platform_get_drvdata(to_platform_device(dev)); @@ -720,7 +734,7 @@ static int avd_runtime_resume(struct device *dev) return ret; } -static int avd_runtime_suspend(struct device *dev) +static __maybe_unused int avd_runtime_suspend(struct device *dev) { struct avd_dev *avd = platform_get_drvdata(to_platform_device(dev)); @@ -746,3 +760,9 @@ module_platform_driver(avd_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Apple avd v4l2 sl m2m"); +MODULE_FIRMWARE("apple/avd-fw-v2-t0.bin"); +MODULE_FIRMWARE("apple/avd-fw-v3-t0.bin"); +MODULE_FIRMWARE("apple/avd-fw-v3-t1.bin"); +MODULE_FIRMWARE("apple/avd-fw-v4-t0.bin"); +MODULE_FIRMWARE("apple/avd-fw-v5-t0.bin"); +MODULE_FIRMWARE("apple/avd-fw-v5-t1.bin"); diff --git a/drivers/media/platform/apple/avd/avd-h264.c b/drivers/media/platform/apple/avd/avd-h264.c index 7309151aab1d91..6f83243096d15c 100644 --- a/drivers/media/platform/apple/avd/avd-h264.c +++ b/drivers/media/platform/apple/avd/avd-h264.c @@ -43,10 +43,6 @@ struct avd_h264_run { const struct v4l2_ctrl_h264_pred_weights *pred_weights; struct run_addr { - dma_addr_t y; - dma_addr_t uv; - dma_addr_t sl; - dma_addr_t rvra; dma_addr_t sps; } addresses; @@ -87,8 +83,8 @@ static const u32 default_8x8_inter[] = { static inline u32 sps_size(u32 w, u32 h) { - /* TODO: does it really need so much? */ - return (((w - 1) * (h - 1) / 0x10000) + 2) * 0x4000; + /* TODO: * 2 is a hack */ + return 2 * DIV_ROUND_UP(w, 16) * DIV_ROUND_UP(h, 16) * 32; } /* sorry for the formatting */ @@ -99,30 +95,28 @@ static void stream_refs(struct avd_ctx *ctx, struct avd_h264_run *run) const struct v4l2_h264_dpb_entry *dpb = decode->dpb; struct avd_h264_ctx *h264_ctx = ctx->priv; struct avd_dev *avd = ctx->dev; + struct avd_decoded_buffer *dst, *ref; + dma_addr_t addr; - push(INST_DMA2, "cm3_dma_config_6"); + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf); + + push(0, ""); pusha(h264_ctx->bufs.pps_tile[4].addr, "hdr_9c_pps_tile_addr_lsb8", 7); pusha(run->addresses.sps, "hdr_bc_sps_tile_addr_lsb8", 0); - push(INST_DMA3, "cm3_dma_config_7"); - push(INST_DMA3, "cm3_dma_config_8"); - push(INST_DMA3, "cm3_dma_config_9"); - push(INST_DMA3, "cm3_dma_config_a"); + push(0, ""); + push(0, ""); + push(0, ""); + push(0, ""); for (int i = 0; i < ARRAY_SIZE(decode->dpb); i++) { if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) continue; - struct vb2_buffer *vb = vb2_find_buffer( - &ctx->fh.m2m_ctx->cap_q_ctx.q, dpb[i].reference_ts); + ref = avd_get_ref_buf(ctx, &dst->base.vb, dpb[i].reference_ts); - dma_addr_t rvra_addr = - vb ? vb2_dma_contig_plane_dma_addr(vb, 0) + - (vb->planes[0].length - - sps_size(fmt_width(ctx), - fmt_height(ctx)) - - ctx->rvra.size) : - run->addresses.rvra; /* safe fallback */ + addr = vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf, 0) + + ref->comp.start_offset; push(AVD_REF_NUM(run->num_valid - 1) | AVD_REF_FLAG_CONST | AVD_REF_FLAG_LONG( @@ -132,7 +126,7 @@ static void stream_refs(struct avd_ctx *ctx, struct avd_h264_run *run) dpb[i].top_field_order_cnt), "hdr_d0_ref_hdr"); - push_rvra(avd, ctx, rvra_addr, ctx->rvra.offsets); + push_comp(avd, ctx, addr, ctx->comp.offsets); } } @@ -208,7 +202,7 @@ static void stream_hdr(struct avd_ctx *ctx, struct avd_h264_run *run) AVD_OP_EXEC_FLAG_START_REV4(avd->variant->revision == 4), "inst_fifo_start"); - push(AVD_OP_HDR | AVD_OP_HDR_FLAG0 | + push(AVD_OP_HDR | AVD_OP_HDR_FLAG_DECOMP(ctx->decomp) | AVD_OP_HDR_FLAG_INTRA( decode->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) | @@ -261,16 +255,16 @@ static void stream_hdr(struct avd_ctx *ctx, struct avd_h264_run *run) !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)), "hdr_58_const_3a"); - push(INST_DMA2, "cm3_dma_config_1"); - push(INST_DMA1, "cm3_dma_config_2"); + push(0, ""); + push(0, ""); if (avd->variant->revision == 3) push(0, "zero"); pusha(h264_ctx->bufs.pps_tile[0].addr, "hdr_9c_pps_tile_addr_lsb8", 0); - push(INST_DMA2, "cm3_dma_config_3"); - push(INST_DMA2, "cm3_dma_config_4"); + push(0, ""); + push(0, ""); if (avd->variant->revision == 3) push(0, "zero"); @@ -280,17 +274,17 @@ static void stream_hdr(struct avd_ctx *ctx, struct avd_h264_run *run) pusha(h264_ctx->bufs.pps_tile[1].addr, "hdr_9c_pps_tile_addr_lsb8", 1); pusha(h264_ctx->bufs.pps_tile[2].addr, "hdr_9c_pps_tile_addr_lsb8", 2); pusha(h264_ctx->bufs.pps_tile[3].addr, "hdr_9c_pps_tile_addr_lsb8", 3); - push(INST_DMA3, "cm3_dma_config_5"); + push(0, ""); - push_rvra(avd, ctx, run->addresses.rvra, ctx->rvra.offsets); + push_comp(avd, ctx, run->base.comp_out, ctx->comp.offsets); bytesperline = ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline; if (avd->variant->quirks & AVD_QUIRK_LSR) bytesperline = bytesperline >> 4; - pusha(run->addresses.y, "hdr_210_y_addr_lsb8", 0); + pusha(run->base.y_out, "hdr_210_y_addr_lsb8", 0); push(bytesperline, "hdr_218_width_align"); - pusha(run->addresses.uv, "hdr_214_uv_addr_lsb8", 0); + pusha(run->base.uv_out, "hdr_214_uv_addr_lsb8", 0); push(bytesperline, "hdr_21c_width_align"); push(0, "cm3_mark_end_section"); @@ -317,22 +311,19 @@ static void stream_weights(struct avd_ctx *ctx, struct avd_h264_run *run) const struct v4l2_ctrl_h264_slice_params *sl = run->slice_params; struct avd_dev *avd = ctx->dev; - bool pred_weight = V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, sl); + bool pred_weight_req = V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, sl); + bool default_weights = pps->weighted_bipred_idc == 2 && + !pred_weight_req; - /* TODO: is there a better flag or something for the - * pps->weighted_bipred_idc == 2 checks? */ - push(AVD_OP_WEIGHTS_HDR | - AVD_OP_WEIGHTS_HDR_FLAG1(pps->weighted_bipred_idc == 2) | - AVD_OP_WEIGHTS_HDR_FLAG0(pred_weight) | + push(AVD_OP_WEIGHTS_HDR | AVD_OP_WEIGHTS_HDR_FLAG1(default_weights) | + AVD_OP_WEIGHTS_HDR_FLAG0(pred_weight_req) | AVD_OP_WEIGHTS_HDR_LUMA(weights->luma_log2_weight_denom) | AVD_OP_WEIGHTS_HDR_CHROMA( - weights->chroma_log2_weight_denom) - /* default luma and chroma denom */ - | - (pps->weighted_bipred_idc == 2 ? DEFAULT_WEIGHT_DENOM : 0), + weights->chroma_log2_weight_denom) | + (default_weights ? DEFAULT_WEIGHT_DENOM : 0), "slc_76c_cmd_weights_denom"); - if (!pred_weight) + if (!pred_weight_req) return; luma_denom = 1 << weights->luma_log2_weight_denom; @@ -418,7 +409,7 @@ static u32 stream_slice(struct avd_ctx *ctx, struct avd_h264_run *run) off++; } - dma_addr_t slc_a84 = run->addresses.sl + off; + dma_addr_t slc_a84 = run->base.coded_in + off; push(AVD_OP_CODED_DATA | AVD_OP_CODED_DATA_BIT_OFF( @@ -526,7 +517,12 @@ static int avd_h264_alloc_bufs(struct avd_ctx *ctx) { struct avd_dev *dev = ctx->dev; struct avd_h264_ctx *h264_ctx = ctx->priv; - int ret; + int ret, w, bit_depth, mb; + w = fmt_width(ctx); + bit_depth = (ctx->image_fmt == AVD_IMG_FMT_420_10BIT || + ctx->image_fmt == AVD_IMG_FMT_422_10BIT) ? + 10 : + 8; ret = avd_buf_alloc(dev, &h264_ctx->bufs.inst, fifo_size()); if (ret) { @@ -542,26 +538,29 @@ static int avd_h264_alloc_bufs(struct avd_ctx *ctx) } } - /* TODO: VERY ugly - * Does it actually need this much? - * */ - for (int i = 0; i < 5; i++) { - u32 mul = fmt_width(ctx) / 16; - u32 size = i == 0 ? 0x20000 : - i == 1 ? (16 + 8 + 8) * mul : - i == 2 ? ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0] - .bytesperline > - 2048 ? - 0xc000 : - (64 + 1 * 32 + 1 * 32) * mul : - 32 * mul; - ret = avd_buf_alloc(dev, &h264_ctx->bufs.pps_tile[i], - max(size, 0x8000)); - if (ret) { - dev_err(dev->dev, "pps[%d] alloc failed\n", i); - return ret; - } - } + mb = DIV_ROUND_UP(w, 16); + + ret = avd_buf_alloc(dev, &h264_ctx->bufs.pps_tile[0], mb * 20); + if (ret) + return ret; + + ret = avd_buf_alloc(dev, &h264_ctx->bufs.pps_tile[1], + bit_depth * 4 * mb); + if (ret) + return ret; + + ret = avd_buf_alloc(dev, &h264_ctx->bufs.pps_tile[2], + bit_depth * 4 * 4 * mb); + if (ret) + return ret; + + ret = avd_buf_alloc(dev, &h264_ctx->bufs.pps_tile[3], 32 * mb); + if (ret) + return ret; + + ret = avd_buf_alloc(dev, &h264_ctx->bufs.pps_tile[4], 32 * mb); + if (ret) + return ret; return 0; } @@ -574,8 +573,7 @@ static void avd_h264_free_bufs(struct avd_ctx *ctx) if (!h264_ctx) return; - if (!(dev->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)) - avd_buf_free(dev, &h264_ctx->bufs.pipe_state); + avd_buf_free(dev, &h264_ctx->bufs.pipe_state); avd_buf_free(dev, &h264_ctx->bufs.inst); for (int i = 0; i < 5; i++) @@ -678,22 +676,9 @@ static void avd_h264_run_preamble(struct avd_ctx *ctx, struct avd_h264_run *run) dst_len = run->base.bufs.dst->vb2_buf.planes[0].length; - run->addresses.y = - vb2_dma_contig_plane_dma_addr(&run->base.bufs.dst->vb2_buf, 0); - - run->addresses.uv = - run->addresses.y + - ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline * - ALIGN(ctx->decoded_fmt.fmt.pix_mp.height, 16); - - run->addresses.sl = - vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0); sps_len = sps_size(fmt_width(ctx), fmt_height(ctx)); - run->addresses.rvra = - run->addresses.y + (dst_len - sps_len - ctx->rvra.size); - - run->addresses.sps = run->addresses.y + (dst_len - sps_len); + run->addresses.sps = run->base.y_out + (dst_len - sps_len); } static int avd_h264_run(struct avd_ctx *ctx) diff --git a/drivers/media/platform/apple/avd/avd-hevc.c b/drivers/media/platform/apple/avd/avd-hevc.c index 73aad4513cbd80..4f47c5124bef7c 100644 --- a/drivers/media/platform/apple/avd/avd-hevc.c +++ b/drivers/media/platform/apple/avd/avd-hevc.c @@ -24,7 +24,7 @@ #include "avd.h" #include "avd-inst.h" -#define PPS_NUM 8 +#define PPS_NUM 9 #define NEW_TILE_ID BIT(0) #define NEW_SLICE BIT(1) @@ -54,10 +54,19 @@ static inline u32 sps_size(u32 w, u32 h) { - /* TODO: does it really need so much? */ - return (((w - 1) * (h - 1) / 0x10000) + 2) * 0x4000; + /* this will waste some memory when max cu size != 64 */ + return DIV_ROUND_UP(w, 64) * DIV_ROUND_UP(h, 64) * 256; } +struct avd_hevc_tile_info { + u16 col_width[22]; + u16 row_height[22]; + u32 col_bd[23]; + u32 row_bd[23]; + u32 *ctb_addr_rs_to_ts; + u32 *tile_ids; +}; + struct avd_hevc_run { struct avd_run base; const struct v4l2_ctrl_hevc_slice_params *sl; @@ -71,19 +80,17 @@ struct avd_hevc_run { int num_slices; struct run_addr { - dma_addr_t y; - dma_addr_t uv; - dma_addr_t sl; - dma_addr_t rvra; dma_addr_t sps; } addresses; + + struct avd_hevc_tile_info tile_info; }; struct avd_hevc_ctx { struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache; struct avd_h264_bufs { - struct avd_buf pps_tile[8]; + struct avd_buf pps_tile[9]; struct avd_buf inst; struct avd_buf pipe_state; } bufs; @@ -102,27 +109,24 @@ static void stream_refs(struct avd_ctx *ctx, struct avd_hevc_run *run) dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf); - push(INST_DMA2, "cm3_dma_config_6"); + push(0, ""); pusha(hevc_ctx->bufs.pps_tile[1].addr, "hdr_9c_pps_tile_addr_lsb8", 7); pusha(run->addresses.sps, "hdr_bc_sps_tile_addr_lsb8", sl->slice_pic_order_cnt); - push(INST_DMA3, "cm3_dma_config_7"); - push(INST_DMA3, "cm3_dma_config_8"); - push(INST_DMA3, "cm3_dma_config_9"); - push(INST_DMA3, "cm3_dma_config_a"); + push(0, ""); + push(0, ""); + push(0, ""); + push(0, ""); for (int i = 0; i < decode->num_active_dpb_entries; i++) { dpb = &decode->dpb[i]; ref_buf = avd_get_ref_buf(ctx, &dst->base.vb, dpb->timestamp); - dma_addr_t rvra_addr = - vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, - 0) + - (ref_buf->base.vb.planes[0].length - - sps_size(fmt_width(ctx), fmt_height(ctx)) - - ref_buf->rvra.size); + dma_addr_t comp_addr = vb2_dma_contig_plane_dma_addr( + &ref_buf->base.vb.vb2_buf, 0) + + ref_buf->comp.start_offset; push(AVD_REF_NUM(decode->num_active_dpb_entries - 1) | AVD_REF_FLAG_CONST | @@ -133,7 +137,7 @@ static void stream_refs(struct avd_ctx *ctx, struct avd_hevc_run *run) dpb->pic_order_cnt_val), "hdr_d0_ref_hdr"); - push_rvra(avd, ctx, rvra_addr, ref_buf->rvra.offsets); + push_comp(avd, ctx, comp_addr, ref_buf->comp.offsets); } } @@ -304,8 +308,8 @@ static void set_header(struct avd_ctx *ctx, struct avd_hevc_run *run) AVD_OP_EXEC_FLAG_START_REV4(avd->variant->revision == 4), "inst_fifo_start"); - push(AVD_OP_HDR | AVD_OP_HDR_FLAG0 | AVD_OP_HDR_FLAG_INTRA(is_intra) | - AVD_OP_HDR_CONST | + push(AVD_OP_HDR | AVD_OP_HDR_FLAG_DECOMP(ctx->decomp) | + AVD_OP_HDR_FLAG_INTRA(is_intra) | AVD_OP_HDR_CONST | AVD_OP_HDR_FLAG_PIPE_STATE( !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)), "hdr_34_start_hdr"); @@ -347,14 +351,14 @@ static void set_header(struct avd_ctx *ctx, struct avd_hevc_run *run) !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)), "hdr_98_const_30"); - push(INST_DMA2, "cm3_dma_config_1"); - push(INST_DMA1, "cm3_dma_config_2"); + push(0, ""); + push(0, ""); if (avd->variant->revision == 3) push(0, "zero"); - push(INST_DMA1, "cm3_dma_config_2"); - push(INST_DMA2, "cm3_dma_config_3"); + push(0, ""); + push(0, ""); if (avd->variant->revision == 3) push(0, "zero"); @@ -377,14 +381,14 @@ static void set_header(struct avd_ctx *ctx, struct avd_hevc_run *run) } else { pusha(0, "", 3); pusha(0, "", 4); - pusha(hevc_ctx->bufs.pps_tile[4].addr, + pusha(hevc_ctx->bufs.pps_tile[8].addr, "hdr_dc_pps_tile_addr_lsb8", 8); pusha(0, "", 9); } - push(INST_DMA3, "cm3_dma_config_5"); + push(0, ""); - push_rvra(avd, ctx, run->addresses.rvra, ctx->rvra.offsets); + push_comp(avd, ctx, run->base.comp_out, ctx->comp.offsets); push(0, "cm3_mark_end_section"); @@ -395,9 +399,9 @@ static void set_header(struct avd_ctx *ctx, struct avd_hevc_run *run) if (avd->variant->quirks & AVD_QUIRK_LSR) bytesperline = bytesperline >> 4; - pusha(run->addresses.y, "hdr_1b4_y_addr_lsb8", 0); + pusha(run->base.y_out, "hdr_1b4_y_addr_lsb8", 0); push(bytesperline, "hdr_1bc_width_align"); - pusha(run->addresses.uv, "hdr_1b8_uv_addr_lsb8", 0); + pusha(run->base.uv_out, "hdr_1b8_uv_addr_lsb8", 0); push(bytesperline, "hdr_1c0_width_align"); push(0, ""); push(AVD_HDR_HEIGHT(height - 1) | AVD_HDR_WIDTH(width - 1), @@ -660,7 +664,8 @@ static void set_slice(struct avd_ctx *ctx, struct avd_hevc_run *run, u32 offset, u32 flags) { struct avd_dev *avd = ctx->dev; - dma_addr_t slc_addr = run->addresses.sl + offset + sl->data_byte_offset; + dma_addr_t slc_addr = + run->base.coded_in + offset + sl->data_byte_offset; push(AVD_OP_CODED_DATA | flags | AVD_OP_CODED_DATA_ADDR(slc_addr >> 32), "cm3_cmd_set_coded_slice"); push((u32)(slc_addr & 0xffffffff), "slc_bd8_slice_addr"); @@ -879,6 +884,7 @@ static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run) const struct v4l2_ctrl_hevc_pps *pps = run->pps; struct avd_hevc_ctx *hevc_ctx = ctx->priv; const struct v4l2_ctrl_hevc_slice_params *sl; + struct avd_hevc_tile_info *tile_info = &run->tile_info; bool tiles_enabled, is_last, first_slice, first_segment; bool hflip, vflip; int slice_segment_offset, entry_point_idx = 0, pos = 0, offset = 0; @@ -886,12 +892,8 @@ static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run) int slice_flag, size, new_offset; int tile_id, last_tile_id; u16 log2_min_cb_size, width, height; - s32 max_cu_width, pic_in_ctbs_width, pic_in_ctbs_height, - pic_in_ctbs_size; + s32 max_cu_width, pic_in_ctbs_width, pic_in_ctbs_height; u32 num_cols, last_tile_block = 0; - u16 col_width[22] = {}, row_height[22] = {}; - u32 col_bd[23] = {}, row_bd[23] = {}; - u32 *ctb_addr_rs_to_ts = NULL, *tile_ids = NULL; struct sl_ctx last = { .q1_col = -1, .q1_row = -1, @@ -900,6 +902,8 @@ static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run) width = sps->pic_width_in_luma_samples; height = sps->pic_height_in_luma_samples; + tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED); + log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3; num_cols = pps->num_tile_columns_minus1 + 1; @@ -908,50 +912,6 @@ static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run) log2_min_cb_size); pic_in_ctbs_width = (width + max_cu_width - 1) / max_cu_width; pic_in_ctbs_height = (height + max_cu_width - 1) / max_cu_width; - pic_in_ctbs_size = pic_in_ctbs_height * pic_in_ctbs_width; - - tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED); - - ctb_addr_rs_to_ts = kzalloc( - sizeof(*ctb_addr_rs_to_ts) * pic_in_ctbs_size, GFP_KERNEL); - if (!ctb_addr_rs_to_ts) { - pr_err("alloc: ctb_addr_rs_to_ts\n"); - goto done; - } - - tile_ids = kzalloc(sizeof(*tile_ids) * pic_in_ctbs_size, GFP_KERNEL); - if (!tile_ids) { - pr_err("alloc: tile_ids\n"); - goto done; - } - - if (tiles_enabled) { - if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) { - compute_tiles_uniform(run, log2_min_cb_size, width, - height, pic_in_ctbs_width, - pic_in_ctbs_height, col_width, - row_height); - } else { - compute_tiles_non_uniform(run, log2_min_cb_size, width, - height, pic_in_ctbs_width, - pic_in_ctbs_height, col_width, - row_height); - } - compute_bd(run, col_bd, row_bd, col_width, row_height); - - /* - * 6.5.1 CTB raster and tile scanning conversion process - * (6-7) and (6-9) - * - * we really only need to know if tileidx != last tileidx - * so doing all this is stupid - */ - compute_rs_to_ts(run, pic_in_ctbs_size, pic_in_ctbs_width, - col_bd, row_bd, col_width, row_height, - ctb_addr_rs_to_ts); - compute_tile_ids(run, pic_in_ctbs_width, col_bd, row_bd, - ctb_addr_rs_to_ts, tile_ids); - } for (s = 0; s < run->num_slices; s++) { sl = &run->sl[s]; @@ -964,7 +924,7 @@ static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run) "to few entry points! has: %d, needs > %d", run->num_entry_point_offsets, sl->num_entry_point_offsets + entry_point_idx); - goto done; + return; } for (i = 0; i < to; i++) { is_last = i == to - 1 && s == run->num_slices - 1; @@ -989,12 +949,14 @@ static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run) new_offset = size + sl->data_byte_offset; } - tile_id = tile_ids - [ctb_addr_rs_to_ts[sl->slice_segment_addr]]; + tile_id = tile_info->tile_ids + [tile_info->ctb_addr_rs_to_ts + [sl->slice_segment_addr]]; last_tile_id = first_slice ? -1 : - tile_ids[ctb_addr_rs_to_ts + tile_info->tile_ids + [tile_info->ctb_addr_rs_to_ts [run->sl[s - 1] .slice_segment_addr]]; @@ -1048,10 +1010,10 @@ static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run) << 13); last_tile_block = submit_slice_segment( - ctx, run, sl, row, col, col_bd, row_bd, - pic_in_ctbs_width, pic_in_ctbs_height, is_last, - first_slice, hflip, vflip, slice_flag, - last_tile_block); + ctx, run, sl, row, col, tile_info->col_bd, + tile_info->row_bd, pic_in_ctbs_width, + pic_in_ctbs_height, is_last, first_slice, hflip, + vflip, slice_flag, last_tile_block); if (slice_flag & NEW_TILE_ID) pos++; @@ -1059,17 +1021,12 @@ static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run) slice_segment_offset += new_offset; if (avd_wait_submission_queue(ctx)) - goto done; + return; } offset += sl->bit_size / 8; } hevc_ctx->submit_num = pos; - -done: - kfree(ctb_addr_rs_to_ts); - - kfree(tile_ids); } static void update_dec_buf_info(struct avd_decoded_buffer *buf, @@ -1125,26 +1082,18 @@ static int avd_hevc_validate_sps(struct avd_ctx *ctx, static int avd_hevc_alloc_bufs(struct avd_ctx *ctx) { - struct avd_dev *dev = ctx->dev; + struct avd_dev *avd = ctx->dev; struct avd_hevc_ctx *hevc_ctx = ctx->priv; int ret; - ret = avd_buf_alloc(dev, &hevc_ctx->bufs.inst, fifo_size()); + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.inst, fifo_size()); if (ret) return ret; - ret = avd_buf_alloc(dev, &hevc_ctx->bufs.pipe_state, 0x200); + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pipe_state, 0x200); if (ret) return ret; - for (int i = 0; i < PPS_NUM; i++) { - /* TODO: this is very waistfull */ - ret = avd_buf_alloc(dev, &hevc_ctx->bufs.pps_tile[i], - fmt_width(ctx) * fmt_height(ctx) / 8); - if (ret) - return ret; - } - return 0; } @@ -1170,6 +1119,181 @@ static int avd_hevc_start(struct avd_ctx *ctx) return ret; } +static int avd_hevc_alloc_scratch(struct avd_ctx *ctx, struct avd_hevc_run *run) +{ + struct avd_hevc_ctx *hevc_ctx = ctx->priv; + struct avd_dev *avd = ctx->dev; + const struct v4l2_ctrl_hevc_sps *sps = run->sps; + const struct v4l2_ctrl_hevc_pps *pps = run->pps; + struct avd_hevc_tile_info *tile_info = &run->tile_info; + int i, ret, w, bit_depth, max_col = 0, max_row = 0, cols, rows; + int log2_min_cb_size, max_cu_width; + cols = pps->num_tile_columns_minus1 + 1; + rows = pps->num_tile_rows_minus1 + 1; + + if (sps->bit_depth_chroma_minus8 > sps->bit_depth_luma_minus8) + bit_depth = sps->bit_depth_chroma_minus8; + else + bit_depth = sps->bit_depth_luma_minus8; + + bit_depth += 8; + + w = sps->pic_width_in_luma_samples; + + log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3; + max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + + log2_min_cb_size); + + for (i = 0; i < cols; i++) + max_col = tile_info->col_width[i] > max_col ? + tile_info->col_width[i] : + max_col; + + for (i = 0; i < rows; i++) + max_row = tile_info->row_height[i] > max_row ? + tile_info->row_height[i] : + max_row; + + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[0], + ((max_col * max_cu_width) / 4) * bit_depth); + if (ret) + return ret; + + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[1], + ((max_col * max_cu_width) / 16) * 20); + if (ret) + return ret; + + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[2], + DIV_ROUND_UP(w, 16) * bit_depth * (10 + 6) + + (cols - 1) * 256); + if (ret) + return ret; + + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[3], + DIV_ROUND_UP(w + 7, 16) * 36 + cols * 128); + if (ret) + return ret; + + if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) { + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[4], + ((max_row * max_cu_width) / 4) * 36 + + 144 /* why? */); + if (ret) + return ret; + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[5], + ((max_row * max_cu_width) / 4) * 9); + if (ret) + return ret; + + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[6], + /* not sure if its cols or rows */ + DIV_ROUND_UP(w, 64) * 144 + + (cols - 1) * 128); + if (ret) + return ret; + + /* 5 or 3 is info? */ + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[7], + ((max_row * max_cu_width) / 4) * 216); + if (ret) + return ret; + } else { + ret = avd_buf_alloc(avd, &hevc_ctx->bufs.pps_tile[8], + DIV_ROUND_UP(w + 7, 16) * 4 * bit_depth); + if (ret) + return ret; + } + + return 0; +} + +static int avd_hevc_compute_tiles(struct avd_ctx *ctx, struct avd_hevc_run *run) +{ + const struct v4l2_ctrl_hevc_sps *sps = run->sps; + const struct v4l2_ctrl_hevc_pps *pps = run->pps; + bool tiles_enabled; + struct avd_hevc_tile_info *tile_info = &run->tile_info; + u16 log2_min_cb_size, width, height; + s32 max_cu_width, pic_in_ctbs_width, pic_in_ctbs_height, + pic_in_ctbs_size; + + width = sps->pic_width_in_luma_samples; + height = sps->pic_height_in_luma_samples; + + log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3; + + max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + + log2_min_cb_size); + pic_in_ctbs_width = (width + max_cu_width - 1) / max_cu_width; + pic_in_ctbs_height = (height + max_cu_width - 1) / max_cu_width; + pic_in_ctbs_size = pic_in_ctbs_height * pic_in_ctbs_width; + + tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED); + + tile_info->ctb_addr_rs_to_ts = kzalloc( + sizeof(*tile_info->ctb_addr_rs_to_ts) * pic_in_ctbs_size, + GFP_KERNEL); + if (!tile_info->ctb_addr_rs_to_ts) + return -ENOMEM; + + tile_info->tile_ids = kzalloc( + sizeof(*tile_info->tile_ids) * pic_in_ctbs_size, GFP_KERNEL); + if (!tile_info->tile_ids) + return -ENOMEM; + + if (tiles_enabled) { + if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) { + compute_tiles_uniform(run, log2_min_cb_size, width, + height, pic_in_ctbs_width, + pic_in_ctbs_height, + tile_info->col_width, + tile_info->row_height); + } else { + compute_tiles_non_uniform(run, log2_min_cb_size, width, + height, pic_in_ctbs_width, + pic_in_ctbs_height, + tile_info->col_width, + tile_info->row_height); + } + + compute_bd(run, tile_info->col_bd, tile_info->row_bd, + tile_info->col_width, tile_info->row_height); + + /* + * 6.5.1 CTB raster and tile scanning conversion process + * (6-7) and (6-9) + * + * we really only need to know if tileidx != last tileidx + * so doing all this is stupid + */ + compute_rs_to_ts(run, pic_in_ctbs_size, pic_in_ctbs_width, + tile_info->col_bd, tile_info->row_bd, + tile_info->col_width, tile_info->row_height, + tile_info->ctb_addr_rs_to_ts); + compute_tile_ids(run, pic_in_ctbs_width, tile_info->col_bd, + tile_info->row_bd, + tile_info->ctb_addr_rs_to_ts, + tile_info->tile_ids); + } else { + tile_info->col_width[0] = + (width + max_cu_width - 1) / max_cu_width; + tile_info->row_height[0] = + (height + max_cu_width - 1) / max_cu_width; + } + + return 0; +} + +static void avd_hevc_dealloc_scratch(struct avd_ctx *ctx) +{ + struct avd_hevc_ctx *hevc_ctx = ctx->priv; + struct avd_dev *avd = ctx->dev; + + for (int i = 0; i < PPS_NUM; i++) + avd_buf_free(avd, &hevc_ctx->bufs.pps_tile[i]); +} + static void avd_hevc_stop(struct avd_ctx *ctx) { struct avd_hevc_ctx *hevc_ctx = ctx->priv; @@ -1181,8 +1305,7 @@ static void avd_hevc_stop(struct avd_ctx *ctx) avd_buf_free(avd, &hevc_ctx->bufs.pipe_state); avd_buf_free(avd, &hevc_ctx->bufs.inst); - for (int i = 0; i < PPS_NUM; i++) - avd_buf_free(avd, &hevc_ctx->bufs.pps_tile[i]); + avd_hevc_dealloc_scratch(ctx); free_vp_slot(avd, ctx); free_inst_slot(avd, ctx); @@ -1221,23 +1344,9 @@ static int avd_hevc_run_preamble(struct avd_ctx *ctx, struct avd_hevc_run *run) dst_len = run->base.bufs.dst->vb2_buf.planes[0].length; - run->addresses.y = - vb2_dma_contig_plane_dma_addr(&run->base.bufs.dst->vb2_buf, 0); - - run->addresses.uv = - run->addresses.y + - ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline * - ALIGN(ctx->decoded_fmt.fmt.pix_mp.height, 16); - - run->addresses.sl = - vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0); - sps_len = sps_size(fmt_width(ctx), fmt_height(ctx)); - run->addresses.rvra = - run->addresses.y + (dst_len - sps_len - ctx->rvra.size); - - run->addresses.sps = run->addresses.y + (dst_len - sps_len); + run->addresses.sps = run->base.y_out + (dst_len - sps_len); return 0; } @@ -1264,6 +1373,15 @@ static int avd_hevc_run(struct avd_ctx *ctx) dev_err(avd->dev, "no free slots: %d", ret); return ret; } + + ret = avd_hevc_compute_tiles(ctx, &run); + if (ret) + goto done; + + ret = avd_hevc_alloc_scratch(ctx, &run); + if (ret) + goto done; + /* pr_info("VP%d: start\n", ctx->vp_slot); */ avd->variant->configure_stream(avd, hevc_ctx->bufs.inst.addr, ctx->fifo_idx, ctx->vp_slot); @@ -1275,7 +1393,11 @@ static int avd_hevc_run(struct avd_ctx *ctx) /* avd_status(avd, ctx->vp_slot); */ avd_run_postamble(ctx, &run.base); - return 0; + ret = 0; +done: + kfree(run.tile_info.ctb_addr_rs_to_ts); + kfree(run.tile_info.tile_ids); + return ret; } static int avd_hevc_try_ctrl(struct avd_ctx *ctx, struct v4l2_ctrl *ctrl) diff --git a/drivers/media/platform/apple/avd/avd-inst.h b/drivers/media/platform/apple/avd/avd-inst.h index 8ee19f65e768e5..db741db572e77c 100644 --- a/drivers/media/platform/apple/avd/avd-inst.h +++ b/drivers/media/platform/apple/avd/avd-inst.h @@ -7,11 +7,6 @@ #include "avd.h" -/* i have no clue what this is */ -#define INST_DMA1 0 /* (0x14 << 16 | 0x14) */ -#define INST_DMA2 0 /* (0x4000000 | INST_DMA1) */ -#define INST_DMA3 0 /* (0x07 << 16 | 0x07) */ - #define AVD_OP_EXEC FIELD_PREP(GENMASK(31, 24), 0x2b) #define AVD_OP_EXEC_FIFO_MASK(v) FIELD_PREP(GENMASK(3, 0), v) #define AVD_OP_EXEC_FIFO_IDX(v) FIELD_PREP(GENMASK(7, 4), v) @@ -22,7 +17,8 @@ #define AVD_OP_HDR FIELD_PREP(GENMASK(31, 20), 0x2db) #define AVD_OP_HDR_CONST FIELD_PREP(GENMASK(10, 0), 0x2e0) -#define AVD_OP_HDR_FLAG0 FIELD_PREP(BIT(12), 1) +/* decompress pixel data */ +#define AVD_OP_HDR_FLAG_DECOMP(v) FIELD_PREP(BIT(12), !!(v)) #define AVD_OP_HDR_FLAG_INTRA(v) FIELD_PREP(BIT(13), !!(v)) #define AVD_OP_HDR_FLAG_PIPE_STATE(v) FIELD_PREP(BIT(19), !!(v)) @@ -172,7 +168,7 @@ static inline void push_address(struct avd_dev *avd, struct avd_ctx *ctx, push(avd, ctx, (u32)(addr >> 32)); } } -static inline void push_rvra(struct avd_dev *avd, struct avd_ctx *ctx, +static inline void push_comp(struct avd_dev *avd, struct avd_ctx *ctx, dma_addr_t addr, u32 offsets[4]) { if (avd->variant->quirks & AVD_QUIRK_LSR) { diff --git a/drivers/media/platform/apple/avd/avd-v4l2.c b/drivers/media/platform/apple/avd/avd-v4l2.c index 4eebc2bb51cb77..7d4b3e138cf994 100644 --- a/drivers/media/platform/apple/avd/avd-v4l2.c +++ b/drivers/media/platform/apple/avd/avd-v4l2.c @@ -15,6 +15,7 @@ #include #include +#include #include "avd.h" @@ -77,8 +78,10 @@ static void avd_fill_decoded_pixfmt(struct avd_ctx *ctx, { v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, pix_mp->width, pix_mp->height); - fill_rvra(&ctx->rvra, ctx->image_fmt, pix_mp->width, pix_mp->height); - pix_mp->plane_fmt[0].sizeimage += ctx->rvra.size; + + ctx->comp.start_offset = pix_mp->plane_fmt[0].sizeimage; + fill_comp(&ctx->comp, ctx->image_fmt, pix_mp->width, pix_mp->height); + pix_mp->plane_fmt[0].sizeimage += ctx->comp.size; if (ctx->coded_fmt_desc->ops->adjust_decoded_fmt) ctx->coded_fmt_desc->ops->adjust_decoded_fmt(ctx, pix_mp); } @@ -259,7 +262,6 @@ static const struct avd_ctrl_desc avd_h264_ctrl_descs[] = { .cfg.min = V4L2_STATELESS_H264_START_CODE_NONE, .cfg.max = V4L2_STATELESS_H264_START_CODE_NONE, .cfg.def = V4L2_STATELESS_H264_START_CODE_NONE, - /* annex b is also possibly but a bit more painfull */ }, { .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, @@ -953,8 +955,18 @@ void avd_run_preamble(struct avd_ctx *ctx, struct avd_run *run) run->bufs.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); run->bufs.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + run->coded_in = + vb2_dma_contig_plane_dma_addr(&run->bufs.src->vb2_buf, 0); + run->y_out = vb2_dma_contig_plane_dma_addr(&run->bufs.dst->vb2_buf, 0); + run->uv_out = run->y_out + + ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline * + ctx->decoded_fmt.fmt.pix_mp.height; + + run->comp_out = run->y_out + ctx->comp.start_offset; + ctx->decomp = true; + dst = vb2_to_avd_decoded_buf(&run->bufs.dst->vb2_buf); - memcpy(&dst->rvra, &ctx->rvra, sizeof(ctx->rvra)); + memcpy(&dst->comp, &ctx->comp, sizeof(ctx->comp)); /* Apply request(s) controls if needed. */ src_req = run->bufs.src->vb2_buf.req_obj.req; diff --git a/drivers/media/platform/apple/avd/avd-vp9.c b/drivers/media/platform/apple/avd/avd-vp9.c index d43d19e631ec4b..869c7257c5960e 100644 --- a/drivers/media/platform/apple/avd/avd-vp9.c +++ b/drivers/media/platform/apple/avd/avd-vp9.c @@ -41,6 +41,8 @@ #define VP9_FEAT_LVL_ALT_Q(v) FIELD_PREP(GENMASK(21, 12), v) +#define VP9_MAX_TILE_COLS (1 << 4) + struct avd_vp9_seg_probs { u8 tree_probs[7]; u8 pred_probs[3]; @@ -137,13 +139,6 @@ struct avd_vp9_frame_info { struct avd_vp9_run { struct avd_run base; - struct run_addr { - dma_addr_t y; - dma_addr_t uv; - dma_addr_t sl; - dma_addr_t rvra; - } addresses; - const struct v4l2_ctrl_vp9_frame *decode_params; const struct v4l2_ctrl_vp9_compressed_hdr *prob_updates; }; @@ -185,15 +180,14 @@ static void set_refs(struct avd_ctx *ctx, struct avd_vp9_run *run) avd_get_ref_buf(ctx, &dst->base.vb, frame->golden_frame_ts); ref_buf[2] = avd_get_ref_buf(ctx, &dst->base.vb, frame->alt_frame_ts); - push(INST_DMA3, "cm3_dma_config_7"); - push(INST_DMA3, "cm3_dma_config_8"); - push(INST_DMA3, "cm3_dma_config_9"); + push(0, ""); + push(0, ""); + push(0, ""); for (int i = 0; i < V4L2_VP9_NUM_FRAME_CTX - 1; i++) { addr = vb2_dma_contig_plane_dma_addr( &ref_buf[i]->base.vb.vb2_buf, 0) + - (ref_buf[i]->base.vb.planes[0].length - - ref_buf[i]->rvra.size); + ref_buf[i]->comp.start_offset; /* TODO */ push(AVD_REF_FLAG_CONST, "hdr_9c_ref_100"); @@ -202,7 +196,7 @@ static void set_refs(struct avd_ctx *ctx, struct avd_vp9_run *run) "hdr_70_ref_height_width"); push(0x40004000, "hdr_7c_ref_align"); - push_rvra(avd, ctx, addr, ref_buf[i]->rvra.offsets); + push_comp(avd, ctx, addr, ref_buf[i]->comp.offsets); } } @@ -295,8 +289,8 @@ static void set_header(struct avd_ctx *ctx, struct avd_vp9_run *run) AVD_OP_EXEC_FIFO_IDX(ctx->fifo_idx), "inst_fifo_start"); - push(AVD_OP_HDR | AVD_OP_HDR_FLAG0 | AVD_OP_HDR_FLAG_INTRA(intra_only) | - AVD_OP_HDR_CONST | + push(AVD_OP_HDR | AVD_OP_HDR_FLAG_DECOMP(ctx->decomp) | + AVD_OP_HDR_FLAG_INTRA(intra_only) | AVD_OP_HDR_CONST | AVD_OP_HDR_FLAG_PIPE_STATE( !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)), "hdr_34_start_hdr"); @@ -306,7 +300,7 @@ static void set_header(struct avd_ctx *ctx, struct avd_vp9_run *run) push(AVD_HDR_HEIGHT(frame->frame_height_minus_1) | AVD_HDR_WIDTH(frame->frame_width_minus_1), "hdr_28_height_width_shift3"); - push(0, "cm3_dma_config_0"); + push(0, ""); push(AVD_HDR_HEIGHT(frame->frame_height_minus_1) | AVD_HDR_WIDTH(frame->frame_width_minus_1), "hdr_38_height_width_shift3"); @@ -327,8 +321,8 @@ static void set_header(struct avd_ctx *ctx, struct avd_vp9_run *run) /* some kind of feature enable? h26{2,5} has 3 instread */ push(AVD_HDR_FEAT_VP9, "unk_const"); - push(INST_DMA2, "cm3_dma_config_2"); - push(INST_DMA1, "cm3_dma_config_3"); + push(0, ""); + push(0, ""); pusha(vp9_ctx->bufs.counts.addr, "frame_counts_addr", 0); pusha(vp9_ctx->bufs.probs.addr, "hdr_104_probs_addr_lsb8", 0); @@ -367,8 +361,8 @@ static void set_header(struct avd_ctx *ctx, struct avd_vp9_run *run) 0), "hdr_48_loop_filter_level"); - push(INST_DMA2, "cm3_dma_config_4"); - push(INST_DMA2, "cm3_dma_config_5"); + push(0, ""); + push(0, ""); if (avd->variant->revision == 3) push(0, ""); @@ -386,9 +380,9 @@ static void set_header(struct avd_ctx *ctx, struct avd_vp9_run *run) /* fatal if missing / wrong */ pusha(vp9_ctx->bufs.tiles[2].addr, "hdr_e8_sps0_tile_addr_lsb8", 0); - push(INST_DMA3, "cm3_dma_config_7"); + push(0, ""); - push_rvra(avd, ctx, run->addresses.rvra, ctx->rvra.offsets); + push_comp(avd, ctx, run->base.comp_out, ctx->comp.offsets); /* confusing */ pusha((u64)0, "hdr_f4_sps1_tile_addr_lsb8", 2); @@ -397,9 +391,9 @@ static void set_header(struct avd_ctx *ctx, struct avd_vp9_run *run) if (avd->variant->quirks & AVD_QUIRK_LSR) bytesperline = bytesperline >> 4; - pusha(run->addresses.y, "hdr_168_y_addr_lsb8", 0); + pusha(run->base.y_out, "hdr_168_y_addr_lsb8", 0); push(bytesperline, "hdr_170_width_align"); - pusha(run->addresses.uv, "hdr_16c_uv_addr_lsb8", 0); + pusha(run->base.uv_out, "hdr_16c_uv_addr_lsb8", 0); push(bytesperline, "hdr_174_width_align"); push(0, ""); push(AVD_HDR_HEIGHT(frame->frame_height_minus_1) | @@ -446,10 +440,10 @@ static void set_tiles(struct avd_ctx *ctx, struct avd_vp9_run *run) size -= 4; } push(AVD_OP_CODED_DATA | - AVD_OP_CODED_DATA_ADDR(run->addresses.sl >> - 32), + AVD_OP_CODED_DATA_ADDR( + run->base.coded_in >> 32), "cm3_cmd_set_slice_data"); - push((u32)((run->addresses.sl + offset) & 0xffffffff), + push((u32)((run->base.coded_in + offset) & 0xffffffff), "til_ab4_tile_addr_low"); push(tile_size, "til_ab8_tile_size"); push(AVD_OP_SL_DIM_START | @@ -620,7 +614,13 @@ static int avd_vp9_alloc_bufs(struct avd_ctx *ctx) { struct avd_dev *avd = ctx->dev; struct avd_vp9_ctx *vp9_ctx = ctx->priv; - int ret, size; + int ret, w, h, bit_depth; + w = fmt_width(ctx); + h = fmt_height(ctx); + bit_depth = (ctx->image_fmt == AVD_IMG_FMT_420_10BIT || + ctx->image_fmt == AVD_IMG_FMT_422_10BIT) ? + 10 : + 8; ret = avd_buf_alloc(avd, &vp9_ctx->bufs.inst, fifo_size()); if (ret) @@ -632,66 +632,61 @@ static int avd_vp9_alloc_bufs(struct avd_ctx *ctx) return ret; } - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.seg, 0x200); + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.probs, + sizeof(struct avd_vp9_probs)); + if (ret) + return ret; + + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.counts, + sizeof(struct avd_vp9_frame_symbol_counts)); if (ret) return ret; - /* scratch buffer? */ - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.tiles[1], 0x200); + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.above_info, + DIV_ROUND_UP(w, 16) * DIV_ROUND_UP(h, 64) * 144); if (ret) return ret; - /* TODO */ - size = (((ctx->decoded_fmt.fmt.pix_mp.height - 1) * - (ctx->decoded_fmt.fmt.pix_mp.height - 1) / 0x10000) + - 2) * - 0x4000; - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.tiles[0], size); + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.color[0], + DIV_ROUND_UP(w, 16) * 4 * bit_depth + + (VP9_MAX_TILE_COLS - 1) * 128); if (ret) return ret; - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.tiles[2], size); + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.color[1], + DIV_ROUND_UP(w, 8) * 16 * bit_depth); if (ret) return ret; - for (int i = 0; i < 2; i++) { - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.color[i], size); - if (ret) - return ret; - } + /* + * randomly needs more space when resizing? + * maybe it does not need it? + */ + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.seg, DIV_ROUND_UP(w, 8) * 24); + if (ret) + return ret; - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.above_info, size + 0xc000); + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.tiles[0], + DIV_ROUND_UP(h, 8) * 16 * bit_depth); if (ret) return ret; - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.state, size); + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.tiles[1], + DIV_ROUND_UP(h, 64) * 16); if (ret) return ret; - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.probs, - sizeof(struct avd_vp9_probs)); + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.tiles[2], + bit_depth * 36 * DIV_ROUND_UP(h, 8) + + bit_depth * 18 * DIV_ROUND_UP(h, 16)); if (ret) return ret; - ret = avd_buf_alloc(avd, &vp9_ctx->bufs.counts, - sizeof(struct avd_vp9_frame_symbol_counts)); + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.state, + DIV_ROUND_UP(w, 64) * 288 + + (VP9_MAX_TILE_COLS - 1) * 128); if (ret) return ret; -#ifdef AVD_DEBUG -#define DBG_BUF(name, buf) \ - pr_info(" %10s %12llx %8lx", name, vp9_ctx->bufs.buf.addr, \ - vp9_ctx->bufs.buf.size) - pr_info("buffers:"); - DBG_BUF("state", state); - DBG_BUF("above_info", above_info); - DBG_BUF("seg", seg); - DBG_BUF("tiles[0]", tiles[0]); - DBG_BUF("tiles[1]", tiles[1]); - DBG_BUF("tiles[2]", tiles[2]); - DBG_BUF("color[0]", color[0]); - DBG_BUF("color[1]", color[1]); - pr_info("\n"); -#endif return 0; } @@ -701,7 +696,6 @@ static int avd_vp9_run_preamble(struct avd_ctx *ctx, struct avd_vp9_run *run) const struct v4l2_ctrl_vp9_frame *dec_params; struct avd_vp9_ctx *vp9_ctx = ctx->priv; unsigned int fctx_idx; - u32 dst_len; int ret; avd_run_preamble(ctx, &run->base); @@ -732,21 +726,6 @@ static int avd_vp9_run_preamble(struct avd_ctx *ctx, struct avd_vp9_run *run) v4l2_vp9_fw_update_probs(&vp9_ctx->probability_tables, run->prob_updates, dec_params); - run->addresses.sl = - vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0); - - dst_len = run->base.bufs.dst->vb2_buf.planes[0].length; - - run->addresses.y = - vb2_dma_contig_plane_dma_addr(&run->base.bufs.dst->vb2_buf, 0); - - run->addresses.uv = - run->addresses.y + - ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline * - ALIGN(ctx->decoded_fmt.fmt.pix_mp.height, 16); - - run->addresses.rvra = run->addresses.y + (dst_len - ctx->rvra.size); - return 0; } diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h index 11daa8c03d558f..92252934cb0d5a 100644 --- a/drivers/media/platform/apple/avd/avd.h +++ b/drivers/media/platform/apple/avd/avd.h @@ -36,6 +36,9 @@ #define VP_SLOT_NONE 255 #define INST_FIFO_SLOT_NONE 255 +/* AVD needs most addresses to be aligned to 256 */ +#define AVD_ALIGN 256 + struct avd_ctx; struct avd_dev; @@ -53,6 +56,11 @@ struct avd_run { struct vb2_v4l2_buffer *src; /* OUTPUT coded */ struct vb2_v4l2_buffer *dst; /* CAPTURE decoded */ } bufs; + + dma_addr_t coded_in; + dma_addr_t y_out; + dma_addr_t uv_out; + dma_addr_t comp_out; }; struct avd_ctrl_desc { @@ -81,6 +89,7 @@ struct avd_av1_decoded_buffer_info { u32 order_hints[V4L2_AV1_TOTAL_REFS_PER_FRAME]; u8 ref_frame_idx[V4L2_AV1_REFS_PER_FRAME]; bool intrabc; + size_t priv_tlb_size; }; struct avd_hevc_decoded_buffer_info { @@ -89,17 +98,19 @@ struct avd_hevc_decoded_buffer_info { }; -struct avd_rvra { - u32 offsets[4]; /* sizes or offsets */ +struct avd_comp { u32 size; + /* offset to start of compressed data */ + size_t start_offset; + /* relative offsets to start */ + u32 offsets[4]; }; -/* TODO: change and use this */ struct avd_decoded_buffer { /* Must be the first field in this struct. */ struct v4l2_m2m_buffer base; - struct avd_rvra rvra; + struct avd_comp comp; union { struct avd_vp9_decoded_buffer_info vp9; @@ -114,6 +125,7 @@ vb2_to_avd_decoded_buf(struct vb2_buffer *buf) { return container_of(buf, struct avd_decoded_buffer, base.vb.vb2_buf); } + struct avd_decoded_buffer * avd_get_ref_buf(struct avd_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp); @@ -209,13 +221,13 @@ struct avd_ctx { const struct avd_coded_fmt_desc *coded_fmt_desc; struct v4l2_ctrl_handler ctrl_hdl; enum avd_image_fmt image_fmt; + bool decomp; struct delayed_work watchdog_work; void *priv; - /* reference VRA (video resolution adaptation) scaler buffer. */ - struct avd_rvra rvra; + struct avd_comp comp; u8 fifo_idx; u8 vp_slot; @@ -258,7 +270,7 @@ static inline u32 fmt_width(struct avd_ctx *ctx) return ctx->coded_fmt.fmt.pix_mp.width; } -void fill_rvra(struct avd_rvra *rvra, enum avd_image_fmt image_fmt, +void fill_comp(struct avd_comp *comp, enum avd_image_fmt image_fmt, u32 width, u32 height); int alloc_slots(struct avd_dev *avd, struct avd_ctx *ctx, enum avd_codec codec);