lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <c57af009-6453-db07-6190-69d9247dd50e@collabora.com>
Date:   Wed, 7 Dec 2022 14:05:54 +0100
From:   AngeloGioacchino Del Regno 
        <angelogioacchino.delregno@...labora.com>
To:     Sebastian Fricke <sebastian.fricke@...labora.com>,
        linux-media@...r.kernel.org, Nas Chung <nas.chung@...psnmedia.com>,
        Robert Beckett <bob.beckett@...labora.com>,
        Mauro Carvalho Chehab <mchehab@...nel.org>
Cc:     kernel@...labora.com, hverkuil-cisco@...all.nl,
        nicolas.dufresne@...labora.com, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v11 2/6] media: chips-media: wave5: Add vpuapi layer

Il 07/12/22 13:13, Sebastian Fricke ha scritto:
> From: Nas Chung <nas.chung@...psnmedia.com>
> 
> Add the vpuapi layer of the wave5 codec driver.
> This layer is used to configure the hardware according
> to the parameters.
> 
> Signed-off-by: Dafna Hirschfeld <dafna.hirschfeld@...labora.com>
> Signed-off-by: Robert Beckett <bob.beckett@...labora.com>
> Signed-off-by: Sebastian Fricke <sebastian.fricke@...labora.com>
> Signed-off-by: Nas Chung <nas.chung@...psnmedia.com>
> ---
>   .../platform/chips-media/wave5/wave5-hw.c     | 3359 +++++++++++++++++
>   .../chips-media/wave5/wave5-regdefine.h       |  743 ++++
>   .../platform/chips-media/wave5/wave5-vdi.c    |  245 ++
>   .../platform/chips-media/wave5/wave5-vdi.h    |   67 +
>   .../platform/chips-media/wave5/wave5-vpuapi.c | 1040 +++++
>   .../platform/chips-media/wave5/wave5-vpuapi.h | 1136 ++++++
>   .../chips-media/wave5/wave5-vpuconfig.h       |   90 +
>   .../chips-media/wave5/wave5-vpuerror.h        |  454 +++
>   .../media/platform/chips-media/wave5/wave5.h  |   94 +
>   9 files changed, 7228 insertions(+)
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5-hw.c
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5-regdefine.h
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vdi.c
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vdi.h
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5-vpuerror.h
>   create mode 100644 drivers/media/platform/chips-media/wave5/wave5.h
> 
> diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c
> new file mode 100644
> index 000000000000..25705e61cdb3
> --- /dev/null
> +++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c
> @@ -0,0 +1,3359 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +/*
> + * Wave5 series multi-standard codec IP - wave5 backend logic
> + *
> + * Copyright (C) 2021 CHIPS&MEDIA INC
> + */
> +
> +#include <linux/iopoll.h>
> +#include "wave5-vpu.h"
> +#include "wave5.h"
> +#include "wave5-regdefine.h"
> +
> +#define FIO_TIMEOUT			10000000

FIO_TIMEOUT_US looks better :-)

> +#define FIO_CTRL_READY			BIT(31)
> +#define FIO_CTRL_WRITE			BIT(16)
> +#define VPU_BUSY_CHECK_TIMEOUT		10000000
> +#define QUEUE_REPORT_MASK		0xffff
> +
> +static void wave5_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason)
> +{
> +	char *caller = __builtin_return_address(0);
> +	struct device *dev = vpu_dev->dev;
> +	u32 reg_val;
> +
> +	switch (reg_fail_reason) {
> +	case WAVE5_SYSERR_QUEUEING_FAIL:
> +		reg_val = vpu_read_reg(vpu_dev, W5_RET_QUEUE_FAIL_REASON);
> +		dev_dbg(dev, "%s: queueing failure: 0x%x\n", caller, reg_val);
> +		break;
> +	case WAVE5_SYSERR_RESULT_NOT_READY:
> +		dev_err(dev, "%s: result not ready: 0x%x\n", caller, reg_fail_reason);
> +		break;
> +	case WAVE5_SYSERR_ACCESS_VIOLATION_HW:
> +		dev_err(dev, "%s: access violation: 0x%x\n", caller, reg_fail_reason);
> +		break;
> +	case WAVE5_SYSERR_WATCHDOG_TIMEOUT:
> +		dev_err(dev, "%s: watchdog timeout: 0x%x\n", caller, reg_fail_reason);
> +		break;
> +	case WAVE5_SYSERR_BUS_ERROR:
> +		dev_err(dev, "%s: bus error: 0x%x\n", caller, reg_fail_reason);
> +		break;
> +	case WAVE5_SYSERR_DOUBLE_FAULT:
> +		dev_err(dev, "%s: double fault: 0x%x\n", caller, reg_fail_reason);
> +		break;
> +	case WAVE5_SYSERR_VPU_STILL_RUNNING:
> +		dev_err(dev, "%s: still running: 0x%x\n", caller, reg_fail_reason);
> +		break;
> +	case WAVE5_SYSERR_VLC_BUF_FULL:
> +		dev_err(dev, "%s: vlc buf full: 0x%x\n", caller, reg_fail_reason);
> +		break;
> +	default:
> +		dev_err(dev, "%s: failure:: 0x%x\n", caller, reg_fail_reason);
> +		break;
> +	}
> +}
> +
> +static int wave5_wait_fio_readl(struct vpu_device *vpu_dev, u32 addr, u32 val)
> +{
> +	u32 ctrl;
> +	int ret;
> +
> +	ctrl = addr & 0xffff;
> +	wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_CTRL_ADDR, ctrl);
> +	ret = read_poll_timeout(wave5_vdi_readl, ctrl, ctrl & FIO_CTRL_READY,
> +				0, FIO_TIMEOUT, false, vpu_dev, W5_VPU_FIO_CTRL_ADDR);
> +	if (ret)
> +		return ret;
> +	if (wave5_vdi_readl(vpu_dev, W5_VPU_FIO_DATA) != val)
> +		return -ETIMEDOUT;

Are you sure that this is a timeout?
if (read_data != expected_data) => invalid data => return -EINVAL ?

> +	return 0;
> +}
> +

..snip..

> +
> +static int wave5_wait_bus_busy(struct vpu_device *vpu_dev, unsigned int addr)
> +{
> +	u32 gdi_status_check_value = 0x3f;
> +
> +	if (vpu_dev->product_code == WAVE521C_CODE ||
> +	    vpu_dev->product_code == WAVE521_CODE ||
> +	    vpu_dev->product_code == WAVE521E1_CODE)
> +		gdi_status_check_value = 0x00ff1f3f;

#define SOME_VALUE 0x3f
#define ANOTHER_VALUE 0xff1f3f

> +
> +	return wave5_wait_fio_readl(vpu_dev, addr, gdi_status_check_value);
> +}
> +

..snip..

> +
> +static int setup_wave5_properties(struct device *dev)
> +{
> +	struct vpu_device *vpu_dev = dev_get_drvdata(dev);
> +	struct vpu_attr *p_attr = &vpu_dev->attr;
> +	u32 reg_val;
> +	u8 *str;
> +	int ret;
> +	u32 hw_config_def0, hw_config_def1, hw_config_feature, hw_config_rev;
> +
> +	vpu_write_reg(vpu_dev, W5_QUERY_OPTION, GET_VPU_INFO);
> +	vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
> +	vpu_write_reg(vpu_dev, W5_COMMAND, W5_QUERY);
> +	vpu_write_reg(vpu_dev, W5_VPU_HOST_INT_REQ, 1);
> +	ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
> +	if (ret)
> +		return ret;
> +
> +	if (!vpu_read_reg(vpu_dev, W5_RET_SUCCESS))
> +		return -EIO;
> +
> +	reg_val = vpu_read_reg(vpu_dev, W5_RET_PRODUCT_NAME);
> +	str = (u8 *)&reg_val;
> +	p_attr->product_name[0] = str[3];
> +	p_attr->product_name[1] = str[2];
> +	p_attr->product_name[2] = str[1];
> +	p_attr->product_name[3] = str[0];
> +	p_attr->product_name[4] = 0;
> +
> +	p_attr->product_id = wave5_vpu_get_product_id(vpu_dev);
> +	p_attr->product_version = vpu_read_reg(vpu_dev, W5_RET_PRODUCT_VERSION);
> +	p_attr->fw_version = vpu_read_reg(vpu_dev, W5_RET_FW_VERSION);
> +	p_attr->customer_id = vpu_read_reg(vpu_dev, W5_RET_CUSTOMER_ID);
> +	hw_config_def0 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF0);
> +	hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1);
> +	hw_config_feature = vpu_read_reg(vpu_dev, W5_RET_CONF_FEATURE);
> +	hw_config_rev = vpu_read_reg(vpu_dev, W5_RET_CONF_REVISION);
> +
> +	p_attr->support_hevc10bit_enc = (hw_config_feature >> 3) & 1;

This looks like being BIT(3), and the latter is BIT(11)...

#define W5_CONF_FEATURE_HEVC10_ENC	BIT(3)
#define W5_CONF_FEATURE_AVC10_ENC	BIT(11)

p_attr->support_hevc10bit_enc = FIELD_GET(W5_CONF_FEATURE_HEVC10_ENC, 
hw_config_feature);

if (hw_config_rev > W5_REVISION_SOMETHING)
	p_attr->support_avc10bit_enc = FIELD_GET(W5_CONF_FEATURE_AVC10_ENC,
						 hw_config_feature);
else
	p_attr->support_avc10bit_enc = p_attr->support_hevc10bit_enc;


> +	if (hw_config_rev > 167455) //20190321
> +		p_attr->support_avc10bit_enc = (hw_config_feature >> 11) & 1;
> +	else
> +		p_attr->support_avc10bit_enc = p_attr->support_hevc10bit_enc;
> +
> +	p_attr->support_decoders = 0;
> +	p_attr->support_encoders = 0;
> +	if (p_attr->product_id == PRODUCT_ID_521) {
> +		p_attr->support_dual_core = ((hw_config_def1 >> 26) & 0x01);

p_attr->support_dual_core = FIELD_GET(W5_CONF_DEF_HW_DUAL_CORE, hw_config_def1);

....and there are others below, but I think I gave enough examples... :-)

> +		if (p_attr->support_dual_core || hw_config_rev < 206116) {
> +			p_attr->support_decoders = BIT(STD_AVC);
> +			p_attr->support_decoders |= BIT(STD_HEVC);
> +			p_attr->support_encoders = BIT(STD_AVC);
> +			p_attr->support_encoders |= BIT(STD_HEVC);
> +		} else {
> +			p_attr->support_decoders |= (((hw_config_def1 >> 3) & 0x01) << STD_AVC);
> +			p_attr->support_decoders |= (((hw_config_def1 >> 2) & 0x01) << STD_HEVC);
> +			p_attr->support_encoders = (((hw_config_def1 >> 1) & 0x01) << STD_AVC);
> +			p_attr->support_encoders |= ((hw_config_def1 & 0x01) << STD_HEVC);
> +		}
> +	} else if (p_attr->product_id == PRODUCT_ID_511) {
> +		p_attr->support_decoders = BIT(STD_HEVC);
> +		p_attr->support_decoders |= BIT(STD_AVC);
> +	} else if (p_attr->product_id == PRODUCT_ID_517) {
> +		p_attr->support_decoders = (((hw_config_def1 >> 4) & 0x01) << STD_AV1);
> +		p_attr->support_decoders |= (((hw_config_def1 >> 3) & 0x01) << STD_AVS2);
> +		p_attr->support_decoders |= (((hw_config_def1 >> 2) & 0x01) << STD_AVC);
> +		p_attr->support_decoders |= (((hw_config_def1 >> 1) & 0x01) << STD_VP9);
> +		p_attr->support_decoders |= ((hw_config_def1 & 0x01) << STD_HEVC);
> +	}
> +
> +	p_attr->support_backbone = (hw_config_def0 >> 16) & 0x01;
> +	p_attr->support_vcpu_backbone = (hw_config_def0 >> 28) & 0x01;
> +	p_attr->support_vcore_backbone = (hw_config_def0 >> 22) & 0x01;
> +	p_attr->support_dual_core = (hw_config_def1 >> 26) & 0x01;
> +	p_attr->support_endian_mask = BIT(VDI_LITTLE_ENDIAN) |
> +				      BIT(VDI_BIG_ENDIAN) |
> +				      BIT(VDI_32BIT_LITTLE_ENDIAN) |
> +				      BIT(VDI_32BIT_BIG_ENDIAN) |
> +				      (0xffffUL << 16);
> +	p_attr->support_bitstream_mode = BIT(BS_MODE_INTERRUPT) |
> +		BIT(BS_MODE_PIC_END);
> +
> +	return 0;
> +}
> +
> +int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision)
> +{
> +	u32 reg_val;
> +	int ret;
> +
> +	vpu_write_reg(vpu_dev, W5_QUERY_OPTION, GET_VPU_INFO);
> +	vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
> +	vpu_write_reg(vpu_dev, W5_COMMAND, W5_QUERY);
> +	vpu_write_reg(vpu_dev, W5_VPU_HOST_INT_REQ, 1);
> +	ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
> +	if (ret) {
> +		dev_err(vpu_dev->dev, "%s: timeout\n", __func__);
> +		return ret;
> +	}
> +
> +	if (!vpu_read_reg(vpu_dev, W5_RET_SUCCESS)) {
> +		dev_err(vpu_dev->dev, "%s: failed\n", __func__);
> +		return -EIO;
> +	}
> +
> +	reg_val = vpu_read_reg(vpu_dev, W5_RET_FW_VERSION);
> +	if (revision)

Move the revision pointer null check at the beginning and return an error
if that happens to be null: it doesn't make a lot of sense to read many
registers before the check as the whole point of this function is to get
the version and return it to that variable.


> +		*revision = reg_val;
> +
> +	return 0;
> +}
> +
> +static void remap_page(struct vpu_device *vpu_dev, dma_addr_t code_base, u32 index)
> +{
> +	u32 remap_size = (W5_REMAP_MAX_SIZE >> 12) & 0x1ff;
> +	u32 reg_val = 0x80000000 | (WAVE5_UPPER_PROC_AXI_ID << 20) | (index << 12) | BIT(11)
> +		| remap_size;
> +
> +	vpu_write_reg(vpu_dev, W5_VPU_REMAP_CTRL, reg_val);
> +	vpu_write_reg(vpu_dev, W5_VPU_REMAP_VADDR, index * W5_REMAP_MAX_SIZE);
> +	vpu_write_reg(vpu_dev, W5_VPU_REMAP_PADDR, code_base + index * W5_REMAP_MAX_SIZE);
> +}
> +

..snip..

> +
> +int wave5_vpu_build_up_dec_param(struct vpu_instance *inst,
> +				 struct dec_open_param *param)
> +{
> +	int ret;
> +	struct dec_info *p_dec_info = &inst->codec_info->dec_info;
> +	u32 bs_endian;
> +	struct dma_vpu_buf *sram_vb;
> +	struct vpu_device *vpu_dev = inst->dev;
> +
> +	p_dec_info->cycle_per_tick = 256;
> +	switch (inst->std) {
> +	case W_HEVC_DEC:
> +		p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_HEVC;
> +		break;
> +	case W_VP9_DEC:
> +		p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_VP9;
> +		break;
> +	case W_AVS2_DEC:
> +		p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AVS2;
> +		break;
> +	case W_AVC_DEC:
> +		p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AVC;
> +		break;
> +	case W_AV1_DEC:
> +		p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AV1;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (vpu_dev->product == PRODUCT_ID_517)

Another switch would be good here.

> +		p_dec_info->vb_work.size = WAVE517_WORKBUF_SIZE;
> +	else if (vpu_dev->product == PRODUCT_ID_521)
> +		p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE;
> +	else if (vpu_dev->product == PRODUCT_ID_511)
> +		p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE;
> +
> +	ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work);
> +	if (ret)
> +		return ret;
> +
> +	vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1);
> +
> +	sram_vb = &vpu_dev->sram_buf;
> +	p_dec_info->sec_axi_info.buf_base = sram_vb->daddr;
> +	p_dec_info->sec_axi_info.buf_size = sram_vb->size;
> +
> +	wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work);
> +
> +	vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr);
> +	vpu_write_reg(inst->dev, W5_WORK_SIZE, p_dec_info->vb_work.size);
> +
> +	vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr);
> +	vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size);
> +
> +	/* NOTE: when endian mode is 0, SDMA reads MSB first */
> +	bs_endian = wave5_vdi_convert_endian(inst->dev, param->stream_endian);
> +	bs_endian = (~bs_endian & VDI_128BIT_ENDIAN_MASK);
> +	vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, bs_endian);
> +	vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, (param->pri_axprot << 20) |
> +			(param->pri_axcache << 16) | param->pri_ext_addr);
> +	vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1));
> +	vpu_write_reg(inst->dev, W5_CMD_ERR_CONCEAL, (param->error_conceal_unit << 2) |
> +			(param->error_conceal_mode));
> +
> +	wave5_bit_issue_command(inst, W5_CREATE_INSTANCE);
> +	// check QUEUE_DONE

Please be consistent in comments format. Use C-style comments.

> +	ret = wave5_wait_vpu_busy(inst->dev, W5_VPU_BUSY_STATUS);
> +	if (ret) {
> +		dev_warn(inst->dev->dev, "command: 'W5_CREATE_INSTANCE' timed out\n");
> +		goto free_vb_work;
> +	}
> +
> +	// Check if we were able to add the parameters into the VCPU QUEUE
> +	if (!vpu_read_reg(inst->dev, W5_RET_SUCCESS)) {
> +		ret = -EIO;
> +		goto free_vb_work;
> +	}
> +
> +	p_dec_info->product_code = vpu_read_reg(inst->dev, W5_PRODUCT_NUMBER);
> +
> +	return 0;
> +free_vb_work:
> +	wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work);
> +	return ret;
> +}
> +

..snip..

> +
> +static void wave5_get_dec_seq_result(struct vpu_instance *inst, struct dec_initial_info *info)
> +{
> +	u32 reg_val, sub_layer_info;
> +	u32 profile_compatibility_flag;
> +	u32 output_bit_depth_minus8;
> +	struct dec_info *p_dec_info = &inst->codec_info->dec_info;
> +
> +	p_dec_info->stream_rd_ptr = wave5_vpu_dec_get_rd_ptr(inst);
> +	info->rd_ptr = p_dec_info->stream_rd_ptr;
> +
> +	p_dec_info->frame_display_flag = vpu_read_reg(inst->dev, W5_RET_DEC_DISP_IDC);
> +
> +	reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_SIZE);
> +	info->pic_width = ((reg_val >> 16) & 0xffff);
> +	info->pic_height = (reg_val & 0xffff);
> +	info->min_frame_buffer_count = vpu_read_reg(inst->dev, W5_RET_DEC_NUM_REQUIRED_FB);
> +	info->frame_buf_delay = vpu_read_reg(inst->dev, W5_RET_DEC_NUM_REORDER_DELAY);
> +
> +	reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_CROP_LEFT_RIGHT);
> +	info->pic_crop_rect.left = (reg_val >> 16) & 0xffff;
> +	info->pic_crop_rect.right = reg_val & 0xffff;
> +	reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_CROP_TOP_BOTTOM);
> +	info->pic_crop_rect.top = (reg_val >> 16) & 0xffff;
> +	info->pic_crop_rect.bottom = reg_val & 0xffff;
> +
> +	info->f_rate_numerator = vpu_read_reg(inst->dev, W5_RET_DEC_FRAME_RATE_NR);
> +	info->f_rate_denominator = vpu_read_reg(inst->dev, W5_RET_DEC_FRAME_RATE_DR);
> +
> +	reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_COLOR_SAMPLE_INFO);
> +	info->luma_bitdepth = reg_val & 0xf;
> +	info->chroma_bitdepth = (reg_val >> 4) & 0xf;
> +	info->chroma_format_idc = (reg_val >> 8) & 0xf;
> +	info->aspect_rate_info = (reg_val >> 16) & 0xff;

Bitfield macros would make this way more readable.

> +	info->is_ext_sar = ((info->aspect_rate_info == 255) ? true : false);
> +	/* [0:15] - vertical size, [16:31] - horizontal size */
> +	if (info->is_ext_sar)
> +		info->aspect_rate_info = vpu_read_reg(inst->dev, W5_RET_DEC_ASPECT_RATIO);
> +	info->bit_rate = vpu_read_reg(inst->dev, W5_RET_DEC_BIT_RATE);
> +
> +	sub_layer_info = vpu_read_reg(inst->dev, W5_RET_DEC_SUB_LAYER_INFO);
> +	info->max_temporal_layers = (sub_layer_info >> 8) & 0x7;
> +
> +	reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_SEQ_PARAM);
> +	info->level = reg_val & 0xff;
> +	profile_compatibility_flag = (reg_val >> 12) & 0xff;
> +	info->profile = (reg_val >> 24) & 0x1f;
> +	info->tier = (reg_val >> 29) & 0x01;
> +	output_bit_depth_minus8 = (reg_val >> 30) & 0x03;
> +
> +	if (inst->std == W_HEVC_DEC) {
> +		/* guessing profile */
> +		if (!info->profile) {
> +			if ((profile_compatibility_flag & 0x06) == 0x06)
> +				info->profile = HEVC_PROFILE_MAIN; /* main profile */

main/main10 profile comments are stating the obvious, please remove them.

> +			else if ((profile_compatibility_flag & 0x04) == 0x04)
> +				info->profile = HEVC_PROFILE_MAIN10; /* main10 profile */
> +			else if ((profile_compatibility_flag & 0x08) == 0x08)
> +				/* main still picture profile */
> +				info->profile = HEVC_PROFILE_STILLPICTURE;
> +			else
> +				info->profile = HEVC_PROFILE_MAIN; /* for old version HM */
> +		}
> +
> +	} else if (inst->std == W_AVS2_DEC) {
> +		if (info->luma_bitdepth == 10 && output_bit_depth_minus8 == 2)
> +			info->output_bit_depth = 10;
> +		else
> +			info->output_bit_depth = 8;
> +
> +	} else if (inst->std == W_AVC_DEC) {
> +		info->profile = (reg_val >> 24) & 0x7f;
> +	}
> +
> +	info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE);
> +	info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE);
> +	p_dec_info->vlc_buf_size = info->vlc_buf_size;
> +	p_dec_info->param_buf_size = info->param_buf_size;
> +}
> +

..snip..

> +
> +static u32 calculate_table_size(u32 bit_depth, u32 frame_width, u32 frame_height, u32 ot_bg_width)
> +{
> +	u32 bgs_width = ((bit_depth > 8) ? 256 : 512);
> +	u32 comp_frame_width = ALIGN(ALIGN(frame_width, 16) + 16, 16);
> +	u32 ot_frame_width = ALIGN(comp_frame_width, ot_bg_width);
> +
> +	// sizeof_offset_table()
> +	u32 ot_bg_height = 32;
> +	u32 bgs_height = BIT(14) / bgs_width / ((bit_depth > 8) ? 2 : 1);

Please, no magic BIT(x) usage: add a definition for that bit.

> +	u32 comp_frame_height = ALIGN(ALIGN(frame_height, 4) + 4, bgs_height);
> +	u32 ot_frame_height = ALIGN(comp_frame_height, ot_bg_height);
> +
> +	return (ot_frame_width / 16) * (ot_frame_height / 4) * 2;
> +}
> +

..snip..

> +
> +int wave5_vpu_decode(struct vpu_instance *inst, struct dec_param *option, u32 *fail_res)
> +{
> +	u32 mode_option = DEC_PIC_NORMAL, bs_option, reg_val;
> +	u32 force_latency = 0;
> +	struct dec_info *p_dec_info = &inst->codec_info->dec_info;
> +	struct dec_open_param *p_open_param = &p_dec_info->open_param;
> +	int ret;
> +

switch (option->skipframe_mode) {
case ...
...
default:
	break;
};

if (p_dec_info->thumbnail_mode) {
	mode_option = DEC_PIC_W_THUMBNAIL;
	if (mode_option != DEC_PIC_NORMAL)
		... do something: as I read the code, this is not a supported case.
}

^^^^ this should improve the flow.

> +	if (p_dec_info->thumbnail_mode) {
> +		mode_option = DEC_PIC_W_THUMBNAIL;
> +	} else if (option->skipframe_mode) {
> +		switch (option->skipframe_mode) {
> +		case WAVE_SKIPMODE_NON_IRAP:
> +			mode_option = SKIP_NON_IRAP;
> +			force_latency = 1;
> +			break;
> +		case WAVE_SKIPMODE_NON_REF:
> +			mode_option = SKIP_NON_REF_PIC;
> +			break;
> +		default:
> +			// skip mode off
> +			break;
> +		}
> +	}
> +
> +	// set disable reorder
> +	if (!p_dec_info->reorder_enable)
> +		force_latency = 1;
> +
> +	/* set attributes of bitstream buffer controller */
> +	bs_option = 0;

You don't have to initialize this variable at all, as you're either writing twice
or failing.

> +	switch (p_open_param->bitstream_mode) {
> +	case BS_MODE_INTERRUPT:
> +		bs_option = BSOPTION_ENABLE_EXPLICIT_END;
> +		break;
> +	case BS_MODE_PIC_END:
> +		bs_option = BSOPTION_ENABLE_EXPLICIT_END;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +

..snip..

> +
> +int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
> +{
> +	struct vpu_buf *common_vb;
> +	dma_addr_t code_base, temp_base;
> +	dma_addr_t old_code_base, temp_size;
> +	u32 code_size;
> +	u32 reg_val;
> +	struct vpu_device *vpu_dev = dev_get_drvdata(dev);
> +
> +	common_vb = &vpu_dev->common_mem;
> +
> +	code_base = common_vb->daddr;
> +	/* ALIGN TO 4KB */
> +	code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
> +	if (code_size < size * 2)
> +		return -EINVAL;
> +	temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET;
> +	temp_size = WAVE5_TEMPBUF_SIZE;
> +
> +	old_code_base = vpu_read_reg(vpu_dev, W5_VPU_REMAP_PADDR);
> +
> +	if (old_code_base != code_base + W5_REMAP_INDEX1 * W5_REMAP_MAX_SIZE) {

Put the contents of this branch into another function maybe?

	if (old_code_base != code_base + W5_REMAP_INDEX1 * W5_REMAP_MAX_SIZE) {
		ret = do_that_vpu_init_flow(things);
		if (ret)
			return ret;
	}


	return setup_wave5_properties(dev);
};

Alternatively, invert the conditional and use a goto, but I personally don't
really like using gotos unless it's *totally* necessary.

> +		int ret;
> +		struct dma_vpu_buf *sram_vb;
> +
> +		ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size,
> +					     VDI_128BIT_LITTLE_ENDIAN);
> +		if (ret < 0) {
> +			dev_err(vpu_dev->dev,
> +				"VPU init, Writing firmware to common buffer, fail: %d\n", ret);
> +			return ret;
> +		}
> +
> +		vpu_write_reg(vpu_dev, W5_PO_CONF, 0);
> +
> +		ret = wave5_vpu_reset(dev, SW_RESET_ON_BOOT);
> +		if (ret < 0) {
> +			dev_err(vpu_dev->dev, "VPU init, Resetting the VPU, fail: %d\n", ret);
> +			return ret;
> +		}
> +
> +		remap_page(vpu_dev, code_base, W5_REMAP_INDEX0);
> +		remap_page(vpu_dev, code_base, W5_REMAP_INDEX1);
> +
> +		vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base);
> +		vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size);
> +		vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0);
> +		vpu_write_reg(vpu_dev, W5_ADDR_TEMP_BASE, temp_base);
> +		vpu_write_reg(vpu_dev, W5_TEMP_SIZE, temp_size);
> +
> +		vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
> +
> +		reg_val = (WAVE5_PROC_AXI_EXT_ADDR & 0xFFFF);
> +		wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, reg_val);
> +		reg_val = ((WAVE5_PROC_AXI_AXPROT & 0x7) << 4) |
> +			(WAVE5_PROC_AXI_AXCACHE & 0xF);
> +		wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, reg_val);
> +		reg_val = ((WAVE5_SEC_AXI_AXPROT & 0x7) << 20) |
> +			((WAVE5_SEC_AXI_AXCACHE & 0xF) << 16) |
> +			(WAVE5_SEC_AXI_EXT_ADDR & 0xFFFF);
> +		vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, reg_val);
> +
> +		/* interrupt */
> +		// encoder
> +		reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
> +		reg_val |= BIT(INT_WAVE5_ENC_PIC);
> +		reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
> +		// decoder
> +		reg_val |= BIT(INT_WAVE5_INIT_SEQ);
> +		reg_val |= BIT(INT_WAVE5_DEC_PIC);
> +		reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
> +		vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
> +
> +		reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
> +		if ((reg_val >> 16) & 1) {
> +			reg_val = ((WAVE5_PROC_AXI_ID << 28) |
> +					(WAVE5_PRP_AXI_ID << 24) |
> +					(WAVE5_FBD_Y_AXI_ID << 20) |
> +					(WAVE5_FBC_Y_AXI_ID << 16) |
> +					(WAVE5_FBD_C_AXI_ID << 12) |
> +					(WAVE5_FBC_C_AXI_ID << 8) |
> +					(WAVE5_PRI_AXI_ID << 4) |
> +					WAVE5_SEC_AXI_ID);
> +			wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
> +		}
> +
> +		sram_vb = &vpu_dev->sram_buf;
> +
> +		vpu_write_reg(vpu_dev, W5_ADDR_SEC_AXI, sram_vb->daddr);
> +		vpu_write_reg(vpu_dev, W5_SEC_AXI_SIZE, sram_vb->size);
> +		vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
> +		vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU);
> +		vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1);
> +
> +		ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
> +		if (ret) {
> +			dev_err(vpu_dev->dev, "VPU reinit(W5_VPU_REMAP_CORE_START) timeout\n");
> +			return ret;
> +		}
> +
> +		reg_val = vpu_read_reg(vpu_dev, W5_RET_SUCCESS);
> +		if (!reg_val) {
> +			u32 reason_code = vpu_read_reg(vpu_dev, W5_RET_FAIL_REASON);
> +
> +			wave5_print_reg_err(vpu_dev, reason_code);
> +			return -EIO;
> +		}
> +	}
> +
> +	return setup_wave5_properties(dev);
> +}
> +

..snip..

> +
> +int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode)
> +{
> +	u32 val = 0;
> +	int ret = 0;
> +	struct vpu_device *vpu_dev = dev_get_drvdata(dev);
> +	struct vpu_attr *p_attr = &vpu_dev->attr;
> +	// VPU doesn't send response. force to set BUSY flag to 0.
> +	vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 0);
> +
> +	if (reset_mode == SW_RESET_SAFETY) {
> +		ret = wave5_vpu_sleep_wake(dev, true, NULL, 0);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
> +	if ((val >> 16) & 0x1)
> +		p_attr->support_backbone = true;

bitfield macros ftw.

> +	if ((val >> 22) & 0x1)
> +		p_attr->support_vcore_backbone = true;
> +	if ((val >> 28) & 0x1)
> +		p_attr->support_vcpu_backbone = true;
> +
> +	val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG1);
> +	if ((val >> 26) & 0x1)
> +		p_attr->support_dual_core = true;
> +


..snip..

> +static void wave5_set_enc_crop_info(u32 codec, struct enc_wave_param *param, int rot_mode,
> +				    int src_width, int src_height)
> +{
> +	int aligned_width = (codec == W_HEVC_ENC) ? ALIGN(src_width, 32) : ALIGN(src_width, 16);
> +	int aligned_height = (codec == W_HEVC_ENC) ? ALIGN(src_height, 32) : ALIGN(src_height, 16);
> +	int pad_right, pad_bot;
> +	int crop_right, crop_left, crop_top, crop_bot;
> +	int prp_mode = rot_mode >> 1; // remove prp_enable bit
> +
> +	if (codec == W_HEVC_ENC &&
> +	    (!rot_mode || prp_mode == 14)) // prp_mode 14 : hor_mir && ver_mir && rot_180
> +		return;
> +
> +	pad_right = aligned_width - src_width;
> +	pad_bot = aligned_height - src_height;
> +
> +	if (param->conf_win_right > 0)
> +		crop_right = param->conf_win_right + pad_right;
> +	else
> +		crop_right = pad_right;
> +
> +	if (param->conf_win_bot > 0)
> +		crop_bot = param->conf_win_bot + pad_bot;
> +	else
> +		crop_bot = pad_bot;
> +
> +	crop_top = param->conf_win_top;
> +	crop_left = param->conf_win_left;
> +
> +	param->conf_win_top = crop_top;
> +	param->conf_win_left = crop_left;
> +	param->conf_win_bot = crop_bot;
> +	param->conf_win_right = crop_right;
> +
> +	if (prp_mode == 1 || prp_mode == 15) {

#define PRP_MODE_SOMETHING 1
#define PRP_MODE_SOMETHING_ELSE 2

or use an enumeration... otherwise it's not really understandable...

> +		param->conf_win_top = crop_right;
> +		param->conf_win_left = crop_top;
> +		param->conf_win_bot = crop_left;
> +		param->conf_win_right = crop_bot;
> +	} else if (prp_mode == 2 || prp_mode == 12) {
> +		param->conf_win_top = crop_bot;
> +		param->conf_win_left = crop_right;
> +		param->conf_win_bot = crop_top;
> +		param->conf_win_right = crop_left;
> +	} else if (prp_mode == 3 || prp_mode == 13) {
> +		param->conf_win_top = crop_left;
> +		param->conf_win_left = crop_bot;
> +		param->conf_win_bot = crop_right;
> +		param->conf_win_right = crop_top;
> +	} else if (prp_mode == 4 || prp_mode == 10) {
> +		param->conf_win_top = crop_bot;
> +		param->conf_win_bot = crop_top;
> +	} else if (prp_mode == 8 || prp_mode == 6) {
> +		param->conf_win_left = crop_right;
> +		param->conf_win_right = crop_left;
> +	} else if (prp_mode == 5 || prp_mode == 11) {
> +		param->conf_win_top = crop_left;
> +		param->conf_win_left = crop_top;
> +		param->conf_win_bot = crop_right;
> +		param->conf_win_right = crop_bot;
> +	} else if (prp_mode == 7 || prp_mode == 9) {
> +		param->conf_win_top = crop_right;
> +		param->conf_win_left = crop_bot;
> +		param->conf_win_bot = crop_left;
> +		param->conf_win_right = crop_top;
> +	}
> +}
> +
> +int wave5_vpu_enc_init_seq(struct vpu_instance *inst)
> +{
> +	u32 reg_val = 0, rot_mir_mode, fixed_cu_size_mode = 0x7;
> +	struct enc_info *p_enc_info = &inst->codec_info->enc_info;
> +	struct enc_open_param *p_open_param = &p_enc_info->open_param;
> +	struct enc_wave_param *p_param = &p_open_param->wave_param;
> +	int ret;
> +
> +	if (inst->dev->product != PRODUCT_ID_521)
> +		return -EINVAL;
> +
> +	/*==============================================*/
> +	/* OPT_CUSTOM_GOP */
> +	/*==============================================*/

Comments like these are usually like

	/*
	 * OPT_CUSTOM_GOP
	 *
	 * SET_PARAM + CUSTOM_GOP
	 * only when... blah
	 */

> +	/*
> +	 * SET_PARAM + CUSTOM_GOP
> +	 * only when gop_preset_idx == custom_gop, custom_gop related registers should be set
> +	 */

..snip..

> +}
> diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
> new file mode 100644
> index 000000000000..1b3ffb737925
> --- /dev/null
> +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
> @@ -0,0 +1,1136 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
> +/*
> + * Wave5 series multi-standard codec IP - helper definitions
> + *
> + * Copyright (C) 2021 CHIPS&MEDIA INC
> + */
> +
> +#ifndef VPUAPI_H_INCLUDED
> +#define VPUAPI_H_INCLUDED
> +
> +#include <linux/kfifo.h>
> +#include <linux/idr.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-mem2mem.h>
> +#include <media/v4l2-ctrls.h>
> +#include "wave5-vpuerror.h"
> +#include "wave5-vpuconfig.h"
> +#include "wave5-vdi.h"
> +
> +enum product_id {
> +	PRODUCT_ID_521,
> +	PRODUCT_ID_511,
> +	PRODUCT_ID_517,
> +	PRODUCT_ID_NONE,
> +};
> +
> +struct vpu_attr;
> +
> +enum vpu_instance_type {
> +	VPU_INST_TYPE_DEC = 0,

The default for the first enum entry is always zero, and the next one will always
be 1, 2, 3, 4.....

.....so you don't need to assign any number.

> +	VPU_INST_TYPE_ENC = 1
> +};
> +
> +enum vpu_instance_state {
> +	VPU_INST_STATE_NONE = 0,
> +	VPU_INST_STATE_OPEN = 1,
> +	VPU_INST_STATE_INIT_SEQ = 2,
> +	VPU_INST_STATE_PIC_RUN = 3,
> +	VPU_INST_STATE_STOP = 4

ditto

> +};
> +
> +#define WAVE5_MAX_FBS 32
> +
> +#define MAX_REG_FRAME (WAVE5_MAX_FBS * 2)
> +
> +#define WAVE5_DEC_HEVC_BUF_SIZE(_w, _h) (DIV_ROUND_UP(_w, 64) * DIV_ROUND_UP(_h, 64) * 256 + 64)
> +#define WAVE5_DEC_AVC_BUF_SIZE(_w, _h) ((((ALIGN(_w, 256) / 16) * (ALIGN(_h, 16) / 16)) + 16) * 80)
> +#define WAVE5_DEC_VP9_BUF_SIZE(_w, _h) (((ALIGN(_w, 64) * ALIGN(_h, 64)) >> 2))
> +#define WAVE5_DEC_AVS2_BUF_SIZE(_w, _h) (((ALIGN(_w, 64) * ALIGN(_h, 64)) >> 5))
> +// AV1 BUF SIZE : MFMV + segment ID + CDF probs table + film grain param Y+ film graim param C
> +#define WAVE5_DEC_AV1_BUF_SZ_1(_w, _h)	\
> +	(((ALIGN(_w, 64) / 64) * (ALIGN(_h, 64) / 64) * 512) + 41984 + 8192 + 4864)
> +#define WAVE5_DEC_AV1_BUF_SZ_2(_w1, _w2, _h)	\
> +	(((ALIGN(_w1, 64) / 64) * 256 + (ALIGN(_w2, 256) / 64) * 128) * (ALIGN(_h, 64) / 64))
> +
> +#define WAVE5_FBC_LUMA_TABLE_SIZE(_w, _h) (ALIGN(_h, 64) * ALIGN(_w, 256) / 32)
> +#define WAVE5_FBC_CHROMA_TABLE_SIZE(_w, _h) (ALIGN((_h), 64) * ALIGN((_w) / 2, 256) / 32)
> +#define WAVE5_ENC_AVC_BUF_SIZE(_w, _h) (ALIGN(_w, 64) * ALIGN(_h, 64) / 32)
> +#define WAVE5_ENC_HEVC_BUF_SIZE(_w, _h) (ALIGN(_w, 64) / 64 * ALIGN(_h, 64) / 64 * 128)
> +
> +/*
> + * common struct and definition
> + */
> +enum cod_std {
> +	STD_AVC = 0,
> +	STD_VC1 = 1,
> +	STD_MPEG2 = 2,
> +	STD_MPEG4 = 3,
> +	STD_H263 = 4,
> +	STD_DIV3 = 5,
> +	STD_RV = 6,
> +	STD_AVS = 7,

and same here, so that becomes

	.....
	STD_AVS,
	STD_RESERVED,
	STD_THO,


> +	STD_THO = 9 > +	STD_VP3 = 10,
> +	STD_VP8 = 11,
> +	STD_HEVC = 12,
> +	STD_VP9 = 13,
> +	STD_AVS2 = 14,

STD_RESERVED2, (which will be 15)...

> +	STD_AV1 = 16,
> +	STD_MAX
> +};
> +
> +enum wave_std {
> +	W_HEVC_DEC = 0x00,
> +	W_HEVC_ENC = 0x01,
> +	W_AVC_DEC = 0x02,
> +	W_AVC_ENC = 0x03,
> +	W_VP9_DEC = 0x16,
> +	W_AVS2_DEC = 0x18,
> +	W_AV1_DEC = 0x1A,
> +	STD_UNKNOWN = 0xFF
> +};
> +
> +enum SET_PARAM_OPTION {

Lowercase names for enums please.

> +	OPT_COMMON = 0, /* SET_PARAM command option for encoding sequence */
> +	OPT_CUSTOM_GOP = 1, /* SET_PARAM command option for setting custom GOP */
> +	OPT_CUSTOM_HEADER = 2, /* SET_PARAM command option for setting custom VPS/SPS/PPS */
> +	OPT_VUI = 3, /* SET_PARAM command option for encoding VUI */
> +	OPT_CHANGE_PARAM = 0x10,
> +};
> +
> +enum DEC_PIC_HDR_OPTION {
> +	INIT_SEQ_NORMAL = 0x01,
> +	INIT_SEQ_W_THUMBNAIL = 0x11,
> +};
> +
> +enum DEC_PIC_OPTION {
> +	DEC_PIC_NORMAL = 0x00, /* it is normal mode of DEC_PIC command */
> +	DEC_PIC_W_THUMBNAIL = 0x10, /* thumbnail mode (skip non-IRAP without reference reg) */
> +	SKIP_NON_IRAP = 0x11, /* it skips to decode non-IRAP pictures */
> +	SKIP_NON_REF_PIC = 0x13
> +};
> +


There's probably more, but starting with that is surely something :-)


Regards,
Angelo

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ