diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index da00f5fc0e5d..168f0514851e 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -542,47 +542,30 @@ const struct vpu_core_resources *vpu_get_resource(struct vpu_inst *inst) static int vpu_core_parse_dt(struct vpu_core *core, struct device_node *np) { - struct device_node *node; struct resource res; int ret; - if (of_count_phandle_with_args(np, "memory-region", NULL) < 2) { - dev_err(core->dev, "need 2 memory-region for boot and rpc\n"); - return -ENODEV; + ret = of_reserved_mem_region_to_resource(np, 0, &res); + if (ret) { + dev_err(core->dev, "Cannot get boot-region\n"); + return ret; } - node = of_parse_phandle(np, "memory-region", 0); - if (!node) { - dev_err(core->dev, "boot-region of_parse_phandle error\n"); - return -ENODEV; - } - if (of_address_to_resource(node, 0, &res)) { - dev_err(core->dev, "boot-region of_address_to_resource error\n"); - of_node_put(node); - return -EINVAL; - } core->fw.phys = res.start; core->fw.length = resource_size(&res); - of_node_put(node); - - node = of_parse_phandle(np, "memory-region", 1); - if (!node) { - dev_err(core->dev, "rpc-region of_parse_phandle error\n"); - return -ENODEV; - } - if (of_address_to_resource(node, 0, &res)) { - dev_err(core->dev, "rpc-region of_address_to_resource error\n"); - of_node_put(node); - return -EINVAL; + ret = of_reserved_mem_region_to_resource(np, 1, &res); + if (ret) { + dev_err(core->dev, "Cannot get rpc-region\n"); + return ret; } + core->rpc.phys = res.start; core->rpc.length = resource_size(&res); if (core->rpc.length < core->res->rpc_size + core->res->fwlog_size) { dev_err(core->dev, "the rpc-region <%pad, 0x%x> is not enough\n", &core->rpc.phys, core->rpc.length); - of_node_put(node); return -EINVAL; } @@ -594,7 +577,6 @@ static int vpu_core_parse_dt(struct vpu_core *core, struct device_node *np) if (ret != VPU_CORE_MEMORY_UNCACHED) { dev_err(core->dev, "rpc region<%pad, 0x%x> isn't uncached\n", &core->rpc.phys, core->rpc.length); - of_node_put(node); return -EINVAL; } @@ -606,8 +588,6 @@ static int vpu_core_parse_dt(struct vpu_core *core, struct device_node *np) core->act.length = core->rpc.length - core->res->rpc_size - core->log.length; core->rpc.length = core->res->rpc_size; - of_node_put(node); - return 0; } diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile index fad3be044e5f..2abbd3aeb4af 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -22,6 +22,7 @@ qcom-iris-objs += iris_buffer.o \ iris_venc.o \ iris_vpu2.o \ iris_vpu3x.o \ + iris_vpu4x.o \ iris_vpu_buffer.o \ iris_vpu_common.o \ diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c index 87f929442ec6..3cec957580f5 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -102,6 +102,16 @@ static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) return PROFILE_AV1; case V4L2_CID_MPEG_VIDEO_AV1_LEVEL: return LEVEL_AV1; + case V4L2_CID_ROTATE: + return ROTATION; + case V4L2_CID_HFLIP: + return HFLIP; + case V4L2_CID_VFLIP: + return VFLIP; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: + return IR_TYPE; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: + return IR_PERIOD; default: return INST_FW_CAP_MAX; } @@ -193,6 +203,16 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) return V4L2_CID_MPEG_VIDEO_AV1_PROFILE; case LEVEL_AV1: return V4L2_CID_MPEG_VIDEO_AV1_LEVEL; + case ROTATION: + return V4L2_CID_ROTATE; + case HFLIP: + return V4L2_CID_HFLIP; + case VFLIP: + return V4L2_CID_VFLIP; + case IR_TYPE: + return V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE; + case IR_PERIOD: + return V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD; default: return 0; } @@ -901,6 +921,81 @@ int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap &range, sizeof(range)); } +int iris_set_rotation(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + switch (inst->fw_caps[cap_id].value) { + case 0: + hfi_val = HFI_ROTATION_NONE; + return 0; + case 90: + hfi_val = HFI_ROTATION_90; + break; + case 180: + hfi_val = HFI_ROTATION_180; + break; + case 270: + hfi_val = HFI_ROTATION_270; + break; + default: + return -EINVAL; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &hfi_val, sizeof(u32)); +} + +int iris_set_flip(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val = HFI_DISABLE_FLIP; + + if (inst->fw_caps[HFLIP].value) + hfi_val |= HFI_HORIZONTAL_FLIP; + + if (inst->fw_caps[VFLIP].value) + hfi_val |= HFI_VERTICAL_FLIP; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_val, sizeof(u32)); +} + +int iris_set_ir_period(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + struct vb2_queue *q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + u32 ir_period = inst->fw_caps[cap_id].value; + u32 ir_type = 0; + + if (inst->fw_caps[IR_TYPE].value == + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) { + if (vb2_is_streaming(q)) + return 0; + ir_type = HFI_PROP_IR_RANDOM_PERIOD; + } else if (inst->fw_caps[IR_TYPE].value == + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC) { + ir_type = HFI_PROP_IR_CYCLIC_PERIOD; + } else { + return -EINVAL; + } + + return hfi_ops->session_set_property(inst, ir_type, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &ir_period, sizeof(u32)); +} + int iris_set_properties(struct iris_inst *inst, u32 plane) { const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h index 30af333cc494..9518803577bc 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.h +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h @@ -32,6 +32,9 @@ int iris_set_min_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_i int iris_set_max_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_frame_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_rotation(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_flip(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_ir_period(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_properties(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index fd1d70d1d4d7..7b22c64f91d1 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -25,8 +25,7 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) struct qcom_scm_pas_context *ctx; const struct firmware *firmware = NULL; struct device *dev = core->dev; - struct reserved_mem *rmem; - struct device_node *node; + struct resource res; phys_addr_t mem_phys; size_t res_size; ssize_t fw_size; @@ -36,17 +35,12 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) return -EINVAL; - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!node) - return -EINVAL; - - rmem = of_reserved_mem_lookup(node); - of_node_put(node); - if (!rmem) - return -EINVAL; + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); + if (ret) + return ret; - mem_phys = rmem->base; - res_size = rmem->size; + mem_phys = res.start; + res_size = resource_size(&res); dev = core->fw.dev ? : core->dev; @@ -104,9 +98,9 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) int iris_fw_load(struct iris_core *core) { - struct tz_cp_config *cp_config = core->iris_platform_data->tz_cp_config_data; + const struct tz_cp_config *cp_config; const char *fwpath = NULL; - int ret; + int i, ret; ret = of_property_read_string_index(core->dev->of_node, "firmware-name", 0, &fwpath); @@ -119,14 +113,17 @@ int iris_fw_load(struct iris_core *core) return -ENOMEM; } - ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, - cp_config->cp_size, - cp_config->cp_nonpixel_start, - cp_config->cp_nonpixel_size); - if (ret) { - dev_err(core->dev, "protect memory failed\n"); - iris_fw_unload(core); - return ret; + for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) { + cp_config = &core->iris_platform_data->tz_cp_config_data[i]; + ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, + cp_config->cp_size, + cp_config->cp_nonpixel_start, + cp_config->cp_nonpixel_size); + if (ret) { + dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret); + iris_fw_unload(core); + return ret; + } } return ret; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index ad2c4a7dfed2..715ec9575b90 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -170,8 +170,7 @@ static int iris_hfi_gen2_session_set_property(struct iris_inst *inst, u32 packet static int iris_hfi_gen2_set_raw_resolution(struct iris_inst *inst, u32 plane) { - u32 resolution = inst->fmt_src->fmt.pix_mp.width << 16 | - inst->fmt_src->fmt.pix_mp.height; + u32 resolution = inst->enc_raw_width << 16 | inst->enc_raw_height; u32 port = iris_hfi_gen2_get_port(inst, plane); return iris_hfi_gen2_session_set_property(inst, @@ -183,22 +182,36 @@ static int iris_hfi_gen2_set_raw_resolution(struct iris_inst *inst, u32 plane) sizeof(u32)); } +static inline u32 iris_hfi_get_aligned_resolution(struct iris_inst *inst, u32 width, u32 height) +{ + u32 codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; + + return (ALIGN(width, codec_align) << 16 | ALIGN(height, codec_align)); +} + static int iris_hfi_gen2_set_bitstream_resolution(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); u32 port = iris_hfi_gen2_get_port(inst, plane); enum hfi_packet_payload_info payload_type; - u32 resolution, codec_align; + u32 width, height; + u32 resolution; if (inst->domain == DECODER) { - resolution = inst->fmt_src->fmt.pix_mp.width << 16 | - inst->fmt_src->fmt.pix_mp.height; + width = inst->fmt_src->fmt.pix_mp.width; + height = inst->fmt_src->fmt.pix_mp.height; + resolution = iris_hfi_get_aligned_resolution(inst, width, height); inst_hfi_gen2->src_subcr_params.bitstream_resolution = resolution; payload_type = HFI_PAYLOAD_U32; } else { - codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; - resolution = ALIGN(inst->fmt_dst->fmt.pix_mp.width, codec_align) << 16 | - ALIGN(inst->fmt_dst->fmt.pix_mp.height, codec_align); + if (is_rotation_90_or_270(inst)) { + width = inst->enc_scale_height; + height = inst->enc_scale_width; + } else { + width = inst->enc_scale_width; + height = inst->enc_scale_height; + } + resolution = iris_hfi_get_aligned_resolution(inst, width, height); inst_hfi_gen2->dst_subcr_params.bitstream_resolution = resolution; payload_type = HFI_PAYLOAD_32_PACKED; } @@ -218,7 +231,7 @@ static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst, u32 plane) u32 port = iris_hfi_gen2_get_port(inst, plane); u32 bottom_offset, right_offset; u32 left_offset, top_offset; - u32 payload[2]; + u32 payload[2], codec_align; if (inst->domain == DECODER) { if (V4L2_TYPE_IS_OUTPUT(plane)) { @@ -233,10 +246,27 @@ static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst, u32 plane) top_offset = inst->compose.top; } } else { - bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height); - right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width); - left_offset = inst->crop.left; - top_offset = inst->crop.top; + codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + bottom_offset = (inst->enc_raw_height - inst->crop.height); + right_offset = (inst->enc_raw_width - inst->crop.width); + left_offset = inst->crop.left; + top_offset = inst->crop.top; + } else { + if (is_rotation_90_or_270(inst)) { + bottom_offset = (ALIGN(inst->enc_scale_width, codec_align) - + inst->enc_scale_width); + right_offset = (ALIGN(inst->enc_scale_height, codec_align) - + inst->enc_scale_height); + } else { + bottom_offset = (ALIGN(inst->enc_scale_height, codec_align) - + inst->enc_scale_height); + right_offset = (ALIGN(inst->enc_scale_width, codec_align) - + inst->enc_scale_width); + } + left_offset = 0; + top_offset = 0; + } } payload[0] = FIELD_PREP(GENMASK(31, 16), left_offset) | top_offset; @@ -813,7 +843,7 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan if ((V4L2_TYPE_IS_OUTPUT(plane) && inst_hfi_gen2->ipsc_properties_set) || (V4L2_TYPE_IS_CAPTURE(plane) && inst_hfi_gen2->opsc_properties_set)) { - dev_err(core->dev, "invalid plane\n"); + dev_dbg(core->dev, "%cPSC already set\n", V4L2_TYPE_IS_OUTPUT(plane) ? 'I' : 'O'); return 0; } @@ -1296,5 +1326,10 @@ void iris_hfi_gen2_command_ops_init(struct iris_core *core) struct iris_inst *iris_hfi_gen2_get_instance(void) { - return kzalloc(sizeof(struct iris_inst_hfi_gen2), GFP_KERNEL); + struct iris_inst_hfi_gen2 *out; + + /* The allocation is intentionally larger than struct iris_inst. */ + out = kzalloc(sizeof(*out), GFP_KERNEL); + + return &out->inst; } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 5f1f1a7eb91f..cecf771c55dd 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -70,6 +70,7 @@ enum hfi_rate_control { #define HFI_PROP_QP_PACKED 0x0300012e #define HFI_PROP_MIN_QP_PACKED 0x0300012f #define HFI_PROP_MAX_QP_PACKED 0x03000130 +#define HFI_PROP_IR_RANDOM_PERIOD 0x03000131 #define HFI_PROP_TOTAL_BITRATE 0x0300013b #define HFI_PROP_MAX_GOP_FRAMES 0x03000146 #define HFI_PROP_MAX_B_FRAMES 0x03000147 @@ -83,6 +84,23 @@ enum hfi_seq_header_mode { }; #define HFI_PROP_SEQ_HEADER_MODE 0x03000149 + +enum hfi_rotation { + HFI_ROTATION_NONE = 0x00000000, + HFI_ROTATION_90 = 0x00000001, + HFI_ROTATION_180 = 0x00000002, + HFI_ROTATION_270 = 0x00000003, +}; + +#define HFI_PROP_ROTATION 0x0300014b + +enum hfi_flip { + HFI_DISABLE_FLIP = 0x00000000, + HFI_HORIZONTAL_FLIP = 0x00000001, + HFI_VERTICAL_FLIP = 0x00000002, +}; + +#define HFI_PROP_FLIP 0x0300014c #define HFI_PROP_SIGNAL_COLOR_INFO 0x03000155 #define HFI_PROP_PICTURE_TYPE 0x03000162 #define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 @@ -96,6 +114,7 @@ enum hfi_seq_header_mode { #define HFI_PROP_AV1_FILM_GRAIN_PRESENT 0x03000180 #define HFI_PROP_AV1_SUPER_BLOCK_ENABLED 0x03000181 #define HFI_PROP_AV1_OP_POINT 0x03000182 +#define HFI_PROP_IR_CYCLIC_PERIOD 0x0300017E #define HFI_PROP_OPB_ENABLE 0x03000184 #define HFI_PROP_AV1_TILE_ROWS_COLUMNS 0x03000187 #define HFI_PROP_AV1_DRAP_CONFIG 0x03000189 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c index eb3373f0ad4a..8e19f61bbbf9 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c @@ -56,6 +56,8 @@ static u32 iris_hfi_gen2_buf_type_to_driver(struct iris_inst *inst, return BUF_PERSIST; case HFI_BUFFER_PARTIAL_DATA: return BUF_PARTIAL; + case HFI_BUFFER_VPSS: + return BUF_VPSS; default: return 0; } diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h index 7e4f5f1dd892..16965150f427 100644 --- a/drivers/media/platform/qcom/iris/iris_instance.h +++ b/drivers/media/platform/qcom/iris/iris_instance.h @@ -70,6 +70,10 @@ struct iris_fmt { * @frame_rate: frame rate of current instance * @operating_rate: operating rate of current instance * @hfi_rc_type: rate control type + * @enc_raw_width: source image width for encoder instance + * @enc_raw_height: source image height for encoder instance + * @enc_scale_width: scale width for encoder instance + * @enc_scale_height: scale height for encoder instance */ struct iris_inst { @@ -108,6 +112,10 @@ struct iris_inst { u32 frame_rate; u32 operating_rate; u32 hfi_rc_type; + u32 enc_raw_width; + u32 enc_raw_height; + u32 enc_scale_width; + u32 enc_scale_height; }; #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index 14a2f4dbe38a..5a489917580e 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -57,6 +57,10 @@ enum platform_clk_type { IRIS_AXI1_CLK, IRIS_CTRL_FREERUN_CLK, IRIS_HW_FREERUN_CLK, + IRIS_BSE_HW_CLK, + IRIS_VPP0_HW_CLK, + IRIS_VPP1_HW_CLK, + IRIS_APV_HW_CLK, }; struct platform_clk_data { @@ -150,6 +154,11 @@ enum platform_inst_fw_cap_type { P_FRAME_QP_HEVC, B_FRAME_QP_H264, B_FRAME_QP_HEVC, + ROTATION, + HFLIP, + VFLIP, + IR_TYPE, + IR_PERIOD, INST_FW_CAP_MAX, }; @@ -198,6 +207,9 @@ struct icc_vote_data { enum platform_pm_domain_type { IRIS_CTRL_POWER_DOMAIN, IRIS_HW_POWER_DOMAIN, + IRIS_VPP0_HW_POWER_DOMAIN, + IRIS_VPP1_HW_POWER_DOMAIN, + IRIS_APV_HW_POWER_DOMAIN, }; struct iris_platform_data { @@ -216,6 +228,7 @@ struct iris_platform_data { const char * const *opp_pd_tbl; unsigned int opp_pd_tbl_size; const struct platform_clk_data *clk_tbl; + const char * const *opp_clk_tbl; unsigned int clk_tbl_size; const char * const *clk_rst_tbl; unsigned int clk_rst_tbl_size; @@ -231,7 +244,8 @@ struct iris_platform_data { u32 inst_fw_caps_dec_size; const struct platform_inst_fw_cap *inst_fw_caps_enc; u32 inst_fw_caps_enc_size; - struct tz_cp_config *tz_cp_config_data; + const struct tz_cp_config *tz_cp_config_data; + u32 tz_cp_config_data_size; u32 core_arch; u32 hw_response_timeout; struct ubwc_config_data *ubwc_config; diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen1.c b/drivers/media/platform/qcom/iris/iris_platform_gen1.c index 712515b0f329..df8e6bf9430e 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen1.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen1.c @@ -289,11 +289,18 @@ static const struct platform_clk_data sm8250_clk_table[] = { {IRIS_HW_CLK, "vcodec0_core" }, }; -static struct tz_cp_config tz_cp_config_sm8250 = { - .cp_start = 0, - .cp_size = 0x25800000, - .cp_nonpixel_start = 0x01000000, - .cp_nonpixel_size = 0x24800000, +static const char * const sm8250_opp_clk_table[] = { + "vcodec0_core", + NULL, +}; + +static const struct tz_cp_config tz_cp_config_sm8250[] = { + { + .cp_start = 0, + .cp_size = 0x25800000, + .cp_nonpixel_start = 0x01000000, + .cp_nonpixel_size = 0x24800000, + }, }; static const u32 sm8250_vdec_input_config_param_default[] = { @@ -349,6 +356,7 @@ const struct iris_platform_data sm8250_data = { .opp_pd_tbl_size = ARRAY_SIZE(sm8250_opp_pd_table), .clk_tbl = sm8250_clk_table, .clk_tbl_size = ARRAY_SIZE(sm8250_clk_table), + .opp_clk_tbl = sm8250_opp_clk_table, /* Upper bound of DMA address range */ .dma_mask = 0xe0000000 - 1, .fwname = "qcom/vpu-1.0/venus.mbn", @@ -360,7 +368,8 @@ const struct iris_platform_data sm8250_data = { .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8250_dec), .inst_fw_caps_enc = inst_fw_cap_sm8250_enc, .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8250_enc), - .tz_cp_config_data = &tz_cp_config_sm8250, + .tz_cp_config_data = tz_cp_config_sm8250, + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_sm8250), .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .num_vpp_pipe = 4, .max_session_count = 16, @@ -400,6 +409,7 @@ const struct iris_platform_data sc7280_data = { .opp_pd_tbl_size = ARRAY_SIZE(sc7280_opp_pd_table), .clk_tbl = sc7280_clk_table, .clk_tbl_size = ARRAY_SIZE(sc7280_clk_table), + .opp_clk_tbl = sc7280_opp_clk_table, /* Upper bound of DMA address range */ .dma_mask = 0xe0000000 - 1, .fwname = "qcom/vpu/vpu20_p1.mbn", @@ -411,7 +421,8 @@ const struct iris_platform_data sc7280_data = { .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8250_dec), .inst_fw_caps_enc = inst_fw_cap_sm8250_enc, .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8250_enc), - .tz_cp_config_data = &tz_cp_config_sm8250, + .tz_cp_config_data = tz_cp_config_sm8250, + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_sm8250), .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .num_vpp_pipe = 1, .no_aon = true, diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index c932dc026616..5da90d47f9c6 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -689,6 +689,57 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { .flags = CAP_FLAG_OUTPUT_PORT, .set = iris_set_u32, }, + { + .cap_id = ROTATION, + .min = 0, + .max = 270, + .step_or_mask = 90, + .value = 0, + .hfi_id = HFI_PROP_ROTATION, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_rotation, + }, + { + .cap_id = HFLIP, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_FLIP, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_flip, + }, + { + .cap_id = VFLIP, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_FLIP, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_flip, + }, + { + .cap_id = IR_TYPE, + .min = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + .max = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC, + .step_or_mask = BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) | + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC), + .value = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = IR_PERIOD, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 0, + .flags = CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_ir_period, + }, }; static struct platform_inst_caps platform_inst_cap_sm8550 = { @@ -734,6 +785,11 @@ static const struct platform_clk_data sm8550_clk_table[] = { {IRIS_HW_CLK, "vcodec0_core" }, }; +static const char * const sm8550_opp_clk_table[] = { + "vcodec0_core", + NULL, +}; + static struct ubwc_config_data ubwc_config_sm8550 = { .max_channels = 8, .mal_length = 32, @@ -744,11 +800,13 @@ static struct ubwc_config_data ubwc_config_sm8550 = { .bank_spreading = 1, }; -static struct tz_cp_config tz_cp_config_sm8550 = { - .cp_start = 0, - .cp_size = 0x25800000, - .cp_nonpixel_start = 0x01000000, - .cp_nonpixel_size = 0x24800000, +static const struct tz_cp_config tz_cp_config_sm8550[] = { + { + .cp_start = 0, + .cp_size = 0x25800000, + .cp_nonpixel_start = 0x01000000, + .cp_nonpixel_size = 0x24800000, + }, }; static const u32 sm8550_vdec_input_config_params_default[] = { @@ -851,6 +909,10 @@ static const u32 sm8550_dec_op_int_buf_tbl[] = { BUF_DPB, }; +static const u32 sm8550_enc_ip_int_buf_tbl[] = { + BUF_VPSS, +}; + static const u32 sm8550_enc_op_int_buf_tbl[] = { BUF_BIN, BUF_COMV, @@ -878,6 +940,7 @@ const struct iris_platform_data sm8550_data = { .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), .clk_tbl = sm8550_clk_table, .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), + .opp_clk_tbl = sm8550_opp_clk_table, /* Upper bound of DMA address range */ .dma_mask = 0xe0000000 - 1, .fwname = "qcom/vpu/vpu30_p4.mbn", @@ -889,7 +952,8 @@ const struct iris_platform_data sm8550_data = { .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), - .tz_cp_config_data = &tz_cp_config_sm8550, + .tz_cp_config_data = tz_cp_config_sm8550, + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_sm8550), .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .ubwc_config = &ubwc_config_sm8550, @@ -947,6 +1011,8 @@ const struct iris_platform_data sm8550_data = { .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + .enc_ip_int_buf_tbl = sm8550_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_ip_int_buf_tbl), .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; @@ -979,6 +1045,7 @@ const struct iris_platform_data sm8650_data = { .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), .clk_tbl = sm8550_clk_table, .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), + .opp_clk_tbl = sm8550_opp_clk_table, /* Upper bound of DMA address range */ .dma_mask = 0xe0000000 - 1, .fwname = "qcom/vpu/vpu33_p4.mbn", @@ -990,7 +1057,8 @@ const struct iris_platform_data sm8650_data = { .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), - .tz_cp_config_data = &tz_cp_config_sm8550, + .tz_cp_config_data = tz_cp_config_sm8550, + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_sm8550), .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .ubwc_config = &ubwc_config_sm8550, @@ -1048,6 +1116,8 @@ const struct iris_platform_data sm8650_data = { .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + .enc_ip_int_buf_tbl = sm8550_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_ip_int_buf_tbl), .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; @@ -1071,6 +1141,7 @@ const struct iris_platform_data sm8750_data = { .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), .clk_tbl = sm8750_clk_table, .clk_tbl_size = ARRAY_SIZE(sm8750_clk_table), + .opp_clk_tbl = sm8550_opp_clk_table, /* Upper bound of DMA address range */ .dma_mask = 0xe0000000 - 1, .fwname = "qcom/vpu/vpu35_p4.mbn", @@ -1082,7 +1153,8 @@ const struct iris_platform_data sm8750_data = { .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), - .tz_cp_config_data = &tz_cp_config_sm8550, + .tz_cp_config_data = tz_cp_config_sm8550, + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_sm8550), .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .ubwc_config = &ubwc_config_sm8550, @@ -1140,6 +1212,8 @@ const struct iris_platform_data sm8750_data = { .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + .enc_ip_int_buf_tbl = sm8550_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_ip_int_buf_tbl), .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; @@ -1167,6 +1241,7 @@ const struct iris_platform_data qcs8300_data = { .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), .clk_tbl = sm8550_clk_table, .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), + .opp_clk_tbl = sm8550_opp_clk_table, /* Upper bound of DMA address range */ .dma_mask = 0xe0000000 - 1, .fwname = "qcom/vpu/vpu30_p4_s6.mbn", @@ -1178,7 +1253,8 @@ const struct iris_platform_data qcs8300_data = { .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), - .tz_cp_config_data = &tz_cp_config_sm8550, + .tz_cp_config_data = tz_cp_config_sm8550, + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_sm8550), .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .ubwc_config = &ubwc_config_sm8550, @@ -1236,6 +1312,8 @@ const struct iris_platform_data qcs8300_data = { .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + .enc_ip_int_buf_tbl = sm8550_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_ip_int_buf_tbl), .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; diff --git a/drivers/media/platform/qcom/iris/iris_platform_sc7280.h b/drivers/media/platform/qcom/iris/iris_platform_sc7280.h index f1bef4d4bcfe..0ec8f334df67 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_sc7280.h +++ b/drivers/media/platform/qcom/iris/iris_platform_sc7280.h @@ -23,4 +23,9 @@ static const struct platform_clk_data sc7280_clk_table[] = { {IRIS_HW_AHB_CLK, "vcodec_bus" }, }; +static const char * const sc7280_opp_clk_table[] = { + "vcodec_core", + NULL, +}; + #endif diff --git a/drivers/media/platform/qcom/iris/iris_power.c b/drivers/media/platform/qcom/iris/iris_power.c index dbca42df0910..91aa21d4070e 100644 --- a/drivers/media/platform/qcom/iris/iris_power.c +++ b/drivers/media/platform/qcom/iris/iris_power.c @@ -91,7 +91,7 @@ static int iris_set_clocks(struct iris_inst *inst) } core->power.clk_freq = freq; - ret = dev_pm_opp_set_rate(core->dev, freq); + ret = iris_opp_set_rate(core->dev, freq); mutex_unlock(&core->lock); return ret; diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index 9bc9b34c2576..ddaacda523ec 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -40,8 +40,6 @@ static int iris_init_icc(struct iris_core *core) static int iris_init_power_domains(struct iris_core *core) { - const struct platform_clk_data *clk_tbl; - u32 clk_cnt, i; int ret; struct dev_pm_domain_attach_data iris_pd_data = { @@ -56,6 +54,11 @@ static int iris_init_power_domains(struct iris_core *core) .pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP, }; + struct dev_pm_opp_config iris_opp_clk_data = { + .clk_names = core->iris_platform_data->opp_clk_tbl, + .config_clks = dev_pm_opp_config_clks_simple, + }; + ret = devm_pm_domain_attach_list(core->dev, &iris_pd_data, &core->pmdomain_tbl); if (ret < 0) return ret; @@ -64,16 +67,9 @@ static int iris_init_power_domains(struct iris_core *core) if (ret < 0) return ret; - clk_tbl = core->iris_platform_data->clk_tbl; - clk_cnt = core->iris_platform_data->clk_tbl_size; - - for (i = 0; i < clk_cnt; i++) { - if (clk_tbl[i].clk_type == IRIS_HW_CLK) { - ret = devm_pm_opp_set_clkname(core->dev, clk_tbl[i].clk_name); - if (ret) - return ret; - } - } + ret = devm_pm_opp_set_config(core->dev, &iris_opp_clk_data); + if (ret) + return ret; return devm_pm_opp_of_add_table(core->dev); } diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c index 164490c49c95..773f6548370a 100644 --- a/drivers/media/platform/qcom/iris/iris_resources.c +++ b/drivers/media/platform/qcom/iris/iris_resources.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -58,11 +59,22 @@ int iris_unset_icc_bw(struct iris_core *core) return icc_bulk_set_bw(core->icc_count, core->icc_tbl); } +int iris_opp_set_rate(struct device *dev, unsigned long freq) +{ + struct dev_pm_opp *opp __free(put_opp); + + opp = devfreq_recommended_opp(dev, &freq, 0); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + return dev_pm_opp_set_opp(dev, opp); +} + int iris_enable_power_domains(struct iris_core *core, struct device *pd_dev) { int ret; - ret = dev_pm_opp_set_rate(core->dev, ULONG_MAX); + ret = iris_opp_set_rate(core->dev, ULONG_MAX); if (ret) return ret; @@ -77,7 +89,7 @@ int iris_disable_power_domains(struct iris_core *core, struct device *pd_dev) { int ret; - ret = dev_pm_opp_set_rate(core->dev, 0); + ret = iris_opp_set_rate(core->dev, 0); if (ret) return ret; diff --git a/drivers/media/platform/qcom/iris/iris_resources.h b/drivers/media/platform/qcom/iris/iris_resources.h index f723dfe5bd81..6bfbd2dc6db0 100644 --- a/drivers/media/platform/qcom/iris/iris_resources.h +++ b/drivers/media/platform/qcom/iris/iris_resources.h @@ -8,6 +8,7 @@ struct iris_core; +int iris_opp_set_rate(struct device *dev, unsigned long freq); int iris_enable_power_domains(struct iris_core *core, struct device *pd_dev); int iris_disable_power_domains(struct iris_core *core, struct device *pd_dev); int iris_unset_icc_bw(struct iris_core *core); diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c index e2f1131de431..cfc5b576ec56 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.c +++ b/drivers/media/platform/qcom/iris/iris_utils.c @@ -125,3 +125,9 @@ int iris_check_core_mbps(struct iris_inst *inst) return 0; } + +bool is_rotation_90_or_270(struct iris_inst *inst) +{ + return inst->fw_caps[ROTATION].value == 90 || + inst->fw_caps[ROTATION].value == 270; +} diff --git a/drivers/media/platform/qcom/iris/iris_utils.h b/drivers/media/platform/qcom/iris/iris_utils.h index 75740181122f..b5705d156431 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.h +++ b/drivers/media/platform/qcom/iris/iris_utils.h @@ -51,5 +51,6 @@ void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush); int iris_check_core_mbpf(struct iris_inst *inst); int iris_check_core_mbps(struct iris_inst *inst); +bool is_rotation_90_or_270(struct iris_inst *inst); #endif diff --git a/drivers/media/platform/qcom/iris/iris_venc.c b/drivers/media/platform/qcom/iris/iris_venc.c index f34bdae8b60f..13394f87b833 100644 --- a/drivers/media/platform/qcom/iris/iris_venc.c +++ b/drivers/media/platform/qcom/iris/iris_venc.c @@ -62,12 +62,17 @@ int iris_venc_inst_init(struct iris_inst *inst) inst->crop.left = 0; inst->crop.top = 0; - inst->crop.width = f->fmt.pix_mp.width; - inst->crop.height = f->fmt.pix_mp.height; + inst->crop.width = DEFAULT_WIDTH; + inst->crop.height = DEFAULT_HEIGHT; inst->operating_rate = DEFAULT_FPS; inst->frame_rate = DEFAULT_FPS; + inst->enc_raw_width = DEFAULT_WIDTH; + inst->enc_raw_height = DEFAULT_HEIGHT; + inst->enc_scale_width = DEFAULT_WIDTH; + inst->enc_scale_height = DEFAULT_HEIGHT; + memcpy(&inst->fw_caps[0], &core->inst_fw_caps_enc[0], INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); @@ -223,15 +228,32 @@ int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f) static int iris_venc_s_fmt_output(struct iris_inst *inst, struct v4l2_format *f) { + const struct iris_fmt *venc_fmt; struct v4l2_format *fmt; + u32 codec_align; iris_venc_try_fmt(inst, f); - if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) + venc_fmt = find_format(inst, f->fmt.pix_mp.pixelformat, f->type); + if (!venc_fmt) return -EINVAL; + codec_align = venc_fmt->pixfmt == V4L2_PIX_FMT_HEVC ? 32 : 16; + fmt = inst->fmt_dst; fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + /* + * If output format size != input format size, + * it is considered a scaling case, + * and the scaled size needs to be saved. + */ + if (f->fmt.pix_mp.width != inst->fmt_src->fmt.pix_mp.width || + f->fmt.pix_mp.height != inst->fmt_src->fmt.pix_mp.height) { + inst->enc_scale_width = f->fmt.pix_mp.width; + inst->enc_scale_height = f->fmt.pix_mp.height; + fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align); + fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align); + } fmt->fmt.pix_mp.num_planes = 1; fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0; fmt->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); @@ -287,6 +309,11 @@ static int iris_venc_s_fmt_input(struct iris_inst *inst, struct v4l2_format *f) inst->buffers[BUF_INPUT].min_count = iris_vpu_buf_count(inst, BUF_INPUT); inst->buffers[BUF_INPUT].size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + inst->enc_raw_width = f->fmt.pix_mp.width; + inst->enc_raw_height = f->fmt.pix_mp.height; + inst->enc_scale_width = f->fmt.pix_mp.width; + inst->enc_scale_height = f->fmt.pix_mp.height; + if (f->fmt.pix_mp.width != inst->crop.width || f->fmt.pix_mp.height != inst->crop.height) { inst->crop.top = 0; diff --git a/drivers/media/platform/qcom/iris/iris_vpu3x.c b/drivers/media/platform/qcom/iris/iris_vpu3x.c index 339776a0b467..fe4423b951b1 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu3x.c +++ b/drivers/media/platform/qcom/iris/iris_vpu3x.c @@ -11,55 +11,11 @@ #include "iris_vpu_common.h" #include "iris_vpu_register_defines.h" -#define WRAPPER_TZ_BASE_OFFS 0x000C0000 -#define AON_BASE_OFFS 0x000E0000 -#define AON_MVP_NOC_RESET 0x0001F000 - -#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x54) -#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS (WRAPPER_BASE_OFFS + 0x58) -#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x5C) -#define REQ_POWER_DOWN_PREP BIT(0) -#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS + 0x60) -#define NOC_LPI_STATUS_DONE BIT(0) /* Indicates the NOC handshake is complete */ -#define NOC_LPI_STATUS_DENY BIT(1) /* Indicates the NOC handshake is denied */ -#define NOC_LPI_STATUS_ACTIVE BIT(2) /* Indicates the NOC is active */ -#define WRAPPER_CORE_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x88) -#define CORE_CLK_RUN 0x0 -/* VPU v3.5 */ -#define WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0 (WRAPPER_BASE_OFFS + 0x78) - -#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) -#define CTL_AXI_CLK_HALT BIT(0) -#define CTL_CLK_HALT BIT(1) - -#define WRAPPER_TZ_QNS4PDXFIFO_RESET (WRAPPER_TZ_BASE_OFFS + 0x18) -#define RESET_HIGH BIT(0) - -#define CPU_CS_AHB_BRIDGE_SYNC_RESET (CPU_CS_BASE_OFFS + 0x160) -#define CORE_BRIDGE_SW_RESET BIT(0) -#define CORE_BRIDGE_HW_RESET_DISABLE BIT(1) - -#define CPU_CS_X2RPMH (CPU_CS_BASE_OFFS + 0x168) -#define MSK_SIGNAL_FROM_TENSILICA BIT(0) -#define MSK_CORE_POWER_ON BIT(1) - -#define AON_WRAPPER_MVP_NOC_RESET_REQ (AON_MVP_NOC_RESET + 0x000) -#define VIDEO_NOC_RESET_REQ (BIT(0) | BIT(1)) - -#define AON_WRAPPER_MVP_NOC_RESET_ACK (AON_MVP_NOC_RESET + 0x004) - -#define VCODEC_SS_IDLE_STATUSN (VCODEC_BASE_OFFS + 0x70) - -#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) -#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) - #define AON_WRAPPER_MVP_NOC_CORE_SW_RESET (AON_BASE_OFFS + 0x18) #define SW_RESET BIT(0) #define AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL (AON_BASE_OFFS + 0x20) #define NOC_HALT BIT(0) #define AON_WRAPPER_SPARE (AON_BASE_OFFS + 0x28) -#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL (AON_BASE_OFFS + 0x2C) -#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS (AON_BASE_OFFS + 0x30) static bool iris_vpu3x_hw_power_collapsed(struct iris_core *core) { @@ -304,155 +260,12 @@ static void iris_vpu35_power_off_hw(struct iris_core *core) iris_disable_unprepare_clock(core, IRIS_AXI_CLK); } -static int iris_vpu35_power_off_controller(struct iris_core *core) -{ - u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; - unsigned int count = 0; - u32 val = 0; - bool handshake_done, handshake_busy; - int ret; - - writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); - - writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); - - ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; - - writel(0, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); - - /* Retry up to 1000 times as recommended by hardware documentation */ - do { - /* set MNoC to low power */ - writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - - udelay(15); - - val = readl(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS); - - handshake_done = val & NOC_LPI_STATUS_DONE; - handshake_busy = val & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); - - if (handshake_done || !handshake_busy) - break; - - writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - - udelay(15); - - } while (++count < 1000); - - if (!handshake_done && handshake_busy) - dev_err(core->dev, "LPI handshake timeout\n"); - - ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; - - writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - - writel(0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); - - ret = readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, - val, val == 0, 200, 2000); - if (ret) - goto disable_power; - -disable_power: - iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); - iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); - iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); - - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - - reset_control_bulk_reset(clk_rst_tbl_size, core->resets); - - return 0; -} - -static int iris_vpu35_power_on_controller(struct iris_core *core) -{ - int ret; - - ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - if (ret) - return ret; - - ret = iris_prepare_enable_clock(core, IRIS_AXI1_CLK); - if (ret) - goto err_disable_power; - - ret = iris_prepare_enable_clock(core, IRIS_CTRL_FREERUN_CLK); - if (ret) - goto err_disable_axi1_clk; - - ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); - if (ret) - goto err_disable_ctrl_free_clk; - - return 0; - -err_disable_ctrl_free_clk: - iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); -err_disable_axi1_clk: - iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); -err_disable_power: - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - - return ret; -} - -static void iris_vpu35_program_bootup_registers(struct iris_core *core) -{ - writel(0x1, core->reg_base + WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0); -} - -static u64 iris_vpu3x_calculate_frequency(struct iris_inst *inst, size_t data_size) -{ - struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; - struct v4l2_format *inp_f = inst->fmt_src; - u32 height, width, mbs_per_second, mbpf; - u64 fw_cycles, fw_vpp_cycles; - u64 vsp_cycles, vpp_cycles; - u32 fps = DEFAULT_FPS; - - width = max(inp_f->fmt.pix_mp.width, inst->crop.width); - height = max(inp_f->fmt.pix_mp.height, inst->crop.height); - - mbpf = NUM_MBS_PER_FRAME(height, width); - mbs_per_second = mbpf * fps; - - fw_cycles = fps * caps->mb_cycles_fw; - fw_vpp_cycles = fps * caps->mb_cycles_fw_vpp; - - vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value); - /* 21 / 20 is minimum overhead factor */ - vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); - - /* 1.059 is multi-pipe overhead */ - if (inst->fw_caps[PIPE].value > 1) - vpp_cycles += div_u64(vpp_cycles * 59, 1000); - - vsp_cycles = fps * data_size * 8; - vsp_cycles = div_u64(vsp_cycles, 2); - /* VSP FW overhead 1.05 */ - vsp_cycles = div_u64(vsp_cycles * 21, 20); - - if (inst->fw_caps[STAGE].value == STAGE_1) - vsp_cycles = vsp_cycles * 3; - - return max3(vpp_cycles, vsp_cycles, fw_cycles); -} - const struct vpu_ops iris_vpu3_ops = { .power_off_hw = iris_vpu3_power_off_hardware, .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu_power_off_controller, .power_on_controller = iris_vpu_power_on_controller, - .calc_freq = iris_vpu3x_calculate_frequency, + .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, }; const struct vpu_ops iris_vpu33_ops = { @@ -460,14 +273,14 @@ const struct vpu_ops iris_vpu33_ops = { .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu33_power_off_controller, .power_on_controller = iris_vpu_power_on_controller, - .calc_freq = iris_vpu3x_calculate_frequency, + .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, }; const struct vpu_ops iris_vpu35_ops = { .power_off_hw = iris_vpu35_power_off_hw, .power_on_hw = iris_vpu35_power_on_hw, - .power_off_controller = iris_vpu35_power_off_controller, - .power_on_controller = iris_vpu35_power_on_controller, - .program_bootup_registers = iris_vpu35_program_bootup_registers, - .calc_freq = iris_vpu3x_calculate_frequency, + .power_off_controller = iris_vpu35_vpu4x_power_off_controller, + .power_on_controller = iris_vpu35_vpu4x_power_on_controller, + .program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers, + .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, }; diff --git a/drivers/media/platform/qcom/iris/iris_vpu4x.c b/drivers/media/platform/qcom/iris/iris_vpu4x.c new file mode 100644 index 000000000000..a8db02ce5c5e --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_vpu4x.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include "iris_instance.h" +#include "iris_vpu_common.h" +#include "iris_vpu_register_defines.h" + +#define AON_WRAPPER_MVP_NOC_RESET_SYNCRST (AON_MVP_NOC_RESET + 0x08) +#define CPU_CS_APV_BRIDGE_SYNC_RESET (CPU_BASE_OFFS + 0x174) +#define MVP_NOC_RESET_REQ_MASK 0x70103 +#define VPU_IDLE_BITS 0x7103 +#define WRAPPER_EFUSE_MONITOR (WRAPPER_BASE_OFFS + 0x08) + +#define APV_CLK_HALT BIT(1) +#define CORE_CLK_HALT BIT(0) +#define CORE_PWR_ON BIT(1) +#define DISABLE_VIDEO_APV_BIT BIT(27) +#define DISABLE_VIDEO_VPP1_BIT BIT(28) +#define DISABLE_VIDEO_VPP0_BIT BIT(29) + +static int iris_vpu4x_genpd_set_hwmode(struct iris_core *core, bool hw_mode, u32 efuse_value) +{ + int ret; + + ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], hw_mode); + if (ret) + return ret; + + if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) { + ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs + [IRIS_VPP0_HW_POWER_DOMAIN], hw_mode); + if (ret) + goto restore_hw_domain_mode; + } + + if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) { + ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs + [IRIS_VPP1_HW_POWER_DOMAIN], hw_mode); + if (ret) + goto restore_vpp0_domain_mode; + } + + if (!(efuse_value & DISABLE_VIDEO_APV_BIT)) { + ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs + [IRIS_APV_HW_POWER_DOMAIN], hw_mode); + if (ret) + goto restore_vpp1_domain_mode; + } + + return 0; + +restore_vpp1_domain_mode: + if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) + dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_VPP1_HW_POWER_DOMAIN], + !hw_mode); +restore_vpp0_domain_mode: + if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) + dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_VPP0_HW_POWER_DOMAIN], + !hw_mode); +restore_hw_domain_mode: + dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], !hw_mode); + + return ret; +} + +static int iris_vpu4x_power_on_apv(struct iris_core *core) +{ + int ret; + + ret = iris_enable_power_domains(core, + core->pmdomain_tbl->pd_devs[IRIS_APV_HW_POWER_DOMAIN]); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_APV_HW_CLK); + if (ret) + goto disable_apv_hw_power_domain; + + return 0; + +disable_apv_hw_power_domain: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_APV_HW_POWER_DOMAIN]); + + return ret; +} + +static void iris_vpu4x_power_off_apv(struct iris_core *core) +{ + bool handshake_done, handshake_busy; + u32 value, count = 0; + int ret; + + value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + + if (value & APV_CLK_HALT) + writel(0x0, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + + do { + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + usleep_range(10, 20); + value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS); + + handshake_done = value & NOC_LPI_STATUS_DONE; + handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); + + if (handshake_done || !handshake_busy) + break; + + writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + usleep_range(10, 20); + + } while (++count < 1000); + + if (!handshake_done && handshake_busy) + dev_err(core->dev, "LPI handshake timeout\n"); + + writel(0x080200, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, + value, value & 0x080200, 200, 2000); + if (ret) + goto disable_clocks_and_power; + + writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_SYNCRST); + writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, + value, value == 0x0, 200, 2000); + if (ret) + goto disable_clocks_and_power; + + writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + + CPU_CS_APV_BRIDGE_SYNC_RESET); + writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_APV_BRIDGE_SYNC_RESET); + writel(0x0, core->reg_base + CPU_CS_APV_BRIDGE_SYNC_RESET); + +disable_clocks_and_power: + iris_disable_unprepare_clock(core, IRIS_APV_HW_CLK); + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_APV_HW_POWER_DOMAIN]); +} + +static void iris_vpu4x_ahb_sync_reset_apv(struct iris_core *core) +{ + writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + + CPU_CS_APV_BRIDGE_SYNC_RESET); + writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_APV_BRIDGE_SYNC_RESET); + writel(0x0, core->reg_base + CPU_CS_APV_BRIDGE_SYNC_RESET); +} + +static void iris_vpu4x_ahb_sync_reset_hardware(struct iris_core *core) +{ + writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); +} + +static int iris_vpu4x_enable_hardware_clocks(struct iris_core *core, u32 efuse_value) +{ + int ret; + + ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_HW_FREERUN_CLK); + if (ret) + goto disable_axi_clock; + + ret = iris_prepare_enable_clock(core, IRIS_HW_CLK); + if (ret) + goto disable_hw_free_run_clock; + + ret = iris_prepare_enable_clock(core, IRIS_BSE_HW_CLK); + if (ret) + goto disable_hw_clock; + + if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) { + ret = iris_prepare_enable_clock(core, IRIS_VPP0_HW_CLK); + if (ret) + goto disable_bse_hw_clock; + } + + if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) { + ret = iris_prepare_enable_clock(core, IRIS_VPP1_HW_CLK); + if (ret) + goto disable_vpp0_hw_clock; + } + + return 0; + +disable_vpp0_hw_clock: + if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) + iris_disable_unprepare_clock(core, IRIS_VPP0_HW_CLK); +disable_bse_hw_clock: + iris_disable_unprepare_clock(core, IRIS_BSE_HW_CLK); +disable_hw_clock: + iris_disable_unprepare_clock(core, IRIS_HW_CLK); +disable_hw_free_run_clock: + iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK); +disable_axi_clock: + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); + + return ret; +} + +static void iris_vpu4x_disable_hardware_clocks(struct iris_core *core, u32 efuse_value) +{ + if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) + iris_disable_unprepare_clock(core, IRIS_VPP1_HW_CLK); + + if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) + iris_disable_unprepare_clock(core, IRIS_VPP0_HW_CLK); + + iris_disable_unprepare_clock(core, IRIS_BSE_HW_CLK); + iris_disable_unprepare_clock(core, IRIS_HW_CLK); + iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); +} + +static int iris_vpu4x_power_on_hardware(struct iris_core *core) +{ + u32 efuse_value = readl(core->reg_base + WRAPPER_EFUSE_MONITOR); + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + if (ret) + return ret; + + if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) { + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs + [IRIS_VPP0_HW_POWER_DOMAIN]); + if (ret) + goto disable_hw_power_domain; + } + + if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) { + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs + [IRIS_VPP1_HW_POWER_DOMAIN]); + if (ret) + goto disable_vpp0_power_domain; + } + + ret = iris_vpu4x_enable_hardware_clocks(core, efuse_value); + if (ret) + goto disable_vpp1_power_domain; + + if (!(efuse_value & DISABLE_VIDEO_APV_BIT)) { + ret = iris_vpu4x_power_on_apv(core); + if (ret) + goto disable_hw_clocks; + + iris_vpu4x_ahb_sync_reset_apv(core); + } + + iris_vpu4x_ahb_sync_reset_hardware(core); + + ret = iris_vpu4x_genpd_set_hwmode(core, true, efuse_value); + if (ret) + goto disable_apv_power_domain; + + return 0; + +disable_apv_power_domain: + if (!(efuse_value & DISABLE_VIDEO_APV_BIT)) + iris_vpu4x_power_off_apv(core); +disable_hw_clocks: + iris_vpu4x_disable_hardware_clocks(core, efuse_value); +disable_vpp1_power_domain: + if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs + [IRIS_VPP1_HW_POWER_DOMAIN]); +disable_vpp0_power_domain: + if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs + [IRIS_VPP0_HW_POWER_DOMAIN]); +disable_hw_power_domain: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + + return ret; +} + +static void iris_vpu4x_power_off_hardware(struct iris_core *core) +{ + u32 efuse_value = readl(core->reg_base + WRAPPER_EFUSE_MONITOR); + bool handshake_done, handshake_busy; + u32 value, count = 0; + int ret; + + iris_vpu4x_genpd_set_hwmode(core, false, efuse_value); + + if (!(efuse_value & DISABLE_VIDEO_APV_BIT)) + iris_vpu4x_power_off_apv(core); + + value = readl(core->reg_base + WRAPPER_CORE_POWER_STATUS); + + if (!(value & CORE_PWR_ON)) + goto disable_clocks_and_power; + + value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + + if (value & CORE_CLK_HALT) + writel(0x0, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + + readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN, value, + value & VPU_IDLE_BITS, 2000, 20000); + + do { + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + usleep_range(10, 20); + value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS); + + handshake_done = value & NOC_LPI_STATUS_DONE; + handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); + + if (handshake_done || !handshake_busy) + break; + + writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + usleep_range(10, 20); + + } while (++count < 1000); + + if (!handshake_done && handshake_busy) + dev_err(core->dev, "LPI handshake timeout\n"); + + writel(MVP_NOC_RESET_REQ_MASK, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, + value, value & MVP_NOC_RESET_REQ_MASK, 200, 2000); + if (ret) + goto disable_clocks_and_power; + + writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_SYNCRST); + writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, + value, value == 0x0, 200, 2000); + if (ret) + goto disable_clocks_and_power; + + writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + +disable_clocks_and_power: + iris_vpu4x_disable_hardware_clocks(core, efuse_value); + + if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs + [IRIS_VPP1_HW_POWER_DOMAIN]); + + if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs + [IRIS_VPP0_HW_POWER_DOMAIN]); + + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); +} + +const struct vpu_ops iris_vpu4x_ops = { + .power_off_hw = iris_vpu4x_power_off_hardware, + .power_on_hw = iris_vpu4x_power_on_hardware, + .power_off_controller = iris_vpu35_vpu4x_power_off_controller, + .power_on_controller = iris_vpu35_vpu4x_power_on_controller, + .program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers, + .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, +}; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c index f4985790bae4..9270422c1601 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c @@ -822,6 +822,22 @@ static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst) iris_vpu_dec_line_size(inst); } +static inline u32 iris_vpu_enc_get_bitstream_width(struct iris_inst *inst) +{ + if (is_rotation_90_or_270(inst)) + return inst->fmt_dst->fmt.pix_mp.height; + else + return inst->fmt_dst->fmt.pix_mp.width; +} + +static inline u32 iris_vpu_enc_get_bitstream_height(struct iris_inst *inst) +{ + if (is_rotation_90_or_270(inst)) + return inst->fmt_dst->fmt.pix_mp.width; + else + return inst->fmt_dst->fmt.pix_mp.height; +} + static inline u32 size_bin_bitstream_enc(u32 width, u32 height, u32 rc_type) { @@ -904,10 +920,9 @@ static inline u32 hfi_buffer_bin_enc(u32 width, u32 height, static u32 iris_vpu_enc_bin_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + u32 height = iris_vpu_enc_get_bitstream_height(inst); + u32 width = iris_vpu_enc_get_bitstream_width(inst); u32 stage = inst->fw_caps[STAGE].value; - struct v4l2_format *f = inst->fmt_dst; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; u32 lcu_size; if (inst->codec == V4L2_PIX_FMT_HEVC) @@ -951,9 +966,8 @@ u32 hfi_buffer_comv_enc(u32 frame_width, u32 frame_height, u32 lcu_size, static u32 iris_vpu_enc_comv_size(struct iris_inst *inst) { - struct v4l2_format *f = inst->fmt_dst; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; + u32 height = iris_vpu_enc_get_bitstream_height(inst); + u32 width = iris_vpu_enc_get_bitstream_width(inst); u32 num_recon = 1; u32 lcu_size = 16; @@ -1233,9 +1247,8 @@ u32 hfi_buffer_non_comv_enc(u32 frame_width, u32 frame_height, static u32 iris_vpu_enc_non_comv_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - struct v4l2_format *f = inst->fmt_dst; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; + u32 height = iris_vpu_enc_get_bitstream_height(inst); + u32 width = iris_vpu_enc_get_bitstream_width(inst); u32 lcu_size = 16; if (inst->codec == V4L2_PIX_FMT_HEVC) { @@ -1326,9 +1339,8 @@ u32 hfi_buffer_line_enc_vpu33(u32 frame_width, u32 frame_height, bool is_ten_bit static u32 iris_vpu_enc_line_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - struct v4l2_format *f = inst->fmt_dst; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; + u32 height = iris_vpu_enc_get_bitstream_height(inst); + u32 width = iris_vpu_enc_get_bitstream_width(inst); u32 lcu_size = 16; if (inst->codec == V4L2_PIX_FMT_HEVC) { @@ -1344,9 +1356,8 @@ static u32 iris_vpu_enc_line_size(struct iris_inst *inst) static u32 iris_vpu33_enc_line_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - struct v4l2_format *f = inst->fmt_dst; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; + u32 height = iris_vpu_enc_get_bitstream_height(inst); + u32 width = iris_vpu_enc_get_bitstream_width(inst); u32 lcu_size = 16; if (inst->codec == V4L2_PIX_FMT_HEVC) { @@ -1406,10 +1417,11 @@ static u32 iris_vpu_enc_arp_size(struct iris_inst *inst) inline bool is_scaling_enabled(struct iris_inst *inst) { - return inst->crop.left != inst->compose.left || - inst->crop.top != inst->compose.top || - inst->crop.width != inst->compose.width || - inst->crop.height != inst->compose.height; + struct v4l2_pix_format_mplane *dst_fmt = &inst->fmt_dst->fmt.pix_mp; + struct v4l2_pix_format_mplane *src_fmt = &inst->fmt_src->fmt.pix_mp; + + return dst_fmt->width != src_fmt->width || + dst_fmt->height != src_fmt->height; } static inline @@ -1566,9 +1578,8 @@ static inline u32 hfi_buffer_scratch1_enc(u32 frame_width, u32 frame_height, static u32 iris_vpu_enc_scratch1_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - struct v4l2_format *f = inst->fmt_dst; - u32 frame_height = f->fmt.pix_mp.height; - u32 frame_width = f->fmt.pix_mp.width; + u32 frame_height = iris_vpu_enc_get_bitstream_height(inst); + u32 frame_width = iris_vpu_enc_get_bitstream_width(inst); u32 num_ref = 1; u32 lcu_size; bool is_h265; @@ -1664,9 +1675,8 @@ static inline u32 hfi_buffer_scratch2_enc(u32 frame_width, u32 frame_height, static u32 iris_vpu_enc_scratch2_size(struct iris_inst *inst) { - struct v4l2_format *f = inst->fmt_dst; - u32 frame_width = f->fmt.pix_mp.width; - u32 frame_height = f->fmt.pix_mp.height; + u32 frame_height = iris_vpu_enc_get_bitstream_height(inst); + u32 frame_width = iris_vpu_enc_get_bitstream_width(inst); u32 num_ref = 1; return hfi_buffer_scratch2_enc(frame_width, frame_height, num_ref, @@ -1683,6 +1693,304 @@ static u32 iris_vpu_enc_vpss_size(struct iris_inst *inst) return hfi_buffer_vpss_enc(width, height, ds_enable, 0, 0); } +static inline u32 size_dpb_opb(u32 height, u32 lcu_size) +{ + u32 max_tile_height = ((height + lcu_size - 1) / lcu_size) * lcu_size + 8; + u32 dpb_opb = 3 * ((max_tile_height >> 3) * DMA_ALIGNMENT); + u32 num_luma_chrome_plane = 2; + + return ALIGN(dpb_opb, DMA_ALIGNMENT) * num_luma_chrome_plane; +} + +static u32 hfi_vpu4x_vp9d_lb_size(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) +{ + u32 vp9_top_lb, vp9_fe_left_lb, vp9_se_left_lb, dpb_opb, vp9d_qp, num_lcu_per_pipe; + u32 lcu_size = 64; + + vp9_top_lb = ALIGN(size_vp9d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT); + vp9_top_lb += ALIGN(size_vpxd_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT); + vp9_top_lb += max3(DIV_ROUND_UP(frame_width, BUFFER_ALIGNMENT_16_BYTES) * + MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE, + DIV_ROUND_UP(frame_width, BUFFER_ALIGNMENT_32_BYTES) * + MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE, + DIV_ROUND_UP(frame_width, BUFFER_ALIGNMENT_64_BYTES) * + MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE); + vp9_top_lb = ALIGN(vp9_top_lb, DMA_ALIGNMENT); + vp9_top_lb += ALIGN((DMA_ALIGNMENT * DIV_ROUND_UP(frame_width, lcu_size)), + DMA_ALIGNMENT) * FE_TOP_CTRL_LINE_NUMBERS; + vp9_top_lb += ALIGN(DMA_ALIGNMENT * 8 * DIV_ROUND_UP(frame_width, lcu_size), + DMA_ALIGNMENT) * (FE_TOP_DATA_LUMA_LINE_NUMBERS + + FE_TOP_DATA_CHROMA_LINE_NUMBERS); + + num_lcu_per_pipe = (DIV_ROUND_UP(frame_height, lcu_size) / num_vpp_pipes) + + (DIV_ROUND_UP(frame_height, lcu_size) % num_vpp_pipes); + vp9_fe_left_lb = ALIGN((DMA_ALIGNMENT * num_lcu_per_pipe), DMA_ALIGNMENT) * + FE_LFT_CTRL_LINE_NUMBERS; + vp9_fe_left_lb += ((ALIGN((DMA_ALIGNMENT * 8 * num_lcu_per_pipe), DMA_ALIGNMENT) * + FE_LFT_DB_DATA_LINE_NUMBERS) + + ALIGN((DMA_ALIGNMENT * 3 * num_lcu_per_pipe), DMA_ALIGNMENT) + + ALIGN((DMA_ALIGNMENT * 4 * num_lcu_per_pipe), DMA_ALIGNMENT) + + (ALIGN((DMA_ALIGNMENT * 24 * num_lcu_per_pipe), DMA_ALIGNMENT) * + FE_LFT_LR_DATA_LINE_NUMBERS)); + vp9_fe_left_lb = vp9_fe_left_lb * num_vpp_pipes; + + vp9_se_left_lb = ALIGN(size_vpxd_lb_se_left_ctrl(frame_width, frame_height), + DMA_ALIGNMENT); + dpb_opb = size_dpb_opb(frame_height, lcu_size); + vp9d_qp = ALIGN(size_vp9d_qp(frame_width, frame_height), DMA_ALIGNMENT); + + return vp9_top_lb + vp9_fe_left_lb + (vp9_se_left_lb * num_vpp_pipes) + + (dpb_opb * num_vpp_pipes) + vp9d_qp; +} + +static u32 hfi_vpu4x_buffer_line_vp9d(u32 frame_width, u32 frame_height, u32 _yuv_bufcount_min, + bool is_opb, u32 num_vpp_pipes) +{ + u32 lb_size = hfi_vpu4x_vp9d_lb_size(frame_width, frame_height, num_vpp_pipes); + u32 dpb_obp_size = 0, lcu_size = 64; + + if (is_opb) + dpb_obp_size = size_dpb_opb(frame_height, lcu_size) * num_vpp_pipes; + + return lb_size + dpb_obp_size; +} + +static u32 iris_vpu4x_dec_line_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + u32 out_min_count = inst->buffers[BUF_OUTPUT].min_count; + struct v4l2_format *f = inst->fmt_src; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + bool is_opb = false; + + if (iris_split_mode_enabled(inst)) + is_opb = true; + + if (inst->codec == V4L2_PIX_FMT_H264) + return hfi_buffer_line_h264d(width, height, is_opb, num_vpp_pipes); + else if (inst->codec == V4L2_PIX_FMT_HEVC) + return hfi_buffer_line_h265d(width, height, is_opb, num_vpp_pipes); + else if (inst->codec == V4L2_PIX_FMT_VP9) + return hfi_vpu4x_buffer_line_vp9d(width, height, out_min_count, is_opb, + num_vpp_pipes); + + return 0; +} + +static u32 hfi_vpu4x_buffer_persist_h265d(u32 rpu_enabled) +{ + return ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + H265_NUM_FRM_INFO * + H265_DISPLAY_BUF_SIZE + (H265_NUM_TILE * sizeof(u32)) + (NUM_HW_PIC_BUF * + (SIZE_SEI_USERDATA + SIZE_H265D_ARP + SIZE_THREE_DIMENSION_USERDATA)) + + rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA), DMA_ALIGNMENT); +} + +static u32 hfi_vpu4x_buffer_persist_vp9d(void) +{ + return ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, DMA_ALIGNMENT) + + (ALIGN(hfi_iris3_vp9d_comv_size(), DMA_ALIGNMENT) * 2) + + ALIGN(MAX_SUPERFRAME_HEADER_LEN, DMA_ALIGNMENT) + + ALIGN(VP9_UDC_HEADER_BUF_SIZE, DMA_ALIGNMENT) + + ALIGN(VP9_NUM_FRAME_INFO_BUF * CCE_TILE_OFFSET_SIZE, DMA_ALIGNMENT) + + ALIGN(VP9_NUM_FRAME_INFO_BUF * VP9_FRAME_INFO_BUF_SIZE_VPU4X, DMA_ALIGNMENT) + + HDR10_HIST_EXTRADATA_SIZE; +} + +static u32 iris_vpu4x_dec_persist_size(struct iris_inst *inst) +{ + if (inst->codec == V4L2_PIX_FMT_H264) + return hfi_buffer_persist_h264d(); + else if (inst->codec == V4L2_PIX_FMT_HEVC) + return hfi_vpu4x_buffer_persist_h265d(0); + else if (inst->codec == V4L2_PIX_FMT_VP9) + return hfi_vpu4x_buffer_persist_vp9d(); + + return 0; +} + +static u32 size_se_lb(u32 standard, u32 num_vpp_pipes_enc, + u32 frame_width_coded, u32 frame_height_coded) +{ + u32 se_tlb_size = ALIGN(frame_width_coded, DMA_ALIGNMENT); + u32 se_llb_size = (standard == HFI_CODEC_ENCODE_HEVC) ? + ((frame_height_coded + BUFFER_ALIGNMENT_32_BYTES - 1) / + BUFFER_ALIGNMENT_32_BYTES) * LOG2_16 * LLB_UNIT_SIZE : + ((frame_height_coded + BUFFER_ALIGNMENT_16_BYTES - 1) / + BUFFER_ALIGNMENT_16_BYTES) * LOG2_32 * LLB_UNIT_SIZE; + + se_llb_size = ALIGN(se_llb_size, BUFFER_ALIGNMENT_32_BYTES); + + if (num_vpp_pipes_enc > 1) + se_llb_size = ALIGN(se_llb_size + BUFFER_ALIGNMENT_512_BYTES, + DMA_ALIGNMENT) * num_vpp_pipes_enc; + + return ALIGN(se_tlb_size + se_llb_size, DMA_ALIGNMENT); +} + +static u32 size_te_lb(bool is_ten_bit, u32 num_vpp_pipes_enc, u32 width_in_lcus, + u32 frame_height_coded, u32 frame_width_coded) +{ + u32 num_pixel_10_bit = 3, num_pixel_8_bit = 2, num_pixel_te_llb = 3; + u32 te_llb_col_rc_size = ALIGN(32 * width_in_lcus / num_vpp_pipes_enc, + DMA_ALIGNMENT) * num_vpp_pipes_enc; + u32 te_tlb_recon_data_size = ALIGN((is_ten_bit ? num_pixel_10_bit : num_pixel_8_bit) * + frame_width_coded, DMA_ALIGNMENT); + u32 te_llb_recon_data_size = ((1 + is_ten_bit) * num_pixel_te_llb * frame_height_coded + + num_vpp_pipes_enc - 1) / num_vpp_pipes_enc; + te_llb_recon_data_size = ALIGN(te_llb_recon_data_size, DMA_ALIGNMENT) * num_vpp_pipes_enc; + + return ALIGN(te_llb_recon_data_size + te_llb_col_rc_size + te_tlb_recon_data_size, + DMA_ALIGNMENT); +} + +static inline u32 calc_fe_tlb_size(u32 size_per_lcu, bool is_ten_bit) +{ + u32 num_pixels_fe_tlb_10_bit = 128, num_pixels_fe_tlb_8_bit = 64; + + return is_ten_bit ? (num_pixels_fe_tlb_10_bit * (size_per_lcu + 1)) : + (size_per_lcu * num_pixels_fe_tlb_8_bit); +} + +static u32 size_fe_lb(bool is_ten_bit, u32 standard, u32 num_vpp_pipes_enc, + u32 frame_height_coded, u32 frame_width_coded) +{ + u32 log2_lcu_size, num_cu_in_height_pipe, num_cu_in_width, + fb_llb_db_ctrl_size, fb_llb_db_luma_size, fb_llb_db_chroma_size, + fb_tlb_db_ctrl_size, fb_tlb_db_luma_size, fb_tlb_db_chroma_size, + fb_llb_sao_ctrl_size, fb_llb_sao_luma_size, fb_llb_sao_chroma_size, + fb_tlb_sao_ctrl_size, fb_tlb_sao_luma_size, fb_tlb_sao_chroma_size, + fb_lb_top_sdc_size, fb_lb_se_ctrl_size, fe_tlb_size, size_per_lcu; + + log2_lcu_size = (standard == HFI_CODEC_ENCODE_HEVC) ? 5 : 4; + num_cu_in_height_pipe = ((frame_height_coded >> log2_lcu_size) + num_vpp_pipes_enc - 1) / + num_vpp_pipes_enc; + num_cu_in_width = frame_width_coded >> log2_lcu_size; + + size_per_lcu = 2; + fe_tlb_size = calc_fe_tlb_size(size_per_lcu, 1); + fb_llb_db_ctrl_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_height_pipe; + fb_llb_db_ctrl_size = ALIGN(fb_llb_db_ctrl_size, DMA_ALIGNMENT) * num_vpp_pipes_enc; + + size_per_lcu = (1 << (log2_lcu_size - 3)); + fe_tlb_size = calc_fe_tlb_size(size_per_lcu, is_ten_bit); + fb_llb_db_luma_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_height_pipe; + fb_llb_db_luma_size = ALIGN(fb_llb_db_luma_size, DMA_ALIGNMENT) * num_vpp_pipes_enc; + + size_per_lcu = ((1 << (log2_lcu_size - 4)) * 2); + fe_tlb_size = calc_fe_tlb_size(size_per_lcu, is_ten_bit); + fb_llb_db_chroma_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_height_pipe; + fb_llb_db_chroma_size = ALIGN(fb_llb_db_chroma_size, DMA_ALIGNMENT) * num_vpp_pipes_enc; + + size_per_lcu = 1; + fe_tlb_size = calc_fe_tlb_size(size_per_lcu, 1); + fb_tlb_db_ctrl_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_width; + fb_llb_sao_ctrl_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_height_pipe; + fb_llb_sao_ctrl_size = fb_llb_sao_ctrl_size * num_vpp_pipes_enc; + fb_tlb_sao_ctrl_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_width; + + size_per_lcu = ((1 << (log2_lcu_size - 3)) + 1); + fe_tlb_size = calc_fe_tlb_size(size_per_lcu, is_ten_bit); + fb_tlb_db_luma_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_width; + + size_per_lcu = (2 * ((1 << (log2_lcu_size - 4)) + 1)); + fe_tlb_size = calc_fe_tlb_size(size_per_lcu, is_ten_bit); + fb_tlb_db_chroma_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_width; + + fb_llb_sao_luma_size = BUFFER_ALIGNMENT_256_BYTES * num_vpp_pipes_enc; + fb_llb_sao_chroma_size = BUFFER_ALIGNMENT_256_BYTES * num_vpp_pipes_enc; + fb_tlb_sao_luma_size = BUFFER_ALIGNMENT_256_BYTES; + fb_tlb_sao_chroma_size = BUFFER_ALIGNMENT_256_BYTES; + fb_lb_top_sdc_size = ALIGN((FE_SDC_DATA_PER_BLOCK * (frame_width_coded >> 5)), + DMA_ALIGNMENT); + fb_lb_se_ctrl_size = ALIGN((SE_CTRL_DATA_PER_BLOCK * (frame_width_coded >> 5)), + DMA_ALIGNMENT); + + return fb_llb_db_ctrl_size + fb_llb_db_luma_size + fb_llb_db_chroma_size + + fb_tlb_db_ctrl_size + fb_tlb_db_luma_size + fb_tlb_db_chroma_size + + fb_llb_sao_ctrl_size + fb_llb_sao_luma_size + fb_llb_sao_chroma_size + + fb_tlb_sao_ctrl_size + fb_tlb_sao_luma_size + fb_tlb_sao_chroma_size + + fb_lb_top_sdc_size + fb_lb_se_ctrl_size; +} + +static u32 size_md_lb(u32 standard, u32 frame_width_coded, + u32 frame_height_coded, u32 num_vpp_pipes_enc) +{ + u32 md_tlb_size = ALIGN(frame_width_coded, DMA_ALIGNMENT); + u32 md_llb_size = (standard == HFI_CODEC_ENCODE_HEVC) ? + ((frame_height_coded + BUFFER_ALIGNMENT_32_BYTES - 1) / + BUFFER_ALIGNMENT_32_BYTES) * LOG2_16 * LLB_UNIT_SIZE : + ((frame_height_coded + BUFFER_ALIGNMENT_16_BYTES - 1) / + BUFFER_ALIGNMENT_16_BYTES) * LOG2_32 * LLB_UNIT_SIZE; + + md_llb_size = ALIGN(md_llb_size, BUFFER_ALIGNMENT_32_BYTES); + + if (num_vpp_pipes_enc > 1) + md_llb_size = ALIGN(md_llb_size + BUFFER_ALIGNMENT_512_BYTES, + DMA_ALIGNMENT) * num_vpp_pipes_enc; + + md_llb_size = ALIGN(md_llb_size, DMA_ALIGNMENT); + + return ALIGN(md_tlb_size + md_llb_size, DMA_ALIGNMENT); +} + +static u32 size_dma_opb_lb(u32 num_vpp_pipes_enc, u32 frame_width_coded, + u32 frame_height_coded) +{ + u32 opb_packet_bytes = 128, opb_bpp = 128, opb_size_per_row = 6; + u32 dma_opb_wr_tlb_y_size = DIV_ROUND_UP(frame_width_coded, 16) * opb_packet_bytes; + u32 dma_opb_wr_tlb_uv_size = DIV_ROUND_UP(frame_width_coded, 16) * opb_packet_bytes; + u32 dma_opb_wr2_tlb_y_size = ALIGN((opb_bpp * opb_size_per_row * frame_height_coded / 8), + DMA_ALIGNMENT) * num_vpp_pipes_enc; + u32 dma_opb_wr2_tlb_uv_size = ALIGN((opb_bpp * opb_size_per_row * frame_height_coded / 8), + DMA_ALIGNMENT) * num_vpp_pipes_enc; + + dma_opb_wr2_tlb_y_size = max(dma_opb_wr2_tlb_y_size, dma_opb_wr_tlb_y_size << 1); + dma_opb_wr2_tlb_uv_size = max(dma_opb_wr2_tlb_uv_size, dma_opb_wr_tlb_uv_size << 1); + + return ALIGN(dma_opb_wr_tlb_y_size + dma_opb_wr_tlb_uv_size + dma_opb_wr2_tlb_y_size + + dma_opb_wr2_tlb_uv_size, DMA_ALIGNMENT); +} + +static u32 hfi_vpu4x_buffer_line_enc(u32 frame_width, u32 frame_height, + bool is_ten_bit, u32 num_vpp_pipes_enc, + u32 lcu_size, u32 standard) +{ + u32 width_in_lcus = (frame_width + lcu_size - 1) / lcu_size; + u32 height_in_lcus = (frame_height + lcu_size - 1) / lcu_size; + u32 frame_width_coded = width_in_lcus * lcu_size; + u32 frame_height_coded = height_in_lcus * lcu_size; + + u32 se_lb_size = size_se_lb(standard, num_vpp_pipes_enc, frame_width_coded, + frame_height_coded); + u32 te_lb_size = size_te_lb(is_ten_bit, num_vpp_pipes_enc, width_in_lcus, + frame_height_coded, frame_width_coded); + u32 fe_lb_size = size_fe_lb(is_ten_bit, standard, num_vpp_pipes_enc, frame_height_coded, + frame_width_coded); + u32 md_lb_size = size_md_lb(standard, frame_width_coded, frame_height_coded, + num_vpp_pipes_enc); + u32 dma_opb_lb_size = size_dma_opb_lb(num_vpp_pipes_enc, frame_width_coded, + frame_height_coded); + u32 dse_lb_size = ALIGN((256 + (16 * (frame_width_coded >> 4))), DMA_ALIGNMENT); + u32 size_vpss_lb_enc = size_vpss_line_buf_vpu33(num_vpp_pipes_enc, frame_width_coded, + frame_height_coded); + + return se_lb_size + te_lb_size + fe_lb_size + md_lb_size + dma_opb_lb_size + + dse_lb_size + size_vpss_lb_enc; +} + +static u32 iris_vpu4x_enc_line_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + u32 lcu_size = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + + return hfi_vpu4x_buffer_line_enc(width, height, 0, num_vpp_pipes, + lcu_size, inst->codec); +} + static int output_min_count(struct iris_inst *inst) { int output_min_count = 4; @@ -1783,6 +2091,50 @@ u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_typ return size; } +u32 iris_vpu4x_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) +{ + const struct iris_vpu_buf_type_handle *buf_type_handle_arr = NULL; + u32 size = 0, buf_type_handle_size = 0, i; + + static const struct iris_vpu_buf_type_handle dec_internal_buf_type_handle[] = { + {BUF_BIN, iris_vpu_dec_bin_size }, + {BUF_COMV, iris_vpu_dec_comv_size }, + {BUF_NON_COMV, iris_vpu_dec_non_comv_size }, + {BUF_LINE, iris_vpu4x_dec_line_size }, + {BUF_PERSIST, iris_vpu4x_dec_persist_size }, + {BUF_DPB, iris_vpu_dec_dpb_size }, + {BUF_SCRATCH_1, iris_vpu_dec_scratch1_size }, + }; + + static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = { + {BUF_BIN, iris_vpu_enc_bin_size }, + {BUF_COMV, iris_vpu_enc_comv_size }, + {BUF_NON_COMV, iris_vpu_enc_non_comv_size }, + {BUF_LINE, iris_vpu4x_enc_line_size }, + {BUF_ARP, iris_vpu_enc_arp_size }, + {BUF_VPSS, iris_vpu_enc_vpss_size }, + {BUF_SCRATCH_1, iris_vpu_enc_scratch1_size }, + {BUF_SCRATCH_2, iris_vpu_enc_scratch2_size }, + }; + + if (inst->domain == DECODER) { + buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle); + buf_type_handle_arr = dec_internal_buf_type_handle; + } else if (inst->domain == ENCODER) { + buf_type_handle_size = ARRAY_SIZE(enc_internal_buf_type_handle); + buf_type_handle_arr = enc_internal_buf_type_handle; + } + + for (i = 0; i < buf_type_handle_size; i++) { + if (buf_type_handle_arr[i].type == buffer_type) { + size = buf_type_handle_arr[i].handle(inst); + break; + } + } + + return size; +} + static u32 internal_buffer_count(struct iris_inst *inst, enum iris_buffer_type buffer_type) { diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h index 13c7199fcf35..12640eb5ed8c 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h @@ -48,7 +48,12 @@ struct iris_inst; #define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) #define VP9_PROB_TABLE_SIZE (3840) #define VP9_FRAME_INFO_BUF_SIZE (6144) +#define VP9_FRAME_INFO_BUF_SIZE_VPU4X (6400) +#define BUFFER_ALIGNMENT_16_BYTES 16 #define BUFFER_ALIGNMENT_32_BYTES 32 +#define BUFFER_ALIGNMENT_64_BYTES 64 +#define BUFFER_ALIGNMENT_256_BYTES 256 +#define BUFFER_ALIGNMENT_512_BYTES 512 #define CCE_TILE_OFFSET_SIZE ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_32_BYTES) #define MAX_SUPERFRAME_HEADER_LEN (34) #define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 @@ -67,6 +72,8 @@ struct iris_inst; #define H265_CABAC_HDR_RATIO_HD_TOT 2 #define H265_CABAC_RES_RATIO_HD_TOT 2 #define SIZE_H265D_VPP_CMD_PER_BUF (256) +#define SIZE_THREE_DIMENSION_USERDATA 768 +#define SIZE_H265D_ARP 9728 #define VPX_DECODER_FRAME_CONCURENCY_LVL (2) #define VPX_DECODER_FRAME_BIN_HDR_BUDGET 1 @@ -77,6 +84,18 @@ struct iris_inst; #define SIZE_H264D_HW_PIC_T (BIT(11)) +#define FE_LFT_CTRL_LINE_NUMBERS 4 +#define FE_LFT_DB_DATA_LINE_NUMBERS 2 +#define FE_LFT_LR_DATA_LINE_NUMBERS 4 +#define FE_TOP_CTRL_LINE_NUMBERS 3 +#define FE_TOP_DATA_LUMA_LINE_NUMBERS 2 +#define FE_TOP_DATA_CHROMA_LINE_NUMBERS 3 +#define FE_SDC_DATA_PER_BLOCK 16 +#define SE_CTRL_DATA_PER_BLOCK 2020 + +#define MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE 96 +#define MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE 192 + #define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 #define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 16 #define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE 384 @@ -113,6 +132,10 @@ struct iris_inst; #define HFI_BUFFER_ARP_ENC 204800 +#define LOG2_16 4 +#define LOG2_32 5 +#define LLB_UNIT_SIZE 16 + #define MAX_WIDTH 4096 #define MAX_HEIGHT 2304 #define NUM_MBS_4K (DIV_ROUND_UP(MAX_WIDTH, 16) * DIV_ROUND_UP(MAX_HEIGHT, 16)) @@ -264,6 +287,7 @@ static inline u32 size_av1d_qp(u32 frame_width, u32 frame_height) u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); +u32 iris_vpu4x_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index 515dd55a3377..548e5f1727fd 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -8,16 +8,12 @@ #include #include "iris_core.h" +#include "iris_instance.h" #include "iris_vpu_common.h" #include "iris_vpu_register_defines.h" -#define WRAPPER_TZ_BASE_OFFS 0x000C0000 -#define AON_BASE_OFFS 0x000E0000 - -#define CPU_IC_BASE_OFFS (CPU_BASE_OFFS) - -#define CPU_CS_A2HSOFTINTCLR (CPU_CS_BASE_OFFS + 0x1C) -#define CLEAR_XTENSA2HOST_INTR BIT(0) +#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL (AON_BASE_OFFS + 0x2C) +#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS (AON_BASE_OFFS + 0x30) #define CTRL_INIT (CPU_CS_BASE_OFFS + 0x48) #define CTRL_STATUS (CPU_CS_BASE_OFFS + 0x4C) @@ -35,42 +31,6 @@ #define UC_REGION_ADDR (CPU_CS_BASE_OFFS + 0x64) #define UC_REGION_SIZE (CPU_CS_BASE_OFFS + 0x68) -#define CPU_CS_H2XSOFTINTEN (CPU_CS_BASE_OFFS + 0x148) -#define HOST2XTENSA_INTR_ENABLE BIT(0) - -#define CPU_CS_X2RPMH (CPU_CS_BASE_OFFS + 0x168) -#define MSK_SIGNAL_FROM_TENSILICA BIT(0) -#define MSK_CORE_POWER_ON BIT(1) - -#define CPU_IC_SOFTINT (CPU_IC_BASE_OFFS + 0x150) -#define CPU_IC_SOFTINT_H2A_SHFT 0x0 - -#define WRAPPER_INTR_STATUS (WRAPPER_BASE_OFFS + 0x0C) -#define WRAPPER_INTR_STATUS_A2HWD_BMSK BIT(3) -#define WRAPPER_INTR_STATUS_A2H_BMSK BIT(2) - -#define WRAPPER_INTR_MASK (WRAPPER_BASE_OFFS + 0x10) -#define WRAPPER_INTR_MASK_A2HWD_BMSK BIT(3) -#define WRAPPER_INTR_MASK_A2HCPU_BMSK BIT(2) - -#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x54) -#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS (WRAPPER_BASE_OFFS + 0x58) -#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x5C) -#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS + 0x60) - -#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10) -#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) -#define CTL_AXI_CLK_HALT BIT(0) -#define CTL_CLK_HALT BIT(1) - -#define WRAPPER_TZ_QNS4PDXFIFO_RESET (WRAPPER_TZ_BASE_OFFS + 0x18) -#define RESET_HIGH BIT(0) - -#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) -#define REQ_POWER_DOWN_PREP BIT(0) - -#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) - static void iris_vpu_interrupt_init(struct iris_core *core) { u32 mask_val; @@ -270,7 +230,7 @@ void iris_vpu_power_off_hw(struct iris_core *core) void iris_vpu_power_off(struct iris_core *core) { - dev_pm_opp_set_rate(core->dev, 0); + iris_opp_set_rate(core->dev, 0); core->iris_platform_data->vpu_ops->power_off_hw(core); core->iris_platform_data->vpu_ops->power_off_controller(core); iris_unset_icc_bw(core); @@ -348,6 +308,144 @@ int iris_vpu_power_on_hw(struct iris_core *core) return ret; } +int iris_vpu35_vpu4x_power_off_controller(struct iris_core *core) +{ + u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; + bool handshake_done, handshake_busy; + u32 count = 0, val = 0; + int ret; + + writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); + + writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + /* Retry up to 1000 times as recommended by hardware documentation */ + do { + /* set MNoC to low power */ + writel(REQ_POWER_DOWN_PREP, core->reg_base + + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + usleep_range(10, 20); + val = readl(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS); + + handshake_done = val & NOC_LPI_STATUS_DONE; + handshake_busy = val & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); + + if (handshake_done || !handshake_busy) + break; + + writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + usleep_range(10, 20); + + } while (++count < 1000); + + if (!handshake_done && handshake_busy) + dev_err(core->dev, "LPI handshake timeout\n"); + + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + + writel(0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); + + readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, + val, val == 0, 200, 2000); + +disable_power: + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); + iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); + + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + + reset_control_bulk_reset(clk_rst_tbl_size, core->resets); + + return 0; +} + +int iris_vpu35_vpu4x_power_on_controller(struct iris_core *core) +{ + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_AXI1_CLK); + if (ret) + goto err_disable_power; + + ret = iris_prepare_enable_clock(core, IRIS_CTRL_FREERUN_CLK); + if (ret) + goto err_disable_axi1_clk; + + ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); + if (ret) + goto err_disable_ctrl_free_clk; + + return 0; + +err_disable_ctrl_free_clk: + iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); +err_disable_axi1_clk: + iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); +err_disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + + return ret; +} + +void iris_vpu35_vpu4x_program_bootup_registers(struct iris_core *core) +{ + writel(0x1, core->reg_base + WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0); +} + +u64 iris_vpu3x_vpu4x_calculate_frequency(struct iris_inst *inst, size_t data_size) +{ + struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; + struct v4l2_format *inp_f = inst->fmt_src; + u32 height, width, mbs_per_second, mbpf; + u64 fw_cycles, fw_vpp_cycles; + u64 vsp_cycles, vpp_cycles; + u32 fps = DEFAULT_FPS; + + width = max(inp_f->fmt.pix_mp.width, inst->crop.width); + height = max(inp_f->fmt.pix_mp.height, inst->crop.height); + + mbpf = NUM_MBS_PER_FRAME(height, width); + mbs_per_second = mbpf * fps; + + fw_cycles = fps * caps->mb_cycles_fw; + fw_vpp_cycles = fps * caps->mb_cycles_fw_vpp; + + vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value); + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); + + /* 1.059 is multi-pipe overhead */ + if (inst->fw_caps[PIPE].value > 1) + vpp_cycles += div_u64(vpp_cycles * 59, 1000); + + vsp_cycles = fps * data_size * 8; + vsp_cycles = div_u64(vsp_cycles, 2); + /* VSP FW overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->fw_caps[STAGE].value == STAGE_1) + vsp_cycles = vsp_cycles * 3; + + return max3(vpp_cycles, vsp_cycles, fw_cycles); +} + int iris_vpu_power_on(struct iris_core *core) { u32 freq; @@ -368,7 +466,7 @@ int iris_vpu_power_on(struct iris_core *core) freq = core->power.clk_freq ? core->power.clk_freq : (u32)ULONG_MAX; - dev_pm_opp_set_rate(core->dev, freq); + iris_opp_set_rate(core->dev, freq); core->iris_platform_data->set_preset_registers(core); diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h index d636e287457a..f6dffc613b82 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h @@ -12,6 +12,7 @@ extern const struct vpu_ops iris_vpu2_ops; extern const struct vpu_ops iris_vpu3_ops; extern const struct vpu_ops iris_vpu33_ops; extern const struct vpu_ops iris_vpu35_ops; +extern const struct vpu_ops iris_vpu4x_ops; struct vpu_ops { void (*power_off_hw)(struct iris_core *core); @@ -33,5 +34,9 @@ int iris_vpu_power_on(struct iris_core *core); int iris_vpu_power_off_controller(struct iris_core *core); void iris_vpu_power_off_hw(struct iris_core *core); void iris_vpu_power_off(struct iris_core *core); +int iris_vpu35_vpu4x_power_off_controller(struct iris_core *core); +int iris_vpu35_vpu4x_power_on_controller(struct iris_core *core); +void iris_vpu35_vpu4x_program_bootup_registers(struct iris_core *core); +u64 iris_vpu3x_vpu4x_calculate_frequency(struct iris_inst *inst, size_t data_size); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h b/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h index fe8a39e5e5a3..72168b9ffa73 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h @@ -7,11 +7,72 @@ #define __IRIS_VPU_REGISTER_DEFINES_H__ #define VCODEC_BASE_OFFS 0x00000000 +#define AON_MVP_NOC_RESET 0x0001F000 #define CPU_BASE_OFFS 0x000A0000 #define WRAPPER_BASE_OFFS 0x000B0000 +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define AON_BASE_OFFS 0x000E0000 + +#define VCODEC_SS_IDLE_STATUSN (VCODEC_BASE_OFFS + 0x70) + +#define AON_WRAPPER_MVP_NOC_RESET_REQ (AON_MVP_NOC_RESET + 0x000) +#define VIDEO_NOC_RESET_REQ (BIT(0) | BIT(1)) + +#define AON_WRAPPER_MVP_NOC_RESET_ACK (AON_MVP_NOC_RESET + 0x004) #define CPU_CS_BASE_OFFS (CPU_BASE_OFFS) +#define CPU_IC_BASE_OFFS (CPU_BASE_OFFS) + +#define CPU_CS_A2HSOFTINTCLR (CPU_CS_BASE_OFFS + 0x1C) +#define CLEAR_XTENSA2HOST_INTR BIT(0) + +#define CPU_CS_H2XSOFTINTEN (CPU_CS_BASE_OFFS + 0x148) +#define HOST2XTENSA_INTR_ENABLE BIT(0) + +#define CPU_IC_SOFTINT (CPU_IC_BASE_OFFS + 0x150) +#define CPU_IC_SOFTINT_H2A_SHFT 0x0 + +#define CPU_CS_AHB_BRIDGE_SYNC_RESET (CPU_CS_BASE_OFFS + 0x160) +#define CORE_BRIDGE_SW_RESET BIT(0) +#define CORE_BRIDGE_HW_RESET_DISABLE BIT(1) + +#define CPU_CS_X2RPMH (CPU_CS_BASE_OFFS + 0x168) +#define MSK_SIGNAL_FROM_TENSILICA BIT(0) +#define MSK_CORE_POWER_ON BIT(1) +#define WRAPPER_INTR_STATUS (WRAPPER_BASE_OFFS + 0x0C) +#define WRAPPER_INTR_STATUS_A2HWD_BMSK BIT(3) +#define WRAPPER_INTR_STATUS_A2H_BMSK BIT(2) + +#define WRAPPER_INTR_MASK (WRAPPER_BASE_OFFS + 0x10) +#define WRAPPER_INTR_MASK_A2HWD_BMSK BIT(3) +#define WRAPPER_INTR_MASK_A2HCPU_BMSK BIT(2) + +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x54) +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS (WRAPPER_BASE_OFFS + 0x58) +#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x5C) +#define REQ_POWER_DOWN_PREP BIT(0) + +#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS + 0x60) +#define NOC_LPI_STATUS_DONE BIT(0) /* Indicates the NOC handshake is complete */ +#define NOC_LPI_STATUS_DENY BIT(1) /* Indicates the NOC handshake is denied */ +#define NOC_LPI_STATUS_ACTIVE BIT(2) /* Indicates the NOC is active */ + +#define WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0 (WRAPPER_BASE_OFFS + 0x78) #define WRAPPER_CORE_POWER_STATUS (WRAPPER_BASE_OFFS + 0x80) +#define WRAPPER_CORE_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x88) +#define CORE_CLK_RUN 0x0 + +#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10) + +#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) +#define CTL_AXI_CLK_HALT BIT(0) +#define CTL_CLK_HALT BIT(1) + +#define WRAPPER_TZ_QNS4PDXFIFO_RESET (WRAPPER_TZ_BASE_OFFS + 0x18) +#define RESET_HIGH BIT(0) + +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) +#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) #endif diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index abf959b8f3a6..24d2b2fd0340 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -1146,6 +1146,5 @@ static struct platform_driver qcom_venus_driver = { }; module_platform_driver(qcom_venus_driver); -MODULE_ALIAS("platform:qcom-venus"); MODULE_DESCRIPTION("Qualcomm Venus video encoder and decoder driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index af0ac40bec9b..1de7436713ed 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -83,8 +82,7 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, phys_addr_t *mem_phys, size_t *mem_size) { const struct firmware *mdt; - struct reserved_mem *rmem; - struct device_node *node; + struct resource res; struct device *dev; ssize_t fw_size; void *mem_va; @@ -94,15 +92,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, *mem_size = 0; dev = core->dev; - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!node) { - dev_err(dev, "no memory-region specified\n"); - return -EINVAL; - } - - rmem = of_reserved_mem_lookup(node); - of_node_put(node); - if (!rmem) { + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); + if (ret) { dev_err(dev, "failed to lookup reserved memory-region\n"); return -EINVAL; } @@ -117,8 +108,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, goto err_release_fw; } - *mem_phys = rmem->base; - *mem_size = rmem->size; + *mem_phys = res.start; + *mem_size = resource_size(&res); if (*mem_size < fw_size || fw_size > VENUS_FW_MEM_SIZE) { ret = -EINVAL; diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 27cb024427b8..d2d46f97bbc3 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -435,9 +435,13 @@ vdec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) static int vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { + struct venus_inst *inst = to_inst(file); + struct venus_core *core = inst->core; + strscpy(cap->driver, "qcom-venus", sizeof(cap->driver)); strscpy(cap->card, "Qualcomm Venus video decoder", sizeof(cap->card)); - strscpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "plat:%s:dec", dev_name(core->dev)); return 0; } @@ -1784,12 +1788,9 @@ static int vdec_probe(struct platform_device *pdev) struct venus_core *core; int ret; - if (!dev->parent) - return -EPROBE_DEFER; - core = dev_get_drvdata(dev->parent); if (!core) - return -EPROBE_DEFER; + return -EINVAL; platform_set_drvdata(pdev, core); @@ -1888,6 +1889,5 @@ static struct platform_driver qcom_venus_dec_driver = { }; module_platform_driver(qcom_venus_dec_driver); -MODULE_ALIAS("platform:qcom-venus-decoder"); MODULE_DESCRIPTION("Qualcomm Venus video decoder driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index fba07557a399..689d39dae631 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -144,9 +144,13 @@ static int venc_v4l2_to_hfi(int id, int value) static int venc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { + struct venus_inst *inst = to_inst(file); + struct venus_core *core = inst->core; + strscpy(cap->driver, "qcom-venus", sizeof(cap->driver)); strscpy(cap->card, "Qualcomm Venus video encoder", sizeof(cap->card)); - strscpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "plat:%s:enc", dev_name(core->dev)); return 0; } @@ -1560,12 +1564,9 @@ static int venc_probe(struct platform_device *pdev) struct venus_core *core; int ret; - if (!dev->parent) - return -EPROBE_DEFER; - core = dev_get_drvdata(dev->parent); if (!core) - return -EPROBE_DEFER; + return -EINVAL; platform_set_drvdata(pdev, core); @@ -1664,6 +1665,5 @@ static struct platform_driver qcom_venus_enc_driver = { }; module_platform_driver(qcom_venus_enc_driver); -MODULE_ALIAS("platform:qcom-venus-encoder"); MODULE_DESCRIPTION("Qualcomm Venus video encoder driver"); MODULE_LICENSE("GPL v2");