static void rk3399_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu, struct rockchip_vpu_ctx *ctx) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; u32 reg; /* * The pix fmt width/height are already macroblock aligned * by .vidioc_s_fmt_vid_cap_mplane() callback */ reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width); vepu_write_relaxed(vpu, reg, VEPU_REG_INPUT_LUMA_INFO); reg = VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) | VEPU_REG_IN_IMG_CTRL_OVRFLB(0); /* * This register controls the input crop, as the offset * from the right/bottom within the last macroblock. The offset from the * right must be divided by 4 and so the crop must be aligned to 4 pixels * horizontally. */ vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_OVER_FILL_STRM_OFFSET); reg = VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1); }
static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu, struct rockchip_vpu_ctx *ctx, struct vb2_buffer *src_buf) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; dma_addr_t src[3]; WARN_ON(pix_fmt->num_planes > 3); vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, VEPU_REG_ADDR_OUTPUT_STREAM); vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, VEPU_REG_STR_BUF_LIMIT); if (pix_fmt->num_planes == 1) { src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); } else if (pix_fmt->num_planes == 2) { src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); } else { src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2); vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2); } }
void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx) { struct rockchip_vpu_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; struct rockchip_vpu_jpeg_ctx jpeg_ctx; u32 reg; src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); jpeg_ctx.width = ctx->dst_fmt.width; jpeg_ctx.height = ctx->dst_fmt.height; jpeg_ctx.quality = ctx->jpeg_quality; rockchip_vpu_jpeg_header_assemble(&jpeg_ctx); /* Switch to JPEG encoder mode before writing registers */ vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG, VEPU_REG_ENCODE_START); rk3399_vpu_set_src_img_ctrl(vpu, ctx); rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); rk3399_vpu_jpeg_enc_set_qtable(vpu, rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0), rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1)); reg = VEPU_REG_OUTPUT_SWAP32 | VEPU_REG_OUTPUT_SWAP16 | VEPU_REG_OUTPUT_SWAP8 | VEPU_REG_INPUT_SWAP8 | VEPU_REG_INPUT_SWAP16 | VEPU_REG_INPUT_SWAP32; /* Make sure that all registers are written at this point. */ vepu_write(vpu, reg, VEPU_REG_DATA_ENDIAN); reg = VEPU_REG_AXI_CTRL_BURST_LEN(16); vepu_write_relaxed(vpu, reg, VEPU_REG_AXI_CTRL); reg = VEPU_REG_MB_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) | VEPU_REG_MB_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) | VEPU_REG_FRAME_TYPE_INTRA | VEPU_REG_ENCODE_FORMAT_JPEG | VEPU_REG_ENCODE_ENABLE; /* Kick the watchdog and start encoding */ schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); vepu_write(vpu, reg, VEPU_REG_ENCODE_START); }
static void rk3399_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu, unsigned char *luma_qtable, unsigned char *chroma_qtable) { u32 reg, i; for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) { reg = get_unaligned_be32(&luma_qtable[i]); vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i)); reg = get_unaligned_be32(&chroma_qtable[i]); vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i)); } }
static void rk3288_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu, struct rockchip_vpu_ctx *ctx) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; u32 reg; reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) | VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) | VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(0) | VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); vepu_write_relaxed(vpu, reg, VEPU_REG_IN_IMG_CTRL); }
void rk3288_vpu_vp8e_run(struct rk3288_vpu_ctx *ctx) { struct rk3288_vpu_dev *vpu = ctx->dev; u32 reg; /* The hardware expects the control buffer to be zeroed. */ memset(ctx->hw.vp8e.ctrl_buf.cpu, 0, sizeof(struct rk3288_vpu_vp8e_ctrl_buf)); /* * Program the hardware. */ rk3288_vpu_power_on(vpu); vepu_write_relaxed(vpu, VEPU_REG_ENC_CTRL_ENC_MODE_VP8, VEPU_REG_ENC_CTRL); rk3288_vpu_vp8e_set_params(vpu, ctx); rk3288_vpu_vp8e_set_buffers(vpu, ctx); /* Make sure that all registers are written at this point. */ wmb(); /* Set the watchdog. */ schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); /* Start the hardware. */ reg = VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 | VEPU_REG_AXI_CTRL_INPUT_SWAP16 | VEPU_REG_AXI_CTRL_BURST_LEN(16) | VEPU_REG_AXI_CTRL_GATE_BIT | VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 | VEPU_REG_AXI_CTRL_INPUT_SWAP32 | VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 | VEPU_REG_AXI_CTRL_INPUT_SWAP8; vepu_write(vpu, reg, VEPU_REG_AXI_CTRL); vepu_write(vpu, 0, VEPU_REG_INTERRUPT); reg = VEPU_REG_ENC_CTRL_NAL_MODE_BIT | VEPU_REG_ENC_CTRL_WIDTH(MB_WIDTH(ctx->src_fmt.width)) | VEPU_REG_ENC_CTRL_HEIGHT(MB_HEIGHT(ctx->src_fmt.height)) | VEPU_REG_ENC_CTRL_ENC_MODE_VP8 | VEPU_REG_ENC_CTRL_EN_BIT; if (ctx->run.dst->b.v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) reg |= VEPU_REG_ENC_CTRL_KEYFRAME_BIT; vepu_write(vpu, reg, VEPU_REG_ENC_CTRL); }
static void rk3288_vpu_vp8e_set_params(struct rk3288_vpu_dev *vpu, struct rk3288_vpu_ctx *ctx) { const struct rk3288_vp8e_reg_params *params = ctx->run.vp8e.reg_params; int i; vepu_write_relaxed(vpu, params->enc_ctrl0, VEPU_REG_ENC_CTRL0); vepu_write_relaxed(vpu, params->enc_ctrl1, VEPU_REG_ENC_CTRL1); vepu_write_relaxed(vpu, params->enc_ctrl2, VEPU_REG_ENC_CTRL2); vepu_write_relaxed(vpu, params->enc_ctrl3, VEPU_REG_ENC_CTRL3); vepu_write_relaxed(vpu, params->enc_ctrl5, VEPU_REG_ENC_CTRL5); vepu_write_relaxed(vpu, params->enc_ctrl4, VEPU_REG_ENC_CTRL4); vepu_write_relaxed(vpu, params->str_hdr_rem_msb, VEPU_REG_STR_HDR_REM_MSB); vepu_write_relaxed(vpu, params->str_hdr_rem_lsb, VEPU_REG_STR_HDR_REM_LSB); vepu_write_relaxed(vpu, params->mad_ctrl, VEPU_REG_MAD_CTRL); for (i = 0; i < ARRAY_SIZE(params->qp_val); ++i) vepu_write_relaxed(vpu, params->qp_val[i], VEPU_REG_VP8_QP_VAL(i)); vepu_write_relaxed(vpu, params->bool_enc, VEPU_REG_VP8_BOOL_ENC); vepu_write_relaxed(vpu, params->vp8_ctrl0, VEPU_REG_VP8_CTRL0); vepu_write_relaxed(vpu, params->rlc_ctrl, VEPU_REG_RLC_CTRL); vepu_write_relaxed(vpu, params->mb_ctrl, VEPU_REG_MB_CTRL); for (i = 0; i < ARRAY_SIZE(params->rgb_yuv_coeff); ++i) vepu_write_relaxed(vpu, params->rgb_yuv_coeff[i], VEPU_REG_RGB_YUV_COEFF(i)); vepu_write_relaxed(vpu, params->rgb_mask_msb, VEPU_REG_RGB_MASK_MSB); vepu_write_relaxed(vpu, params->intra_area_ctrl, VEPU_REG_INTRA_AREA_CTRL); vepu_write_relaxed(vpu, params->cir_intra_ctrl, VEPU_REG_CIR_INTRA_CTRL); vepu_write_relaxed(vpu, params->first_roi_area, VEPU_REG_FIRST_ROI_AREA); vepu_write_relaxed(vpu, params->second_roi_area, VEPU_REG_SECOND_ROI_AREA); vepu_write_relaxed(vpu, params->mvc_ctrl, VEPU_REG_MVC_CTRL); for (i = 0; i < ARRAY_SIZE(params->intra_penalty); ++i) vepu_write_relaxed(vpu, params->intra_penalty[i], VEPU_REG_VP8_INTRA_PENALTY(i)); for (i = 0; i < ARRAY_SIZE(params->seg_qp); ++i) vepu_write_relaxed(vpu, params->seg_qp[i], VEPU_REG_VP8_SEG_QP(i)); for (i = 0; i < ARRAY_SIZE(params->dmv_4p_1p_penalty); ++i) vepu_write_relaxed(vpu, params->dmv_4p_1p_penalty[i], VEPU_REG_DMV_4P_1P_PENALTY(i)); for (i = 0; i < ARRAY_SIZE(params->dmv_qpel_penalty); ++i) vepu_write_relaxed(vpu, params->dmv_qpel_penalty[i], VEPU_REG_DMV_QPEL_PENALTY(i)); vepu_write_relaxed(vpu, params->vp8_ctrl1, VEPU_REG_VP8_CTRL1); vepu_write_relaxed(vpu, params->bit_cost_golden, VEPU_REG_VP8_BIT_COST_GOLDEN); for (i = 0; i < ARRAY_SIZE(params->loop_flt_delta); ++i) vepu_write_relaxed(vpu, params->loop_flt_delta[i], VEPU_REG_VP8_LOOP_FLT_DELTA(i)); }
static void rk3288_vpu_vp8e_set_buffers(struct rk3288_vpu_dev *vpu, struct rk3288_vpu_ctx *ctx) { const struct rk3288_vp8e_reg_params *params = ctx->run.vp8e.reg_params; dma_addr_t ref_buf_dma, rec_buf_dma; dma_addr_t stream_dma; size_t rounded_size; dma_addr_t dst_dma; u32 start_offset; size_t dst_size; rounded_size = ref_luma_size(ctx->src_fmt.width, ctx->src_fmt.height); ref_buf_dma = rec_buf_dma = ctx->hw.vp8e.ext_buf.dma; if (ctx->hw.vp8e.ref_rec_ptr) ref_buf_dma += rounded_size * 3 / 2; else rec_buf_dma += rounded_size * 3 / 2; ctx->hw.vp8e.ref_rec_ptr ^= 1; dst_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0); dst_size = vb2_plane_size(&ctx->run.dst->b, 0); /* * stream addr-->| * align 64bits->|<-start offset->| * |<---------header size-------->|<---dst buf--- */ start_offset = (params->rlc_ctrl & VEPU_REG_RLC_CTRL_STR_OFFS_MASK) >> VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT; stream_dma = dst_dma + params->hdr_len; /** * Userspace will pass 8 bytes aligned size(round_down) to us, * so we need to plus start offset to get real header size. * * |<-aligned size->|<-start offset->| * |<----------header size---------->| */ ctx->run.dst->vp8e.hdr_size = params->hdr_len + (start_offset >> 3); if (params->enc_ctrl & VEPU_REG_ENC_CTRL_KEYFRAME_BIT) ctx->run.dst->b.v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; else ctx->run.dst->b.v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; /* * We assume here that 1/10 of the buffer is enough for headers. * DCT partition will be placed in remaining 9/10 of the buffer. */ ctx->run.dst->vp8e.dct_offset = round_up(dst_size / 10, 8); /* Destination buffer. */ vepu_write_relaxed(vpu, stream_dma, VEPU_REG_ADDR_OUTPUT_STREAM); vepu_write_relaxed(vpu, dst_dma + ctx->run.dst->vp8e.dct_offset, VEPU_REG_ADDR_VP8_DCT_PART(0)); vepu_write_relaxed(vpu, dst_size - ctx->run.dst->vp8e.dct_offset, VEPU_REG_STR_BUF_LIMIT); /* Auxilliary buffers. */ vepu_write_relaxed(vpu, ctx->hw.vp8e.ctrl_buf.dma, VEPU_REG_ADDR_OUTPUT_CTRL); vepu_write_relaxed(vpu, ctx->hw.vp8e.mv_buf.dma, VEPU_REG_ADDR_MV_OUT); vepu_write_relaxed(vpu, ctx->run.priv_dst.dma, VEPU_REG_ADDR_VP8_PROB_CNT); vepu_write_relaxed(vpu, ctx->run.priv_src.dma + VP8_CABAC_CTX_OFFSET, VEPU_REG_ADDR_CABAC_TBL); vepu_write_relaxed(vpu, ctx->run.priv_src.dma + VP8_CABAC_CTX_OFFSET + VP8_CABAC_CTX_SIZE, VEPU_REG_ADDR_VP8_SEG_MAP); /* Reference buffers. */ vepu_write_relaxed(vpu, ref_buf_dma, VEPU_REG_ADDR_REF_LUMA); vepu_write_relaxed(vpu, ref_buf_dma + rounded_size, VEPU_REG_ADDR_REF_CHROMA); /* Reconstruction buffers. */ vepu_write_relaxed(vpu, rec_buf_dma, VEPU_REG_ADDR_REC_LUMA); vepu_write_relaxed(vpu, rec_buf_dma + rounded_size, VEPU_REG_ADDR_REC_CHROMA); /* Source buffer. */ vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(&ctx->run.src->b, PLANE_Y), VEPU_REG_ADDR_IN_LUMA); vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(&ctx->run.src->b, PLANE_CB), VEPU_REG_ADDR_IN_CB); vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(&ctx->run.src->b, PLANE_CR), VEPU_REG_ADDR_IN_CR); /* Source parameters. */ vepu_write_relaxed(vpu, enc_in_img_ctrl(ctx), VEPU_REG_IN_IMG_CTRL); }