From: Alpha Lin Date: Mon, 29 Dec 2014 02:04:19 +0000 (+0800) Subject: rk3288, rk3036, rk312x, vpu: new vpu driver. X-Git-Tag: firefly_0821_release~4361 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=c1b99a7acb98e3d88cf96f5831df091d10689e8c;p=firefly-linux-kernel-4.4.55.git rk3288, rk3036, rk312x, vpu: new vpu driver. Define the vpu and hevc as the sub-devices of the vpu_combo on rk3036 and rk312x, combine the work queue of two device, avoid two device running in the same time, (cause bus error on platform rk3036 and rk312x). --- diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 64f4f0182f4f..daba534a2c04 100755 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -649,7 +649,7 @@ }; }; - vpu: vpu_service@10108000 { + /*vpu: vpu_service@10108000 { compatible = "vpu_service"; iommu_enabled = <1>; reg = <0x10108000 0x800>; @@ -671,6 +671,37 @@ clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core"; name = "hevc_service"; status = "okay"; + };*/ + vpu: vpu_service { + compatible = "rockchip,vpu_sub"; + iommu_enabled = <1>; + reg = <0x10108400 0x400>; + interrupts = ; + interrupt-names = "irq_dec"; + dev_mode = <0>; + name = "vpu_service"; + }; + + hevc: hevc_service { + compatible = "rockchip,hevc_sub"; + iommu_enabled = <1>; + reg = <0x1010c000 0x400>; + interrupts = ; + interrupt-names = "irq_dec"; + dev_mode = <1>; + name = "hevc_service"; + }; + + vpu_combo: vpu_combo@ff9a0000 { + compatible = "rockchip,vpu_combo"; + subcnt = <2>; + rockchip,sub = <&vpu>, <&hevc>; + clocks = <&aclk_vcodec_pre>, <&clk_gates3 12>, <&clk_hevc_core>; + clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core"; + mode_bit = <3>; + mode_ctrl = <0x144>; + name = "vpu_combo"; + status = "okay"; }; vop_mmu { diff --git a/arch/arm/boot/dts/rk312x.dtsi b/arch/arm/boot/dts/rk312x.dtsi index b39e094dc4ca..607235eb277d 100755 --- a/arch/arm/boot/dts/rk312x.dtsi +++ b/arch/arm/boot/dts/rk312x.dtsi @@ -772,27 +772,36 @@ status = "disabled"; }; - vpu: vpu_service@10106000 { - compatible = "vpu_service"; + vpu: vpu_service { + compatible = "rockchip,vpu_sub"; iommu_enabled = <1>; reg = <0x10106000 0x800>; - interrupts = , ; + interrupts = , + ; interrupt-names = "irq_enc", "irq_dec"; - clocks = <&clk_vdpu>, <&hclk_vdpu>; - clock-names = "aclk_vcodec", "hclk_vcodec"; + dev_mode = <0>; name = "vpu_service"; - status = "okay"; }; - hevc: hevc_service@10104000 { - compatible = "rockchip,hevc_service"; + hevc: hevc_service { + compatible = "rockchip,hevc_sub"; iommu_enabled = <1>; reg = <0x10104000 0x400>; interrupts = ; interrupt-names = "irq_dec"; + dev_mode = <1>; + name = "hevc_service"; + }; + + vpu_combo: vpu_combo@ff9a0000 { + compatible = "rockchip,vpu_combo"; + subcnt = <2>; + rockchip,sub = <&vpu>, <&hevc>; clocks = <&clk_vdpu>, <&hclk_vdpu>, <&clk_hevc_core>; clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core"; - name = "hevc_service"; + mode_bit = <15>; + mode_ctrl = <0x144>; + name = "vpu_combo"; status = "okay"; }; diff --git a/arch/arm/mach-rockchip/vcodec_service.c b/arch/arm/mach-rockchip/vcodec_service.c old mode 100755 new mode 100644 index 31a3645aa67a..e271f60ffc67 --- a/arch/arm/mach-rockchip/vcodec_service.c +++ b/arch/arm/mach-rockchip/vcodec_service.c @@ -1,8 +1,7 @@ - -/* arch/arm/mach-rk29/vpu.c - * - * Copyright (C) 2010 ROCKCHIP, Inc. +/** + * Copyright (C) 2014 ROCKCHIP, Inc. * author: chenhengming chm@rock-chips.com + * Alpha Lin, alpha.lin@rock-chips.com * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -34,8 +33,11 @@ #include #include #include +#include #include #include +#include +#include #include #include @@ -64,8 +66,12 @@ #include "vcodec_service.h" +static int debug; +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, + "Debug level - higher value produces more verbose messages"); + #define HEVC_TEST_ENABLE 0 -#define HEVC_SIM_ENABLE 0 #define VCODEC_CLOCK_ENABLE 1 typedef enum { @@ -75,6 +81,13 @@ typedef enum { HEVC_ID = 0x6867, } VPU_HW_ID; +enum VPU_HW_SPEC { + VPU_TYPE_VPU, + VPU_TYPE_HEVC, + VPU_TYPE_COMBO_NOENC, + VPU_TYPE_COMBO +}; + typedef enum { VPU_DEC_TYPE_9190 = 0, VPU_ENC_TYPE_8270 = 0x100, @@ -175,11 +188,10 @@ static VPU_HW_INFO_E vpu_hw_set[] = { .enc_offset = 0x0, .enc_reg_num = 0, .enc_io_size = 0, - .dec_offset = REG_SIZE_ENC_4831, + .dec_offset = 0, .dec_reg_num = REG_NUM_9190_DEC_PP, .dec_io_size = REG_NUM_9190_DEC_PP * 4, }, - }; @@ -211,6 +223,24 @@ static VPU_HW_INFO_E vpu_hw_set[] = { #define VPU_REG_DEC_PP_GATE 61 #define VPU_REG_DEC_PP_GATE_BIT (1<<8) +#define DEBUG +#ifdef DEBUG +#define vpu_debug(level, fmt, args...) \ + do { \ + if (debug >= level) \ + pr_info("%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) +#else +#define vpu_debug(level, fmt, args...) +#endif + +#define vpu_debug_enter() vpu_debug(4, "enter\n") +#define vpu_debug_leave() vpu_debug(4, "leave\n") + +#define vpu_err(fmt, args...) \ + pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) + #if defined(CONFIG_VCODEC_MMU) static u8 addr_tbl_vpu_h264dec[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, @@ -315,7 +345,14 @@ typedef struct vpu_device { enum vcodec_device_id { VCODEC_DEVICE_ID_VPU, - VCODEC_DEVICE_ID_HEVC + VCODEC_DEVICE_ID_HEVC, + VCODEC_DEVICE_ID_COMBO +}; + +enum VCODEC_RUNNING_MODE { + VCODEC_RUNNING_MODE_NONE = -1, + VCODEC_RUNNING_MODE_VPU, + VCODEC_RUNNING_MODE_HEVC, }; struct vcodec_mem_region { @@ -328,23 +365,54 @@ struct vcodec_mem_region { struct ion_handle *hdl; }; +enum vpu_ctx_state { + MMU_ACTIVATED = BIT(0) +}; + +struct vpu_subdev_data { + struct cdev cdev; + dev_t dev_t; + struct class *cls; + struct device *child_dev; + + int irq_enc; + int irq_dec; + struct vpu_service_info *pservice; + + u32 *regs; + enum VCODEC_RUNNING_MODE mode; + struct list_head lnk_service; + + struct device *dev; + + vpu_device enc_dev; + vpu_device dec_dev; + VPU_HW_INFO_E *hw_info; + + unsigned long reg_size; + unsigned long state; + +#if defined(CONFIG_VCODEC_MMU) + struct device *mmu_dev; +#endif +}; + typedef struct vpu_service_info { struct wake_lock wake_lock; struct delayed_work power_off_work; - struct mutex *lock; - struct list_head *waiting; /* link to link_reg in struct vpu_reg */ - struct list_head *running; /* link to link_reg in struct vpu_reg */ + struct mutex lock; + struct list_head waiting; /* link to link_reg in struct vpu_reg */ + struct list_head running; /* link to link_reg in struct vpu_reg */ struct list_head done; /* link to link_reg in struct vpu_reg */ struct list_head session; /* link to list_session in struct vpu_session */ atomic_t total_running; bool enabled; - vpu_reg **reg_codec; + vpu_reg *reg_codec; vpu_reg *reg_pproc; vpu_reg *reg_resev; VPUHwDecConfig_t dec_config; VPUHwEncConfig_t enc_config; - VPU_HW_INFO_E *hw_info; - unsigned long reg_size; + bool auto_freq; bool bug_dec_addr; atomic_t freq_status; @@ -355,19 +423,8 @@ typedef struct vpu_service_info { struct clk *clk_cabac; struct clk *pd_video; - int irq_dec; - int irq_enc; - - vpu_device enc_dev; - vpu_device dec_dev; - struct device *dev; - struct cdev cdev; - dev_t dev_t; - struct class *cls; - struct device *child_dev; - struct dentry *debugfs_dir; struct dentry *debugfs_file_regs; @@ -375,14 +432,24 @@ typedef struct vpu_service_info { #if defined(CONFIG_VCODEC_MMU) struct ion_client *ion_client; struct list_head mem_region_list; - struct device *mmu_dev; #endif enum vcodec_device_id dev_id; - u32 reserved_mode; + enum VCODEC_RUNNING_MODE curr_mode; + u32 prev_mode; struct delayed_work simulate_work; + + u32 mode_bit; + u32 mode_ctrl; + u32 *reg_base; + u32 ioaddr; + u32 *grf_base; + char *name; + + u32 subcnt; + struct list_head subdev_list; } vpu_service_info; struct vcodec_combo { @@ -395,18 +462,13 @@ struct vcodec_combo { enum vcodec_device_id current_hw_mode; }; -typedef struct vpu_request -{ +typedef struct vpu_request { unsigned long *req; unsigned long size; } vpu_request; -/// global variable -//static struct clk *pd_video; -static struct dentry *parent; // debugfs root directory for all device (vpu, hevc). -/* mutex for selecting operation registers of vpu or hevc */ -static struct mutex g_mode_mutex; -static struct vcodec_combo g_combo; +/* debugfs root directory for all device (vpu, hevc).*/ +static struct dentry *parent; #ifdef CONFIG_DEBUG_FS static int vcodec_debugfs_init(void); @@ -423,121 +485,105 @@ static const struct file_operations debug_vcodec_fops = { #endif #define VDPU_SOFT_RESET_REG 101 -#define VDPU_CLEAR_CACHE_REG 516 -#define VEPU_CLEAR_CACHE_REG 772 -#define HEVC_CLEAR_CACHE_REG 260 +#define VDPU_CLEAN_CACHE_REG 516 +#define VEPU_CLEAN_CACHE_REG 772 +#define HEVC_CLEAN_CACHE_REG 260 #define VPU_REG_ENABLE(base, reg) do { \ base[reg] = 1; \ } while (0) #define VDPU_SOFT_RESET(base) VPU_REG_ENABLE(base, VDPU_SOFT_RESET_REG) -#define VDPU_CLEAR_CACHE(base) VPU_REG_ENABLE(base, VDPU_CLEAR_CACHE_REG) -#define VEPU_CLEAR_CACHE(base) VPU_REG_ENABLE(base, VEPU_CLEAR_CACHE_REG) -#define HEVC_CLEAR_CACHE(base) VPU_REG_ENABLE(base, HEVC_CLEAR_CACHE_REG) +#define VDPU_CLEAN_CACHE(base) VPU_REG_ENABLE(base, VDPU_CLEAN_CACHE_REG) +#define VEPU_CLEAN_CACHE(base) VPU_REG_ENABLE(base, VEPU_CLEAN_CACHE_REG) +#define HEVC_CLEAN_CACHE(base) VPU_REG_ENABLE(base, HEVC_CLEAN_CACHE_REG) #define VPU_POWER_OFF_DELAY 4*HZ /* 4s */ #define VPU_TIMEOUT_DELAY 2*HZ /* 2s */ -#define VPU_SIMULATE_DELAY msecs_to_jiffies(15) -#define BIT_VCODEC_SEL_RK3036 (1<<3) -#define BIT_VCODEC_SEL_RK312X (1<<15) -static void vcodec_enter_mode_nolock(enum vcodec_device_id id, u32 *reserved_mode) +static void vcodec_enter_mode(struct vpu_subdev_data *data) { - if (cpu_is_rk3036() || cpu_is_rk312x()) { - int bits = cpu_is_rk3036() ? BIT_VCODEC_SEL_RK3036 : BIT_VCODEC_SEL_RK312X; - void __iomem *addr = cpu_is_rk3036() ? (RK_GRF_VIRT + RK3036_GRF_SOC_CON1) : (RK_GRF_VIRT + RK312X_GRF_SOC_CON1); - if (reserved_mode) - *reserved_mode = readl_relaxed(addr); - if (id == VCODEC_DEVICE_ID_HEVC) - writel_relaxed(readl_relaxed(addr) | (bits) | (bits << 16), addr); - else - writel_relaxed((readl_relaxed(addr) & (~bits)) | (bits << 16), addr); + int bits; + u32 raw = 0; + struct vpu_service_info *pservice = data->pservice; + struct vpu_subdev_data *subdata, *n; + if (pservice->subcnt < 2 || pservice->curr_mode == data->mode) { + pservice->prev_mode = pservice->curr_mode; + return; } -} - -static void vcodec_exit_mode_nolock(enum vcodec_device_id id, u32 reserved_mode) -{ - if (cpu_is_rk3036() || cpu_is_rk312x()) { - int bits = cpu_is_rk3036() ? BIT_VCODEC_SEL_RK3036 : BIT_VCODEC_SEL_RK312X; - void __iomem *addr = cpu_is_rk3036() ? (RK_GRF_VIRT + RK3036_GRF_SOC_CON1) : (RK_GRF_VIRT + RK312X_GRF_SOC_CON1); - writel_relaxed(reserved_mode | (bits << 16), addr); + vpu_debug(3, "vcodec enter mode %d\n", data->mode); +#if defined(CONFIG_VCODEC_MMU) + list_for_each_entry_safe(subdata, n, &pservice->subdev_list, lnk_service) { + if (data != subdata && subdata->mmu_dev && + test_bit(MMU_ACTIVATED, &subdata->state)) { + clear_bit(MMU_ACTIVATED, &subdata->state); + rockchip_iovmm_deactivate(subdata->dev); + } + } +#endif + bits = 1 << pservice->mode_bit; + raw = readl_relaxed(pservice->grf_base + pservice->mode_ctrl / 4); + if (data->mode == VCODEC_RUNNING_MODE_HEVC) + writel_relaxed(raw | bits | (bits << 16), + pservice->grf_base + pservice->mode_ctrl / 4); + else + writel_relaxed((raw & (~bits)) | (bits << 16), + pservice->grf_base + pservice->mode_ctrl / 4); +#if defined(CONFIG_VCODEC_MMU) + if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) { + set_bit(MMU_ACTIVATED, &data->state); + rockchip_iovmm_activate(data->dev); } +#endif + pservice->prev_mode = pservice->curr_mode; + pservice->curr_mode = data->mode; } -static void vcodec_enter_mode(enum vcodec_device_id id) +static void vcodec_exit_mode(struct vpu_service_info *pservice) { - if (cpu_is_rk3036() || cpu_is_rk312x()) - mutex_lock(&g_mode_mutex); - vcodec_enter_mode_nolock(id, NULL); -} -static void vcodec_exit_mode(void) -{ - if (cpu_is_rk3036() || cpu_is_rk312x()) - mutex_unlock(&g_mode_mutex); } static int vpu_get_clk(struct vpu_service_info *pservice) { #if VCODEC_CLOCK_ENABLE do { - pservice->aclk_vcodec = devm_clk_get(pservice->dev, "aclk_vcodec"); - if (IS_ERR(pservice->aclk_vcodec)) { - dev_err(pservice->dev, "failed on clk_get aclk_vcodec\n"); - break; - } - - pservice->hclk_vcodec = devm_clk_get(pservice->dev, "hclk_vcodec"); - if (IS_ERR(pservice->hclk_vcodec)) { - dev_err(pservice->dev, "failed on clk_get hclk_vcodec\n"); - break; - } + switch (pservice->dev_id) { + case VCODEC_DEVICE_ID_HEVC: + pservice->clk_cabac = devm_clk_get(pservice->dev, "clk_cabac"); + if (IS_ERR(pservice->clk_cabac)) { + dev_err(pservice->dev, "failed on clk_get clk_cabac\n"); + break; + } - if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) { + pservice->pd_video = devm_clk_get(pservice->dev, "pd_hevc"); + if (IS_ERR(pservice->pd_video)) { + dev_err(pservice->dev, "failed on clk_get pd_hevc\n"); + break; + } + case VCODEC_DEVICE_ID_COMBO: pservice->clk_core = devm_clk_get(pservice->dev, "clk_core"); if (IS_ERR(pservice->clk_core)) { dev_err(pservice->dev, "failed on clk_get clk_core\n"); break; } - - if (!cpu_is_rk3036() && !cpu_is_rk312x()) { - pservice->clk_cabac = devm_clk_get(pservice->dev, "clk_cabac"); - if (IS_ERR(pservice->clk_cabac)) { - dev_err(pservice->dev, "failed on clk_get clk_cabac\n"); - break; - } - } else { - pservice->clk_cabac = NULL; - } - - if (!cpu_is_rk3036() && !cpu_is_rk312x()) { - pservice->pd_video = devm_clk_get(pservice->dev, "pd_hevc"); - if (IS_ERR(pservice->pd_video)) { - dev_err(pservice->dev, "failed on clk_get pd_hevc\n"); - break; - } - } else { - pservice->pd_video = NULL; - } - } else { - if (!cpu_is_rk3036() && !cpu_is_rk312x()) { - pservice->pd_video = devm_clk_get(pservice->dev, "pd_video"); - if (IS_ERR(pservice->pd_video)) { - dev_err(pservice->dev, "failed on clk_get pd_video\n"); - break; - } - } else { - pservice->pd_video = NULL; + case VCODEC_DEVICE_ID_VPU: + pservice->aclk_vcodec = devm_clk_get(pservice->dev, "aclk_vcodec"); + if (IS_ERR(pservice->aclk_vcodec)) { + dev_err(pservice->dev, "failed on clk_get aclk_vcodec\n"); + break; } - } - if (cpu_is_rk312x()) { - pservice->pd_video = devm_clk_get(pservice->dev, "pd_video"); - if (IS_ERR(pservice->pd_video)) { - dev_err(pservice->dev, "failed on clk_get pd_video\n"); + pservice->hclk_vcodec = devm_clk_get(pservice->dev, "hclk_vcodec"); + if (IS_ERR(pservice->hclk_vcodec)) { + dev_err(pservice->dev, "failed on clk_get hclk_vcodec\n"); break; } + if (pservice->pd_video == NULL) + pservice->pd_video = devm_clk_get(pservice->dev, "pd_video"); + break; + default: + ; } return 0; @@ -552,27 +598,16 @@ static int vpu_get_clk(struct vpu_service_info *pservice) static void vpu_put_clk(struct vpu_service_info *pservice) { #if VCODEC_CLOCK_ENABLE - if (pservice->pd_video) { + if (pservice->pd_video) devm_clk_put(pservice->dev, pservice->pd_video); - } - - if (pservice->aclk_vcodec) { + if (pservice->aclk_vcodec) devm_clk_put(pservice->dev, pservice->aclk_vcodec); - } - - if (pservice->hclk_vcodec) { + if (pservice->hclk_vcodec) devm_clk_put(pservice->dev, pservice->hclk_vcodec); - } - - if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) { - if (pservice->clk_core) { - devm_clk_put(pservice->dev, pservice->clk_core); - } - - if (pservice->clk_cabac) { - devm_clk_put(pservice->dev, pservice->clk_cabac); - } - } + if (pservice->clk_core) + devm_clk_put(pservice->dev, pservice->clk_core); + if (pservice->clk_cabac) + devm_clk_put(pservice->dev, pservice->clk_cabac); #endif } @@ -603,58 +638,34 @@ static void vpu_reset(struct vpu_service_info *pservice) cru_set_soft_reset(SOFT_RST_CPU_VCODEC, false); pmu_set_idle_request(IDLE_REQ_VIDEO, false); #endif - *pservice->reg_codec = NULL; + pservice->reg_codec = NULL; pservice->reg_pproc = NULL; pservice->reg_resev = NULL; } -static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg); -static void vpu_service_session_clear(struct vpu_service_info *pservice, vpu_session *session) +static void reg_deinit(struct vpu_subdev_data *data, vpu_reg *reg); +static void vpu_service_session_clear(struct vpu_subdev_data *data, vpu_session *session) { vpu_reg *reg, *n; list_for_each_entry_safe(reg, n, &session->waiting, session_link) { - reg_deinit(pservice, reg); + reg_deinit(data, reg); } list_for_each_entry_safe(reg, n, &session->running, session_link) { - reg_deinit(pservice, reg); + reg_deinit(data, reg); } list_for_each_entry_safe(reg, n, &session->done, session_link) { - reg_deinit(pservice, reg); + reg_deinit(data, reg); } } static void vpu_service_dump(struct vpu_service_info *pservice) { - int running; - vpu_reg *reg, *reg_tmp; - vpu_session *session, *session_tmp; - - running = atomic_read(&pservice->total_running); - printk("total_running %d\n", running); - - printk("reg_codec 0x%.8x\n", (unsigned int)(*pservice->reg_codec)); - printk("reg_pproc 0x%.8x\n", (unsigned int)pservice->reg_pproc); - printk("reg_resev 0x%.8x\n", (unsigned int)pservice->reg_resev); - - list_for_each_entry_safe(session, session_tmp, &pservice->session, list_session) { - printk("session pid %d type %d:\n", session->pid, session->type); - running = atomic_read(&session->task_running); - printk("task_running %d\n", running); - list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) { - printk("waiting register set 0x%.8x\n", (unsigned int)reg); - } - list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) { - printk("running register set 0x%.8x\n", (unsigned int)reg); - } - list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) { - printk("done register set 0x%.8x\n", (unsigned int)reg); - } - } } static void vpu_service_power_off(struct vpu_service_info *pservice) { int total_running; + struct vpu_subdev_data *data = NULL, *n; if (!pservice->enabled) return; @@ -669,13 +680,14 @@ static void vpu_service_power_off(struct vpu_service_info *pservice) pr_info("%s: power off...", dev_name(pservice->dev)); udelay(10); - #if defined(CONFIG_VCODEC_MMU) - if (pservice->mmu_dev && !(cpu_is_rk3036() || cpu_is_rk312x())) { - vcodec_enter_mode(pservice->dev_id); - rockchip_iovmm_deactivate(pservice->dev); - vcodec_exit_mode(); + list_for_each_entry_safe(data, n, &pservice->subdev_list, lnk_service) { + if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) { + clear_bit(MMU_ACTIVATED, &data->state); + rockchip_iovmm_deactivate(data->dev); + } } + pservice->curr_mode = VCODEC_RUNNING_MODE_NONE; #endif #if VCODEC_CLOCK_ENABLE @@ -685,12 +697,10 @@ static void vpu_service_power_off(struct vpu_service_info *pservice) clk_disable_unprepare(pservice->hclk_vcodec); if (pservice->aclk_vcodec) clk_disable_unprepare(pservice->aclk_vcodec); - if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) { - if (pservice->clk_core) - clk_disable_unprepare(pservice->clk_core); - if (pservice->clk_cabac) - clk_disable_unprepare(pservice->clk_cabac); - } + if (pservice->clk_core) + clk_disable_unprepare(pservice->clk_core); + if (pservice->clk_cabac) + clk_disable_unprepare(pservice->clk_cabac); #endif wake_unlock(&pservice->wake_lock); @@ -707,9 +717,9 @@ static void vpu_power_off_work(struct work_struct *work_s) struct delayed_work *dlwork = container_of(work_s, struct delayed_work, work); struct vpu_service_info *pservice = container_of(dlwork, struct vpu_service_info, power_off_work); - if (mutex_trylock(pservice->lock)) { + if (mutex_trylock(&pservice->lock)) { vpu_service_power_off(pservice); - mutex_unlock(pservice->lock); + mutex_unlock(&pservice->lock); } else { /* Come back later if the device is busy... */ vpu_queue_power_off_work(pservice); @@ -729,49 +739,29 @@ static void vpu_service_power_on(struct vpu_service_info *pservice) return ; pservice->enabled = true; - printk("%s: power on\n", dev_name(pservice->dev)); + pr_info("%s: power on\n", dev_name(pservice->dev)); + +#define BIT_VCODEC_CLK_SEL (1<<10) + if (cpu_is_rk312x()) + writel_relaxed(readl_relaxed(RK_GRF_VIRT + RK312X_GRF_SOC_CON1) | + BIT_VCODEC_CLK_SEL | (BIT_VCODEC_CLK_SEL << 16), + RK_GRF_VIRT + RK312X_GRF_SOC_CON1); #if VCODEC_CLOCK_ENABLE if (pservice->aclk_vcodec) clk_prepare_enable(pservice->aclk_vcodec); - if (pservice->hclk_vcodec) clk_prepare_enable(pservice->hclk_vcodec); - - if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) { - if (pservice->clk_core) - clk_prepare_enable(pservice->clk_core); + if (pservice->clk_core) + clk_prepare_enable(pservice->clk_core); if (pservice->clk_cabac) clk_prepare_enable(pservice->clk_cabac); - } - if (pservice->pd_video) clk_prepare_enable(pservice->pd_video); #endif -#if defined(CONFIG_ARCH_RK319X) - /// select aclk_vepu as vcodec clock source. -#define BIT_VCODEC_SEL (1<<7) - writel_relaxed(readl_relaxed(RK319X_GRF_BASE + GRF_SOC_CON1) | - (BIT_VCODEC_SEL) | (BIT_VCODEC_SEL << 16), - RK319X_GRF_BASE + GRF_SOC_CON1); -#endif -#define BIT_VCODEC_CLK_SEL (1<<10) - if (cpu_is_rk312x()) - writel_relaxed(readl_relaxed(RK_GRF_VIRT + RK312X_GRF_SOC_CON1) | - BIT_VCODEC_CLK_SEL | (BIT_VCODEC_CLK_SEL << 16), - RK_GRF_VIRT + RK312X_GRF_SOC_CON1); - udelay(10); wake_lock(&pservice->wake_lock); - -#if defined(CONFIG_VCODEC_MMU) - if (pservice->mmu_dev && !(cpu_is_rk3036() || cpu_is_rk312x())) { - vcodec_enter_mode(pservice->dev_id); - rockchip_iovmm_activate(pservice->dev); - vcodec_exit_mode(); - } -#endif } static inline bool reg_check_rmvb_wmv(vpu_reg *reg) @@ -799,32 +789,34 @@ static inline int reg_probe_width(vpu_reg *reg) } #if defined(CONFIG_VCODEC_MMU) -static int vcodec_fd_to_iova(struct vpu_service_info *pservice, vpu_reg *reg,int fd) +static int vcodec_fd_to_iova(struct vpu_subdev_data *data, vpu_reg *reg,int fd) { + struct vpu_service_info *pservice = data->pservice; struct ion_handle *hdl; int ret = 0; struct vcodec_mem_region *mem_region; hdl = ion_import_dma_buf(pservice->ion_client, fd); if (IS_ERR(hdl)) { - dev_err(pservice->dev, "import dma-buf from fd %d failed\n", fd); + vpu_err("import dma-buf from fd %d failed\n", fd); return PTR_ERR(hdl); } mem_region = kzalloc(sizeof(struct vcodec_mem_region), GFP_KERNEL); if (mem_region == NULL) { - dev_err(pservice->dev, "allocate memory for iommu memory region failed\n"); + vpu_err("allocate memory for iommu memory region failed\n"); ion_free(pservice->ion_client, hdl); return -1; } mem_region->hdl = hdl; - vcodec_enter_mode(pservice->dev_id); - ret = ion_map_iommu(pservice->dev, pservice->ion_client, mem_region->hdl, &mem_region->iova, &mem_region->len); - vcodec_exit_mode(); + vcodec_enter_mode(data); + ret = ion_map_iommu(data->dev, pservice->ion_client, + mem_region->hdl, &mem_region->iova, &mem_region->len); + vcodec_exit_mode(pservice); if (ret < 0) { - dev_err(pservice->dev, "ion map iommu failed\n"); + vpu_err("ion map iommu failed\n"); kfree(mem_region); ion_free(pservice->ion_client, hdl); return ret; @@ -834,10 +826,11 @@ static int vcodec_fd_to_iova(struct vpu_service_info *pservice, vpu_reg *reg,int return mem_region->iova; } -static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, +static int vcodec_bufid_to_iova(struct vpu_subdev_data *data, u8 *tbl, int size, vpu_reg *reg, struct extra_info_for_iommu *ext_inf) { + struct vpu_service_info *pservice = data->pservice; int i; int usr_fd = 0; int offset = 0; @@ -852,7 +845,7 @@ static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, for (i = 0; i < size; i++) { usr_fd = reg->reg[tbl[i]] & 0x3FF; - if (tbl[i] == 41 && pservice->hw_info->hw_id != HEVC_ID && + if (tbl[i] == 41 && data->hw_info->hw_id != HEVC_ID && (reg->type == VPU_DEC || reg->type == VPU_DEC_PP)) /* special for vpu dec num 41 regitster */ offset = reg->reg[tbl[i]] >> 10 << 4; @@ -870,7 +863,7 @@ static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, return PTR_ERR(hdl); } - if (tbl[i] == 42 && pservice->hw_info->hw_id == HEVC_ID){ + if (tbl[i] == 42 && data->hw_info->hw_id == HEVC_ID){ int i = 0; char *pps; pps = (char *)ion_map_kernel(pservice->ion_client,hdl); @@ -885,7 +878,7 @@ static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, scaling_fd = scaling_offset&0x3ff; scaling_offset = scaling_offset >> 10; if(scaling_fd > 0) { - tmp = vcodec_fd_to_iova(pservice,reg,scaling_fd); + tmp = vcodec_fd_to_iova(data, reg, scaling_fd); tmp += scaling_offset; pps[i*80+74] = tmp & 0xff; pps[i*80+75] = (tmp >> 8) & 0xff; @@ -905,13 +898,13 @@ static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, mem_region->hdl = hdl; mem_region->reg_idx = tbl[i]; - vcodec_enter_mode(pservice->dev_id); - ret = ion_map_iommu(pservice->dev, + vcodec_enter_mode(data); + ret = ion_map_iommu(data->dev, pservice->ion_client, mem_region->hdl, &mem_region->iova, &mem_region->len); - vcodec_exit_mode(); + vcodec_exit_mode(pservice); if (ret < 0) { dev_err(pservice->dev, "ion map iommu failed\n"); @@ -927,7 +920,7 @@ static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, if (ext_inf != NULL && ext_inf->magic == EXTRA_INFO_MAGIC) { for (i=0; icnt; i++) { - pr_info("reg[%d] + offset %d\n", ext_inf->elem[i].index, ext_inf->elem[i].offset); + vpu_debug(3, "reg[%d] + offset %d\n", ext_inf->elem[i].index, ext_inf->elem[i].offset); reg->reg[ext_inf->elem[i].index] += ext_inf->elem[i].offset; } } @@ -935,7 +928,7 @@ static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, return 0; } -static int vcodec_reg_address_translate(struct vpu_service_info *pservice, +static int vcodec_reg_address_translate(struct vpu_subdev_data *data, vpu_reg *reg, struct extra_info_for_iommu *ext_inf) { @@ -943,7 +936,7 @@ static int vcodec_reg_address_translate(struct vpu_service_info *pservice, u8 *tbl; int size = 0; - hw_id = pservice->hw_info->hw_id; + hw_id = data->hw_info->hw_id; if (hw_id == HEVC_ID) { tbl = addr_tbl_hevc_dec; @@ -996,28 +989,34 @@ static int vcodec_reg_address_translate(struct vpu_service_info *pservice, } if (size != 0) { - return vcodec_bufid_to_iova(pservice, tbl, size, reg, ext_inf); + return vcodec_bufid_to_iova(data, tbl, size, reg, ext_inf); } else { return -1; } } #endif -static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session, void __user *src, unsigned long size) +static vpu_reg *reg_init(struct vpu_subdev_data *data, + vpu_session *session, void __user *src, unsigned long size) { + struct vpu_service_info *pservice = data->pservice; int extra_size = 0; struct extra_info_for_iommu extra_info; - vpu_reg *reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL); + vpu_reg *reg = kmalloc(sizeof(vpu_reg) + data->reg_size, GFP_KERNEL); + + vpu_debug_enter(); + if (NULL == reg) { - pr_err("error: kmalloc fail in reg_init\n"); + vpu_err("error: kmalloc fail in reg_init\n"); return NULL; } - if (size > pservice->reg_size) { - /*printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size); + if (size > data->reg_size) { + /*printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", + size, pservice->reg_size); size = pservice->reg_size;*/ - extra_size = size - pservice->reg_size; - size = pservice->reg_size; + extra_size = size - data->reg_size; + size = data->reg_size; } reg->session = session; reg->type = session->type; @@ -1028,34 +1027,35 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session INIT_LIST_HEAD(®->status_link); #if defined(CONFIG_VCODEC_MMU) - if (pservice->mmu_dev) + if (data->mmu_dev) INIT_LIST_HEAD(®->mem_region_list); #endif if (copy_from_user(®->reg[0], (void __user *)src, size)) { - pr_err("error: copy_from_user failed in reg_init\n"); + vpu_err("error: copy_from_user failed in reg_init\n"); kfree(reg); return NULL; } if (copy_from_user(&extra_info, (u8 *)src + size, extra_size)) { - pr_err("error: copy_from_user failed in reg_init\n"); + vpu_err("error: copy_from_user failed in reg_init\n"); kfree(reg); return NULL; } #if defined(CONFIG_VCODEC_MMU) - if (pservice->mmu_dev && 0 > vcodec_reg_address_translate(pservice, reg, &extra_info)) { - pr_err("error: translate reg address failed\n"); + if (data->mmu_dev && + 0 > vcodec_reg_address_translate(data, reg, &extra_info)) { + vpu_err("error: translate reg address failed\n"); kfree(reg); return NULL; } #endif - mutex_lock(pservice->lock); - list_add_tail(®->status_link, pservice->waiting); + mutex_lock(&pservice->lock); + list_add_tail(®->status_link, &pservice->waiting); list_add_tail(®->session_link, &session->waiting); - mutex_unlock(pservice->lock); + mutex_unlock(&pservice->lock); if (pservice->auto_freq) { if (!soc_is_rk2928g()) { @@ -1078,33 +1078,33 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session } } } - - /*reg->reg[2] &= (~0x800000L);*/ - + vpu_debug_leave(); return reg; } -static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg) +static void reg_deinit(struct vpu_subdev_data *data, vpu_reg *reg) { + struct vpu_service_info *pservice = data->pservice; #if defined(CONFIG_VCODEC_MMU) struct vcodec_mem_region *mem_region = NULL, *n; #endif list_del_init(®->session_link); list_del_init(®->status_link); - if (reg == (*pservice->reg_codec)) - *pservice->reg_codec = NULL; + if (reg == pservice->reg_codec) + pservice->reg_codec = NULL; if (reg == pservice->reg_pproc) pservice->reg_pproc = NULL; #if defined(CONFIG_VCODEC_MMU) - // release memory region attach to this registers table. - if (pservice->mmu_dev) { - list_for_each_entry_safe(mem_region, n, ®->mem_region_list, reg_lnk) { + /* release memory region attach to this registers table. */ + if (data->mmu_dev) { + list_for_each_entry_safe(mem_region, n, + ®->mem_region_list, reg_lnk) { /* do not unmap iommu manually, unmap will proccess when memory release */ - /*vcodec_enter_mode(pservice->dev_id); - ion_unmap_iommu(pservice->dev, + /*vcodec_enter_mode(data); + ion_unmap_iommu(data->dev, pservice->ion_client, mem_region->hdl); vcodec_exit_mode();*/ @@ -1120,67 +1120,73 @@ static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg) static void reg_from_wait_to_run(struct vpu_service_info *pservice, vpu_reg *reg) { + vpu_debug_enter(); list_del_init(®->status_link); - list_add_tail(®->status_link, pservice->running); + list_add_tail(®->status_link, &pservice->running); list_del_init(®->session_link); list_add_tail(®->session_link, ®->session->running); + vpu_debug_leave(); } static void reg_copy_from_hw(vpu_reg *reg, volatile u32 *src, u32 count) { int i; u32 *dst = (u32 *)®->reg[0]; - + vpu_debug_enter(); for (i = 0; i < count; i++) *dst++ = *src++; + vpu_debug_leave(); } -static void reg_from_run_to_done(struct vpu_service_info *pservice, vpu_reg *reg) +static void reg_from_run_to_done(struct vpu_subdev_data *data, + vpu_reg *reg) { + struct vpu_service_info *pservice = data->pservice; int irq_reg = -1; + + vpu_debug_enter(); + list_del_init(®->status_link); list_add_tail(®->status_link, &pservice->done); list_del_init(®->session_link); list_add_tail(®->session_link, ®->session->done); - vcodec_enter_mode(pservice->dev_id); + vcodec_enter_mode(data); switch (reg->type) { case VPU_ENC : { - *pservice->reg_codec = NULL; - reg_copy_from_hw(reg, pservice->enc_dev.hwregs, pservice->hw_info->enc_reg_num); + pservice->reg_codec = NULL; + reg_copy_from_hw(reg, data->enc_dev.hwregs, data->hw_info->enc_reg_num); irq_reg = ENC_INTERRUPT_REGISTER; break; } case VPU_DEC : { - int reg_len = pservice->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC; - *pservice->reg_codec = NULL; - reg_copy_from_hw(reg, pservice->dec_dev.hwregs, reg_len); + int reg_len = REG_NUM_9190_DEC; + pservice->reg_codec = NULL; + reg_copy_from_hw(reg, data->dec_dev.hwregs, reg_len); irq_reg = DEC_INTERRUPT_REGISTER; break; } case VPU_PP : { pservice->reg_pproc = NULL; - reg_copy_from_hw(reg, pservice->dec_dev.hwregs + PP_INTERRUPT_REGISTER, REG_NUM_9190_PP); - pservice->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0; + reg_copy_from_hw(reg, data->dec_dev.hwregs + PP_INTERRUPT_REGISTER, REG_NUM_9190_PP); + data->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0; break; } case VPU_DEC_PP : { - *pservice->reg_codec = NULL; + pservice->reg_codec = NULL; pservice->reg_pproc = NULL; - reg_copy_from_hw(reg, pservice->dec_dev.hwregs, REG_NUM_9190_DEC_PP); - pservice->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0; + reg_copy_from_hw(reg, data->dec_dev.hwregs, REG_NUM_9190_DEC_PP); + data->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0; break; } default : { - pr_err("error: copy reg from hw with unknown type %d\n", reg->type); + vpu_err("error: copy reg from hw with unknown type %d\n", reg->type); break; } } - if (cpu_is_rk3036() || cpu_is_rk312x()) - rockchip_iovmm_deactivate(pservice->dev); - vcodec_exit_mode(); + vcodec_exit_mode(pservice); if (irq_reg != -1) { reg->reg[irq_reg] = pservice->irq_status; @@ -1189,6 +1195,8 @@ static void reg_from_run_to_done(struct vpu_service_info *pservice, vpu_reg *reg atomic_sub(1, ®->session->task_running); atomic_sub(1, &pservice->total_running); wake_up(®->session->wait); + + vpu_debug_leave(); } static void vpu_service_set_freq(struct vpu_service_info *pservice, vpu_reg *reg) @@ -1201,19 +1209,15 @@ static void vpu_service_set_freq(struct vpu_service_info *pservice, vpu_reg *reg switch (reg->freq) { case VPU_FREQ_200M : { clk_set_rate(pservice->aclk_vcodec, 200*MHZ); - //printk("default: 200M\n"); } break; case VPU_FREQ_266M : { clk_set_rate(pservice->aclk_vcodec, 266*MHZ); - //printk("default: 266M\n"); } break; case VPU_FREQ_300M : { clk_set_rate(pservice->aclk_vcodec, 300*MHZ); - //printk("default: 300M\n"); } break; case VPU_FREQ_400M : { clk_set_rate(pservice->aclk_vcodec, 400*MHZ); - //printk("default: 400M\n"); } break; case VPU_FREQ_500M : { clk_set_rate(pservice->aclk_vcodec, 500*MHZ); @@ -1227,35 +1231,30 @@ static void vpu_service_set_freq(struct vpu_service_info *pservice, vpu_reg *reg } else { clk_set_rate(pservice->aclk_vcodec, 300*MHZ); } - //printk("default: 300M\n"); } break; } } -#if HEVC_SIM_ENABLE -static void simulate_start(struct vpu_service_info *pservice); -#endif -static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) +static void reg_copy_to_hw(struct vpu_subdev_data *data, vpu_reg *reg) { + struct vpu_service_info *pservice = data->pservice; int i; u32 *src = (u32 *)®->reg[0]; + vpu_debug_enter(); + atomic_add(1, &pservice->total_running); atomic_add(1, ®->session->task_running); - if (pservice->auto_freq) { + if (pservice->auto_freq) vpu_service_set_freq(pservice, reg); - } - - vcodec_enter_mode(pservice->dev_id); - if (cpu_is_rk3036() || cpu_is_rk312x()) - rockchip_iovmm_activate(pservice->dev); + vcodec_enter_mode(data); switch (reg->type) { case VPU_ENC : { - int enc_count = pservice->hw_info->enc_reg_num; - u32 *dst = (u32 *)pservice->enc_dev.hwregs; + int enc_count = data->hw_info->enc_reg_num; + u32 *dst = (u32 *)data->enc_dev.hwregs; - *pservice->reg_codec = reg; + pservice->reg_codec = reg; dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC] & 0x6; @@ -1265,7 +1264,7 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) for (i = VPU_REG_EN_ENC + 1; i < enc_count; i++) dst[i] = src[i]; - VEPU_CLEAR_CACHE(dst); + VEPU_CLEAN_CACHE(dst); dsb(); @@ -1278,39 +1277,36 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) } break; case VPU_DEC : { - u32 *dst = (u32 *)pservice->dec_dev.hwregs; + u32 *dst = (u32 *)data->dec_dev.hwregs; - *pservice->reg_codec = reg; + pservice->reg_codec = reg; - if (pservice->hw_info->hw_id != HEVC_ID) { + if (data->hw_info->hw_id != HEVC_ID) { for (i = REG_NUM_9190_DEC - 1; i > VPU_REG_DEC_GATE; i--) dst[i] = src[i]; - VDPU_CLEAR_CACHE(dst); + VDPU_CLEAN_CACHE(dst); } else { for (i = REG_NUM_HEVC_DEC - 1; i > VPU_REG_EN_DEC; i--) dst[i] = src[i]; - HEVC_CLEAR_CACHE(dst); + HEVC_CLEAN_CACHE(dst); } dsb(); - if (pservice->hw_info->hw_id != HEVC_ID) { + if (data->hw_info->hw_id != HEVC_ID) { dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT; - dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC]; + dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC]; } else { dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC]; } - dsb(); dmb(); - #if VPU_SERVICE_SHOW_TIME do_gettimeofday(&dec_start); #endif - } break; case VPU_PP : { - u32 *dst = (u32 *)pservice->dec_dev.hwregs + PP_INTERRUPT_REGISTER; + u32 *dst = (u32 *)data->dec_dev.hwregs + PP_INTERRUPT_REGISTER; pservice->reg_pproc = reg; dst[VPU_REG_PP_GATE] = src[VPU_REG_PP_GATE] | VPU_REG_PP_GATE_BIT; @@ -1321,19 +1317,18 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) dsb(); dst[VPU_REG_EN_PP] = src[VPU_REG_EN_PP]; - #if VPU_SERVICE_SHOW_TIME do_gettimeofday(&pp_start); #endif } break; case VPU_DEC_PP : { - u32 *dst = (u32 *)pservice->dec_dev.hwregs; - *pservice->reg_codec = reg; + u32 *dst = (u32 *)data->dec_dev.hwregs; + pservice->reg_codec = reg; pservice->reg_pproc = reg; VDPU_SOFT_RESET(dst); - VDPU_CLEAR_CACHE(dst); + VDPU_CLEAN_CACHE(dst); for (i = VPU_REG_EN_DEC_PP + 1; i < REG_NUM_9190_DEC_PP; i++) dst[i] = src[i]; @@ -1344,65 +1339,59 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) dst[VPU_REG_DEC_PP_GATE] = src[VPU_REG_DEC_PP_GATE] | VPU_REG_PP_GATE_BIT; dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT; dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC]; - #if VPU_SERVICE_SHOW_TIME do_gettimeofday(&dec_start); #endif - } break; default : { - pr_err("error: unsupport session type %d", reg->type); + vpu_err("error: unsupport session type %d", reg->type); atomic_sub(1, &pservice->total_running); atomic_sub(1, ®->session->task_running); break; } } - vcodec_exit_mode(); - -#if HEVC_SIM_ENABLE - if (pservice->hw_info->hw_id == HEVC_ID) { - simulate_start(pservice); - } -#endif + vcodec_exit_mode(pservice); + vpu_debug_leave(); } -static void try_set_reg(struct vpu_service_info *pservice) +static void try_set_reg(struct vpu_subdev_data *data) { - // first get reg from reg list - if (!list_empty(pservice->waiting)) { + struct vpu_service_info *pservice = data->pservice; + vpu_debug_enter(); + if (!list_empty(&pservice->waiting)) { int can_set = 0; - vpu_reg *reg = list_entry(pservice->waiting->next, vpu_reg, status_link); + vpu_reg *reg = list_entry(pservice->waiting.next, vpu_reg, status_link); vpu_service_power_on(pservice); switch (reg->type) { case VPU_ENC : { - if ((NULL == *pservice->reg_codec) && (NULL == pservice->reg_pproc)) + if ((NULL == pservice->reg_codec) && (NULL == pservice->reg_pproc)) can_set = 1; } break; case VPU_DEC : { - if (NULL == *pservice->reg_codec) + if (NULL == pservice->reg_codec) can_set = 1; if (pservice->auto_freq && (NULL != pservice->reg_pproc)) { can_set = 0; } } break; case VPU_PP : { - if (NULL == *pservice->reg_codec) { + if (NULL == pservice->reg_codec) { if (NULL == pservice->reg_pproc) can_set = 1; } else { - if ((VPU_DEC == (*pservice->reg_codec)->type) && (NULL == pservice->reg_pproc)) + if ((VPU_DEC == pservice->reg_codec->type) && (NULL == pservice->reg_pproc)) can_set = 1; - // can not charge frequency when vpu is working + /* can not charge frequency when vpu is working */ if (pservice->auto_freq) { can_set = 0; } } } break; case VPU_DEC_PP : { - if ((NULL == *pservice->reg_codec) && (NULL == pservice->reg_pproc)) + if ((NULL == pservice->reg_codec) && (NULL == pservice->reg_pproc)) can_set = 1; } break; default : { @@ -1411,22 +1400,25 @@ static void try_set_reg(struct vpu_service_info *pservice) } if (can_set) { reg_from_wait_to_run(pservice, reg); - reg_copy_to_hw(pservice, reg); + reg_copy_to_hw(data, reg); } } + vpu_debug_leave(); } -static int return_reg(struct vpu_service_info *pservice, vpu_reg *reg, u32 __user *dst) +static int return_reg(struct vpu_subdev_data *data, + vpu_reg *reg, u32 __user *dst) { int ret = 0; + vpu_debug_enter(); switch (reg->type) { case VPU_ENC : { - if (copy_to_user(dst, ®->reg[0], pservice->hw_info->enc_io_size)) + if (copy_to_user(dst, ®->reg[0], data->hw_info->enc_io_size)) ret = -EFAULT; break; } case VPU_DEC : { - int reg_len = pservice->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC; + int reg_len = data->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC; if (copy_to_user(dst, ®->reg[0], SIZE_REG(reg_len))) ret = -EFAULT; break; @@ -1443,21 +1435,27 @@ static int return_reg(struct vpu_service_info *pservice, vpu_reg *reg, u32 __use } default : { ret = -EFAULT; - pr_err("error: copy reg to user with unknown type %d\n", reg->type); + vpu_err("error: copy reg to user with unknown type %d\n", reg->type); break; } } - reg_deinit(pservice, reg); + reg_deinit(data, reg); + vpu_debug_leave(); return ret; } -static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static long vpu_service_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) { - struct vpu_service_info *pservice = container_of(filp->f_dentry->d_inode->i_cdev, struct vpu_service_info, cdev); + struct vpu_subdev_data *data = + container_of(filp->f_dentry->d_inode->i_cdev, + struct vpu_subdev_data, cdev); + struct vpu_service_info *pservice = data->pservice; vpu_session *session = (vpu_session *)filp->private_data; - if (NULL == session) { + vpu_debug_enter(); + vpu_debug(3, "cmd %x, VPU_IOC_SET_CLIENT_TYPE %x\n", cmd, VPU_IOC_SET_CLIENT_TYPE); + if (NULL == session) return -EINVAL; - } switch (cmd) { case VPU_IOC_SET_CLIENT_TYPE : { @@ -1467,17 +1465,23 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long case VPU_IOC_GET_HW_FUSE_STATUS : { vpu_request req; if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) { - pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_from_user failed\n"); + vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_from_user failed\n"); return -EFAULT; } else { if (VPU_ENC != session->type) { - if (copy_to_user((void __user *)req.req, &pservice->dec_config, sizeof(VPUHwDecConfig_t))) { - pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", session->type); + if (copy_to_user((void __user *)req.req, + &pservice->dec_config, + sizeof(VPUHwDecConfig_t))) { + vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", + session->type); return -EFAULT; } } else { - if (copy_to_user((void __user *)req.req, &pservice->enc_config, sizeof(VPUHwEncConfig_t))) { - pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", session->type); + if (copy_to_user((void __user *)req.req, + &pservice->enc_config, + sizeof(VPUHwEncConfig_t))) { + vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", + session->type); return -EFAULT; } } @@ -1488,17 +1492,19 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long case VPU_IOC_SET_REG : { vpu_request req; vpu_reg *reg; - if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) { - pr_err("error: VPU_IOC_SET_REG copy_from_user failed\n"); + if (copy_from_user(&req, (void __user *)arg, + sizeof(vpu_request))) { + vpu_err("error: VPU_IOC_SET_REG copy_from_user failed\n"); return -EFAULT; } - reg = reg_init(pservice, session, (void __user *)req.req, req.size); + reg = reg_init(data, session, + (void __user *)req.req, req.size); if (NULL == reg) { return -EFAULT; } else { - mutex_lock(pservice->lock); - try_set_reg(pservice); - mutex_unlock(pservice->lock); + mutex_lock(&pservice->lock); + try_set_reg(data); + mutex_unlock(&pservice->lock); } break; @@ -1506,27 +1512,28 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long case VPU_IOC_GET_REG : { vpu_request req; vpu_reg *reg; - if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) { - pr_err("error: VPU_IOC_GET_REG copy_from_user failed\n"); + if (copy_from_user(&req, (void __user *)arg, + sizeof(vpu_request))) { + vpu_err("error: VPU_IOC_GET_REG copy_from_user failed\n"); return -EFAULT; } else { int ret = wait_event_timeout(session->wait, !list_empty(&session->done), VPU_TIMEOUT_DELAY); if (!list_empty(&session->done)) { if (ret < 0) { - pr_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session->pid, ret); + vpu_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session->pid, ret); } ret = 0; } else { if (unlikely(ret < 0)) { - pr_err("error: pid %d wait task ret %d\n", session->pid, ret); + vpu_err("error: pid %d wait task ret %d\n", session->pid, ret); } else if (0 == ret) { - pr_err("error: pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running)); + vpu_err("error: pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running)); ret = -ETIMEDOUT; } } if (ret < 0) { int task_running = atomic_read(&session->task_running); - mutex_lock(pservice->lock); + mutex_lock(&pservice->lock); vpu_service_dump(pservice); if (task_running) { atomic_set(&session->task_running, 0); @@ -1535,58 +1542,51 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long vpu_reset(pservice); printk("done\n"); } - vpu_service_session_clear(pservice, session); - mutex_unlock(pservice->lock); + vpu_service_session_clear(data, session); + mutex_unlock(&pservice->lock); return ret; } } - mutex_lock(pservice->lock); + mutex_lock(&pservice->lock); reg = list_entry(session->done.next, vpu_reg, session_link); - return_reg(pservice, reg, (u32 __user *)req.req); - mutex_unlock(pservice->lock); + return_reg(data, reg, (u32 __user *)req.req); + mutex_unlock(&pservice->lock); break; } case VPU_IOC_PROBE_IOMMU_STATUS: { int iommu_enable = 0; #if defined(CONFIG_VCODEC_MMU) - iommu_enable = pservice->mmu_dev ? 1 : 0; + iommu_enable = data->mmu_dev ? 1 : 0; #endif if (copy_to_user((void __user *)arg, &iommu_enable, sizeof(int))) { - pr_err("error: VPU_IOC_PROBE_IOMMU_STATUS copy_to_user failed\n"); + vpu_err("error: VPU_IOC_PROBE_IOMMU_STATUS copy_to_user failed\n"); return -EFAULT; } break; } default : { - pr_err("error: unknow vpu service ioctl cmd %x\n", cmd); + vpu_err("error: unknow vpu service ioctl cmd %x\n", cmd); break; } } - + vpu_debug_leave(); return 0; } -static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr) +static int vpu_service_check_hw(struct vpu_subdev_data *data, u32 hw_addr) { int ret = -EINVAL, i = 0; volatile u32 *tmp = (volatile u32 *)ioremap_nocache(hw_addr, 0x4); u32 enc_id = *tmp; -#if HEVC_SIM_ENABLE - /// temporary, hevc driver test. - if (strncmp(dev_name(p->dev), "hevc_service", strlen("hevc_service")) == 0) { - p->hw_info = &vpu_hw_set[2]; - return 0; - } -#endif enc_id = (enc_id >> 16) & 0xFFFF; pr_info("checking hw id %x\n", enc_id); - p->hw_info = NULL; + data->hw_info = NULL; for (i = 0; i < ARRAY_SIZE(vpu_hw_set); i++) { if (enc_id == vpu_hw_set[i].hw_id) { - p->hw_info = &vpu_hw_set[i]; + data->hw_info = &vpu_hw_set[i]; ret = 0; break; } @@ -1597,10 +1597,14 @@ static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr) static int vpu_service_open(struct inode *inode, struct file *filp) { - struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev); + struct vpu_subdev_data *data = container_of(inode->i_cdev, struct vpu_subdev_data, cdev); + struct vpu_service_info *pservice = data->pservice; vpu_session *session = (vpu_session *)kmalloc(sizeof(vpu_session), GFP_KERNEL); + + vpu_debug_enter(); + if (NULL == session) { - pr_err("error: unable to allocate memory for vpu_session."); + vpu_err("error: unable to allocate memory for vpu_session."); return -ENOMEM; } @@ -1612,39 +1616,43 @@ static int vpu_service_open(struct inode *inode, struct file *filp) INIT_LIST_HEAD(&session->list_session); init_waitqueue_head(&session->wait); atomic_set(&session->task_running, 0); - mutex_lock(pservice->lock); + mutex_lock(&pservice->lock); list_add_tail(&session->list_session, &pservice->session); filp->private_data = (void *)session; - mutex_unlock(pservice->lock); + mutex_unlock(&pservice->lock); pr_debug("dev opened\n"); + vpu_debug_leave(); return nonseekable_open(inode, filp); } static int vpu_service_release(struct inode *inode, struct file *filp) { - struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev); + struct vpu_subdev_data *data = container_of(inode->i_cdev, struct vpu_subdev_data, cdev); + struct vpu_service_info *pservice = data->pservice; int task_running; vpu_session *session = (vpu_session *)filp->private_data; + vpu_debug_enter(); if (NULL == session) return -EINVAL; task_running = atomic_read(&session->task_running); if (task_running) { - pr_err("error: vpu_service session %d still has %d task running when closing\n", session->pid, task_running); + vpu_err("error: vpu_service session %d still has %d task running when closing\n", session->pid, task_running); msleep(50); } wake_up(&session->wait); - mutex_lock(pservice->lock); + mutex_lock(&pservice->lock); /* remove this filp from the asynchronusly notified filp's */ list_del_init(&session->list_session); - vpu_service_session_clear(pservice, session); + vpu_service_session_clear(data, session); kfree(session); filp->private_data = NULL; - mutex_unlock(pservice->lock); + mutex_unlock(&pservice->lock); pr_debug("dev closed\n"); + vpu_debug_leave(); return 0; } @@ -1659,38 +1667,10 @@ static irqreturn_t vdpu_irq(int irq, void *dev_id); static irqreturn_t vdpu_isr(int irq, void *dev_id); static irqreturn_t vepu_irq(int irq, void *dev_id); static irqreturn_t vepu_isr(int irq, void *dev_id); -static void get_hw_info(struct vpu_service_info *pservice); - -#if HEVC_SIM_ENABLE -static void simulate_work(struct work_struct *work_s) -{ - struct delayed_work *dlwork = container_of(work_s, struct delayed_work, work); - struct vpu_service_info *pservice = container_of(dlwork, struct vpu_service_info, simulate_work); - vpu_device *dev = &pservice->dec_dev; - - if (!list_empty(&pservice->running)) { - atomic_add(1, &dev->irq_count_codec); - vdpu_isr(0, (void*)pservice); - } else { - //simulate_start(pservice); - pr_err("empty running queue\n"); - } -} - -static void simulate_init(struct vpu_service_info *pservice) -{ - INIT_DELAYED_WORK(&pservice->simulate_work, simulate_work); -} - -static void simulate_start(struct vpu_service_info *pservice) -{ - cancel_delayed_work_sync(&pservice->power_off_work); - queue_delayed_work(system_nrt_wq, &pservice->simulate_work, VPU_SIMULATE_DELAY); -} -#endif +static void get_hw_info(struct vpu_subdev_data *data); #ifdef CONFIG_VCODEC_MMU -static struct device *rockchip_get_sysmmu_device_by_compatible(const char *compt) +static struct device *rockchip_get_sysmmu_dev(const char *compt) { struct device_node *dn = NULL; struct platform_device *pd = NULL; @@ -1725,7 +1705,7 @@ static inline void platform_set_sysmmu(struct device *iommu, } #endif -int vcodec_sysmmu_fault_handler(struct device *dev, +int vcodec_sysmmu_fault_hdl(struct device *dev, enum rk_iommu_inttype itype, unsigned long pgtable_base, unsigned long fault_addr, unsigned int status) @@ -1733,7 +1713,7 @@ int vcodec_sysmmu_fault_handler(struct device *dev, struct platform_device *pdev; struct vpu_service_info *pservice; - pr_info("%s in\n", __func__); + vpu_debug_enter(); pdev = container_of(dev, struct platform_device, dev); @@ -1742,17 +1722,17 @@ int vcodec_sysmmu_fault_handler(struct device *dev, if (pservice->reg_codec) { struct vcodec_mem_region *mem, *n; int i = 0; - pr_info("vcodec, fault addr 0x%08x\n", (u32)fault_addr); + vpu_debug(3, "vcodec, fault addr 0x%08x\n", (u32)fault_addr); list_for_each_entry_safe(mem, n, - &(*pservice->reg_codec)->mem_region_list, + &pservice->reg_codec->mem_region_list, reg_lnk) { - pr_info("vcodec, reg[%02u] mem region [%02d] 0x%08x %ld\n", + vpu_debug(3, "vcodec, reg[%02u] mem region [%02d] 0x%08x %ld\n", mem->reg_idx, i, (u32)mem->iova, mem->len); i++; } pr_alert("vcodec, page fault occur, reset hw\n"); - (*pservice->reg_codec)->reg[101] = 1; + pservice->reg_codec->reg[101] = 1; vpu_reset(pservice); } @@ -1766,186 +1746,289 @@ static int hevc_test_case0(vpu_service_info *pservice); #if defined(CONFIG_ION_ROCKCHIP) extern struct ion_client *rockchip_ion_client_create(const char * name); #endif -static int vcodec_probe(struct platform_device *pdev) + +static int vcodec_subdev_probe(struct platform_device *pdev, + struct vpu_service_info *pservice) { int ret = 0; struct resource *res = NULL; + u32 ioaddr = 0; struct device *dev = &pdev->dev; - void __iomem *regs = NULL; + char *name = (char*)dev_name(dev); struct device_node *np = pdev->dev.of_node; - struct vpu_service_info *pservice = devm_kzalloc(dev, sizeof(struct vpu_service_info), GFP_KERNEL); - char *prop = (char*)dev_name(dev); - u32 config; + struct vpu_subdev_data *data = + devm_kzalloc(dev, sizeof(struct vpu_subdev_data), GFP_KERNEL); #if defined(CONFIG_VCODEC_MMU) u32 iommu_en = 0; char mmu_dev_dts_name[40]; of_property_read_u32(np, "iommu_enabled", &iommu_en); #endif - pr_info("probe device %s\n", dev_name(dev)); - of_property_read_string(np, "name", (const char**)&prop); - dev_set_name(dev, prop); + data->pservice = pservice; + data->dev = dev; - if (strcmp(dev_name(dev), "hevc_service") == 0) { - pservice->dev_id = VCODEC_DEVICE_ID_HEVC; - g_combo.hevc_srv = pservice; - } else if (strcmp(dev_name(dev), "vpu_service") == 0) { - pservice->dev_id = VCODEC_DEVICE_ID_VPU; - g_combo.vpu_srv = pservice; + of_property_read_string(np, "name", (const char**)&name); + of_property_read_u32(np, "dev_mode", &data->mode); + dev_set_name(dev, name); + + if (pservice->reg_base == 0) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(data->regs)) { + ret = PTR_ERR(data->regs); + goto err; + } + ioaddr = res->start; } else { - dev_err(dev, "Unknown device %s to probe\n", dev_name(dev)); - return -1; + data->regs = pservice->reg_base; + ioaddr = pservice->ioaddr; + } + + clear_bit(MMU_ACTIVATED, &data->state); + vcodec_enter_mode(data); + ret = vpu_service_check_hw(data, ioaddr); + if (ret < 0) { + vpu_err("error: hw info check faild\n"); + goto err; } - mutex_init(&g_mode_mutex); - vcodec_enter_mode_nolock(pservice->dev_id, &config); + data->dec_dev.iosize = data->hw_info->dec_io_size; + data->dec_dev.hwregs = (volatile u32 *)((u8 *)data->regs + data->hw_info->dec_offset); + data->reg_size = data->dec_dev.iosize; - wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu"); - if (cpu_is_rk3036() || cpu_is_rk312x()) { - pservice->waiting = &g_combo.waiting; - pservice->running = &g_combo.running; - pservice->lock = &g_combo.run_lock; - pservice->reg_codec = &g_combo.reg_codec; - } else { - pservice->waiting = kzalloc(sizeof(struct list_head), GFP_KERNEL); - pservice->running = kzalloc(sizeof(struct list_head), GFP_KERNEL); - pservice->lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); - pservice->reg_codec = kzalloc(sizeof(vpu_reg*), GFP_KERNEL); - INIT_LIST_HEAD(pservice->waiting); - INIT_LIST_HEAD(pservice->running); - mutex_init(pservice->lock); + if (data->mode == VCODEC_RUNNING_MODE_VPU) { + data->enc_dev.iosize = data->hw_info->enc_io_size; + data->reg_size = data->reg_size > data->enc_dev.iosize ? data->reg_size : data->enc_dev.iosize; + data->enc_dev.hwregs = (volatile u32 *)((u8 *)data->regs + data->hw_info->enc_offset); } - INIT_LIST_HEAD(&pservice->done); - INIT_LIST_HEAD(&pservice->session); - pservice->reg_pproc = NULL; - atomic_set(&pservice->total_running, 0); - pservice->enabled = false; + data->irq_enc = platform_get_irq_byname(pdev, "irq_enc"); + if (data->irq_enc > 0) { + ret = devm_request_threaded_irq(dev, + data->irq_enc, vepu_irq, vepu_isr, + IRQF_SHARED, dev_name(dev), + (void *)data); + if (ret) { + dev_err(dev, + "error: can't request vepu irq %d\n", + data->irq_enc); + goto err; + } + } + data->irq_dec = platform_get_irq_byname(pdev, "irq_dec"); + if (data->irq_dec > 0) { + ret = devm_request_threaded_irq(dev, + data->irq_dec, vdpu_irq, vdpu_isr, + IRQF_SHARED, dev_name(dev), + (void *)data); + if (ret) { + dev_err(dev, + "error: can't request vdpu irq %d\n", + data->irq_dec); + goto err; + } + } + atomic_set(&data->dec_dev.irq_count_codec, 0); + atomic_set(&data->dec_dev.irq_count_pp, 0); + atomic_set(&data->enc_dev.irq_count_codec, 0); + atomic_set(&data->enc_dev.irq_count_pp, 0); #if defined(CONFIG_VCODEC_MMU) - pservice->mmu_dev = NULL; -#endif - pservice->dev = dev; + if (iommu_en) { + vcodec_enter_mode(data); + if (data->mode == VCODEC_RUNNING_MODE_HEVC) + sprintf(mmu_dev_dts_name, + HEVC_IOMMU_COMPATIBLE_NAME); + else + sprintf(mmu_dev_dts_name, + VPU_IOMMU_COMPATIBLE_NAME); - if (0 > vpu_get_clk(pservice)) - goto err; + data->mmu_dev = + rockchip_get_sysmmu_dev(mmu_dev_dts_name); - INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work); + if (data->mmu_dev) + platform_set_sysmmu(data->mmu_dev, dev); - vpu_service_power_on(pservice); + rockchip_iovmm_set_fault_handler(dev, vcodec_sysmmu_fault_hdl); + } +#endif + /* create device node */ + ret = alloc_chrdev_region(&data->dev_t, 0, 1, dev_name(dev)); + if (ret) { + dev_err(dev, "alloc dev_t failed\n"); + goto err; + } - mdelay(1); + cdev_init(&data->cdev, &vpu_service_fops); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->cdev.owner = THIS_MODULE; + data->cdev.ops = &vpu_service_fops; - res->flags &= ~IORESOURCE_CACHEABLE; + ret = cdev_add(&data->cdev, data->dev_t, 1); - regs = devm_ioremap_resource(pservice->dev, res); - if (IS_ERR(regs)) { - ret = PTR_ERR(regs); + if (ret) { + dev_err(dev, "add dev_t failed\n"); goto err; } - { - u32 offset = res->start; - if (cpu_is_rk3036()) { - if (pservice->dev_id == VCODEC_DEVICE_ID_VPU) - offset += 0x400; - } - ret = vpu_service_check_hw(pservice, offset); - if (ret < 0) { - pr_err("error: hw info check faild\n"); - goto err; - } + data->cls = class_create(THIS_MODULE, dev_name(dev)); + + if (IS_ERR(data->cls)) { + ret = PTR_ERR(data->cls); + dev_err(dev, "class_create err:%d\n", ret); + goto err; } - /// define regs address. - pservice->dec_dev.iobaseaddr = res->start + pservice->hw_info->dec_offset; - pservice->dec_dev.iosize = pservice->hw_info->dec_io_size; + data->child_dev = device_create(data->cls, dev, + data->dev_t, NULL, dev_name(dev)); + + get_hw_info(data); - pservice->dec_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->dec_offset); + platform_set_drvdata(pdev, data); + + INIT_LIST_HEAD(&data->lnk_service); + list_add_tail(&data->lnk_service, &pservice->subdev_list); + return 0; +err: + if (data->irq_enc > 0) + free_irq(data->irq_enc, (void *)data); + if (data->irq_dec > 0) + free_irq(data->irq_dec, (void *)data); - pservice->reg_size = pservice->dec_dev.iosize; + if (data->child_dev) { + device_destroy(data->cls, data->dev_t); + cdev_del(&data->cdev); + unregister_chrdev_region(data->dev_t, 1); + } - if (pservice->hw_info->hw_id != HEVC_ID && !cpu_is_rk3036()) { - pservice->enc_dev.iobaseaddr = res->start + pservice->hw_info->enc_offset; - pservice->enc_dev.iosize = pservice->hw_info->enc_io_size; + if (data->cls) + class_destroy(data->cls); + return -1; +} - pservice->reg_size = pservice->reg_size > pservice->enc_dev.iosize ? pservice->reg_size : pservice->enc_dev.iosize; +static void vcodec_subdev_remove(struct vpu_subdev_data *data) +{ + device_destroy(data->cls, data->dev_t); + class_destroy(data->cls); + cdev_del(&data->cdev); + unregister_chrdev_region(data->dev_t, 1); - pservice->enc_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->enc_offset); + free_irq(data->irq_enc, (void *)&data); + free_irq(data->irq_dec, (void *)&data); +} - pservice->irq_enc = platform_get_irq_byname(pdev, "irq_enc"); - if (pservice->irq_enc < 0) { - dev_err(pservice->dev, "cannot find IRQ encoder\n"); - ret = -ENXIO; - goto err; - } +static void vcodec_read_property(struct device_node *np, + struct vpu_service_info *pservice) +{ + pservice->mode_bit = 0; + pservice->mode_ctrl = 0; + pservice->subcnt = 0; - ret = devm_request_threaded_irq(pservice->dev, pservice->irq_enc, vepu_irq, vepu_isr, IRQF_DISABLED, dev_name(pservice->dev), (void *)pservice); - if (ret) { - dev_err(pservice->dev, "error: can't request vepu irq %d\n", pservice->irq_enc); - goto err; - } - } + of_property_read_u32(np, "subcnt", &pservice->subcnt); - pservice->irq_dec = platform_get_irq_byname(pdev, "irq_dec"); - if (pservice->irq_dec < 0) { - dev_err(pservice->dev, "cannot find IRQ decoder\n"); - ret = -ENXIO; - goto err; + if (pservice->subcnt > 1) { + of_property_read_u32(np, "mode_bit", &pservice->mode_bit); + of_property_read_u32(np, "mode_ctrl", &pservice->mode_ctrl); } - - /* get the IRQ line */ - ret = devm_request_threaded_irq(pservice->dev, pservice->irq_dec, vdpu_irq, vdpu_isr, 0, dev_name(pservice->dev), (void *)pservice); - if (ret) { - dev_err(pservice->dev, "error: can't request vdpu irq %d\n", pservice->irq_dec); - goto err; + pservice->grf_base = RK_GRF_VIRT;/*syscon_regmap_lookup_by_phandle(np, "rockchip,grf");*/ + if (IS_ERR(pservice->grf_base)) { + vpu_err("can't find vpu grf property\n"); + return; } + of_property_read_string(np, "name", (const char**)&pservice->name); +} - atomic_set(&pservice->dec_dev.irq_count_codec, 0); - atomic_set(&pservice->dec_dev.irq_count_pp, 0); - atomic_set(&pservice->enc_dev.irq_count_codec, 0); - atomic_set(&pservice->enc_dev.irq_count_pp, 0); +static void vcodec_init_drvdata(struct vpu_service_info *pservice) +{ + pservice->dev_id = VCODEC_DEVICE_ID_VPU; + pservice->curr_mode = -1; - /// create device - ret = alloc_chrdev_region(&pservice->dev_t, 0, 1, dev_name(dev)); - if (ret) { - dev_err(dev, "alloc dev_t failed\n"); - goto err; - } + wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu"); + INIT_LIST_HEAD(&pservice->waiting); + INIT_LIST_HEAD(&pservice->running); + mutex_init(&pservice->lock); - cdev_init(&pservice->cdev, &vpu_service_fops); + INIT_LIST_HEAD(&pservice->done); + INIT_LIST_HEAD(&pservice->session); + INIT_LIST_HEAD(&pservice->subdev_list); - pservice->cdev.owner = THIS_MODULE; - pservice->cdev.ops = &vpu_service_fops; + pservice->reg_pproc = NULL; + atomic_set(&pservice->total_running, 0); + pservice->enabled = false; - ret = cdev_add(&pservice->cdev, pservice->dev_t, 1); + INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work); - if (ret) { - dev_err(dev, "add dev_t failed\n"); - goto err; + pservice->ion_client = rockchip_ion_client_create("vpu"); + if (IS_ERR(pservice->ion_client)) { + vpu_err("failed to create ion client for vcodec ret %ld\n", + PTR_ERR(pservice->ion_client)); + } else { + vpu_debug(3, "vcodec ion client create success!\n"); } +} - pservice->cls = class_create(THIS_MODULE, dev_name(dev)); +static int vcodec_probe(struct platform_device *pdev) +{ + int i; + int ret = 0; + struct resource *res = NULL; + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + struct vpu_service_info *pservice = + devm_kzalloc(dev, sizeof(struct vpu_service_info), GFP_KERNEL); - if (IS_ERR(pservice->cls)) { - ret = PTR_ERR(pservice->cls); - dev_err(dev, "class_create err:%d\n", ret); + pr_info("probe device %s\n", dev_name(dev)); + + vcodec_read_property(np, pservice); + vcodec_init_drvdata(pservice); + + if (strncmp(pservice->name, "hevc_service", 12) == 0) + pservice->dev_id = VCODEC_DEVICE_ID_HEVC; + else if (strncmp(pservice->name, "vpu_service", 11) == 0) + pservice->dev_id = VCODEC_DEVICE_ID_VPU; + else + pservice->dev_id = VCODEC_DEVICE_ID_COMBO; + + pservice->dev = dev; + + if (0 > vpu_get_clk(pservice)) goto err; - } - pservice->child_dev = device_create(pservice->cls, dev, pservice->dev_t, NULL, dev_name(dev)); + vpu_service_power_on(pservice); + + if (of_property_read_bool(np, "reg")) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - platform_set_drvdata(pdev, pservice); + pservice->reg_base = devm_ioremap_resource(pservice->dev, res); + if (IS_ERR(pservice->reg_base)) { + vpu_err("ioremap registers base failed\n"); + ret = PTR_ERR(pservice->reg_base); + goto err; + } + pservice->ioaddr = res->start; + } else { + pservice->reg_base = 0; + } - get_hw_info(pservice); + if (of_property_read_bool(np, "subcnt")) { + for (i = 0; isubcnt; i++) { + struct device_node *sub_np; + struct platform_device *sub_pdev; + sub_np = of_parse_phandle(np, "rockchip,sub", i); + sub_pdev = of_find_device_by_node(sub_np); + vcodec_subdev_probe(sub_pdev, pservice); + } + } else { + vcodec_subdev_probe(pdev, pservice); + } + platform_set_drvdata(pdev, pservice); #ifdef CONFIG_DEBUG_FS - pservice->debugfs_dir = vcodec_debugfs_create_device_dir((char*)dev_name(dev), parent); + pservice->debugfs_dir = + vcodec_debugfs_create_device_dir((char*)dev_name(dev), parent); if (pservice->debugfs_dir == NULL) - pr_err("create debugfs dir %s failed\n", dev_name(dev)); + vpu_err("create debugfs dir %s failed\n", dev_name(dev)); pservice->debugfs_file_regs = debugfs_create_file("regs", 0664, @@ -1953,69 +2036,20 @@ static int vcodec_probe(struct platform_device *pdev) &debug_vcodec_fops); #endif -#if defined(CONFIG_VCODEC_MMU) - if (iommu_en) { - pservice->ion_client = rockchip_ion_client_create("vpu"); - if (IS_ERR(pservice->ion_client)) { - dev_err(&pdev->dev, "failed to create ion client for vcodec"); - return PTR_ERR(pservice->ion_client); - } else { - dev_info(&pdev->dev, "vcodec ion client create success!\n"); - } - - if (pservice->hw_info->hw_id == HEVC_ID) - sprintf(mmu_dev_dts_name, HEVC_IOMMU_COMPATIBLE_NAME); - else - sprintf(mmu_dev_dts_name, VPU_IOMMU_COMPATIBLE_NAME); - - pservice->mmu_dev = rockchip_get_sysmmu_device_by_compatible(mmu_dev_dts_name); - - if (pservice->mmu_dev) { - platform_set_sysmmu(pservice->mmu_dev, pservice->dev); - /*rockchip_iovmm_activate(pservice->dev);*/ - } - - rockchip_iovmm_set_fault_handler(pservice->dev, vcodec_sysmmu_fault_handler); - } -#endif - vcodec_exit_mode_nolock(pservice->dev_id, config); vpu_service_power_off(pservice); pr_info("init success\n"); -#if HEVC_SIM_ENABLE - if (pservice->hw_info->hw_id == HEVC_ID) - simulate_init(pservice); -#endif - -#if HEVC_TEST_ENABLE - hevc_test_case0(pservice); -#endif - return 0; err: pr_info("init failed\n"); - vcodec_exit_mode_nolock(pservice->dev_id, config); vpu_service_power_off(pservice); vpu_put_clk(pservice); wake_lock_destroy(&pservice->wake_lock); if (res) devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); - if (pservice->irq_enc > 0) - free_irq(pservice->irq_enc, (void *)pservice); - if (pservice->irq_dec > 0) - free_irq(pservice->irq_dec, (void *)pservice); - - if (pservice->child_dev) { - device_destroy(pservice->cls, pservice->dev_t); - cdev_del(&pservice->cdev); - unregister_chrdev_region(pservice->dev_t, 1); - } - - if (pservice->cls) - class_destroy(pservice->cls); return ret; } @@ -2024,14 +2058,12 @@ static int vcodec_remove(struct platform_device *pdev) { struct vpu_service_info *pservice = platform_get_drvdata(pdev); struct resource *res; + struct vpu_subdev_data *data, *n; - device_destroy(pservice->cls, pservice->dev_t); - class_destroy(pservice->cls); - cdev_del(&pservice->cdev); - unregister_chrdev_region(pservice->dev_t, 1); + list_for_each_entry_safe(data, n, &pservice->subdev_list, lnk_service) { + vcodec_subdev_remove(data); + } - free_irq(pservice->irq_enc, (void *)&pservice->enc_dev); - free_irq(pservice->irq_dec, (void *)&pservice->dec_dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); vpu_put_clk(pservice); @@ -2049,6 +2081,7 @@ static int vcodec_remove(struct platform_device *pdev) static const struct of_device_id vcodec_service_dt_ids[] = { {.compatible = "vpu_service",}, {.compatible = "rockchip,hevc_service",}, + {.compatible = "rockchip,vpu_combo",}, {}, }; #endif @@ -2065,14 +2098,14 @@ static struct platform_driver vcodec_driver = { }, }; -static void get_hw_info(struct vpu_service_info *pservice) +static void get_hw_info(struct vpu_subdev_data *data) { + struct vpu_service_info *pservice = data->pservice; VPUHwDecConfig_t *dec = &pservice->dec_config; VPUHwEncConfig_t *enc = &pservice->enc_config; - - if (pservice->dev_id == VCODEC_DEVICE_ID_VPU) { - u32 configReg = pservice->dec_dev.hwregs[VPU_DEC_HWCFG0]; - u32 asicID = pservice->dec_dev.hwregs[0]; + if (data->mode == VCODEC_RUNNING_MODE_VPU) { + u32 configReg = data->dec_dev.hwregs[VPU_DEC_HWCFG0]; + u32 asicID = data->dec_dev.hwregs[0]; dec->h264Support = (configReg >> DWL_H264_E) & 0x3U; dec->jpegSupport = (configReg >> DWL_JPEG_E) & 0x01U; @@ -2085,15 +2118,10 @@ static void get_hw_info(struct vpu_service_info *pservice) dec->refBufSupport = (configReg >> DWL_REF_BUFF_E) & 0x01U; dec->vp6Support = (configReg >> DWL_VP6_E) & 0x01U; - if (soc_is_rk3190() || soc_is_rk3288()) - dec->maxDecPicWidth = 4096; - else if (cpu_is_rk3036() || cpu_is_rk312x()) - dec->maxDecPicWidth = 1920; - else - dec->maxDecPicWidth = configReg & 0x07FFU; + dec->maxDecPicWidth = 4096; /* 2nd Config register */ - configReg = pservice->dec_dev.hwregs[VPU_DEC_HWCFG1]; + configReg = data->dec_dev.hwregs[VPU_DEC_HWCFG1]; if (dec->refBufSupport) { if ((configReg >> DWL_REF_BUFF_ILACE_E) & 0x01U) dec->refBufSupport |= 2; @@ -2120,142 +2148,20 @@ static void get_hw_info(struct vpu_service_info *pservice) if (dec->refBufSupport && (asicID >> 16) == 0x6731U ) dec->refBufSupport |= 8; /* enable HW support for offset */ - /// invalidate fuse register value in rk319x vpu and following. - if (!soc_is_rk3190() && !soc_is_rk3288() && !cpu_is_rk3036() && !cpu_is_rk312x()) { - VPUHwFuseStatus_t hwFuseSts; - /* Decoder fuse configuration */ - u32 fuseReg = pservice->dec_dev.hwregs[VPU_DEC_HW_FUSE_CFG]; - - hwFuseSts.h264SupportFuse = (fuseReg >> DWL_H264_FUSE_E) & 0x01U; - hwFuseSts.mpeg4SupportFuse = (fuseReg >> DWL_MPEG4_FUSE_E) & 0x01U; - hwFuseSts.mpeg2SupportFuse = (fuseReg >> DWL_MPEG2_FUSE_E) & 0x01U; - hwFuseSts.sorensonSparkSupportFuse = (fuseReg >> DWL_SORENSONSPARK_FUSE_E) & 0x01U; - hwFuseSts.jpegSupportFuse = (fuseReg >> DWL_JPEG_FUSE_E) & 0x01U; - hwFuseSts.vp6SupportFuse = (fuseReg >> DWL_VP6_FUSE_E) & 0x01U; - hwFuseSts.vc1SupportFuse = (fuseReg >> DWL_VC1_FUSE_E) & 0x01U; - hwFuseSts.jpegProgSupportFuse = (fuseReg >> DWL_PJPEG_FUSE_E) & 0x01U; - hwFuseSts.rvSupportFuse = (fuseReg >> DWL_RV_FUSE_E) & 0x01U; - hwFuseSts.avsSupportFuse = (fuseReg >> DWL_AVS_FUSE_E) & 0x01U; - hwFuseSts.vp7SupportFuse = (fuseReg >> DWL_VP7_FUSE_E) & 0x01U; - hwFuseSts.vp8SupportFuse = (fuseReg >> DWL_VP8_FUSE_E) & 0x01U; - hwFuseSts.customMpeg4SupportFuse = (fuseReg >> DWL_CUSTOM_MPEG4_FUSE_E) & 0x01U; - hwFuseSts.mvcSupportFuse = (fuseReg >> DWL_MVC_FUSE_E) & 0x01U; - - /* check max. decoder output width */ - - if (fuseReg & 0x8000U) - hwFuseSts.maxDecPicWidthFuse = 1920; - else if (fuseReg & 0x4000U) - hwFuseSts.maxDecPicWidthFuse = 1280; - else if (fuseReg & 0x2000U) - hwFuseSts.maxDecPicWidthFuse = 720; - else if (fuseReg & 0x1000U) - hwFuseSts.maxDecPicWidthFuse = 352; - else /* remove warning */ - hwFuseSts.maxDecPicWidthFuse = 352; - - hwFuseSts.refBufSupportFuse = (fuseReg >> DWL_REF_BUFF_FUSE_E) & 0x01U; - - /* Pp configuration */ - configReg = pservice->dec_dev.hwregs[VPU_PP_HW_SYNTH_CFG]; - - if ((configReg >> DWL_PP_E) & 0x01U) { - dec->ppSupport = 1; - dec->maxPpOutPicWidth = configReg & 0x07FFU; - /*pHwCfg->ppConfig = (configReg >> DWL_CFG_E) & 0x0FU; */ - dec->ppConfig = configReg; - } else { - dec->ppSupport = 0; - dec->maxPpOutPicWidth = 0; - dec->ppConfig = 0; - } - - /* check the HW versio */ - if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U)) { - /* Pp configuration */ - configReg = pservice->dec_dev.hwregs[VPU_DEC_HW_FUSE_CFG]; - if ((configReg >> DWL_PP_E) & 0x01U) { - /* Pp fuse configuration */ - u32 fuseRegPp = pservice->dec_dev.hwregs[VPU_PP_HW_FUSE_CFG]; - - if ((fuseRegPp >> DWL_PP_FUSE_E) & 0x01U) { - hwFuseSts.ppSupportFuse = 1; - /* check max. pp output width */ - if (fuseRegPp & 0x8000U) - hwFuseSts.maxPpOutPicWidthFuse = 1920; - else if (fuseRegPp & 0x4000U) - hwFuseSts.maxPpOutPicWidthFuse = 1280; - else if (fuseRegPp & 0x2000U) - hwFuseSts.maxPpOutPicWidthFuse = 720; - else if (fuseRegPp & 0x1000U) - hwFuseSts.maxPpOutPicWidthFuse = 352; - else - hwFuseSts.maxPpOutPicWidthFuse = 352; - hwFuseSts.ppConfigFuse = fuseRegPp; - } else { - hwFuseSts.ppSupportFuse = 0; - hwFuseSts.maxPpOutPicWidthFuse = 0; - hwFuseSts.ppConfigFuse = 0; - } - } else { - hwFuseSts.ppSupportFuse = 0; - hwFuseSts.maxPpOutPicWidthFuse = 0; - hwFuseSts.ppConfigFuse = 0; - } - - if (dec->maxDecPicWidth > hwFuseSts.maxDecPicWidthFuse) - dec->maxDecPicWidth = hwFuseSts.maxDecPicWidthFuse; - if (dec->maxPpOutPicWidth > hwFuseSts.maxPpOutPicWidthFuse) - dec->maxPpOutPicWidth = hwFuseSts.maxPpOutPicWidthFuse; - if (!hwFuseSts.h264SupportFuse) dec->h264Support = H264_NOT_SUPPORTED; - if (!hwFuseSts.mpeg4SupportFuse) dec->mpeg4Support = MPEG4_NOT_SUPPORTED; - if (!hwFuseSts.customMpeg4SupportFuse) dec->customMpeg4Support = MPEG4_CUSTOM_NOT_SUPPORTED; - if (!hwFuseSts.jpegSupportFuse) dec->jpegSupport = JPEG_NOT_SUPPORTED; - if ((dec->jpegSupport == JPEG_PROGRESSIVE) && !hwFuseSts.jpegProgSupportFuse) - dec->jpegSupport = JPEG_BASELINE; - if (!hwFuseSts.mpeg2SupportFuse) dec->mpeg2Support = MPEG2_NOT_SUPPORTED; - if (!hwFuseSts.vc1SupportFuse) dec->vc1Support = VC1_NOT_SUPPORTED; - if (!hwFuseSts.vp6SupportFuse) dec->vp6Support = VP6_NOT_SUPPORTED; - if (!hwFuseSts.vp7SupportFuse) dec->vp7Support = VP7_NOT_SUPPORTED; - if (!hwFuseSts.vp8SupportFuse) dec->vp8Support = VP8_NOT_SUPPORTED; - if (!hwFuseSts.ppSupportFuse) dec->ppSupport = PP_NOT_SUPPORTED; - - /* check the pp config vs fuse status */ - if ((dec->ppConfig & 0xFC000000) && ((hwFuseSts.ppConfigFuse & 0xF0000000) >> 5)) { - u32 deInterlace = ((dec->ppConfig & PP_DEINTERLACING) >> 25); - u32 alphaBlend = ((dec->ppConfig & PP_ALPHA_BLENDING) >> 24); - u32 deInterlaceFuse = (((hwFuseSts.ppConfigFuse >> 5) & PP_DEINTERLACING) >> 25); - u32 alphaBlendFuse = (((hwFuseSts.ppConfigFuse >> 5) & PP_ALPHA_BLENDING) >> 24); - - if (deInterlace && !deInterlaceFuse) dec->ppConfig &= 0xFD000000; - if (alphaBlend && !alphaBlendFuse) dec->ppConfig &= 0xFE000000; - } - if (!hwFuseSts.sorensonSparkSupportFuse) dec->sorensonSparkSupport = SORENSON_SPARK_NOT_SUPPORTED; - if (!hwFuseSts.refBufSupportFuse) dec->refBufSupport = REF_BUF_NOT_SUPPORTED; - if (!hwFuseSts.rvSupportFuse) dec->rvSupport = RV_NOT_SUPPORTED; - if (!hwFuseSts.avsSupportFuse) dec->avsSupport = AVS_NOT_SUPPORTED; - if (!hwFuseSts.mvcSupportFuse) dec->mvcSupport = MVC_NOT_SUPPORTED; - } - } - if (!cpu_is_rk3036()) { - configReg = pservice->enc_dev.hwregs[63]; + configReg = data->enc_dev.hwregs[63]; enc->maxEncodedWidth = configReg & ((1 << 11) - 1); enc->h264Enabled = (configReg >> 27) & 1; enc->mpeg4Enabled = (configReg >> 26) & 1; enc->jpegEnabled = (configReg >> 25) & 1; enc->vsEnabled = (configReg >> 24) & 1; enc->rgbEnabled = (configReg >> 28) & 1; - /*enc->busType = (configReg >> 20) & 15; - enc->synthesisLanguage = (configReg >> 16) & 15; - enc->busWidth = (configReg >> 12) & 15;*/ - enc->reg_size = pservice->reg_size; + enc->reg_size = data->reg_size; enc->reserv[0] = enc->reserv[1] = 0; } - pservice->auto_freq = soc_is_rk2928g() || soc_is_rk2928l() || soc_is_rk2926() || soc_is_rk3288(); if (pservice->auto_freq) { - pr_info("vpu_service set to auto frequency mode\n"); + vpu_debug(3, "vpu_service set to auto frequency mode\n"); atomic_set(&pservice->freq_status, VPU_FREQ_BUT); } @@ -2272,35 +2178,33 @@ static void get_hw_info(struct vpu_service_info *pservice) static irqreturn_t vdpu_irq(int irq, void *dev_id) { - struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; - vpu_device *dev = &pservice->dec_dev; + struct vpu_subdev_data *data = (struct vpu_subdev_data*)dev_id; + struct vpu_service_info *pservice = data->pservice; + vpu_device *dev = &data->dec_dev; u32 raw_status; u32 irq_status; - vcodec_enter_mode_nolock(pservice->dev_id, &pservice->reserved_mode); + vcodec_enter_mode(data); irq_status = raw_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER); - pr_debug("dec_irq\n"); + vpu_debug(3, "%s status %08x\n", __func__, raw_status); if (irq_status & DEC_INTERRUPT_BIT) { pr_debug("dec_isr dec %x\n", irq_status); - if ((irq_status & 0x40001) == 0x40001) - { + if ((irq_status & 0x40001) == 0x40001) { do { - irq_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER); + irq_status = + readl(dev->hwregs + + DEC_INTERRUPT_REGISTER); } while ((irq_status & 0x40001) == 0x40001); } - /* clear dec IRQ */ - if (pservice->hw_info->hw_id != HEVC_ID) - writel(irq_status & (~DEC_INTERRUPT_BIT|DEC_BUFFER_EMPTY_BIT), dev->hwregs + DEC_INTERRUPT_REGISTER); - else - writel(0, dev->hwregs + DEC_INTERRUPT_REGISTER); + writel(0, dev->hwregs + DEC_INTERRUPT_REGISTER); atomic_add(1, &dev->irq_count_codec); } - if (pservice->hw_info->hw_id != HEVC_ID) { + if (data->hw_info->hw_id != HEVC_ID) { irq_status = readl(dev->hwregs + PP_INTERRUPT_REGISTER); if (irq_status & PP_INTERRUPT_BIT) { pr_debug("vdpu_isr pp %x\n", irq_status); @@ -2312,67 +2216,67 @@ static irqreturn_t vdpu_irq(int irq, void *dev_id) pservice->irq_status = raw_status; - vcodec_exit_mode_nolock(pservice->dev_id, pservice->reserved_mode); + vcodec_exit_mode(pservice); return IRQ_WAKE_THREAD; } static irqreturn_t vdpu_isr(int irq, void *dev_id) { - struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; - vpu_device *dev = &pservice->dec_dev; + struct vpu_subdev_data *data = (struct vpu_subdev_data*)dev_id; + struct vpu_service_info *pservice = data->pservice; + vpu_device *dev = &data->dec_dev; - mutex_lock(pservice->lock); + mutex_lock(&pservice->lock); if (atomic_read(&dev->irq_count_codec)) { #if VPU_SERVICE_SHOW_TIME do_gettimeofday(&dec_end); - pr_info("dec task: %ld ms\n", + vpu_debug(3, "dec task: %ld ms\n", (dec_end.tv_sec - dec_start.tv_sec) * 1000 + (dec_end.tv_usec - dec_start.tv_usec) / 1000); #endif atomic_sub(1, &dev->irq_count_codec); if (NULL == pservice->reg_codec) { - pr_err("error: dec isr with no task waiting\n"); + vpu_err("error: dec isr with no task waiting\n"); } else { - reg_from_run_to_done(pservice, *pservice->reg_codec); + reg_from_run_to_done(data, pservice->reg_codec); } } if (atomic_read(&dev->irq_count_pp)) { - #if VPU_SERVICE_SHOW_TIME do_gettimeofday(&pp_end); printk("pp task: %ld ms\n", (pp_end.tv_sec - pp_start.tv_sec) * 1000 + (pp_end.tv_usec - pp_start.tv_usec) / 1000); #endif - atomic_sub(1, &dev->irq_count_pp); if (NULL == pservice->reg_pproc) { - pr_err("error: pp isr with no task waiting\n"); + vpu_err("error: pp isr with no task waiting\n"); } else { - reg_from_run_to_done(pservice, pservice->reg_pproc); + reg_from_run_to_done(data, pservice->reg_pproc); } } - try_set_reg(pservice); - mutex_unlock(pservice->lock); + try_set_reg(data); + mutex_unlock(&pservice->lock); return IRQ_HANDLED; } static irqreturn_t vepu_irq(int irq, void *dev_id) { - struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; - vpu_device *dev = &pservice->enc_dev; + struct vpu_subdev_data *data = (struct vpu_subdev_data*)dev_id; + struct vpu_service_info *pservice = data->pservice; + vpu_device *dev = &data->enc_dev; u32 irq_status; - vcodec_enter_mode_nolock(pservice->dev_id, &pservice->reserved_mode); + vcodec_enter_mode(data); irq_status= readl(dev->hwregs + ENC_INTERRUPT_REGISTER); pr_debug("vepu_irq irq status %x\n", irq_status); #if VPU_SERVICE_SHOW_TIME do_gettimeofday(&enc_end); - pr_info("enc task: %ld ms\n", + vpu_debug(3, "enc task: %ld ms\n", (enc_end.tv_sec - enc_start.tv_sec) * 1000 + (enc_end.tv_usec - enc_start.tv_usec) / 1000); #endif @@ -2384,27 +2288,28 @@ static irqreturn_t vepu_irq(int irq, void *dev_id) pservice->irq_status = irq_status; - vcodec_exit_mode_nolock(pservice->dev_id, pservice->reserved_mode); + vcodec_exit_mode(pservice); return IRQ_WAKE_THREAD; } static irqreturn_t vepu_isr(int irq, void *dev_id) { - struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; - vpu_device *dev = &pservice->enc_dev; + struct vpu_subdev_data *data = (struct vpu_subdev_data*)dev_id; + struct vpu_service_info *pservice = data->pservice; + vpu_device *dev = &data->enc_dev; - mutex_lock(pservice->lock); + mutex_lock(&pservice->lock); if (atomic_read(&dev->irq_count_codec)) { atomic_sub(1, &dev->irq_count_codec); if (NULL == pservice->reg_codec) { - pr_err("error: enc isr with no task waiting\n"); + vpu_err("error: enc isr with no task waiting\n"); } else { - reg_from_run_to_done(pservice, *pservice->reg_codec); + reg_from_run_to_done(data, pservice->reg_codec); } } - try_set_reg(pservice); - mutex_unlock(pservice->lock); + try_set_reg(data); + mutex_unlock(&pservice->lock); return IRQ_HANDLED; } @@ -2412,16 +2317,8 @@ static int __init vcodec_service_init(void) { int ret; - g_combo.hevc_srv = NULL; - g_combo.vpu_srv = NULL; - INIT_LIST_HEAD(&g_combo.waiting); - INIT_LIST_HEAD(&g_combo.running); - mutex_init(&g_combo.run_lock); - g_combo.reg_codec = NULL; - g_combo.current_hw_mode = VCODEC_DEVICE_ID_VPU; - if ((ret = platform_driver_register(&vcodec_driver)) != 0) { - pr_err("Platform device register failed (%d).\n", ret); + vpu_err("Platform device register failed (%d).\n", ret); return ret; } @@ -2468,24 +2365,24 @@ static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct den static int debug_vcodec_show(struct seq_file *s, void *unused) { - struct vpu_service_info *pservice = s->private; + struct vpu_subdev_data *data = s->private; + struct vpu_service_info *pservice = data->pservice; unsigned int i, n; vpu_reg *reg, *reg_tmp; vpu_session *session, *session_tmp; - mutex_lock(pservice->lock); + mutex_lock(&pservice->lock); vpu_service_power_on(pservice); - if (pservice->hw_info->hw_id != HEVC_ID) { + if (data->hw_info->hw_id != HEVC_ID) { seq_printf(s, "\nENC Registers:\n"); - n = pservice->enc_dev.iosize >> 2; - for (i = 0; i < n; i++) { - seq_printf(s, "\tswreg%d = %08X\n", i, readl(pservice->enc_dev.hwregs + i)); - } + n = data->enc_dev.iosize >> 2; + for (i = 0; i < n; i++) + seq_printf(s, "\tswreg%d = %08X\n", i, readl(data->enc_dev.hwregs + i)); } seq_printf(s, "\nDEC Registers:\n"); - n = pservice->dec_dev.iosize >> 2; + n = data->dec_dev.iosize >> 2; for (i = 0; i < n; i++) - seq_printf(s, "\tswreg%d = %08X\n", i, readl(pservice->dec_dev.hwregs + i)); + seq_printf(s, "\tswreg%d = %08X\n", i, readl(data->dec_dev.hwregs + i)); seq_printf(s, "\nvpu service status:\n"); list_for_each_entry_safe(session, session_tmp, &pservice->session, list_session) { @@ -2501,7 +2398,7 @@ static int debug_vcodec_show(struct seq_file *s, void *unused) seq_printf(s, "done register set\n"); } } - mutex_unlock(pservice->lock); + mutex_unlock(&pservice->lock); return 0; } @@ -2577,7 +2474,6 @@ static int hevc_test_case0(vpu_service_info *pservice) unsigned long size = 272;//sizeof(register_00); // registers array length int testidx = 0; int ret = 0; - u8 *pps_tbl[TEST_CNT]; u8 *register_tbl[TEST_CNT]; u8 *rps_tbl[TEST_CNT]; @@ -2658,7 +2554,7 @@ static int hevc_test_case0(vpu_service_info *pservice) /* create registers */ reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL); if (NULL == reg) { - pr_err("error: kmalloc fail in reg_init\n"); + vpu_err("error: kmalloc fail in reg_init\n"); return -1; } @@ -2717,26 +2613,24 @@ static int hevc_test_case0(vpu_service_info *pservice) reg->reg[i] = phy_yuv; mutex_lock(pservice->lock); - list_add_tail(®->status_link, pservice->waiting); + list_add_tail(®->status_link, &pservice->waiting); list_add_tail(®->session_link, &session.waiting); mutex_unlock(pservice->lock); - printk("%s %d %p\n", __func__, __LINE__, pservice); - /* stuff hardware */ - try_set_reg(pservice); + try_set_reg(data); /* wait for result */ ret = wait_event_timeout(session.wait, !list_empty(&session.done), VPU_TIMEOUT_DELAY); if (!list_empty(&session.done)) { if (ret < 0) - pr_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session.pid, ret); + vpu_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session.pid, ret); ret = 0; } else { if (unlikely(ret < 0)) { - pr_err("error: pid %d wait task ret %d\n", session.pid, ret); + vpu_err("error: pid %d wait task ret %d\n", session.pid, ret); } else if (0 == ret) { - pr_err("error: pid %d wait %d task done timeout\n", session.pid, atomic_read(&session.task_running)); + vpu_err("error: pid %d wait %d task done timeout\n", session.pid, atomic_read(&session.task_running)); ret = -ETIMEDOUT; } } @@ -2756,14 +2650,14 @@ static int hevc_test_case0(vpu_service_info *pservice) mutex_unlock(pservice->lock); printk("\nDEC Registers:\n"); - n = pservice->dec_dev.iosize >> 2; + n = data->dec_dev.iosize >> 2; for (i=0; idec_dev.hwregs + i)); + printk("\tswreg%d = %08X\n", i, readl(data->dec_dev.hwregs + i)); - pr_err("test index %d failed\n", testidx); + vpu_err("test index %d failed\n", testidx); break; } else { - pr_info("test index %d success\n", testidx); + vpu_debug(3, "test index %d success\n", testidx); vpu_reg *reg = list_entry(session.done.next, vpu_reg, session_link); @@ -2778,7 +2672,7 @@ static int hevc_test_case0(vpu_service_info *pservice) testidx++; } - reg_deinit(pservice, reg); + reg_deinit(data, reg); } return 0;