diff --git a/arch/arm64/boot/dts/freescale/fsl-imx8dx.dtsi b/arch/arm64/boot/dts/freescale/fsl-imx8dx.dtsi index 8be64e051a7e..bbc58f8b78a6 100644 --- a/arch/arm64/boot/dts/freescale/fsl-imx8dx.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-imx8dx.dtsi @@ -3343,6 +3343,9 @@ compatible = "nxp,imx8qm-b0-vpuenc", "nxp,imx8qxp-b0-vpuenc"; boot-region = <&encoder_boot>; rpc-region = <&encoder_rpc>; + fw-buf_size = <0x1000000>; + rpc-buf-size = <0x500000>; + print-buf-size = <0x300000>; reg = <0x0 0x2d000000 0x0 0x1000000>; reg-names = "vpu_regs"; power-domains = <&pd_vpu_enc>; diff --git a/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-domu-dpu1.dts b/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-domu-dpu1.dts index c58fb763f221..6628f1e00766 100644 --- a/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-domu-dpu1.dts +++ b/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-domu-dpu1.dts @@ -234,6 +234,9 @@ compatible = "nxp,imx8qm-b0-vpuenc", "nxp,imx8qxp-b0-vpuenc"; boot-region = <&encoder_boot>; rpc-region = <&encoder_rpc>; + fw-buf_size = <0x1000000 0x1000000>; + rpc-buf-size = <0x500000 0x500000>; + print-buf-size = <0x300000 0x300000>; reg = <0x0 0x2d000000 0x0 0x1000000>; reg-names = "vpu_regs"; power-domains = <&pd_vpu_enc>; diff --git a/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-domu.dts b/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-domu.dts index 4865d7d8648f..6ff0bcac6b93 100644 --- a/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-domu.dts +++ b/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-domu.dts @@ -266,6 +266,9 @@ compatible = "nxp,imx8qm-b0-vpuenc", "nxp,imx8qxp-b0-vpuenc"; boot-region = <&encoder_boot>; rpc-region = <&encoder_rpc>; + fw-buf_size = <0x1000000 0x1000000>; + rpc-buf-size = <0x500000 0x500000>; + print-buf-size = <0x300000 0x300000>; reg = <0x0 0x2d000000 0x0 0x1000000>; reg-names = "vpu_regs"; power-domains = <&pd_vpu_enc>; diff --git a/arch/arm64/boot/dts/freescale/fsl-imx8qm.dtsi b/arch/arm64/boot/dts/freescale/fsl-imx8qm.dtsi index 27b9ff84f778..8e237d30e0f1 100644 --- a/arch/arm64/boot/dts/freescale/fsl-imx8qm.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-imx8qm.dtsi @@ -197,6 +197,9 @@ compatible = "nxp,imx8qm-b0-vpuenc", "nxp,imx8qxp-b0-vpuenc"; boot-region = <&encoder_boot>; rpc-region = <&encoder_rpc>; + fw-buf_size = <0x1000000 0x1000000>; + rpc-buf-size = <0x500000 0x500000>; + print-buf-size = <0x300000 0x300000>; reg = <0x0 0x2d000000 0x0 0x1000000>; reg-names = "vpu_regs"; power-domains = <&pd_vpu_enc>; diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c index 6547b6436d45..6b9cd31fba45 100644 --- a/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c +++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c @@ -2251,14 +2251,15 @@ static void vpu_api_event_handler(struct vpu_ctx *ctx, static void enable_mu(struct core_device *dev) { - MU_sendMesgToFW(dev->mu_base_virtaddr, - PRINT_BUF_OFFSET, - cpu_phy_to_mu(dev, dev->m0_rpc_phy + M0_PRINT_OFFSET)); - MU_sendMesgToFW(dev->mu_base_virtaddr, - RPC_BUF_OFFSET, - cpu_phy_to_mu(dev, dev->m0_rpc_phy)); - MU_sendMesgToFW(dev->mu_base_virtaddr, - BOOT_ADDRESS, + u32 mu_addr; + + mu_addr = cpu_phy_to_mu(dev, dev->m0_rpc_phy + dev->rpc_buf_size); + MU_sendMesgToFW(dev->mu_base_virtaddr, PRINT_BUF_OFFSET, mu_addr); + + mu_addr = cpu_phy_to_mu(dev, dev->m0_rpc_phy); + MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, mu_addr); + + MU_sendMesgToFW(dev->mu_base_virtaddr, BOOT_ADDRESS, dev->m0_p_fw_space_phy); MU_sendMesgToFW(dev->mu_base_virtaddr, INIT_DONE, 2); } @@ -2643,38 +2644,34 @@ static int set_vpu_fw_addr(struct vpu_dev *dev, struct core_device *core_dev) static int vpu_firmware_download(struct vpu_dev *This, u_int32 core_id) { - unsigned char *image; + const struct firmware *m0_pfw = NULL; + const u8 *image; unsigned int FW_Size = 0; int ret = 0; char *p = This->core_dev[core_id].m0_p_fw_space_vir; - ret = request_firmware((const struct firmware **)&This->m0_pfw, - M0FW_FILENAME, - This->generic_dev - ); + ret = request_firmware(&m0_pfw, M0FW_FILENAME, This->generic_dev); if (ret) { vpu_dbg(LVL_ERR, "%s() request fw %s failed(%d)\n", __func__, M0FW_FILENAME, ret); - if (This->m0_pfw) { - release_firmware(This->m0_pfw); - This->m0_pfw = NULL; - } return ret; - } else { - vpu_dbg(LVL_DEBUG, "%s() request fw %s got size(%d)\n", - __func__, M0FW_FILENAME, (int)This->m0_pfw->size); - image = (uint8_t *)This->m0_pfw->data; - FW_Size = This->m0_pfw->size; } - memcpy(This->core_dev[core_id].m0_p_fw_space_vir, - image, - FW_Size - ); + vpu_dbg(LVL_DEBUG, "%s() request fw %s got size(%ld)\n", + __func__, M0FW_FILENAME, m0_pfw->size); + + image = m0_pfw->data; + FW_Size = min_t(u32, m0_pfw->size, This->core_dev[core_id].fw_buf_size); + This->core_dev[core_id].fw_actual_size = FW_Size; + + memcpy(This->core_dev[core_id].m0_p_fw_space_vir, image, FW_Size); p[16] = This->plat_type; p[17] = core_id + 1; set_vpu_fw_addr(This, &This->core_dev[core_id]); + release_firmware(m0_pfw); + m0_pfw = NULL; + return ret; } @@ -2750,6 +2747,8 @@ static struct core_device *find_proper_core(struct vpu_dev *dev) minimum = count; core = dev->core_dev + i; } + if (minimum == 0) + break; } return core; @@ -2915,14 +2914,12 @@ static ssize_t show_instance_info(struct device *dev, int i; int num = 0; int size; - char *fw = NULL; vpu_attr = container_of(attr, struct vpu_attr, dev_attr); vpudev = vpu_attr->core->vdev; statistic = &vpu_attr->statistic; param = rpc_get_enc_param(&vpu_attr->core->shared_mem, vpu_attr->index); - fw = vpu_attr->core->m0_p_fw_space_vir; num += snprintf(buf + num, PAGE_SIZE, "pid: %d; tgid: %d\n", vpu_attr->pid, vpu_attr->tgid); @@ -3042,20 +3039,54 @@ static ssize_t show_instance_info(struct device *dev, if (!vpu_attr->core->ctx[vpu_attr->index]) num += snprintf(buf + num, PAGE_SIZE - num, "\n"); - num += snprintf(buf + num, PAGE_SIZE - num, - "core[%d] info:\n", vpu_attr->core->id); - num += snprintf(buf + num, PAGE_SIZE - num, - "fw_is_ready:%d\n", vpu_attr->core->fw_is_ready); - num += snprintf(buf + num, PAGE_SIZE - num, - "firmware_started:%d\n", - vpu_attr->core->firmware_started); - num += snprintf(buf + num, PAGE_SIZE - num, - "hang:%d\n", - vpu_attr->core->hang); return num; } +static ssize_t show_core_info(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct core_device *core = NULL; + char *fw = NULL; + int num = 0; + + core = container_of(attr, struct core_device, core_attr); + fw = core->m0_p_fw_space_vir; + + num += snprintf(buf + num, PAGE_SIZE - num, + "core[%d] info:\n", core->id); + num += snprintf(buf + num, PAGE_SIZE - num, + "vpu mu id :%d\n", core->vpu_mu_id); + num += snprintf(buf + num, PAGE_SIZE - num, + "reg fw base :0x%08lx\n", core->reg_fw_base); + num += snprintf(buf + num, PAGE_SIZE - num, + "fw space phy :0x%08x\n", core->m0_p_fw_space_phy); + num += snprintf(buf + num, PAGE_SIZE - num, + "fw space size :0x%08x\n", core->fw_buf_size); + num += snprintf(buf + num, PAGE_SIZE - num, + "fw actual size :0x%08x\n", core->fw_actual_size); + num += snprintf(buf + num, PAGE_SIZE - num, + "rpc phy :0x%08x\n", core->m0_rpc_phy); + num += snprintf(buf + num, PAGE_SIZE - num, + "rpc buf size :0x%08x\n", core->rpc_buf_size); + num += snprintf(buf + num, PAGE_SIZE - num, + "rpc actual size :0x%08x\n", core->rpc_actual_size); + num += snprintf(buf + num, PAGE_SIZE - num, + "print buf phy :0x%08x\n", + core->m0_rpc_phy + core->rpc_buf_size); + num += snprintf(buf + num, PAGE_SIZE - num, + "print buf size :0x%08x\n", core->print_buf_size); + num += snprintf(buf + num, PAGE_SIZE - num, + "fw info :0x%02x 0x%02x\n", fw[16], fw[17]); + num += snprintf(buf + num, PAGE_SIZE - num, + "fw_is_ready :%d\n", core->fw_is_ready); + num += snprintf(buf + num, PAGE_SIZE - num, + "firmware_started:%d\n", core->firmware_started); + num += snprintf(buf + num, PAGE_SIZE - num, + "hang :%d\n", core->hang); + return num; +} + static int init_vpu_attr(struct vpu_attr *attr) { if (!attr || !attr->core) @@ -3339,12 +3370,59 @@ static int get_platform_info_by_core_type(struct vpu_dev *dev, u32 core_type) return ret; } +static int parse_core_info(struct core_device *core, struct device_node *np) +{ + int ret; + u32 val; + + WARN_ON(!core || !np); + + ret = of_property_read_u32_index(np, "reg-fw-base", core->id, &val); + if (ret) { + vpu_err("find reg-fw-base for core[%d] fail\n", core->id); + return ret; + } + core->reg_fw_base = val; + + ret = of_property_read_u32_index(np, "fw-buf_size", core->id, &val); + if (ret) { + vpu_err("find fw-buf-size for core[%d] fail\n", core->id); + core->fw_buf_size = M0_BOOT_SIZE_DEFAULT; + } else { + core->fw_buf_size = val; + } + core->fw_buf_size = max_t(u32, core->fw_buf_size, M0_BOOT_SIZE_MIN); + + ret = of_property_read_u32_index(np, "rpc-buf-size", core->id, &val); + if (ret) { + vpu_err("find rpc-buf-size for core[%d] fail\n", core->id); + core->rpc_buf_size = RPC_SIZE_DEFAULT; + } else { + core->rpc_buf_size = val; + } + core->rpc_buf_size = max_t(u32, core->rpc_buf_size, RPC_SIZE_MIN); + + ret = of_property_read_u32_index(np, "print-buf-size", core->id, &val); + if (ret) { + vpu_err("find print-buf-size for core[%d] fail\n", core->id); + core->print_buf_size = PRINT_SIZE_DEFAULT; + } else { + core->print_buf_size = val; + } + core->print_buf_size = max_t(u32, core->print_buf_size, PRINT_SIZE_MIN); + + return 0; +} + static int parse_dt_info(struct vpu_dev *dev, struct device_node *np) { int ret; struct device_node *reserved_node = NULL; - struct resource reserved_res; + struct resource reserved_fw; + struct resource reserved_rpc; u_int32 core_type; + u32 fw_total_size = 0; + u32 rpc_total_size = 0; u32 i; if (!dev || !np) @@ -3365,39 +3443,50 @@ static int parse_dt_info(struct vpu_dev *dev, struct device_node *np) vpu_dbg(LVL_ERR, "error: boot-region of_parse_phandle error\n"); return -ENODEV; } - - if (of_address_to_resource(reserved_node, 0, &reserved_res)) { + if (of_address_to_resource(reserved_node, 0, &reserved_fw)) { vpu_dbg(LVL_ERR, "error: boot-region of_address_to_resource error\n"); return -EINVAL; } - dev->core_dev[0].m0_p_fw_space_phy = reserved_res.start; - dev->core_dev[1].m0_p_fw_space_phy = reserved_res.start + M0_BOOT_SIZE; + reserved_node = of_parse_phandle(np, "rpc-region", 0); if (!reserved_node) { vpu_dbg(LVL_ERR, "error: rpc-region of_parse_phandle error\n"); return -ENODEV; } - - if (of_address_to_resource(reserved_node, 0, &reserved_res)) { + if (of_address_to_resource(reserved_node, 0, &reserved_rpc)) { vpu_dbg(LVL_ERR, "error: rpc-region of_address_to_resource error\n"); return -EINVAL; } - dev->core_dev[0].m0_rpc_phy = reserved_res.start; - dev->core_dev[1].m0_rpc_phy = reserved_res.start + SHARED_SIZE; + fw_total_size = 0; + rpc_total_size = 0; for (i = 0; i < dev->core_num; i++) { - u32 val; + struct core_device *core = &dev->core_dev[i]; - ret = of_property_read_u32_index(np, "reg-fw-base", i, &val); - if (ret) { - vpu_dbg(LVL_ERR, - "find reg-fw-base for core[%d] fail\n", i); + core->id = i; + ret = parse_core_info(core, np); + if (ret) return ret; - } - dev->core_dev[i].reg_fw_base = val; + + core->m0_p_fw_space_phy = reserved_fw.start + fw_total_size; + core->m0_rpc_phy = reserved_rpc.start + rpc_total_size; + fw_total_size += core->fw_buf_size; + rpc_total_size += core->rpc_buf_size; + rpc_total_size += core->print_buf_size; + } + + if (fw_total_size > resource_size(&reserved_fw)) { + vpu_err("boot-region's size(0x%llx) is less than wanted:0x%x\n", + resource_size(&reserved_fw), fw_total_size); + return -EINVAL; + } + if (rpc_total_size > resource_size(&reserved_rpc)) { + vpu_err("rpc-region's size(0x%llx) is less than wanted:0x%x\n", + resource_size(&reserved_rpc), rpc_total_size); + return -EINVAL; } return 0; @@ -3445,10 +3534,15 @@ static int reset_vpu_core_dev(struct core_device *core_dev) core_dev->firmware_started = false; rpc_init_shared_memory_encoder(&core_dev->shared_mem, cpu_phy_to_mu(core_dev, core_dev->m0_rpc_phy), - core_dev->m0_rpc_virt, SHARED_SIZE); + core_dev->m0_rpc_virt, core_dev->rpc_buf_size, + &core_dev->rpc_actual_size); rpc_set_system_cfg_value_encoder(core_dev->shared_mem.pSharedInterface, VPU_REG_BASE, core_dev->id); + if (core_dev->rpc_actual_size > core_dev->rpc_buf_size) + vpu_err("rpc actual size(0x%x) > (0x%x), may occur overlay\n", + core_dev->rpc_actual_size, core_dev->rpc_buf_size); + return 0; } @@ -3521,22 +3615,30 @@ static int init_vpu_core_dev(struct core_device *core_dev) } //firmware space for M0 core_dev->m0_p_fw_space_vir = - ioremap_wc(core_dev->m0_p_fw_space_phy, M0_BOOT_SIZE); + ioremap_wc(core_dev->m0_p_fw_space_phy, core_dev->fw_buf_size); if (!core_dev->m0_p_fw_space_vir) vpu_dbg(LVL_ERR, "failed to remap space for M0 firmware\n"); - memset_io(core_dev->m0_p_fw_space_vir, 0, M0_BOOT_SIZE); + memset_io(core_dev->m0_p_fw_space_vir, 0, core_dev->fw_buf_size); - core_dev->m0_rpc_virt = ioremap_wc(core_dev->m0_rpc_phy, SHARED_SIZE); + core_dev->m0_rpc_virt = + ioremap_wc(core_dev->m0_rpc_phy, core_dev->rpc_buf_size); if (!core_dev->m0_rpc_virt) vpu_dbg(LVL_ERR, "failed to remap space for shared memory\n"); - memset_io(core_dev->m0_rpc_virt, 0, SHARED_SIZE); + memset_io(core_dev->m0_rpc_virt, 0, core_dev->rpc_buf_size); reset_vpu_core_dev(core_dev); init_vpu_attrs(core_dev); + snprintf(core_dev->name, sizeof(core_dev->name) - 1, + "core.%d", core_dev->id); + core_dev->core_attr.attr.name = core_dev->name; + core_dev->core_attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444); + core_dev->core_attr.show = show_core_info; + device_create_file(core_dev->generic_dev, &core_dev->core_attr); + return 0; error: if (core_dev->workqueue) { @@ -3551,6 +3653,7 @@ static int uninit_vpu_core_dev(struct core_device *core_dev) if (!core_dev) return -EINVAL; + device_remove_file(core_dev->generic_dev, &core_dev->core_attr); release_vpu_attrs(core_dev); if (core_dev->workqueue) { cancel_work_sync(&core_dev->msg_work); @@ -3660,6 +3763,8 @@ static int vpu_probe(struct platform_device *pdev) mutex_unlock(&dev->dev_mutex); pm_runtime_put_sync(&pdev->dev); + vpu_dbg(LVL_ALL, "VPU Encoder registered\n"); + return 0; error_init_core: @@ -3699,10 +3804,6 @@ static int vpu_remove(struct platform_device *pdev) uninit_vpu_core_dev(&dev->core_dev[i]); mutex_unlock(&dev->dev_mutex); - if (dev->m0_pfw) { - release_firmware(dev->m0_pfw); - dev->m0_pfw = NULL; - } vpu_disable_hw(dev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h index 086dc465ce1a..993b41498a42 100644 --- a/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h +++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h @@ -49,9 +49,12 @@ extern unsigned int vpu_dbg_level_encoder; #define M0FW_FILENAME "vpu/vpu_fw_imx8_enc.bin" #define MMAP_BUF_TYPE_SHIFT 28 #define MMAP_BUF_TYPE_MASK 0xF0000000 -#define M0_BOOT_SIZE 0x1000000 -#define M0_PRINT_OFFSET 0x500000 -#define SHARED_SIZE 0x00400000 +#define M0_BOOT_SIZE_DEFAULT 0x1000000 +#define M0_BOOT_SIZE_MIN 0x100000 +#define RPC_SIZE_DEFAULT 0x500000 +#define RPC_SIZE_MIN 0x100000 +#define PRINT_SIZE_DEFAULT 0x300000 +#define PRINT_SIZE_MIN 0x100000 #define MEM_SIZE 0x2800000 #define YUV_SIZE 0x4000000 #define STREAM_SIZE 0x300000 @@ -227,11 +230,15 @@ struct vpu_attr { }; struct core_device { - struct firmware *m0_pfw; void *m0_p_fw_space_vir; u_int32 m0_p_fw_space_phy; + u32 fw_buf_size; + u32 fw_actual_size; void *m0_rpc_virt; u_int32 m0_rpc_phy; + u32 rpc_buf_size; + u32 print_buf_size; + u32 rpc_actual_size; struct mutex core_mutex; struct mutex cmd_mutex; bool fw_is_ready; @@ -254,6 +261,8 @@ struct core_device { bool snapshot; bool suspend; bool hang; + struct device_attribute core_attr; + char name[64]; }; struct vpu_dev { @@ -262,7 +271,6 @@ struct vpu_dev { struct video_device *pvpu_encoder_dev; struct platform_device *plat_dev; struct clk *clk_m0; - struct firmware *m0_pfw; void __iomem *regs_base; void __iomem *regs_enc; struct mutex dev_mutex; diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c index 0cb4a0722590..366e76ef4d3d 100644 --- a/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c +++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c @@ -58,7 +58,8 @@ void rpc_init_shared_memory_encoder(struct shared_addr *This, unsigned long long base_phy_addr, void *base_virt_addr, - u_int32 total_size) + u_int32 total_size, + u32 *actual_size) { pENC_RPC_HOST_IFACE pSharedInterface; unsigned int phy_addr; @@ -124,6 +125,8 @@ void rpc_init_shared_memory_encoder(struct shared_addr *This, pEncCtrlInterface->pEncDSAStatus = phy_addr; phy_addr += sizeof(ENC_DSA_STATUS_t); } + if (actual_size) + *actual_size = phy_addr - base_phy_addr; } void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base, u_int32 core_id) diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h index fde75484a72e..7078d80da280 100644 --- a/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h +++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h @@ -102,7 +102,8 @@ struct event_msg { void rpc_init_shared_memory_encoder(struct shared_addr *This, unsigned long long base_phy_addr, void *base_virt_addr, - u_int32 total_size); + u_int32 total_size, + u32 *actual_size); void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base, u_int32 core_id); void rpc_send_cmd_buf_encoder(struct shared_addr *This, u_int32 idx,