diff --git a/phase2_field_mapping.md b/phase2_field_mapping.md new file mode 100644 index 0000000..62e429e --- /dev/null +++ b/phase2_field_mapping.md @@ -0,0 +1,129 @@ +# Phase 2 field-mapping table — legacy `struct rkvdec_regs` → `struct rkvdec_vdpu381_regs_vp9` + +The translation guide for porting `rkvdec_vp9_run` and its helpers from the legacy vdpu34x flat register layout to the vdpu381 segmented layout. Each row gives the legacy field, the new vdpu381 field, and notes on the semantic delta. Sourced from cross-reading legacy `rkvdec-vp9.c`, mainline `rkvdec-vdpu381-hevc.c`, mainline `rkvdec-vdpu381-regs.h`, and Rockchip BSP MPP `mpp/hal/rkdec/vp9d/hal_vp9d_vdpu382.c`. + +## Common block (segment 1, `OFFSET_COMMON_REGS = 0x020`) + +| Legacy | New (vdpu381) | Notes | +|---|---|---| +| `common.reg02.dec_mode = RKVDEC_MODE_VP9` | `common.reg009_dec_mode.dec_mode = VDPU381_MODE_VP9` | `VDPU381_MODE_VP9 = 2` already defined in `rkvdec-vdpu381-regs.h:22` | +| `common.reg03.y_hor_virstride` | `common.reg018_y_hor_stride.y_hor_virstride` | same semantic (aligned_pitch / 16) | +| `common.reg03.uv_hor_virstride` | `common.reg019_uv_hor_stride.uv_hor_virstride` | same semantic | +| `common.reg08.y_virstride` | `common.reg020_y_stride.y_virstride` | same semantic (y_len / 16) | +| `common.reg09.yuv_virstride` | **dropped** | vdpu381 common-block doesn't carry yuv_virstride; not consulted by hardware in segmented layout | +| `common.stream_len` | `common.reg016_stream_len` | same field | +| `common.decout_base` | `common_addr.reg130_decout_base` | moved to common_addr segment | +| `common.strm_rlc_base` | `common_addr.reg128_rlc_base` | moved to common_addr segment | +| `common.cabactbl_base` | `vp9_addr.reg197_cabactbl_base` | moved to vp9_addr segment | +| — | `common.reg028_multiply_core_ctrl.vp9_rd_prob_idx` | NEW: set per frame, prob slot ID | +| — | `common.reg028_multiply_core_ctrl.vp9_wr_prob_idx` | NEW: prob writeback slot | +| — | `common.reg011_important_en.dec_e_strmd_clkgate_dis = 1` | NEW: vdpu381 boilerplate | +| — | `common.reg011_important_en.dec_irq_dis = 0` | NEW: ensure IRQ enabled | +| — | `common.reg011_important_en.dec_timeout_e = 1` | NEW: timeout monitor | +| — | `common.reg026_block_gating_en.*` | NEW: per-block clock gates (mirror HEVC defaults from `rkvdec-vdpu381-hevc.c`) | + +## VP9 params block (segment 2, `OFFSET_CODEC_PARAMS_REGS = 0x100`) + +| Legacy | New (vdpu381) | Notes | +|---|---|---| +| `vp9.reg17_19[i].framewidth/frameheight` | `vp9_param.reg106_framewidth_last`, `reg107_frameheight_last`, `reg108_framewidth_golden`, `reg109_frameheight_golden`, `reg110_framewidth_altref`, `reg111_frameheight_altref` | indexed array → separate per-ref registers (last/golden/altref) | +| `vp9.reg20_27[segid]` (8 entries) | `vp9_param.reg067_074_segid[segid]` | direct array mapping, fields preserved (segid_*, segid_frame_qp_delta, segid_frame_loopfilter_value, etc.) | +| `vp9.reg28.tx_mode` | `vp9_param.reg076_tx_and_ref_mode.tx_mode` | same semantic | +| `vp9.reg28.frame_reference_mode` | `vp9_param.reg076_tx_and_ref_mode.frame_reference_mode` | same semantic | +| `vp9.reg29_31[i].ref_hor_scale` | `vp9_param.reg088_lref_hor_scale`, `reg090_gref_hor_scale`, `reg092_aref_hor_scale` | per-ref separation | +| `vp9.reg29_31[i].ref_ver_scale` | `vp9_param.reg089_lref_ver_scale`, `reg091_gref_ver_scale`, `reg093_aref_ver_scale` | per-ref separation | +| `vp9.reg32.ref_deltas_lastframe0..3` | `vp9_param.reg094_ref_deltas_lastframe.ref_deltas_lastframe` (single 28-bit field) | pack 4× 7-bit deltas into 28 bits | +| `vp9.reg33.mode_deltas_lastframe0/1` | `vp9_param.reg075_last_frame_info.mode_deltas_lastframe` (single 14-bit field) | pack 2× 7-bit deltas into 14 bits | +| `vp9.reg33.last_show_frame` | `vp9_param.reg075_last_frame_info.last_show_frame` | same semantic | +| `vp9.reg33.last_intra_only` | `vp9_param.reg075_last_frame_info.last_intra_only` | same semantic | +| `vp9.reg33.last_widthheight_eqcur` | `vp9_param.reg075_last_frame_info.last_widthheight_eqcur` | same semantic | +| `vp9.reg33.segmentation_enable_lstframe` | `vp9_param.reg075_last_frame_info.segmentation_enable_lstframe` | same semantic | +| `vp9.reg36.lasttile_size` | `vp9_param.reg078_lasttile_size.lasttile_size` | same semantic | +| `vp9.reg37_39[i].y_hor_virstride/uv_hor_virstride` | `vp9_param.reg079_lastfy_hor_stride`, `reg080_lastfuv_hor_stride`, `reg081_goldenfy_hor_stride`, `reg082_goldenfuv_hor_stride`, `reg083_altreffy_hor_stride`, `reg084_altreffuv_hor_stride` | per-ref separation | +| `vp9.reg48_50[i].virstride` | `vp9_param.reg085_lastfy_virstride`, `reg086_goldeny_virstride`, `reg087_altrefy_virstride` | per-ref separation | +| `vp9.reg51.lastref_yuv_virstride` | **dropped** | not present in vdpu381 layout; legacy-only convenience field | +| — | `vp9_param.reg103_frame_flags.intra_only_flag` | NEW: set when KEY_FRAME or INTRA_ONLY | +| — | `vp9_param.reg103_frame_flags.prob_update_en` | NEW: ! (compressed_header.tx_mode == previous && ...) | +| — | `vp9_param.reg103_frame_flags.refresh_en` | NEW: from V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX | +| — | `vp9_param.reg103_frame_flags.allow_high_precision_mv` | NEW: from V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV | +| — | `vp9_param.reg103_frame_flags.interp_filter_switch_en` | NEW: from dec_params->interpolation_filter == SWITCHABLE | +| — | `vp9_param.reg064_cprheader.cprheader_offset` | NEW: byte offset of compressed header (= dec_params->uncompressed_header_size) | +| — | `vp9_param.reg105_count_update_en.count_update_en = 1` | NEW: always enable count update on RX | + +## Common address block (segment 3, `OFFSET_COMMON_ADDR_REGS = 0x200`) + +| Legacy | New | Notes | +|---|---|---| +| `common.strm_rlc_base` | `common_addr.reg128_rlc_base` | bitstream OUTPUT buffer DMA addr | +| `common.decout_base` | `common_addr.reg130_decout_base` | CAPTURE buffer DMA addr | +| `vp9.refcolmv_base` (target buf's mv area) | `common_addr.reg131_colmv_cur_base` | current frame's collocated MV buffer | +| (legacy RCB allocations) | `common_addr.reg133_142[10]` from `rkvdec_allocate_rcb` | populated automatically by `rkvdec_start_streaming`; backend just writes the RCB array | + +## VP9 address block (segment 4, `OFFSET_CODEC_ADDR_REGS = 0x280`) + +| Legacy | New | Notes | +|---|---|---| +| `vp9.refer_bases[0]` (last_frame) | `vp9_addr.reg164_ref_last_base` | DMA addr of last ref frame | +| `vp9.refer_bases[1]` (golden) | `vp9_addr.reg165_ref_golden_base` | DMA addr of golden ref | +| `vp9.refer_bases[2]` (altref) | `vp9_addr.reg166_ref_alfter_base` | DMA addr of alt ref (BSP typo "alfter") | +| `common.cabactbl_base` | `vp9_addr.reg197_cabactbl_base` | probs table DMA addr | +| `vp9.count_base` | `vp9_addr.reg167_count_prob_base` | count buffer DMA addr | +| `vp9.segidlast_base` | `vp9_addr.reg168_segidlast_base` | last segmap DMA addr | +| `vp9.segidcur_base` | `vp9_addr.reg169_segidcur_base` | current segmap DMA addr | +| `vp9.refcolmv_base` (mv_ref) | `vp9_addr.reg170_ref_colmv_base` | reference collocated MV buffer | +| — | `vp9_addr.reg161_pps_base = 0` | not used for VP9 (HEVC concept); zero-init | +| — | `vp9_addr.reg163_rps_base = 0` | not used for VP9 (HEVC RPS); zero-init | +| — | `vp9_addr.reg160_delta_prob_base = probs.dma + offsetof(..., delta)` | NEW: forward-update probability delta input | +| — | `vp9_addr.reg162_last_prob_base` | NEW: previous frame's saved probs (frame_context) | +| — | `vp9_addr.reg171_intercmd_base = 0` | inter-frame command buffer (optional, can be 0) | +| — | `vp9_addr.reg172_update_prob_wr_base` | probs to write back after decode | +| — | `vp9_addr.reg180_scanlist_base = 0` | scanlist (not used for VP9 modes) | +| — | `vp9_addr.reg181_196_ref_colmv_base[16]` | unused for VP9 (HEVC DPB feature); zero-init | +| — | `vp9_addr.reg198_scale_down_luma_base = 0` | scale-down output (optional) | +| — | `vp9_addr.reg199_scale_down_chroma_base = 0` | scale-down output (optional) | + +## Decode trigger (NOT in any segmented write — done with `writel` after segment memcpy) + +| Legacy | New | +|---|---| +| `writel(RKVDEC_INTERRUPT_DEC_E \| RKVDEC_CONFIG_DEC_CLK_GATE_E \| RKVDEC_TIMEOUT_E \| RKVDEC_BUF_EMPTY_E, rkvdec->regs + RKVDEC_REG_INTERRUPT)` (0x004) | `writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E)` (0x028) | +| `writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND)` | **drop** — vdpu381 path doesn't precharge cache this way | +| `writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND)` | **drop** — same | + +## Segment write sequence in new `rkvdec_vdpu381_vp9_run` + +```c +rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS, + &vp9_ctx->regs.common, sizeof(vp9_ctx->regs.common)); +rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS, + &vp9_ctx->regs.vp9_param, sizeof(vp9_ctx->regs.vp9_param)); +rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS, + &vp9_ctx->regs.common_addr, sizeof(vp9_ctx->regs.common_addr)); +rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS, + &vp9_ctx->regs.vp9_addr, sizeof(vp9_ctx->regs.vp9_addr)); + +/* Trigger decode */ +writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E); +``` + +## Open implementation questions for Phase 2 code + +| # | Question | +|---|---| +| C-1 | `reg103_frame_flags` has many flags not present in legacy (`prob_update_en`, `refresh_en`, etc.). Are these required for first decode, or can they be left zero? Cross-check against BSP `hal_vp9d_vdpu382.c` `vp9d_gen_regs_legacy` or equivalent setup function | +| C-2 | `reg160_delta_prob_base` and `reg162_last_prob_base` — do they require new DMA allocations in `rkvdec_vp9_start`, or can they alias existing probs/count buffers? | +| C-3 | `reg028_multiply_core_ctrl.vp9_rd_prob_idx`/`vp9_wr_prob_idx` — what values for first-frame intra? Check BSP `Vdpu382Vp9dCtx_t::prob_idx` rotation logic | +| C-4 | RCB write-out is done by `rkvdec_setup_rcb` or similar shared helper — need to confirm legacy VP9 doesn't touch RCB but vdpu381 VP9 must (mirror HEVC backend) | +| C-5 | `reg032_timeout_threshold` — set to `RKVDEC_TIMEOUT_4K` for 4K-max VP9? | + +## Files to be written in Phase 2 + +| File | Status | +|---|---| +| `rkvdec-vdpu381-regs.h` extension (VP9 structs) | DONE, committed `47431635801d` | +| `rkvdec-vp9-common.h` static-inline helpers | next session — straightforward extraction | +| `rkvdec-vdpu381-vp9.c` (new backend) | next session — uses this field-mapping | +| `rkvdec.c` wiring (vdpu38x_vp9_ctrls + vdpu381_coded_fmts[] entry) | next session — minimal | +| `rkvdec-vp9.c` refactor (consume common header) | next session — minimal | + +This field-mapping table is the load-bearing artifact for the Phase 2 code-writing session. Future-self: start by walking this table line-by-line in `rkvdec_vdpu381_vp9_run` / `config_vp9_common_regs` / `config_vp9_param_regs` / `config_vp9_addr_regs` helpers.