#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/wakelock.h>
#include <linux/of_irq.h>
#include <linux/rockchip/cpu.h>
#include <linux/rockchip/cru.h>
-#ifdef CONFIG_MFD_SYSCON
+#include <linux/rockchip/pmu.h>
#include <linux/regmap.h>
-#endif
#include <linux/mfd/syscon.h>
#include <asm/cacheflush.h>
#include "vcodec_service.h"
+/*
+ * debug flag usage:
+ * +------+-------------------+
+ * | 8bit | 24bit |
+ * +------+-------------------+
+ * 0~23 bit is for different information type
+ * 24~31 bit is for information print format
+ */
+
+#define DEBUG_POWER 0x00000001
+#define DEBUG_CLOCK 0x00000002
+#define DEBUG_IRQ_STATUS 0x00000004
+#define DEBUG_IOMMU 0x00000008
+#define DEBUG_IOCTL 0x00000010
+#define DEBUG_FUNCTION 0x00000020
+#define DEBUG_REGISTER 0x00000040
+#define DEBUG_EXTRA_INFO 0x00000080
+#define DEBUG_TIMING 0x00000100
+
+#define PRINT_FUNCTION 0x80000000
+#define PRINT_LINE 0x40000000
+
static int debug;
module_param(debug, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug,
struct extra_info_elem elem[20];
};
-#define VPU_SERVICE_SHOW_TIME 0
-
-#if VPU_SERVICE_SHOW_TIME
-static struct timeval enc_start, enc_end;
-static struct timeval dec_start, dec_end;
-static struct timeval pp_start, pp_end;
-#endif
-
#define MHZ (1000*1000)
#define REG_NUM_9190_DEC (60)
},
};
+#ifndef BIT
+#define BIT(x) (1<<(x))
+#endif
+// interrupt and error status register
#define DEC_INTERRUPT_REGISTER 1
-#define PP_INTERRUPT_REGISTER 60
-#define ENC_INTERRUPT_REGISTER 1
+#define DEC_INTERRUPT_BIT BIT(8)
+#define DEC_READY_BIT BIT(12)
+#define DEC_BUS_ERROR_BIT BIT(13)
+#define DEC_BUFFER_EMPTY_BIT BIT(14)
+#define DEC_ASO_ERROR_BIT BIT(15)
+#define DEC_STREAM_ERROR_BIT BIT(16)
+#define DEC_SLICE_DONE_BIT BIT(17)
+#define DEC_TIMEOUT_BIT BIT(18)
+#define DEC_ERR_MASK DEC_BUS_ERROR_BIT \
+ |DEC_BUFFER_EMPTY_BIT \
+ |DEC_STREAM_ERROR_BIT \
+ |DEC_TIMEOUT_BIT
-#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 PP_INTERRUPT_REGISTER 60
+#define PP_INTERRUPT_BIT BIT(8)
+#define PP_READY_BIT BIT(12)
+#define PP_BUS_ERROR_BIT BIT(13)
+#define PP_ERR_MASK PP_BUS_ERROR_BIT
+#define ENC_INTERRUPT_REGISTER 1
+#define ENC_INTERRUPT_BIT BIT(0)
+#define ENC_READY_BIT BIT(2)
+#define ENC_BUS_ERROR_BIT BIT(3)
+#define ENC_BUFFER_FULL_BIT BIT(5)
+#define ENC_TIMEOUT_BIT BIT(6)
+#define ENC_ERR_MASK ENC_BUS_ERROR_BIT \
+ |ENC_BUFFER_FULL_BIT \
+ |ENC_TIMEOUT_BIT
+
+#define HEVC_INTERRUPT_REGISTER 1
+#define HEVC_DEC_INT_RAW_BIT BIT(9)
+#define HEVC_DEC_BUS_ERROR_BIT BIT(13)
+#define HEVC_DEC_STR_ERROR_BIT BIT(14)
+#define HEVC_DEC_TIMEOUT_BIT BIT(15)
+#define HEVC_DEC_BUFFER_EMPTY_BIT BIT(16)
+#define HEVC_DEC_COLMV_ERROR_BIT BIT(17)
+#define HEVC_DEC_ERR_MASK HEVC_DEC_BUS_ERROR_BIT \
+ |HEVC_DEC_STR_ERROR_BIT \
+ |HEVC_DEC_TIMEOUT_BIT \
+ |HEVC_DEC_BUFFER_EMPTY_BIT \
+ |HEVC_DEC_COLMV_ERROR_BIT
+
+
+// gating configuration set
#define VPU_REG_EN_ENC 14
#define VPU_REG_ENC_GATE 2
#define VPU_REG_ENC_GATE_BIT (1<<4)
#define DEBUG
#ifdef DEBUG
-#define vpu_debug(level, fmt, args...) \
+#define vpu_debug_func(type, fmt, args...) \
do { \
- if (debug >= level) \
+ if (unlikely(debug & type)) { \
pr_info("%s:%d: " fmt, \
__func__, __LINE__, ##args); \
+ } \
+ } while (0)
+#define vpu_debug(type, fmt, args...) \
+ do { \
+ if (unlikely(debug & type)) { \
+ pr_info(fmt, ##args); \
+ } \
} while (0)
#else
+#define vpu_debug_func(level, fmt, args...)
#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_debug_enter() vpu_debug_func(DEBUG_FUNCTION, "enter\n")
+#define vpu_debug_leave() vpu_debug_func(DEBUG_FUNCTION, "leave\n")
#define vpu_err(fmt, args...) \
pr_err("%s:%d: " fmt, __func__, __LINE__, ##args)
unsigned long size;
#if defined(CONFIG_VCODEC_MMU)
struct list_head mem_region_list;
+ u32 dec_base;
#endif
u32 *reg;
} vpu_reg;
struct list_head session_lnk;
unsigned long iova; /* virtual address for iommu */
unsigned long len;
- u32 reg_idx;
+ u32 reg_idx;
struct ion_handle *hdl;
};
struct clk *clk_cabac;
struct clk *pd_video;
+#ifdef CONFIG_RESET_CONTROLLER
+ struct reset_control *rst_a;
+ struct reset_control *rst_h;
+ struct reset_control *rst_v;
+#endif
struct device *dev;
u32 irq_status;
+ atomic_t reset_request;
#if defined(CONFIG_VCODEC_MMU)
struct ion_client *ion_client;
struct list_head mem_region_list;
u32 mode_ctrl;
u32 *reg_base;
u32 ioaddr;
-#ifdef CONFIG_MFD_SYSCON
- struct regmap *grf_base;
-#else
+ struct regmap *grf;
u32 *grf_base;
-#endif
+
char *name;
u32 subcnt;
struct list_head running;
struct mutex run_lock;
vpu_reg *reg_codec;
- enum vcodec_device_id current_hw_mode;
+ enum vcodec_device_id current_hw_mode;
};
struct vpu_request {
u32 size;
};
+#ifdef CONFIG_COMPAT
struct compat_vpu_request {
compat_uptr_t req;
u32 size;
};
+#endif
/* debugfs root directory for all device (vpu, hevc).*/
static struct dentry *parent;
#define VPU_POWER_OFF_DELAY 4*HZ /* 4s */
#define VPU_TIMEOUT_DELAY 2*HZ /* 2s */
+typedef struct {
+ char *name;
+ struct timeval start;
+ struct timeval end;
+ u32 error_mask;
+} task_info;
+
+typedef enum {
+ TASK_VPU_ENC,
+ TASK_VPU_DEC,
+ TASK_VPU_PP,
+ TASK_RKDEC_HEVC,
+ TASK_TYPE_BUTT,
+} TASK_TYPE;
+
+task_info tasks[TASK_TYPE_BUTT] = {
+ {
+ .name = "enc",
+ .error_mask = ENC_ERR_MASK
+ },
+ {
+ .name = "dec",
+ .error_mask = DEC_ERR_MASK
+ },
+ {
+ .name = "pp",
+ .error_mask = PP_ERR_MASK
+ },
+ {
+ .name = "hevc",
+ .error_mask = HEVC_DEC_ERR_MASK
+ },
+};
+
+static void time_record(task_info *task, int is_end)
+{
+ if (unlikely(debug & DEBUG_TIMING)) {
+ do_gettimeofday((is_end)?(&task->end):(&task->start));
+ }
+}
+
+static void time_diff(task_info *task)
+{
+ vpu_debug(DEBUG_TIMING, "%s task: %ld ms\n", task->name,
+ (task->end.tv_sec - task->start.tv_sec) * 1000 +
+ (task->end.tv_usec - task->start.tv_usec) / 1000);
+}
+
static void vcodec_enter_mode(struct vpu_subdev_data *data)
{
int bits;
if (pservice->curr_mode == data->mode)
return;
- vpu_debug(3, "vcodec enter mode %d\n", data->mode);
+ vpu_debug(DEBUG_IOMMU, "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 &&
#endif
bits = 1 << pservice->mode_bit;
#ifdef CONFIG_MFD_SYSCON
- regmap_read(pservice->grf_base, pservice->mode_ctrl, &raw);
+ if (pservice->grf) {
+ regmap_read(pservice->grf, pservice->mode_ctrl, &raw);
- if (data->mode == VCODEC_RUNNING_MODE_HEVC)
- regmap_write(pservice->grf_base, pservice->mode_ctrl,
- raw | bits | (bits << 16));
- else
- regmap_write(pservice->grf_base, pservice->mode_ctrl,
- (raw & (~bits)) | (bits << 16));
+ if (data->mode == VCODEC_RUNNING_MODE_HEVC)
+ regmap_write(pservice->grf, pservice->mode_ctrl,
+ raw | bits | (bits << 16));
+ else
+ regmap_write(pservice->grf, pservice->mode_ctrl,
+ (raw & (~bits)) | (bits << 16));
+ } else if (pservice->grf_base) {
+ 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);
+ } else {
+ vpu_err("no grf resource define, switch decoder failed\n");
+ return;
+ }
#else
- 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 (pervice->grf_base) {
+ 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);
+ } else {
+ vpu_err("no grf resource define, switch decoder failed\n");
+ return;
+ }
#endif
#if defined(CONFIG_VCODEC_MMU)
if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
static void vpu_reset(struct vpu_subdev_data *data)
{
struct vpu_service_info *pservice = data->pservice;
+ enum pmu_idle_req type = IDLE_REQ_VIDEO;
+
+ if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC)
+ type = IDLE_REQ_HEVC;
+
+ pr_info("%s: resetting...", dev_name(pservice->dev));
+
#if defined(CONFIG_ARCH_RK29)
clk_disable(aclk_ddr_vepu);
cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, true);
cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, false);
cru_set_soft_reset(SOFT_RST_CPU_VCODEC, false);
pmu_set_idle_request(IDLE_REQ_VIDEO, false);
+#else
#endif
+ WARN_ON(pservice->reg_codec != NULL);
+ WARN_ON(pservice->reg_pproc != NULL);
+ WARN_ON(pservice->reg_resev != NULL);
pservice->reg_codec = NULL;
pservice->reg_pproc = NULL;
pservice->reg_resev = NULL;
+ pr_info("for 3288/3368...");
+#ifdef CONFIG_RESET_CONTROLLER
+ if (pservice->rst_a && pservice->rst_h) {
+ if (rockchip_pmu_ops.set_idle_request)
+ rockchip_pmu_ops.set_idle_request(type, true);
+ pr_info("reset in\n");
+ if (pservice->rst_v)
+ reset_control_assert(pservice->rst_v);
+ reset_control_assert(pservice->rst_a);
+ reset_control_assert(pservice->rst_h);
+ usleep_range(10, 20);
+ reset_control_deassert(pservice->rst_h);
+ reset_control_deassert(pservice->rst_a);
+ if (pservice->rst_v)
+ reset_control_deassert(pservice->rst_v);
+ if (rockchip_pmu_ops.set_idle_request)
+ rockchip_pmu_ops.set_idle_request(type, false);
+ }
+#endif
+
#if defined(CONFIG_VCODEC_MMU)
if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
clear_bit(MMU_ACTIVATED, &data->state);
BUG_ON(!atomic_read(&pservice->enabled));
}
#endif
+ atomic_set(&pservice->reset_request, 0);
+ pr_info("done\n");
}
static void reg_deinit(struct vpu_subdev_data *data, vpu_reg *reg);
return width_in_mb * 16;
}
+static inline int reg_probe_hevc_y_stride(vpu_reg *reg)
+{
+ int y_virstride = reg->reg[8];
+ return y_virstride;
+}
+
#if defined(CONFIG_VCODEC_MMU)
static int vcodec_fd_to_iova(struct vpu_subdev_data *data, vpu_reg *reg,int fd)
{
mem_region->hdl = hdl;
mem_region->reg_idx = tbl[i];
ret = ion_map_iommu(data->dev,
- pservice->ion_client,
- mem_region->hdl,
- &mem_region->iova,
- &mem_region->len);
+ pservice->ion_client,
+ mem_region->hdl,
+ &mem_region->iova,
+ &mem_region->len);
if (ret < 0) {
dev_err(pservice->dev, "ion map iommu failed\n");
ion_free(pservice->ion_client, hdl);
return ret;
}
+
+ /* special for vpu dec num 12: record decoded length
+ hacking for decoded length
+ NOTE: not a perfect fix, the fd is not recorded */
+ if (tbl[i] == 12 && data->hw_info->hw_id != HEVC_ID &&
+ (reg->type == VPU_DEC || reg->type == VPU_DEC_PP)) {
+ reg->dec_base = mem_region->iova + offset;
+ vpu_debug(DEBUG_REGISTER, "dec_set %08x\n", reg->dec_base);
+ }
+
reg->reg[tbl[i]] = mem_region->iova + offset;
INIT_LIST_HEAD(&mem_region->reg_lnk);
list_add_tail(&mem_region->reg_lnk, ®->mem_region_list);
if (ext_inf != NULL && ext_inf->magic == EXTRA_INFO_MAGIC) {
for (i=0; i<ext_inf->cnt; i++) {
- vpu_debug(3, "reg[%d] + offset %d\n",
+ vpu_debug(DEBUG_IOMMU, "reg[%d] + offset %d\n",
ext_inf->elem[i].index,
ext_inf->elem[i].offset);
reg->reg[ext_inf->elem[i].index] +=
} else if (reg_check_fmt(reg) == VPU_DEC_FMT_H264) {
if (reg_probe_width(reg) > 3200) {
/*raise frequency for 4k avc.*/
- reg->freq = VPU_FREQ_500M;
+ reg->freq = VPU_FREQ_600M;
}
} else {
if (reg_check_interlace(reg)) {
}
}
}
+ if (data->hw_info->hw_id == HEVC_ID) {
+ if (reg_probe_hevc_y_stride(reg) > 60000)
+ reg->freq = VPU_FREQ_400M;
+ }
if (reg->type == VPU_PP) {
reg->freq = VPU_FREQ_400M;
}
int reg_len = REG_NUM_9190_DEC;
pservice->reg_codec = NULL;
reg_copy_from_hw(reg, data->dec_dev.hwregs, reg_len);
+#if defined(CONFIG_VCODEC_MMU)
+ /* revert hack for decoded length */
+ if (data->hw_info->hw_id != HEVC_ID) {
+ u32 dec_get = reg->reg[12];
+ s32 dec_length = dec_get - reg->dec_base;
+ vpu_debug(DEBUG_REGISTER, "dec_get %08x dec_length %d\n", dec_get, dec_length);
+ reg->reg[12] = dec_length << 10;
+ }
+#endif
irq_reg = DEC_INTERRUPT_REGISTER;
break;
}
pservice->reg_pproc = NULL;
reg_copy_from_hw(reg, data->dec_dev.hwregs, REG_NUM_9190_DEC_PP);
data->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;
+#if defined(CONFIG_VCODEC_MMU)
+ /* revert hack for decoded length */
+ if (data->hw_info->hw_id != HEVC_ID) {
+ u32 dec_get = reg->reg[12];
+ s32 dec_length = dec_get - reg->dec_base;
+ vpu_debug(DEBUG_REGISTER, "dec_get %08x dec_length %d\n", dec_get, dec_length);
+ reg->reg[12] = dec_length << 10;
+ }
+#endif
break;
}
default : {
dst[VPU_REG_ENC_GATE] = src[VPU_REG_ENC_GATE] | VPU_REG_ENC_GATE_BIT;
dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC];
-#if VPU_SERVICE_SHOW_TIME
- do_gettimeofday(&enc_start);
-#endif
-
+ time_record(&tasks[TASK_VPU_ENC], 0);
} break;
case VPU_DEC : {
u32 *dst = (u32 *)data->dec_dev.hwregs;
}
dsb(sy);
dmb(sy);
-#if VPU_SERVICE_SHOW_TIME
- do_gettimeofday(&dec_start);
-#endif
+
+ time_record(&tasks[TASK_VPU_DEC], 0);
} break;
case VPU_PP : {
u32 *dst = (u32 *)data->dec_dev.hwregs + PP_INTERRUPT_REGISTER;
dsb(sy);
dst[VPU_REG_EN_PP] = src[VPU_REG_EN_PP];
-#if VPU_SERVICE_SHOW_TIME
- do_gettimeofday(&pp_start);
-#endif
+ time_record(&tasks[TASK_VPU_PP], 0);
} break;
case VPU_DEC_PP : {
u32 *dst = (u32 *)data->dec_dev.hwregs;
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
+
+ time_record(&tasks[TASK_VPU_DEC], 0);
} break;
default : {
vpu_err("error: unsupport session type %d", reg->type);
atomic_sub(1, &pservice->total_running);
atomic_sub(1, ®->session->task_running);
- break;
- }
+ } break;
}
/*vcodec_exit_mode(data);*/
vpu_debug_enter();
if (!list_empty(&pservice->waiting)) {
int can_set = 0;
+ bool change_able = (NULL == pservice->reg_codec) && (NULL == pservice->reg_pproc);
+ int reset_request = atomic_read(&pservice->reset_request);
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))
- can_set = 1;
- } break;
- case VPU_DEC : {
- 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_pproc)
+ // first check can_set flag
+ if (change_able || !reset_request) {
+ switch (reg->type) {
+ case VPU_ENC : {
+ if (change_able)
can_set = 1;
- } else {
- if ((VPU_DEC == pservice->reg_codec->type) && (NULL == pservice->reg_pproc))
+ } break;
+ case VPU_DEC : {
+ if (NULL == pservice->reg_codec)
can_set = 1;
- /* can not charge frequency when vpu is working */
- if (pservice->auto_freq)
+ if (pservice->auto_freq && (NULL != pservice->reg_pproc))
can_set = 0;
- }
- } break;
- case VPU_DEC_PP : {
- if ((NULL == pservice->reg_codec) && (NULL == pservice->reg_pproc))
- can_set = 1;
} break;
- default : {
- printk("undefined reg type %d\n", reg->type);
- } break;
+ case VPU_PP : {
+ 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))
+ can_set = 1;
+ /* can not charge frequency when vpu is working */
+ if (pservice->auto_freq)
+ can_set = 0;
+ }
+ } break;
+ case VPU_DEC_PP : {
+ if (change_able)
+ can_set = 1;
+ } break;
+ default : {
+ printk("undefined reg type %d\n", reg->type);
+ } break;
+ }
}
+
+ // then check reset request
+ if (reset_request && !change_able)
+ reset_request = 0;
+
+ // do reset before setting registers
+ if (reset_request)
+ vpu_reset(data);
+
if (can_set) {
reg_from_wait_to_run(pservice, reg);
reg_copy_to_hw(reg->data, reg);
struct vpu_service_info *pservice = data->pservice;
vpu_session *session = (vpu_session *)filp->private_data;
vpu_debug_enter();
- vpu_debug(3, "cmd %x, VPU_IOC_SET_CLIENT_TYPE %x\n", cmd, (u32)VPU_IOC_SET_CLIENT_TYPE);
if (NULL == session)
return -EINVAL;
switch (cmd) {
case VPU_IOC_SET_CLIENT_TYPE : {
session->type = (enum VPU_CLIENT_TYPE)arg;
+ vpu_debug(DEBUG_IOCTL, "VPU_IOC_SET_CLIENT_TYPE %d\n", session->type);
break;
}
case VPU_IOC_GET_HW_FUSE_STATUS : {
struct vpu_request req;
+ vpu_debug(DEBUG_IOCTL, "VPU_IOC_GET_HW_FUSE_STATUS type %d\n", session->type);
if (copy_from_user(&req, (void __user *)arg, sizeof(struct vpu_request))) {
vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_from_user failed\n");
return -EFAULT;
case VPU_IOC_SET_REG : {
struct vpu_request req;
vpu_reg *reg;
+ vpu_debug(DEBUG_IOCTL, "VPU_IOC_SET_REG type %d\n", session->type);
if (copy_from_user(&req, (void __user *)arg,
sizeof(struct vpu_request))) {
vpu_err("error: VPU_IOC_SET_REG copy_from_user failed\n");
case VPU_IOC_GET_REG : {
struct vpu_request req;
vpu_reg *reg;
+ vpu_debug(DEBUG_IOCTL, "VPU_IOC_GET_REG type %d\n", session->type);
if (copy_from_user(&req, (void __user *)arg,
sizeof(struct vpu_request))) {
vpu_err("error: VPU_IOC_GET_REG copy_from_user failed\n");
case VPU_IOC_PROBE_IOMMU_STATUS: {
int iommu_enable = 0;
+ vpu_debug(DEBUG_IOCTL, "VPU_IOC_PROBE_IOMMU_STATUS\n");
+
#if defined(CONFIG_VCODEC_MMU)
iommu_enable = data->mmu_dev ? 1 : 0;
#endif
switch (cmd) {
case COMPAT_VPU_IOC_SET_CLIENT_TYPE : {
session->type = (enum VPU_CLIENT_TYPE)arg;
+ vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_SET_CLIENT_TYPE type %d\n", session->type);
break;
}
case COMPAT_VPU_IOC_GET_HW_FUSE_STATUS : {
struct compat_vpu_request req;
-
+ vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_GET_HW_FUSE_STATUS type %d\n", session->type);
if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
sizeof(struct compat_vpu_request))) {
vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS"
case COMPAT_VPU_IOC_SET_REG : {
struct compat_vpu_request req;
vpu_reg *reg;
+ vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_SET_REG type %d\n", session->type);
if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
sizeof(struct compat_vpu_request))) {
vpu_err("VPU_IOC_SET_REG copy_from_user failed\n");
case COMPAT_VPU_IOC_GET_REG : {
struct compat_vpu_request req;
vpu_reg *reg;
+ vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_GET_REG type %d\n", session->type);
if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
sizeof(struct compat_vpu_request))) {
vpu_err("VPU_IOC_GET_REG copy_from_user failed\n");
case COMPAT_VPU_IOC_PROBE_IOMMU_STATUS : {
int iommu_enable = 0;
+ vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_PROBE_IOMMU_STATUS\n");
#if defined(CONFIG_VCODEC_MMU)
iommu_enable = data->mmu_dev ? 1 : 0;
#endif
if (pservice->reg_codec) {
struct vcodec_mem_region *mem, *n;
int i = 0;
- vpu_debug(3, "vcodec, fault addr 0x%08x\n", (u32)fault_addr);
+ vpu_debug(DEBUG_IOMMU, "vcodec, fault addr 0x%08x\n", (u32)fault_addr);
list_for_each_entry_safe(mem, n,
&pservice->reg_codec->mem_region_list,
reg_lnk) {
- vpu_debug(3, "vcodec, reg[%02u] mem region [%02d] 0x%08x %ld\n",
+ vpu_debug(DEBUG_IOMMU, "vcodec, reg[%02u] mem region [%02d] 0x%08x %ld\n",
mem->reg_idx, i, (u32)mem->iova, mem->len);
i++;
}
rockchip_iovmm_set_fault_handler(dev, vcodec_sysmmu_fault_hdl);
}
#endif
+ get_hw_info(data);
+ pservice->auto_freq = true;
+
vcodec_exit_mode(data);
/* create device node */
ret = alloc_chrdev_region(&data->dev_t, 0, 1, name);
data->child_dev = device_create(data->cls, dev,
data->dev_t, NULL, name);
- get_hw_info(data);
-
platform_set_drvdata(pdev, data);
INIT_LIST_HEAD(&data->lnk_service);
free_irq(data->irq_dec, (void *)&data);
#ifdef CONFIG_DEBUG_FS
- debugfs_remove(data->debugfs_file_regs);
- debugfs_remove(data->debugfs_dir);
+ debugfs_remove_recursive(data->debugfs_dir);
#endif
}
pservice->mode_bit = 0;
pservice->mode_ctrl = 0;
pservice->subcnt = 0;
+ pservice->grf_base = NULL;
of_property_read_u32(np, "subcnt", &pservice->subcnt);
of_property_read_u32(np, "mode_ctrl", &pservice->mode_ctrl);
}
#ifdef CONFIG_MFD_SYSCON
- pservice->grf_base = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
-#else
- pservice->grf_base = (u32*)RK_GRF_VIRT;
-#endif
- if (IS_ERR(pservice->grf_base)) {
+ pservice->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR_OR_NULL(pservice->grf)) {
+ pservice->grf = NULL;
#ifdef CONFIG_ARM
pservice->grf_base = RK_GRF_VIRT;
#else
return;
#endif
}
+#else
+#ifdef CONFIG_ARM
+ pservice->grf_base = RK_GRF_VIRT;
+#else
+ vpu_err("can't find vpu grf property\n");
+ return;
+#endif
+#endif
+
+#ifdef CONFIG_RESET_CONTROLLER
+ pservice->rst_a = devm_reset_control_get(pservice->dev, "video_a");
+ pservice->rst_h = devm_reset_control_get(pservice->dev, "video_h");
+ pservice->rst_v = devm_reset_control_get(pservice->dev, "video");
+
+ if (IS_ERR_OR_NULL(pservice->rst_a)) {
+ pr_warn("No reset resource define\n");
+ pservice->rst_a = NULL;
+ }
+
+ if (IS_ERR_OR_NULL(pservice->rst_h)) {
+ pr_warn("No reset resource define\n");
+ pservice->rst_h = NULL;
+ }
+
+ if (IS_ERR_OR_NULL(pservice->rst_v)) {
+ pr_warn("No reset resource define\n");
+ pservice->rst_v = NULL;
+ }
+#endif
+
of_property_read_string(np, "name", (const char**)&pservice->name);
}
atomic_set(&pservice->enabled, 0);
atomic_set(&pservice->power_on_cnt, 0);
atomic_set(&pservice->power_off_cnt, 0);
+ atomic_set(&pservice->reset_request, 0);
INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work);
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");
+ vpu_debug(DEBUG_IOMMU, "vcodec ion client create success!\n");
}
}
pr_info("probe device %s\n", dev_name(dev));
+ pservice->dev = dev;
+
vcodec_read_property(np, pservice);
vcodec_init_drvdata(pservice);
else
pservice->dev_id = VCODEC_DEVICE_ID_COMBO;
- pservice->dev = dev;
-
if (0 > vpu_get_clk(pservice))
goto err;
enc->reserv[0] = enc->reserv[1] = 0;
}
pservice->auto_freq = true;
- vpu_debug(3, "vpu_service set to auto frequency mode\n");
+ vpu_debug(DEBUG_EXTRA_INFO, "vpu_service set to auto frequency mode\n");
atomic_set(&pservice->freq_status, VPU_FREQ_BUT);
pservice->bug_dec_addr = cpu_is_rk30xx();
}
}
+static bool check_irq_err(task_info *task, u32 irq_status)
+{
+ return (task->error_mask & irq_status) ? true : false;
+}
+
static irqreturn_t vdpu_irq(int irq, void *dev_id)
{
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;
+ u32 dec_status;
/*vcodec_enter_mode(data);*/
- irq_status = raw_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);
+ dec_status = raw_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);
- 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 (dec_status & DEC_INTERRUPT_BIT) {
+ time_record(&tasks[TASK_VPU_DEC], 1);
+ vpu_debug(DEBUG_IRQ_STATUS, "vdpu_irq dec status %08x\n", dec_status);
+ if ((dec_status & 0x40001) == 0x40001) {
do {
- irq_status =
+ dec_status =
readl(dev->hwregs +
DEC_INTERRUPT_REGISTER);
- } while ((irq_status & 0x40001) == 0x40001);
+ } while ((dec_status & 0x40001) == 0x40001);
+ }
+
+ if (check_irq_err((data->hw_info->hw_id == HEVC_ID)?
+ (&tasks[TASK_RKDEC_HEVC]) : (&tasks[TASK_VPU_DEC]),
+ dec_status)) {
+ atomic_add(1, &pservice->reset_request);
}
writel(0, dev->hwregs + DEC_INTERRUPT_REGISTER);
atomic_add(1, &dev->irq_count_codec);
+ time_diff(&tasks[TASK_VPU_DEC]);
}
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);
+ u32 pp_status = readl(dev->hwregs + PP_INTERRUPT_REGISTER);
+ if (pp_status & PP_INTERRUPT_BIT) {
+ time_record(&tasks[TASK_VPU_PP], 1);
+ vpu_debug(DEBUG_IRQ_STATUS, "vdpu_irq pp status %08x\n", pp_status);
+
+ if (check_irq_err(&tasks[TASK_VPU_PP], dec_status))
+ atomic_add(1, &pservice->reset_request);
+
/* clear pp IRQ */
- writel(irq_status & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER);
+ writel(pp_status & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER);
atomic_add(1, &dev->irq_count_pp);
+ time_diff(&tasks[TASK_VPU_PP]);
}
}
mutex_lock(&pservice->lock);
if (atomic_read(&dev->irq_count_codec)) {
-#if VPU_SERVICE_SHOW_TIME
- do_gettimeofday(&dec_end);
- 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) {
vpu_err("error: dec isr with no task waiting\n");
}
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) {
vpu_err("error: pp isr with no task waiting\n");
/*vcodec_enter_mode(data);*/
irq_status= readl(dev->hwregs + ENC_INTERRUPT_REGISTER);
- pr_debug("vepu_irq irq status %x\n", irq_status);
+ vpu_debug(DEBUG_IRQ_STATUS, "vepu_irq irq status %x\n", irq_status);
-#if VPU_SERVICE_SHOW_TIME
- do_gettimeofday(&enc_end);
- 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
if (likely(irq_status & ENC_INTERRUPT_BIT)) {
+ time_record(&tasks[TASK_VPU_ENC], 1);
+
+ if (check_irq_err(&tasks[TASK_VPU_ENC], irq_status))
+ atomic_add(1, &pservice->reset_request);
+
/* clear enc IRQ */
writel(irq_status & (~ENC_INTERRUPT_BIT), dev->hwregs + ENC_INTERRUPT_REGISTER);
atomic_add(1, &dev->irq_count_codec);
+ time_diff(&tasks[TASK_VPU_ENC]);
}
pservice->irq_status = irq_status;
vpu_err("test index %d failed\n", testidx);
break;
} else {
- vpu_debug(3, "test index %d success\n", testidx);
+ vpu_debug(DEBUG_EXTRA_INFO, "test index %d success\n", testidx);
vpu_reg *reg = list_entry(session.done.next, vpu_reg, session_link);