From 62b46993f34d0ca51ee56c01bef98218d954a785 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 17 Jul 2014 16:10:08 +0800 Subject: [PATCH] rk3036: enable vpu and hevc, modified vcodec_service adapt to rk3036 --- arch/arm/boot/dts/rk3036.dtsi | 10 +- arch/arm/mach-rockchip/vcodec_service.c | 1786 ++++++++++++----------- 2 files changed, 920 insertions(+), 876 deletions(-) diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 950614e321e0..a93daa85b823 100755 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -568,23 +568,23 @@ vpu: vpu_service@10108000 { compatible = "vpu_service"; reg = <0x10108000 0x800>; - interrupts = , ; - interrupt-names = "irq_enc", "irq_dec"; + interrupts = ; + interrupt-names = "irq_dec"; clocks = <&aclk_vcodec_pre>, <&clk_gates3 12>; clock-names = "aclk_vcodec", "hclk_vcodec"; name = "vpu_service"; - status = "disabled"; + status = "okay"; }; hevc: hevc_service@1010c000 { compatible = "rockchip,hevc_service"; - reg = <0x1010c000 0x800>; + reg = <0x1010c000 0x400>; interrupts = ; interrupt-names = "irq_dec"; clocks = <&aclk_vcodec_pre>, <&clk_gates3 12>, <&clk_hevc_core>; clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core"; name = "hevc_service"; - status = "disabled"; + status = "okay"; }; vop_mmu { diff --git a/arch/arm/mach-rockchip/vcodec_service.c b/arch/arm/mach-rockchip/vcodec_service.c index 1d410e28d9ab..73c48ee6317c 100755 --- a/arch/arm/mach-rockchip/vcodec_service.c +++ b/arch/arm/mach-rockchip/vcodec_service.c @@ -37,7 +37,8 @@ #include #include -#include +#include +#include #if defined(CONFIG_ION_ROCKCHIP) #include @@ -63,15 +64,15 @@ #include "vcodec_service.h" -#define HEVC_TEST_ENABLE 0 -#define HEVC_SIM_ENABLE 0 -#define VCODEC_CLOCK_ENABLE 1 +#define HEVC_TEST_ENABLE 0 +#define HEVC_SIM_ENABLE 0 +#define VCODEC_CLOCK_ENABLE 1 typedef enum { VPU_DEC_ID_9190 = 0x6731, VPU_ID_8270 = 0x8270, VPU_ID_4831 = 0x4831, - HEVC_ID = 0x6867, + HEVC_ID = 0x6867, } VPU_HW_ID; typedef enum { @@ -85,8 +86,8 @@ typedef enum VPU_FREQ { VPU_FREQ_266M, VPU_FREQ_300M, VPU_FREQ_400M, - VPU_FREQ_500M, - VPU_FREQ_600M, + VPU_FREQ_500M, + VPU_FREQ_600M, VPU_FREQ_DEFAULT, VPU_FREQ_BUT, } VPU_FREQ; @@ -123,7 +124,7 @@ static struct timeval pp_start, pp_end; #define REG_NUM_ENC_4831 (164) #define REG_SIZE_ENC_4831 (0x400) -#define REG_NUM_HEVC_DEC (68) +#define REG_NUM_HEVC_DEC (68) #define SIZE_REG(reg) ((reg)*4) @@ -136,7 +137,7 @@ static VPU_HW_INFO_E vpu_hw_set[] = { .enc_io_size = REG_NUM_ENC_8270 * 4, .dec_offset = REG_SIZE_ENC_8270, .dec_reg_num = REG_NUM_9190_DEC_PP, - .dec_io_size = REG_NUM_9190_DEC_PP * 4, + .dec_io_size = REG_NUM_9190_DEC_PP * 4, }, [1] = { .hw_id = VPU_ID_4831, @@ -146,31 +147,42 @@ static VPU_HW_INFO_E vpu_hw_set[] = { .enc_io_size = REG_NUM_ENC_4831 * 4, .dec_offset = REG_SIZE_ENC_4831, .dec_reg_num = REG_NUM_9190_DEC_PP, - .dec_io_size = REG_NUM_9190_DEC_PP * 4, + .dec_io_size = REG_NUM_9190_DEC_PP * 4, }, - [2] = { - .hw_id = HEVC_ID, - .hw_addr = 0, - .dec_offset = 0x0, - .dec_reg_num = REG_NUM_HEVC_DEC, - .dec_io_size = REG_NUM_HEVC_DEC * 4, - }, + [2] = { + .hw_id = HEVC_ID, + .hw_addr = 0, + .dec_offset = 0x0, + .dec_reg_num = REG_NUM_HEVC_DEC, + .dec_io_size = REG_NUM_HEVC_DEC * 4, + }, + [3] = { + .hw_id = VPU_DEC_ID_9190, + .hw_addr = 0, + .enc_offset = 0x0, + .enc_reg_num = 0, + .enc_io_size = 0, + .dec_offset = REG_SIZE_ENC_4831, + .dec_reg_num = REG_NUM_9190_DEC_PP, + .dec_io_size = REG_NUM_9190_DEC_PP * 4, + }, + }; -#define DEC_INTERRUPT_REGISTER 1 -#define PP_INTERRUPT_REGISTER 60 -#define ENC_INTERRUPT_REGISTER 1 +#define DEC_INTERRUPT_REGISTER 1 +#define PP_INTERRUPT_REGISTER 60 +#define ENC_INTERRUPT_REGISTER 1 #define DEC_INTERRUPT_BIT 0x100 #define DEC_BUFFER_EMPTY_BIT 0x4000 #define PP_INTERRUPT_BIT 0x100 #define ENC_INTERRUPT_BIT 0x1 -#define HEVC_DEC_INT_RAW_BIT 0x200 -#define HEVC_DEC_STR_ERROR_BIT 0x4000 -#define HEVC_DEC_BUS_ERROR_BIT 0x2000 -#define HEVC_DEC_BUFFER_EMPTY_BIT 0x10000 +#define HEVC_DEC_INT_RAW_BIT 0x200 +#define HEVC_DEC_STR_ERROR_BIT 0x4000 +#define HEVC_DEC_BUS_ERROR_BIT 0x2000 +#define HEVC_DEC_BUFFER_EMPTY_BIT 0x10000 #define VPU_REG_EN_ENC 14 #define VPU_REG_ENC_GATE 2 @@ -188,7 +200,8 @@ static VPU_HW_INFO_E vpu_hw_set[] = { #if defined(CONFIG_VCODEC_MMU) static u8 addr_tbl_vpu_h264dec[] = { - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40, 41 + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 40, 41 }; static u8 addr_tbl_vpu_vp8dec[] = { @@ -216,7 +229,8 @@ static u8 addr_tbl_vpu_enc[] = { }; static u8 addr_tbl_hevc_dec[] = { - 4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 42, 43 + 4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 42, 43 }; #endif @@ -292,12 +306,12 @@ enum vcodec_device_id { }; struct vcodec_mem_region { - struct list_head srv_lnk; - struct list_head reg_lnk; - struct list_head session_lnk; - unsigned long iova; /* virtual address for iommu */ - unsigned long len; - struct ion_handle *hdl; + struct list_head srv_lnk; + struct list_head reg_lnk; + struct list_head session_lnk; + unsigned long iova; /* virtual address for iommu */ + unsigned long len; + struct ion_handle *hdl; }; typedef struct vpu_service_info { @@ -321,44 +335,44 @@ typedef struct vpu_service_info { bool bug_dec_addr; atomic_t freq_status; - struct clk *aclk_vcodec; - struct clk *hclk_vcodec; - struct clk *clk_core; - struct clk *clk_cabac; - struct clk *pd_video; + struct clk *aclk_vcodec; + struct clk *hclk_vcodec; + struct clk *clk_core; + struct clk *clk_cabac; + struct clk *pd_video; - int irq_dec; - int irq_enc; + int irq_dec; + int irq_enc; - vpu_device enc_dev; - vpu_device dec_dev; + vpu_device enc_dev; + vpu_device dec_dev; - struct device *dev; + struct device *dev; - struct cdev cdev; - dev_t dev_t; - struct class *cls; - struct device *child_dev; + struct cdev cdev; + dev_t dev_t; + struct class *cls; + struct device *child_dev; - struct dentry *debugfs_dir; - struct dentry *debugfs_file_regs; + struct dentry *debugfs_dir; + struct dentry *debugfs_file_regs; - u32 irq_status; + u32 irq_status; #if defined(CONFIG_VCODEC_MMU) - struct ion_client * ion_client; - struct list_head mem_region_list; - struct device *mmu_dev; + struct ion_client *ion_client; + struct list_head mem_region_list; + struct device *mmu_dev; #endif - enum vcodec_device_id dev_id; + enum vcodec_device_id dev_id; - struct delayed_work simulate_work; + struct delayed_work simulate_work; } vpu_service_info; typedef struct vpu_request { - unsigned long *req; - unsigned long size; + unsigned long *req; + unsigned long size; } vpu_request; /// global variable @@ -372,91 +386,116 @@ static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct den static int debug_vcodec_open(struct inode *inode, struct file *file); static const struct file_operations debug_vcodec_fops = { - .open = debug_vcodec_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, + .open = debug_vcodec_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; #endif #define VPU_POWER_OFF_DELAY 4*HZ /* 4s */ #define VPU_TIMEOUT_DELAY 2*HZ /* 2s */ +#define VPU_SIMULATE_DELAY msecs_to_jiffies(15) -#define VPU_SIMULATE_DELAY msecs_to_jiffies(15) +static void vcodec_select_mode(enum vcodec_device_id id) +{ + if (soc_is_rk3036()) { +#define BIT_VCODEC_SEL (1<<3) + if (id == VCODEC_DEVICE_ID_HEVC) { + writel_relaxed(readl_relaxed(RK_GRF_VIRT + RK3036_GRF_SOC_CON1) | (BIT_VCODEC_SEL) | (BIT_VCODEC_SEL << 16), RK_GRF_VIRT + RK3036_GRF_SOC_CON1); + } else { + writel_relaxed((readl_relaxed(RK_GRF_VIRT + RK3036_GRF_SOC_CON1) & (~BIT_VCODEC_SEL)) | (BIT_VCODEC_SEL << 16), RK_GRF_VIRT + RK3036_GRF_SOC_CON1); + } + } +} 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; - } - - if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) { - 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; - } - - 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; - } - - 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 = 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; - } - } - - return 0; - } while (0); - - return -1; + 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; + } + + if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) { + 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 (!soc_is_rk3036()) { + 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 (!soc_is_rk3036()) { + 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 (!soc_is_rk3036()) { + 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; + } + } + + return 0; + } while (0); + + return -1; +#else + return 0; #endif } static void vpu_put_clk(struct vpu_service_info *pservice) { #if VCODEC_CLOCK_ENABLE - if (pservice->pd_video) { - devm_clk_put(pservice->dev, pservice->pd_video); - } - - if (pservice->aclk_vcodec) { - devm_clk_put(pservice->dev, pservice->aclk_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->pd_video) { + devm_clk_put(pservice->dev, pservice->pd_video); + } + + if (pservice->aclk_vcodec) { + devm_clk_put(pservice->dev, pservice->aclk_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); + } + } #endif } @@ -538,39 +577,42 @@ static void vpu_service_dump(struct vpu_service_info *pservice) static void vpu_service_power_off(struct vpu_service_info *pservice) { - int total_running; - if (!pservice->enabled) { - return; - } - - pservice->enabled = false; - total_running = atomic_read(&pservice->total_running); - if (total_running) { - pr_alert("alert: power off when %d task running!!\n", total_running); - mdelay(50); - pr_alert("alert: delay 50 ms for running task\n"); - vpu_service_dump(pservice); - } - + int total_running; + if (!pservice->enabled) + return; + + pservice->enabled = false; + total_running = atomic_read(&pservice->total_running); + if (total_running) { + pr_alert("alert: power off when %d task running!!\n", total_running); + mdelay(50); + pr_alert("alert: delay 50 ms for running task\n"); + vpu_service_dump(pservice); + } + #if defined(CONFIG_VCODEC_MMU) - if (pservice->mmu_dev) { - iovmm_deactivate(pservice->dev); - } -#endif + if (pservice->mmu_dev) + iovmm_deactivate(pservice->dev); +#endif - printk("%s: power off...", dev_name(pservice->dev)); - udelay(10); + pr_info("%s: power off...", dev_name(pservice->dev)); + udelay(10); #if VCODEC_CLOCK_ENABLE - clk_disable_unprepare(pservice->pd_video); - clk_disable_unprepare(pservice->hclk_vcodec); - clk_disable_unprepare(pservice->aclk_vcodec); - if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) { - clk_disable_unprepare(pservice->clk_core); - clk_disable_unprepare(pservice->clk_cabac); - } + if (pservice->pd_video) + clk_disable_unprepare(pservice->pd_video); + if (pservice->hclk_vcodec) + 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); + } #endif - wake_unlock(&pservice->wake_lock); - printk("done\n"); + wake_unlock(&pservice->wake_lock); + pr_info("done\n"); } static inline void vpu_queue_power_off_work(struct vpu_service_info *pservice) @@ -580,8 +622,8 @@ static inline void vpu_queue_power_off_work(struct vpu_service_info *pservice) 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); + 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)) { vpu_service_power_off(pservice); @@ -594,45 +636,52 @@ static void vpu_power_off_work(struct work_struct *work_s) static void vpu_service_power_on(struct vpu_service_info *pservice) { - static ktime_t last; - ktime_t now = ktime_get(); - if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) { - cancel_delayed_work_sync(&pservice->power_off_work); - vpu_queue_power_off_work(pservice); - last = now; - } - if (pservice->enabled) - return ; - - pservice->enabled = true; - printk("%s: power on\n", dev_name(pservice->dev)); + static ktime_t last; + ktime_t now = ktime_get(); + if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) { + cancel_delayed_work_sync(&pservice->power_off_work); + vpu_queue_power_off_work(pservice); + last = now; + } + if (pservice->enabled) + return ; + + pservice->enabled = true; + printk("%s: power on\n", dev_name(pservice->dev)); #if VCODEC_CLOCK_ENABLE - clk_prepare_enable(pservice->aclk_vcodec); - clk_prepare_enable(pservice->hclk_vcodec); - - if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) { - clk_prepare_enable(pservice->clk_core); - clk_prepare_enable(pservice->clk_cabac); - } - - clk_prepare_enable(pservice->pd_video); + 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_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); + /// 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 + + udelay(10); + wake_lock(&pservice->wake_lock); + +#if defined(CONFIG_VCODEC_MMU) + if (pservice->mmu_dev) + iovmm_activate(pservice->dev); #endif - - udelay(10); - wake_lock(&pservice->wake_lock); - -#if defined(CONFIG_VCODEC_MMU) - if (pservice->mmu_dev) { - iovmm_activate(pservice->dev); - } -#endif } static inline bool reg_check_rmvb_wmv(vpu_reg *reg) @@ -655,9 +704,8 @@ static inline enum VPU_DEC_FMT reg_check_fmt(vpu_reg *reg) static inline int reg_probe_width(vpu_reg *reg) { - int width_in_mb = reg->reg[4] >> 23; - - return width_in_mb * 16; + int width_in_mb = reg->reg[4] >> 23; + return width_in_mb * 16; } #if defined(CONFIG_VCODEC_MMU) @@ -677,12 +725,12 @@ static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, int for (i = 0; i < size; i++) { usr_fd = reg->reg[tbl[i]] & 0x3FF; - if (tbl[i] == 41 && pservice->hw_info->hw_id != HEVC_ID && (reg->type == VPU_DEC || reg->type == VPU_DEC_PP)) { + if (tbl[i] == 41 && pservice->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; - } else { + else offset = reg->reg[tbl[i]] >> 10; - } if (usr_fd != 0) { struct ion_handle *hdl; @@ -807,9 +855,8 @@ 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) { - INIT_LIST_HEAD(®->mem_region_list); - } + if (pservice->mmu_dev) + INIT_LIST_HEAD(®->mem_region_list); #endif if (copy_from_user(®->reg[0], (void __user *)src, size)) { @@ -893,10 +940,12 @@ static void reg_from_wait_to_run(struct vpu_service_info *pservice, vpu_reg *reg list_add_tail(®->session_link, ®->session->running); } -static void reg_copy_from_hw(vpu_reg *reg, volatile u32 *src, u32 count) +static void reg_copy_from_hw(struct vpu_service_info *pservice, vpu_reg *reg, volatile u32 *src, u32 count) { int i; u32 *dst = (u32 *)®->reg[0]; + + vcodec_select_mode(pservice->dev_id); for (i = 0; i < count; i++) *dst++ = *src++; } @@ -913,27 +962,28 @@ static void reg_from_run_to_done(struct vpu_service_info *pservice, vpu_reg *reg 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); + reg_copy_from_hw(pservice, reg, pservice->enc_dev.hwregs, pservice->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); + reg_copy_from_hw(pservice, reg, pservice->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); + reg_copy_from_hw(pservice, reg, pservice->dec_dev.hwregs + PP_INTERRUPT_REGISTER, REG_NUM_9190_PP); pservice->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0; break; } case VPU_DEC_PP : { pservice->reg_codec = NULL; pservice->reg_pproc = NULL; - reg_copy_from_hw(reg, pservice->dec_dev.hwregs, REG_NUM_9190_DEC_PP); + reg_copy_from_hw(pservice, reg, pservice->dec_dev.hwregs, REG_NUM_9190_DEC_PP); + vcodec_select_mode(pservice->dev_id); pservice->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0; break; } @@ -1005,6 +1055,9 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) if (pservice->auto_freq) { vpu_service_set_freq(pservice, reg); } + + vcodec_select_mode(pservice->dev_id); + switch (reg->type) { case VPU_ENC : { int enc_count = pservice->hw_info->enc_reg_num; @@ -1296,9 +1349,9 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long case VPU_IOC_PROBE_IOMMU_STATUS: { int iommu_enable = 0; -#if defined(CONFIG_VCODEC_MMU) - iommu_enable = pservice->mmu_dev ? 1 : 0; -#endif +#if defined(CONFIG_VCODEC_MMU) + iommu_enable = pservice->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"); @@ -1314,7 +1367,7 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long return 0; } - +#if 1 static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr) { int ret = -EINVAL, i = 0; @@ -1328,7 +1381,6 @@ static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr) return 0; } #endif - enc_id = (enc_id >> 16) & 0xFFFF; pr_info("checking hw id %x\n", enc_id); p->hw_info = NULL; @@ -1342,6 +1394,7 @@ static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr) iounmap((void *)tmp); return ret; } +#endif static int vpu_service_open(struct inode *inode, struct file *filp) { @@ -1412,28 +1465,28 @@ 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"); - } + 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); + 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); + cancel_delayed_work_sync(&pservice->power_off_work); + queue_delayed_work(system_nrt_wq, &pservice->simulate_work, VPU_SIMULATE_DELAY); } #endif @@ -1445,488 +1498,493 @@ extern struct ion_client *rockchip_ion_client_create(const char * name); #endif static int vcodec_probe(struct platform_device *pdev) { - int ret = 0; - struct resource *res = NULL; - struct device *dev = &pdev->dev; - void __iomem *regs = NULL; - 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); + int ret = 0; + struct resource *res = NULL; + struct device *dev = &pdev->dev; + void __iomem *regs = NULL; + 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); #if defined(CONFIG_VCODEC_MMU) - char mmu_dev_dts_name[40]; + char mmu_dev_dts_name[40]; #endif - pr_info("probe device %s\n", dev_name(dev)); - - of_property_read_string(np, "name", (const char**)&prop); - dev_set_name(dev, prop); - - if (strcmp(dev_name(dev), "hevc_service") == 0) { - pservice->dev_id = VCODEC_DEVICE_ID_HEVC; - } else if (strcmp(dev_name(dev), "vpu_service") == 0) { - pservice->dev_id = VCODEC_DEVICE_ID_VPU; - } else { - dev_err(dev, "Unknown device %s to probe\n", dev_name(dev)); - return -1; - } - - wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu"); - INIT_LIST_HEAD(&pservice->waiting); - INIT_LIST_HEAD(&pservice->running); - INIT_LIST_HEAD(&pservice->done); - INIT_LIST_HEAD(&pservice->session); - mutex_init(&pservice->lock); - pservice->reg_codec = NULL; - pservice->reg_pproc = NULL; - atomic_set(&pservice->total_running, 0); - pservice->enabled = false; + pr_info("probe device %s\n", dev_name(dev)); + + of_property_read_string(np, "name", (const char**)&prop); + dev_set_name(dev, prop); + + if (strcmp(dev_name(dev), "hevc_service") == 0) { + pservice->dev_id = VCODEC_DEVICE_ID_HEVC; + vcodec_select_mode(VCODEC_DEVICE_ID_HEVC); + } else if (strcmp(dev_name(dev), "vpu_service") == 0) { + pservice->dev_id = VCODEC_DEVICE_ID_VPU; + } else { + dev_err(dev, "Unknown device %s to probe\n", dev_name(dev)); + return -1; + } + + wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu"); + INIT_LIST_HEAD(&pservice->waiting); + INIT_LIST_HEAD(&pservice->running); + INIT_LIST_HEAD(&pservice->done); + INIT_LIST_HEAD(&pservice->session); + mutex_init(&pservice->lock); + pservice->reg_codec = NULL; + pservice->reg_pproc = NULL; + atomic_set(&pservice->total_running, 0); + pservice->enabled = false; #if defined(CONFIG_VCODEC_MMU) - pservice->mmu_dev = NULL; -#endif - pservice->dev = dev; - - if (0 > vpu_get_clk(pservice)) { - goto err; - } + pservice->mmu_dev = NULL; +#endif + pservice->dev = dev; + + if (0 > vpu_get_clk(pservice)) + goto err; - INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work); + INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work); - vpu_service_power_on(pservice); - - mdelay(1); + vpu_service_power_on(pservice); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mdelay(1); - regs = devm_ioremap_resource(pservice->dev, res); - if (IS_ERR(regs)) { - ret = PTR_ERR(regs); - goto err; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ret = vpu_service_check_hw(pservice, res->start); - if (ret < 0) { - pr_err("error: hw info check faild\n"); - goto err; - } + res->flags &= ~IORESOURCE_CACHEABLE; - /// define regs address. - pservice->dec_dev.iobaseaddr = res->start + pservice->hw_info->dec_offset; - pservice->dec_dev.iosize = pservice->hw_info->dec_io_size; + regs = devm_ioremap_resource(pservice->dev, res); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + goto err; + } - pservice->dec_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->dec_offset); + { + u32 offset = res->start; + if (soc_is_rk3036()) { + if (pservice->dev_id == VCODEC_DEVICE_ID_VPU) + offset += 0x400; + vcodec_select_mode(pservice->dev_id); + } + ret = vpu_service_check_hw(pservice, offset); + if (ret < 0) { + pr_err("error: hw info check faild\n"); + goto err; + } + } - pservice->reg_size = pservice->dec_dev.iosize; + /// define regs address. + pservice->dec_dev.iobaseaddr = res->start + pservice->hw_info->dec_offset; + pservice->dec_dev.iosize = pservice->hw_info->dec_io_size; - if (pservice->hw_info->hw_id != HEVC_ID) { - pservice->enc_dev.iobaseaddr = res->start + pservice->hw_info->enc_offset; - pservice->enc_dev.iosize = pservice->hw_info->enc_io_size; + printk("%s %d\n", __func__, __LINE__); - pservice->reg_size = pservice->reg_size > pservice->enc_dev.iosize ? pservice->reg_size : pservice->enc_dev.iosize; + pservice->dec_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->dec_offset); - pservice->enc_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->enc_offset); + pservice->reg_size = pservice->dec_dev.iosize; - 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; - } + printk("%s %d\n", __func__, __LINE__); - ret = devm_request_threaded_irq(pservice->dev, pservice->irq_enc, vepu_irq, vepu_isr, 0, 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; - } - } + if (pservice->hw_info->hw_id != HEVC_ID && !soc_is_rk3036()) { + pservice->enc_dev.iobaseaddr = res->start + pservice->hw_info->enc_offset; + pservice->enc_dev.iosize = pservice->hw_info->enc_io_size; - 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; - } + pservice->reg_size = pservice->reg_size > pservice->enc_dev.iosize ? pservice->reg_size : pservice->enc_dev.iosize; - /* 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->enc_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->enc_offset); - 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); + 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; + } - /// 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; - } + ret = devm_request_threaded_irq(pservice->dev, pservice->irq_enc, vepu_irq, vepu_isr, 0, 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; + } + } - cdev_init(&pservice->cdev, &vpu_service_fops); + 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; + } - pservice->cdev.owner = THIS_MODULE; - pservice->cdev.ops = &vpu_service_fops; + /* 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; + } - ret = cdev_add(&pservice->cdev, pservice->dev_t, 1); + 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); - if (ret) { - dev_err(dev, "add dev_t failed\n"); - goto err; - } + /// 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; + } - pservice->cls = class_create(THIS_MODULE, dev_name(dev)); + cdev_init(&pservice->cdev, &vpu_service_fops); - if (IS_ERR(pservice->cls)) { - ret = PTR_ERR(pservice->cls); - dev_err(dev, "class_create err:%d\n", ret); - goto err; - } + pservice->cdev.owner = THIS_MODULE; + pservice->cdev.ops = &vpu_service_fops; - pservice->child_dev = device_create(pservice->cls, dev, pservice->dev_t, NULL, dev_name(dev)); + ret = cdev_add(&pservice->cdev, pservice->dev_t, 1); - platform_set_drvdata(pdev, pservice); + if (ret) { + dev_err(dev, "add dev_t failed\n"); + goto err; + } - get_hw_info(pservice); + pservice->cls = class_create(THIS_MODULE, dev_name(dev)); + + if (IS_ERR(pservice->cls)) { + ret = PTR_ERR(pservice->cls); + dev_err(dev, "class_create err:%d\n", ret); + goto err; + } + + pservice->child_dev = device_create(pservice->cls, dev, pservice->dev_t, NULL, dev_name(dev)); + + platform_set_drvdata(pdev, pservice); + + get_hw_info(pservice); #ifdef CONFIG_DEBUG_FS - 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)); - } - - pservice->debugfs_file_regs = debugfs_create_file("regs", 0664, - pservice->debugfs_dir, pservice, - &debug_vcodec_fops); + 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)); + + pservice->debugfs_file_regs = + debugfs_create_file("regs", 0664, + pservice->debugfs_dir, pservice, + &debug_vcodec_fops); #endif #if defined(CONFIG_VCODEC_MMU) - 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, "iommu,hevc_mmu"); - } else { - sprintf(mmu_dev_dts_name, "iommu,vpu_mmu"); - } - - 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); - iovmm_activate(pservice->dev); - } + 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, "iommu,hevc_mmu"); + else + sprintf(mmu_dev_dts_name, "iommu,vpu_mmu"); + 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); + iovmm_activate(pservice->dev); + } #endif - vpu_service_power_off(pservice); - pr_info("init success\n"); + 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); - } + if (pservice->hw_info->hw_id == HEVC_ID) + simulate_init(pservice); #endif #if HEVC_TEST_ENABLE - hevc_test_case0(pservice); + hevc_test_case0(pservice); #endif - return 0; + return 0; err: - pr_info("init failed\n"); - 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; + pr_info("init failed\n"); + 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; } static int vcodec_remove(struct platform_device *pdev) { - struct vpu_service_info *pservice = platform_get_drvdata(pdev); - struct resource *res; - - device_destroy(pservice->cls, pservice->dev_t); - class_destroy(pservice->cls); - cdev_del(&pservice->cdev); - unregister_chrdev_region(pservice->dev_t, 1); - - 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); - wake_lock_destroy(&pservice->wake_lock); - -#ifdef CONFIG_DEBUG_FS - if (pservice->debugfs_file_regs) { - debugfs_remove(pservice->debugfs_file_regs); - } + struct vpu_service_info *pservice = platform_get_drvdata(pdev); + struct resource *res; + + device_destroy(pservice->cls, pservice->dev_t); + class_destroy(pservice->cls); + cdev_del(&pservice->cdev); + unregister_chrdev_region(pservice->dev_t, 1); + + 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); + wake_lock_destroy(&pservice->wake_lock); - if (pservice->debugfs_dir) { - debugfs_remove(pservice->debugfs_dir); - } +#ifdef CONFIG_DEBUG_FS + debugfs_remove(pservice->debugfs_file_regs); + debugfs_remove(pservice->debugfs_dir); #endif - return 0; + return 0; } #if defined(CONFIG_OF) static const struct of_device_id vcodec_service_dt_ids[] = { - {.compatible = "vpu_service",}, - {.compatible = "rockchip,hevc_service",}, - {}, + {.compatible = "vpu_service",}, + {.compatible = "rockchip,hevc_service",}, + {}, }; #endif static struct platform_driver vcodec_driver = { - .probe = vcodec_probe, - .remove = vcodec_remove, - .driver = { - .name = "vcodec", - .owner = THIS_MODULE, + .probe = vcodec_probe, + .remove = vcodec_remove, + .driver = { + .name = "vcodec", + .owner = THIS_MODULE, #if defined(CONFIG_OF) - .of_match_table = of_match_ptr(vcodec_service_dt_ids), + .of_match_table = of_match_ptr(vcodec_service_dt_ids), #endif - }, + }, }; static void get_hw_info(struct vpu_service_info *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]; - - dec->h264Support = (configReg >> DWL_H264_E) & 0x3U; - dec->jpegSupport = (configReg >> DWL_JPEG_E) & 0x01U; - if (dec->jpegSupport && ((configReg >> DWL_PJPEG_E) & 0x01U)) - dec->jpegSupport = JPEG_PROGRESSIVE; - dec->mpeg4Support = (configReg >> DWL_MPEG4_E) & 0x3U; - dec->vc1Support = (configReg >> DWL_VC1_E) & 0x3U; - dec->mpeg2Support = (configReg >> DWL_MPEG2_E) & 0x01U; - dec->sorensonSparkSupport = (configReg >> DWL_SORENSONSPARK_E) & 0x01U; - dec->refBufSupport = (configReg >> DWL_REF_BUFF_E) & 0x01U; - dec->vp6Support = (configReg >> DWL_VP6_E) & 0x01U; - - if (!soc_is_rk3190() && !soc_is_rk3288()) { - dec->maxDecPicWidth = configReg & 0x07FFU; - } else { - dec->maxDecPicWidth = 4096; - } - - /* 2nd Config register */ - configReg = pservice->dec_dev.hwregs[VPU_DEC_HWCFG1]; - if (dec->refBufSupport) { - if ((configReg >> DWL_REF_BUFF_ILACE_E) & 0x01U) - dec->refBufSupport |= 2; - if ((configReg >> DWL_REF_BUFF_DOUBLE_E) & 0x01U) - dec->refBufSupport |= 4; - } - dec->customMpeg4Support = (configReg >> DWL_MPEG4_CUSTOM_E) & 0x01U; - dec->vp7Support = (configReg >> DWL_VP7_E) & 0x01U; - dec->vp8Support = (configReg >> DWL_VP8_E) & 0x01U; - dec->avsSupport = (configReg >> DWL_AVS_E) & 0x01U; - - /* JPEG xtensions */ - if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U)) { - dec->jpegESupport = (configReg >> DWL_JPEG_EXT_E) & 0x01U; - } else { - dec->jpegESupport = JPEG_EXT_NOT_SUPPORTED; - } - - if (((asicID >> 16) >= 0x9170U) || ((asicID >> 16) == 0x6731U) ) { - dec->rvSupport = (configReg >> DWL_RV_E) & 0x03U; - } else { - dec->rvSupport = RV_NOT_SUPPORTED; - } - - dec->mvcSupport = (configReg >> DWL_MVC_E) & 0x03U; - - 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()) { - 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; - } - } - - configReg = pservice->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->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"); - atomic_set(&pservice->freq_status, VPU_FREQ_BUT); - } - pservice->bug_dec_addr = cpu_is_rk30xx(); - //printk("cpu 3066b bug %d\n", service.bug_dec_addr); - } else { - // disable frequency switch in hevc. - pservice->auto_freq = false; - } + 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]; + + dec->h264Support = (configReg >> DWL_H264_E) & 0x3U; + dec->jpegSupport = (configReg >> DWL_JPEG_E) & 0x01U; + if (dec->jpegSupport && ((configReg >> DWL_PJPEG_E) & 0x01U)) + dec->jpegSupport = JPEG_PROGRESSIVE; + dec->mpeg4Support = (configReg >> DWL_MPEG4_E) & 0x3U; + dec->vc1Support = (configReg >> DWL_VC1_E) & 0x3U; + dec->mpeg2Support = (configReg >> DWL_MPEG2_E) & 0x01U; + dec->sorensonSparkSupport = (configReg >> DWL_SORENSONSPARK_E) & 0x01U; + dec->refBufSupport = (configReg >> DWL_REF_BUFF_E) & 0x01U; + dec->vp6Support = (configReg >> DWL_VP6_E) & 0x01U; + + if (!soc_is_rk3190() && !soc_is_rk3288()) { + dec->maxDecPicWidth = configReg & 0x07FFU; + } else { + dec->maxDecPicWidth = 4096; + } + + /* 2nd Config register */ + configReg = pservice->dec_dev.hwregs[VPU_DEC_HWCFG1]; + if (dec->refBufSupport) { + if ((configReg >> DWL_REF_BUFF_ILACE_E) & 0x01U) + dec->refBufSupport |= 2; + if ((configReg >> DWL_REF_BUFF_DOUBLE_E) & 0x01U) + dec->refBufSupport |= 4; + } + dec->customMpeg4Support = (configReg >> DWL_MPEG4_CUSTOM_E) & 0x01U; + dec->vp7Support = (configReg >> DWL_VP7_E) & 0x01U; + dec->vp8Support = (configReg >> DWL_VP8_E) & 0x01U; + dec->avsSupport = (configReg >> DWL_AVS_E) & 0x01U; + + /* JPEG xtensions */ + if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U)) + dec->jpegESupport = (configReg >> DWL_JPEG_EXT_E) & 0x01U; + else + dec->jpegESupport = JPEG_EXT_NOT_SUPPORTED; + + if (((asicID >> 16) >= 0x9170U) || ((asicID >> 16) == 0x6731U) ) + dec->rvSupport = (configReg >> DWL_RV_E) & 0x03U; + else + dec->rvSupport = RV_NOT_SUPPORTED; + dec->mvcSupport = (configReg >> DWL_MVC_E) & 0x03U; + + 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()) { + 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 (!soc_is_rk3036()) { + configReg = pservice->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->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"); + atomic_set(&pservice->freq_status, VPU_FREQ_BUT); + } + + pservice->bug_dec_addr = cpu_is_rk30xx(); + } else { + /* disable frequency switch in hevc.*/ + pservice->auto_freq = false; + } } 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; - u32 raw_status; - u32 irq_status = raw_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER); + struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; + vpu_device *dev = &pservice->dec_dev; + u32 raw_status; + u32 irq_status; + + vcodec_select_mode(pservice->dev_id); + + irq_status = raw_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER); pr_debug("dec_irq\n"); @@ -1940,37 +1998,32 @@ static irqreturn_t vdpu_irq(int irq, void *dev_id) } /* 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(irq_status - & (~(DEC_INTERRUPT_BIT|HEVC_DEC_INT_RAW_BIT|HEVC_DEC_STR_ERROR_BIT|HEVC_DEC_BUS_ERROR_BIT|HEVC_DEC_BUFFER_EMPTY_BIT)), - dev->hwregs + DEC_INTERRUPT_REGISTER);*/ - - writel(0, dev->hwregs + DEC_INTERRUPT_REGISTER); - } + 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); atomic_add(1, &dev->irq_count_codec); } - if (pservice->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); - /* clear pp IRQ */ - writel(irq_status & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER); - atomic_add(1, &dev->irq_count_pp); - } - } + if (pservice->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); + /* clear pp IRQ */ + writel(irq_status & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER); + atomic_add(1, &dev->irq_count_pp); + } + } - pservice->irq_status = raw_status; + pservice->irq_status = raw_status; 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_service_info *pservice = (struct vpu_service_info*)dev_id; + vpu_device *dev = &pservice->dec_dev; mutex_lock(&pservice->lock); if (atomic_read(&dev->irq_count_codec)) { @@ -2011,10 +2064,13 @@ static irqreturn_t vdpu_isr(int irq, void *dev_id) static irqreturn_t vepu_irq(int irq, void *dev_id) { - //struct vpu_device *dev = (struct vpu_device *) dev_id; - struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; - vpu_device *dev = &pservice->enc_dev; - u32 irq_status = readl(dev->hwregs + ENC_INTERRUPT_REGISTER); + struct vpu_device *dev = (struct vpu_device *) dev_id; + struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; + vpu_device *dev = &pservice->enc_dev; + u32 irq_status; + + vcodec_select_mode(pservice->dev_id); + irq_status= readl(dev->hwregs + ENC_INTERRUPT_REGISTER); pr_debug("vepu_irq irq status %x\n", irq_status); @@ -2024,23 +2080,21 @@ static irqreturn_t vepu_irq(int irq, void *dev_id) (enc_end.tv_sec - enc_start.tv_sec) * 1000 + (enc_end.tv_usec - enc_start.tv_usec) / 1000); #endif - if (likely(irq_status & ENC_INTERRUPT_BIT)) { /* clear enc IRQ */ writel(irq_status & (~ENC_INTERRUPT_BIT), dev->hwregs + ENC_INTERRUPT_REGISTER); atomic_add(1, &dev->irq_count_codec); } - - pservice->irq_status = irq_status; + + pservice->irq_status = irq_status; return IRQ_WAKE_THREAD; } static irqreturn_t vepu_isr(int irq, void *dev_id) { - //struct vpu_device *dev = (struct vpu_device *) dev_id; - struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; - vpu_device *dev = &pservice->enc_dev; + struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id; + vpu_device *dev = &pservice->enc_dev; mutex_lock(&pservice->lock); if (atomic_read(&dev->irq_count_codec)) { @@ -2058,24 +2112,24 @@ static irqreturn_t vepu_isr(int irq, void *dev_id) static int __init vcodec_service_init(void) { - int ret; + int ret; - if ((ret = platform_driver_register(&vcodec_driver)) != 0) { - pr_err("Platform device register failed (%d).\n", ret); - return ret; - } + if ((ret = platform_driver_register(&vcodec_driver)) != 0) { + pr_err("Platform device register failed (%d).\n", ret); + return ret; + } #ifdef CONFIG_DEBUG_FS - vcodec_debugfs_init(); + vcodec_debugfs_init(); #endif - return ret; + return ret; } static void __exit vcodec_service_exit(void) { #ifdef CONFIG_DEBUG_FS - vcodec_debugfs_exit(); + vcodec_debugfs_exit(); #endif platform_driver_unregister(&vcodec_driver); @@ -2089,49 +2143,48 @@ module_exit(vcodec_service_exit); static int vcodec_debugfs_init() { - parent = debugfs_create_dir("vcodec", NULL); - if (!parent) - return -1; + parent = debugfs_create_dir("vcodec", NULL); + if (!parent) + return -1; - return 0; + return 0; } static void vcodec_debugfs_exit() { - debugfs_remove(parent); + debugfs_remove(parent); } static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct dentry *parent) { - return debugfs_create_dir(dirname, parent); + return debugfs_create_dir(dirname, parent); } static int debug_vcodec_show(struct seq_file *s, void *unused) { struct vpu_service_info *pservice = s->private; - unsigned int i, n; + unsigned int i, n; vpu_reg *reg, *reg_tmp; vpu_session *session, *session_tmp; mutex_lock(&pservice->lock); vpu_service_power_on(pservice); - if (pservice->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)); - } - } + if (pservice->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)); + } + } seq_printf(s, "\nDEC Registers:\n"); n = pservice->dec_dev.iosize >> 2; - for (i = 0; i < n; i++) { + for (i = 0; i < n; i++) seq_printf(s, "\tswreg%d = %08X\n", i, readl(pservice->dec_dev.hwregs + i)); - } seq_printf(s, "\nvpu service status:\n"); list_for_each_entry_safe(session, session_tmp, &pservice->session, list_session) { seq_printf(s, "session pid %d type %d:\n", session->pid, session->type); - //seq_printf(s, "waiting reg set %d\n"); + /*seq_printf(s, "waiting reg set %d\n");*/ list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) { seq_printf(s, "waiting register set\n"); } @@ -2144,7 +2197,7 @@ static int debug_vcodec_show(struct seq_file *s, void *unused) } mutex_unlock(&pservice->lock); - return 0; + return 0; } static int debug_vcodec_open(struct inode *inode, struct file *file) @@ -2175,18 +2228,17 @@ static struct ion_client *ion_client = NULL; u8* get_align_ptr(u8* tbl, int len, u32 *phy) { int size = (len+15) & (~15); - struct ion_handle *handle; + struct ion_handle *handle; u8 *ptr;// = (u8*)kzalloc(size, GFP_KERNEL); - if (ion_client == NULL) { - ion_client = rockchip_ion_client_create("vcodec"); - } + if (ion_client == NULL) + ion_client = rockchip_ion_client_create("vcodec"); - handle = ion_alloc(ion_client, (size_t)len, 16, ION_HEAP(ION_CMA_HEAP_ID), 0); + handle = ion_alloc(ion_client, (size_t)len, 16, ION_HEAP(ION_CMA_HEAP_ID), 0); - ptr = ion_map_kernel(ion_client, handle); + ptr = ion_map_kernel(ion_client, handle); - ion_phys(ion_client, handle, phy, &size); + ion_phys(ion_client, handle, phy, &size); memcpy(ptr, tbl, len); @@ -2196,18 +2248,17 @@ u8* get_align_ptr(u8* tbl, int len, u32 *phy) u8* get_align_ptr_no_copy(int len, u32 *phy) { int size = (len+15) & (~15); - struct ion_handle *handle; - u8 *ptr;// = (u8*)kzalloc(size, GFP_KERNEL); + struct ion_handle *handle; + u8 *ptr; - if (ion_client == NULL) { - ion_client = rockchip_ion_client_create("vcodec"); - } + if (ion_client == NULL) + ion_client = rockchip_ion_client_create("vcodec"); - handle = ion_alloc(ion_client, (size_t)len, 16, ION_HEAP(ION_CMA_HEAP_ID), 0); + handle = ion_alloc(ion_client, (size_t)len, 16, ION_HEAP(ION_CMA_HEAP_ID), 0); - ptr = ion_map_kernel(ion_client, handle); + ptr = ion_map_kernel(ion_client, handle); - ion_phys(ion_client, handle, phy, &size); + ion_phys(ion_client, handle, phy, &size); return ptr; } @@ -2215,17 +2266,17 @@ u8* get_align_ptr_no_copy(int len, u32 *phy) #define TEST_CNT 2 static int hevc_test_case0(vpu_service_info *pservice) { - vpu_session session; - vpu_reg *reg; - 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]; - u8 *scaling_list_tbl[TEST_CNT]; - u8 *stream_tbl[TEST_CNT]; + vpu_session session; + vpu_reg *reg; + 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]; + u8 *scaling_list_tbl[TEST_CNT]; + u8 *stream_tbl[TEST_CNT]; int stream_size[2]; int pps_size[2]; @@ -2233,13 +2284,13 @@ static int hevc_test_case0(vpu_service_info *pservice) int scl_size[2]; int cabac_size[2]; - u32 phy_pps; - u32 phy_rps; - u32 phy_scl; - u32 phy_str; - u32 phy_yuv; - u32 phy_ref; - u32 phy_cabac; + u32 phy_pps; + u32 phy_rps; + u32 phy_scl; + u32 phy_str; + u32 phy_yuv; + u32 phy_ref; + u32 phy_cabac; volatile u8 *stream_buf; volatile u8 *pps_buf; @@ -2249,27 +2300,27 @@ static int hevc_test_case0(vpu_service_info *pservice) volatile u8 *cabac_buf; volatile u8 *ref_buf; - u8 *pps; - u8 *yuv[2]; - int i; - - pps_tbl[0] = pps_00; - pps_tbl[1] = pps_01; + u8 *pps; + u8 *yuv[2]; + int i; + + pps_tbl[0] = pps_00; + pps_tbl[1] = pps_01; + + register_tbl[0] = register_00; + register_tbl[1] = register_01; + + rps_tbl[0] = rps_00; + rps_tbl[1] = rps_01; - register_tbl[0] = register_00; - register_tbl[1] = register_01; - - rps_tbl[0] = rps_00; - rps_tbl[1] = rps_01; - - scaling_list_tbl[0] = scaling_list_00; - scaling_list_tbl[1] = scaling_list_01; + scaling_list_tbl[0] = scaling_list_00; + scaling_list_tbl[1] = scaling_list_01; - stream_tbl[0] = stream_00; - stream_tbl[1] = stream_01; + stream_tbl[0] = stream_00; + stream_tbl[1] = stream_01; - stream_size[0] = sizeof(stream_00); - stream_size[1] = sizeof(stream_01); + stream_size[0] = sizeof(stream_00); + stream_size[1] = sizeof(stream_01); pps_size[0] = sizeof(pps_00); pps_size[1] = sizeof(pps_01); @@ -2283,10 +2334,10 @@ static int hevc_test_case0(vpu_service_info *pservice) cabac_size[0] = sizeof(Cabac_table); cabac_size[1] = sizeof(Cabac_table); - // create session - session.pid = current->pid; - session.type = VPU_DEC; - INIT_LIST_HEAD(&session.waiting); + /* create session */ + session.pid = current->pid; + session.type = VPU_DEC; + INIT_LIST_HEAD(&session.waiting); INIT_LIST_HEAD(&session.running); INIT_LIST_HEAD(&session.done); INIT_LIST_HEAD(&session.list_session); @@ -2294,33 +2345,31 @@ static int hevc_test_case0(vpu_service_info *pservice) atomic_set(&session.task_running, 0); list_add_tail(&session.list_session, &pservice->session); - yuv[0] = get_align_ptr_no_copy(256*256*2, &phy_yuv); - yuv[1] = get_align_ptr_no_copy(256*256*2, &phy_ref); + yuv[0] = get_align_ptr_no_copy(256*256*2, &phy_yuv); + yuv[1] = get_align_ptr_no_copy(256*256*2, &phy_ref); while (testidx < TEST_CNT) { - - // create registers - reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL); - if (NULL == reg) { - pr_err("error: kmalloc fail in reg_init\n"); - return -1; - } - - - if (size > pservice->reg_size) { - printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size); - size = pservice->reg_size; - } - reg->session = &session; - reg->type = session.type; - reg->size = size; - reg->freq = VPU_FREQ_DEFAULT; - reg->reg = (unsigned long *)®[1]; - INIT_LIST_HEAD(®->session_link); - INIT_LIST_HEAD(®->status_link); - - // TODO: stuff registers - memcpy(®->reg[0], register_tbl[testidx], /*sizeof(register_00)*/ 176); + /* create registers */ + reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL); + if (NULL == reg) { + pr_err("error: kmalloc fail in reg_init\n"); + return -1; + } + + if (size > pservice->reg_size) { + printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size); + size = pservice->reg_size; + } + reg->session = &session; + reg->type = session.type; + reg->size = size; + reg->freq = VPU_FREQ_DEFAULT; + reg->reg = (unsigned long *)®[1]; + INIT_LIST_HEAD(®->session_link); + INIT_LIST_HEAD(®->status_link); + + /* TODO: stuff registers */ + memcpy(®->reg[0], register_tbl[testidx], /*sizeof(register_00)*/ 176); stream_buf = get_align_ptr(stream_tbl[testidx], stream_size[testidx], &phy_str); pps_buf = get_align_ptr(pps_tbl[0], pps_size[0], &phy_pps); @@ -2330,108 +2379,103 @@ static int hevc_test_case0(vpu_service_info *pservice) pps = pps_buf; - // TODO: replace reigster address - - for (i=0; i<64; i++) { - u32 scaling_offset; - u32 tmp; - - scaling_offset = (u32)pps[i*80+74]; - scaling_offset += (u32)pps[i*80+75] << 8; - scaling_offset += (u32)pps[i*80+76] << 16; - scaling_offset += (u32)pps[i*80+77] << 24; - - tmp = phy_scl + scaling_offset; - - pps[i*80+74] = tmp & 0xff; - pps[i*80+75] = (tmp >> 8) & 0xff; - pps[i*80+76] = (tmp >> 16) & 0xff; - pps[i*80+77] = (tmp >> 24) & 0xff; - } - - printk("%s %d, phy stream %08x, phy pps %08x, phy rps %08x\n", __func__, __LINE__, phy_str, phy_pps, phy_rps); - - reg->reg[1] = 0x21; - reg->reg[4] = phy_str; - reg->reg[5] = ((stream_size[testidx]+15)&(~15))+64; - reg->reg[6] = phy_cabac; - reg->reg[7] = testidx?phy_ref:phy_yuv; - reg->reg[42] = phy_pps; - reg->reg[43] = phy_rps; - for (i = 10; i <= 24; i++) { - reg->reg[i] = phy_yuv; - } - - mutex_lock(&pservice->lock); - 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); - - // 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); - } - ret = 0; - } else { - if (unlikely(ret < 0)) { - pr_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)); - ret = -ETIMEDOUT; - } - } - if (ret < 0) { - int task_running = atomic_read(&session.task_running); - int n; - mutex_lock(&pservice->lock); - vpu_service_dump(pservice); - if (task_running) { - atomic_set(&session.task_running, 0); - atomic_sub(task_running, &pservice->total_running); - printk("%d task is running but not return, reset hardware...", task_running); - vpu_reset(pservice); - printk("done\n"); - } - vpu_service_session_clear(pservice, &session); - mutex_unlock(&pservice->lock); - - printk("\nDEC Registers:\n"); - n = pservice->dec_dev.iosize >> 2; - for (i=0; idec_dev.hwregs + i)); - } - - pr_err("test index %d failed\n", testidx); - break; - } else { - pr_info("test index %d success\n", testidx); - - vpu_reg *reg = list_entry(session.done.next, vpu_reg, session_link); - - for (i=0; i<68; i++) { - if (i % 4 == 0) { - printk("%02d: ", i); - } - printk("%08x ", reg->reg[i]); - if ((i+1) % 4 == 0) { - printk("\n"); - } - } - - testidx++; - } - - reg_deinit(pservice, reg); - } - - return 0; + /* TODO: replace reigster address */ + for (i=0; i<64; i++) { + u32 scaling_offset; + u32 tmp; + + scaling_offset = (u32)pps[i*80+74]; + scaling_offset += (u32)pps[i*80+75] << 8; + scaling_offset += (u32)pps[i*80+76] << 16; + scaling_offset += (u32)pps[i*80+77] << 24; + + tmp = phy_scl + scaling_offset; + + pps[i*80+74] = tmp & 0xff; + pps[i*80+75] = (tmp >> 8) & 0xff; + pps[i*80+76] = (tmp >> 16) & 0xff; + pps[i*80+77] = (tmp >> 24) & 0xff; + } + + printk("%s %d, phy stream %08x, phy pps %08x, phy rps %08x\n", + __func__, __LINE__, phy_str, phy_pps, phy_rps); + + reg->reg[1] = 0x21; + reg->reg[4] = phy_str; + reg->reg[5] = ((stream_size[testidx]+15)&(~15))+64; + reg->reg[6] = phy_cabac; + reg->reg[7] = testidx?phy_ref:phy_yuv; + reg->reg[42] = phy_pps; + reg->reg[43] = phy_rps; + for (i = 10; i <= 24; i++) + reg->reg[i] = phy_yuv; + + mutex_lock(&pservice->lock); + 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); + + /* 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); + ret = 0; + } else { + if (unlikely(ret < 0)) { + pr_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)); + ret = -ETIMEDOUT; + } + } + if (ret < 0) { + int task_running = atomic_read(&session.task_running); + int n; + mutex_lock(&pservice->lock); + vpu_service_dump(pservice); + if (task_running) { + atomic_set(&session.task_running, 0); + atomic_sub(task_running, &pservice->total_running); + printk("%d task is running but not return, reset hardware...", task_running); + vpu_reset(pservice); + printk("done\n"); + } + vpu_service_session_clear(pservice, &session); + mutex_unlock(&pservice->lock); + + printk("\nDEC Registers:\n"); + n = pservice->dec_dev.iosize >> 2; + for (i=0; idec_dev.hwregs + i)); + + pr_err("test index %d failed\n", testidx); + break; + } else { + pr_info("test index %d success\n", testidx); + + vpu_reg *reg = list_entry(session.done.next, vpu_reg, session_link); + + for (i=0; i<68; i++) { + if (i % 4 == 0) + printk("%02d: ", i); + printk("%08x ", reg->reg[i]); + if ((i+1) % 4 == 0) + printk("\n"); + } + + testidx++; + } + + reg_deinit(pservice, reg); + } + + return 0; } #endif -- 2.34.1