build/patch/kernel/rockchip-next/8001_rk_vcodec_driver.patch

9484 lines
282 KiB
Diff
Raw Normal View History

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 041e15f..67e31ad 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -25,6 +25,8 @@ menu "Frame buffer Devices"
source "drivers/video/fbdev/Kconfig"
endmenu
+source "drivers/video/rk_vcodec/Kconfig"
+
source "drivers/video/backlight/Kconfig"
config VGASTATE
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 445b2c2..2da42ff 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -4,6 +4,8 @@ obj-$(CONFIG_HDMI) += hdmi.o
obj-$(CONFIG_VT) += console/
obj-$(CONFIG_FB_STI) += console/
obj-$(CONFIG_LOGO) += logo/
+obj-$(CONFIG_RK_VCODEC) += rk_vcodec/
+
obj-y += backlight/
obj-y += fbdev/
diff --git a/drivers/video/rk_vcodec/Kconfig b/drivers/video/rk_vcodec/Kconfig
new file mode 100644
index 0000000..1f86583
--- /dev/null
+++ b/drivers/video/rk_vcodec/Kconfig
@@ -0,0 +1,10 @@
+menu "VCODEC"
+ depends on ARCH_ROCKCHIP
+
+config RK_VCODEC
+ tristate "VCODEC (VPU HEVC) service driver in kernel"
+ depends on ARCH_ROCKCHIP
+ depends on ROCKCHIP_PM_DOMAINS
+ default n
+
+endmenu
diff --git a/drivers/video/rk_vcodec/Makefile b/drivers/video/rk_vcodec/Makefile
new file mode 100644
index 0000000..eb62b77
--- /dev/null
+++ b/drivers/video/rk_vcodec/Makefile
@@ -0,0 +1,8 @@
+ccflags-y += -I${src}/include
+
+rk-vcodec-objs := vcodec_service.o vcodec_iommu_ops.o
+
+rk-vcodec-objs += vcodec_iommu_drm.o
+
+obj-$(CONFIG_RK_VCODEC) += rk-vcodec.o
+
diff --git a/drivers/video/rk_vcodec/README.md b/drivers/video/rk_vcodec/README.md
new file mode 100644
index 0000000..f04f88f
--- /dev/null
+++ b/drivers/video/rk_vcodec/README.md
@@ -0,0 +1,74 @@
+If you appreciate this project, support me on Patreon !
+
+[![Patreon !](https://raw.githubusercontent.com/Miouyouyou/RockMyy/master/.img/button-patreon.png)](https://www.patreon.com/Miouyouyou)
+
+# About
+
+This repository goal is to focus on this Rockchip VPU driver code in
+order to use it with 4.13 kernels and onward.
+
+Most of the code is written by the Rockchip engineers, in the
+[rockchip_forwardports](https://github.com/rockchip-linux/rockchip_forwardports)
+repository initiated by [phh](https://github.com/phhusson), and updated
+by [wzyy2](https://github.com/wzyy2), and in the
+[kernel 4.4 patched and maintained by Rockchip](https://github.com/rockchip-linux/kernel).
+
+[phh](https://github.com/phhusson) took care of making it compilable in
+an Out-Of-Tree fashion.
+
+Currently being tested against
+[RockMyy-Build](https://github.com/Miouyouyou/RockMyy-Build) kernels.
+Note that this might generate crashes and/or freezes in its current
+state.
+
+The kernel patches required to use this driver will be integrated in
+RockMyy and RockMyy-Build this week-end.
+If you're in a hurry, for whatever reason,
+[the patch is here](https://raw.githubusercontent.com/Miouyouyou/MyyQi/master/patches/kernel/v4.11/0012-Export-rockchip_pmu_set_idle_request-for-out-of-tree.patch).
+
+# Compilation
+
+## If you're cross-compiling
+
+If you're cross-compiling this module, first set the `ARCH` and
+`CROSS_COMPILE` variables. If you're compiling from the Rockchip board
+itself, skip this example.
+
+Example :
+
+``bash
+export ARCH=arm
+export CROSS_COMPILE=armv7a-hardfloat-linux-gnueabi-
+``
+
+## Anyway
+
+To compile this module, type the following :
+
+ make M=$PWD -C /path/to/linux/sources CONFIG_RK_VCODEC=m
+
+The command will generate a 'rk-vcodec.ko' file that you can `insmod`
+on the Rockchip board executing the kernel generated from the sources
+you specified.
+
+# Installation
+
+## If you're cross-compiling
+
+Type the following command as **root**
+
+ make INSTALL_PATH=/install_root M=$PWD -C /path/to/linux/sources CONFIG_RK_VCODEC=m
+
+Note that this will install `extra/rk-vcodec.ko`, along with the others
+kernel modules, in `/install_root/lib/modules/kernel_version/kernel`.
+Once you copy the modules directory in the board's `/lib` directory,
+you'll be able to modprobe the module directly from the board.
+
+The kernel will also try to auto-load the module when possible.
+
+## If you're compiling directly
+
+ make M=$PWD -C /path/to/linux/sources CONFIG_RK_VCODEC=m modules_install
+
+The module will then be loaded at boot. You can still load it directly through
+`modprobe rk-vcodec`.
diff --git a/drivers/video/rk_vcodec/config.h b/drivers/video/rk_vcodec/config.h
new file mode 100644
index 0000000..822c053
--- /dev/null
+++ b/drivers/video/rk_vcodec/config.h
@@ -0,0 +1,7 @@
+#ifndef ROCKCHIP_VCODEC_CONFIG_H
+#define ROCKCHIP_VCODEC_CONFIG_H 1
+
+#define CONFIG_DRM 1
+#undef CONFIG_ION
+
+#endif
diff --git a/drivers/video/rk_vcodec/vcodec_hw_info.h b/drivers/video/rk_vcodec/vcodec_hw_info.h
new file mode 100644
index 0000000..a394650
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_hw_info.h
@@ -0,0 +1,240 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: Herman Chen herman.chen@rock-chips.com
+ * Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_INFO_H
+#define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_INFO_H
+
+/*
+ * Hardware id is for hardware detection
+ * Driver will read the hardware ID register first, then try to find a mactch
+ * hardware from the enum ID below.
+ */
+enum VPU_HW_ID {
+ VPU_DEC_ID_9190 = 0x6731,
+ VPU_ID_8270 = 0x8270,
+ VPU_ID_4831 = 0x4831,
+ HEVC_ID = 0x6867,
+ RKV_DEC_ID = 0x6876,
+ RKV_DEC_ID2 = 0x3410,
+ VPU2_ID = 0x0000,
+};
+
+/*
+ * Different hardware has different feature. So we catalogue these features
+ * into three class:
+ *
+ * 1. register io feature determined by hardware type
+ * including register offset, register file size, etc
+ *
+ * 2. runtime register config feature determined by task type
+ * including irq / enable / length register, bit mask, etc
+ *
+ * 3. file handle translate feature determined by vcodec format type
+ * register translation map table
+ *
+ * These three type features composite a complete codec information structure
+ */
+
+/* VPU1 and VPU2 */
+#define VCODEC_DEVICE_TYPE_VPUX 0x56505558
+/* VPU Combo */
+#define VCODEC_DEVICE_TYPE_VPUC 0x56505543
+#define VCODEC_DEVICE_TYPE_HEVC 0x56505532
+#define VCODEC_DEVICE_TYPE_RKVD 0x524B5644
+
+enum TASK_TYPE {
+ TASK_ENC,
+ TASK_DEC,
+ TASK_PP,
+ TASK_DEC_PP,
+ TASK_TYPE_BUTT,
+};
+
+enum FORMAT_TYPE {
+ FMT_DEC_BASE = 0,
+ FMT_JPEGD = FMT_DEC_BASE,
+
+ FMT_H263D,
+ FMT_H264D,
+ FMT_H265D,
+
+ FMT_MPEG1D,
+ FMT_MPEG2D,
+ FMT_MPEG4D,
+
+ FMT_VP6D,
+ FMT_VP7D,
+ FMT_VP8D,
+ FMT_VP9D,
+
+ FMT_VC1D,
+ FMT_AVSD,
+
+ FMT_DEC_BUTT,
+
+ FMT_PP_BASE = FMT_DEC_BUTT,
+ FMT_PP = FMT_PP_BASE,
+ FMT_PP_BUTT,
+
+ FMT_ENC_BASE = FMT_PP_BUTT,
+ FMT_JPEGE = FMT_ENC_BASE,
+
+ FMT_H264E,
+
+ FMT_VP8E,
+
+ FMT_ENC_BUTT,
+ FMT_TYPE_BUTT = FMT_ENC_BUTT,
+};
+
+/**
+ * struct for hardware task operation
+ */
+struct vpu_hw_info {
+ enum VPU_HW_ID hw_id;
+ u32 enc_offset;
+ u32 enc_reg_num;
+ u32 enc_io_size;
+
+ u32 dec_offset;
+ u32 dec_reg_num;
+ u32 dec_io_size;
+
+ /*
+ * register range for enc/dec/pp/dec_pp
+ * base/end of dec/pp/dec_pp specify the register range to config
+ */
+ u32 base_dec;
+ u32 base_pp;
+ u32 base_dec_pp;
+ u32 end_dec;
+ u32 end_pp;
+ u32 end_dec_pp;
+};
+
+struct vpu_task_info {
+ char *name;
+ struct timeval start;
+ struct timeval end;
+
+ /*
+ * input stream register
+ * use for map/unmap drm buffer for avoiding
+ * cache sync issue
+ */
+ int reg_rlc;
+ /*
+ * task enable register
+ * use for enable hardware task process
+ * -1 for invalid
+ */
+ int reg_en;
+
+ /* register of task auto gating, alway valid */
+ int reg_gating;
+
+ /* register of task irq, alway valid */
+ int reg_irq;
+
+ /*
+ * stream length register
+ * only valid for decoder task
+ * -1 for invalid (encoder)
+ */
+ int reg_len;
+
+ /*
+ * direct mv register
+ * special offset scale, offset multiply by 16
+ *
+ * valid on vpu & vpu2
+ * -1 for invalid
+ */
+ int reg_dir_mv;
+
+ /*
+ * pps register
+ * special register for scaling list address process
+ *
+ * valid on rkv
+ * -1 for invalid
+ */
+ int reg_pps;
+
+ /*
+ * decoder pipeline mode register
+ *
+ * valid on vpu & vpu2
+ * -1 for invalid
+ */
+ int reg_pipe;
+
+ /* task enable bit mask for enable register */
+ u32 enable_mask;
+
+ /* task auto gating mask for enable register */
+ u32 gating_mask;
+
+ /* task pipeline mode mask for pipe register */
+ u32 pipe_mask;
+
+ /* task inturrpt bit mask for irq register */
+ u32 irq_mask;
+
+ /* task ready bit mask for irq register */
+ u32 ready_mask;
+
+ /* task error bit mask for irq register */
+ u32 error_mask;
+
+ enum FORMAT_TYPE (*get_fmt)(u32 *regs);
+};
+
+struct vpu_trans_info {
+ const int count;
+ const char * const table;
+};
+
+struct vcodec_info {
+ enum VPU_HW_ID hw_id;
+ struct vpu_hw_info *hw_info;
+ struct vpu_task_info *task_info;
+ const struct vpu_trans_info *trans_info;
+};
+
+struct vcodec_device_info {
+ int32_t device_type;
+ int8_t *name;
+};
+
+#define DEF_FMT_TRANS_TBL(fmt, args...) \
+ static const char trans_tbl_##fmt[] = { \
+ args \
+ }
+
+#define SETUP_FMT_TBL(id, fmt) \
+ [id] = { \
+ .count = sizeof(trans_tbl_##fmt), \
+ .table = trans_tbl_##fmt, \
+ }
+
+#define EMPTY_FMT_TBL(id) \
+ [id] = { \
+ .count = 0, \
+ .table = NULL, \
+ }
+
+#endif
diff --git a/drivers/video/rk_vcodec/vcodec_hw_rkv.h b/drivers/video/rk_vcodec/vcodec_hw_rkv.h
new file mode 100644
index 0000000..6839959
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_hw_rkv.h
@@ -0,0 +1,227 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ * Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_RKV_H
+#define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_RKV_H
+
+#include "vcodec_hw_info.h"
+
+/* hardware information */
+#define REG_NUM_HEVC_DEC (68)
+#define REG_NUM_RKV_DEC (78)
+
+/* enable and gating register */
+#define RKV_REG_EN_DEC 1
+#define RKV_REG_DEC_GATING_BIT BIT(1)
+
+/* interrupt and error status register */
+#define HEVC_INTERRUPT_REGISTER 1
+#define HEVC_INTERRUPT_BIT BIT(8)
+#define HEVC_DEC_INT_RAW_BIT BIT(9)
+#define HEVC_READY_BIT BIT(12)
+#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)
+
+#define RKV_DEC_INTERRUPT_REGISTER 1
+#define RKV_DEC_INTERRUPT_BIT BIT(8)
+#define RKV_DEC_INT_RAW_BIT BIT(9)
+#define RKV_DEC_READY_BIT BIT(12)
+#define RKV_DEC_BUS_ERROR_BIT BIT(13)
+#define RKV_DEC_STR_ERROR_BIT BIT(14)
+#define RKV_DEC_TIMEOUT_BIT BIT(15)
+#define RKV_DEC_BUFFER_EMPTY_BIT BIT(16)
+#define RKV_DEC_COLMV_ERROR_BIT BIT(17)
+#define RKV_DEC_ERR_MASK (RKV_DEC_BUS_ERROR_BIT \
+ |RKV_DEC_STR_ERROR_BIT \
+ |RKV_DEC_TIMEOUT_BIT \
+ |RKV_DEC_BUFFER_EMPTY_BIT \
+ |RKV_DEC_COLMV_ERROR_BIT)
+
+static const enum FORMAT_TYPE rkv_dec_fmt_tbl[] = {
+ [0] = FMT_H265D,
+ [1] = FMT_H264D,
+ [2] = FMT_VP9D,
+ [3] = FMT_TYPE_BUTT,
+};
+
+static enum FORMAT_TYPE rkv_dec_get_fmt(u32 *regs)
+{
+ u32 fmt_id = (regs[2] >> 20) & 0x3;
+ enum FORMAT_TYPE type = rkv_dec_fmt_tbl[fmt_id];
+ return type;
+}
+
+static struct vpu_task_info task_rkv[TASK_TYPE_BUTT] = {
+ {
+ .name = "invalid",
+ .reg_en = 0,
+ .reg_irq = 0,
+ .reg_len = 0,
+ .reg_dir_mv = 0,
+ .reg_pps = 0,
+ .reg_pipe = 0,
+ .enable_mask = 0,
+ .gating_mask = 0,
+ .pipe_mask = 0,
+ .irq_mask = 0,
+ .ready_mask = 0,
+ .error_mask = 0,
+ .get_fmt = NULL,
+ },
+ {
+ .name = "rkvdec",
+ .reg_rlc = 4,
+ .reg_en = RKV_REG_EN_DEC,
+ .reg_irq = RKV_DEC_INTERRUPT_REGISTER,
+ .reg_len = 4,
+ .reg_dir_mv = 52,
+ .reg_pps = 42,
+ .reg_pipe = 0,
+ .enable_mask = 0,
+ .gating_mask = RKV_REG_DEC_GATING_BIT,
+ .irq_mask = HEVC_INTERRUPT_BIT,
+ .pipe_mask = 0,
+ .ready_mask = HEVC_READY_BIT,
+ .error_mask = HEVC_DEC_ERR_MASK,
+ .get_fmt = rkv_dec_get_fmt,
+ },
+ {
+ .name = "invalid",
+ .reg_en = 0,
+ .reg_irq = 0,
+ .reg_len = 0,
+ .reg_dir_mv = 0,
+ .reg_pps = 0,
+ .reg_pipe = 0,
+ .enable_mask = 0,
+ .gating_mask = 0,
+ .pipe_mask = 0,
+ .irq_mask = 0,
+ .ready_mask = 0,
+ .error_mask = 0,
+ .get_fmt = NULL,
+ },
+ {
+ .name = "invalid",
+ .reg_en = 0,
+ .reg_irq = 0,
+ .reg_len = 0,
+ .reg_dir_mv = 0,
+ .reg_pps = 0,
+ .reg_pipe = 0,
+ .enable_mask = 0,
+ .gating_mask = 0,
+ .pipe_mask = 0,
+ .irq_mask = 0,
+ .ready_mask = 0,
+ .error_mask = 0,
+ .get_fmt = NULL,
+ },};
+
+static struct vpu_hw_info hw_rkhevc = {
+ .hw_id = HEVC_ID,
+
+ .enc_offset = 0,
+ .enc_reg_num = 0,
+ .enc_io_size = 0,
+
+ .dec_offset = 0,
+ .dec_reg_num = REG_NUM_HEVC_DEC,
+ .dec_io_size = REG_NUM_HEVC_DEC * 4,
+
+ /* NOTE: can not write to register 0 */
+ .base_dec = 1,
+ .base_pp = 0,
+ .base_dec_pp = 0,
+ .end_dec = REG_NUM_HEVC_DEC,
+ .end_pp = 0,
+ .end_dec_pp = 0,
+};
+
+static struct vpu_hw_info hw_rkvdec = {
+ .hw_id = RKV_DEC_ID,
+
+ .enc_offset = 0,
+ .enc_reg_num = 0,
+ .enc_io_size = 0,
+
+ .dec_offset = 0x0,
+ .dec_reg_num = REG_NUM_RKV_DEC,
+ .dec_io_size = REG_NUM_RKV_DEC * 4,
+
+ /* NOTE: can not write to register 0 */
+ .base_dec = 1,
+ .base_pp = 0,
+ .base_dec_pp = 0,
+ .end_dec = REG_NUM_RKV_DEC,
+ .end_pp = 0,
+ .end_dec_pp = 0,
+};
+
+/*
+ * file handle translate information
+ */
+DEF_FMT_TRANS_TBL(rkv_h264d,
+ 4, 6, 7, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 41, 42, 43, 48, 75
+);
+
+DEF_FMT_TRANS_TBL(rkv_h265d,
+ 4, 6, 7, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 42, 43
+);
+
+DEF_FMT_TRANS_TBL(rkv_vp9d,
+ 4, 6, 7, 11, 12, 13, 14, 15,
+ 16, 52
+);
+
+const struct vpu_trans_info trans_rkv[FMT_TYPE_BUTT] = {
+ EMPTY_FMT_TBL(FMT_JPEGD),
+ EMPTY_FMT_TBL(FMT_H263D),
+ SETUP_FMT_TBL(FMT_H264D , rkv_h264d),
+ SETUP_FMT_TBL(FMT_H265D , rkv_h265d),
+
+ EMPTY_FMT_TBL(FMT_MPEG1D),
+ EMPTY_FMT_TBL(FMT_MPEG2D),
+ EMPTY_FMT_TBL(FMT_MPEG4D),
+
+ EMPTY_FMT_TBL(FMT_VP6D),
+ EMPTY_FMT_TBL(FMT_VP7D),
+ EMPTY_FMT_TBL(FMT_VP8D),
+ SETUP_FMT_TBL(FMT_VP9D , rkv_vp9d),
+
+ EMPTY_FMT_TBL(FMT_PP),
+
+ EMPTY_FMT_TBL(FMT_VC1D),
+ EMPTY_FMT_TBL(FMT_AVSD),
+
+ EMPTY_FMT_TBL(FMT_JPEGE),
+ EMPTY_FMT_TBL(FMT_H264E),
+ EMPTY_FMT_TBL(FMT_VP8E),
+};
+
+#endif
diff --git a/drivers/video/rk_vcodec/vcodec_hw_vpu.h b/drivers/video/rk_vcodec/vcodec_hw_vpu.h
new file mode 100644
index 0000000..ae771b6
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_hw_vpu.h
@@ -0,0 +1,325 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ * Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU_H
+#define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU_H
+
+#include "vcodec_hw_info.h"
+
+/* hardware information */
+#define REG_NUM_9190_DEC (60)
+#define REG_NUM_9190_PP (41)
+#define REG_NUM_9190_DEC_PP (REG_NUM_9190_DEC + REG_NUM_9190_PP)
+
+#define REG_NUM_DEC_PP (REG_NUM_9190_DEC + REG_NUM_9190_PP)
+
+#define REG_NUM_ENC_8270 (96)
+#define REG_SIZE_ENC_8270 (0x200)
+#define REG_NUM_ENC_4831 (164)
+#define REG_SIZE_ENC_4831 (0x400)
+
+
+/* enable and gating register */
+#define VPU_REG_EN_ENC 14
+#define VPU_REG_ENC_GATE 2
+#define VPU_REG_ENC_GATE_BIT BIT(4)
+
+#define VPU_REG_EN_DEC 1
+#define VPU_REG_DEC_GATE 2
+#define VPU_REG_DEC_GATE_BIT BIT(10)
+#define VPU_REG_EN_PP 0
+#define VPU_REG_PP_GATE 1
+#define VPU_REG_PP_GATE_BIT BIT(8)
+#define VPU_REG_EN_DEC_PP 1
+#define VPU_REG_DEC_PP_GATE 61
+#define VPU_REG_DEC_PP_GATE_BIT BIT(8)
+
+/* interrupt and error status register */
+#define VPU_DEC_INTERRUPT_REGISTER 1
+#define VPU_DEC_INTERRUPT_BIT BIT(8)
+#define VPU_DEC_READY_BIT BIT(12)
+#define VPU_DEC_BUS_ERROR_BIT BIT(13)
+#define VPU_DEC_BUFFER_EMPTY_BIT BIT(14)
+#define VPU_DEC_ASO_ERROR_BIT BIT(15)
+#define VPU_DEC_STREAM_ERROR_BIT BIT(16)
+#define VPU_DEC_SLICE_DONE_BIT BIT(17)
+#define VPU_DEC_TIMEOUT_BIT BIT(18)
+#define VPU_DEC_ERR_MASK (VPU_DEC_BUS_ERROR_BIT \
+ |VPU_DEC_BUFFER_EMPTY_BIT \
+ |VPU_DEC_STREAM_ERROR_BIT \
+ |VPU_DEC_TIMEOUT_BIT)
+
+#define VPU_PP_INTERRUPT_REGISTER 60
+#define VPU_PP_PIPELINE_MODE_BIT BIT(1)
+#define VPU_PP_INTERRUPT_BIT BIT(8)
+#define VPU_PP_READY_BIT BIT(12)
+#define VPU_PP_BUS_ERROR_BIT BIT(13)
+#define VPU_PP_ERR_MASK VPU_PP_BUS_ERROR_BIT
+
+#define VPU_ENC_INTERRUPT_REGISTER 1
+#define VPU_ENC_INTERRUPT_BIT BIT(0)
+#define VPU_ENC_READY_BIT BIT(2)
+#define VPU_ENC_BUS_ERROR_BIT BIT(3)
+#define VPU_ENC_BUFFER_FULL_BIT BIT(5)
+#define VPU_ENC_TIMEOUT_BIT BIT(6)
+#define VPU_ENC_ERR_MASK (VPU_ENC_BUS_ERROR_BIT \
+ |VPU_ENC_BUFFER_FULL_BIT \
+ |VPU_ENC_TIMEOUT_BIT)
+
+static const enum FORMAT_TYPE vpu_dec_fmt_tbl[] = {
+ [0] = FMT_H264D,
+ [1] = FMT_MPEG4D,
+ [2] = FMT_H263D,
+ [3] = FMT_JPEGD,
+ [4] = FMT_VC1D,
+ [5] = FMT_MPEG2D,
+ [6] = FMT_MPEG1D,
+ [7] = FMT_VP6D,
+ [8] = FMT_TYPE_BUTT,
+ [9] = FMT_VP7D,
+ [10] = FMT_VP8D,
+ [11] = FMT_AVSD,
+ [12] = FMT_TYPE_BUTT,
+ [13] = FMT_TYPE_BUTT,
+ [14] = FMT_TYPE_BUTT,
+ [15] = FMT_TYPE_BUTT,
+};
+
+static enum FORMAT_TYPE vpu_dec_get_fmt(u32 *regs)
+{
+ u32 fmt_id = (regs[3] >> 28) & 0xf;
+ enum FORMAT_TYPE type = vpu_dec_fmt_tbl[fmt_id];
+ return type;
+}
+
+static enum FORMAT_TYPE vpu_pp_get_fmt(u32 *regs)
+{
+ return FMT_PP;
+}
+
+static const enum FORMAT_TYPE vpu_enc_fmt_tbl[] = {
+ [0] = FMT_TYPE_BUTT,
+ [1] = FMT_VP8E,
+ [2] = FMT_JPEGE,
+ [3] = FMT_H264E,
+};
+
+static enum FORMAT_TYPE vpu_enc_get_fmt(u32 *regs)
+{
+ u32 fmt_id = (regs[VPU_REG_EN_ENC] >> 1) & 0x3;
+ enum FORMAT_TYPE type = vpu_enc_fmt_tbl[fmt_id];
+ return type;
+}
+
+static struct vpu_task_info task_vpu[TASK_TYPE_BUTT] = {
+ {
+ .name = "vpu_enc",
+ .reg_rlc = 11,
+ .reg_en = VPU_REG_EN_ENC,
+ .reg_irq = VPU_ENC_INTERRUPT_REGISTER,
+ .reg_len = -1,
+ .reg_dir_mv = -1,
+ .reg_pps = -1,
+ .reg_pipe = -1,
+ .enable_mask = 0x6,
+ .gating_mask = 0,
+ .pipe_mask = 0,
+ .irq_mask = VPU_ENC_INTERRUPT_BIT,
+ .ready_mask = VPU_ENC_READY_BIT,
+ .error_mask = VPU_ENC_ERR_MASK,
+ .get_fmt = vpu_enc_get_fmt,
+ },
+ {
+ .name = "vpu_dec",
+ .reg_rlc = 12,
+ .reg_en = VPU_REG_EN_DEC,
+ .reg_irq = VPU_DEC_INTERRUPT_REGISTER,
+ .reg_len = 12,
+ .reg_dir_mv = 41,
+ .reg_pps = -1,
+ .reg_pipe = VPU_PP_INTERRUPT_REGISTER,
+ .enable_mask = 0,
+ .gating_mask = 0,
+ .pipe_mask = VPU_PP_PIPELINE_MODE_BIT,
+ .irq_mask = VPU_DEC_INTERRUPT_BIT,
+ .ready_mask = VPU_DEC_READY_BIT,
+ .error_mask = VPU_DEC_ERR_MASK,
+ .get_fmt = vpu_dec_get_fmt,
+ },
+ {
+ .name = "vpu_pp",
+ .reg_en = VPU_REG_EN_PP,
+ .reg_irq = VPU_PP_INTERRUPT_REGISTER,
+ .reg_len = -1,
+ .reg_dir_mv = -1,
+ .reg_pps = -1,
+ .reg_pipe = VPU_PP_INTERRUPT_REGISTER,
+ .enable_mask = 0,
+ .gating_mask = 0,
+ .pipe_mask = VPU_PP_PIPELINE_MODE_BIT,
+ .irq_mask = VPU_PP_INTERRUPT_BIT,
+ .ready_mask = VPU_PP_READY_BIT,
+ .error_mask = VPU_PP_ERR_MASK,
+ .get_fmt = vpu_pp_get_fmt,
+ },
+ {
+ .name = "vpu_dec_pp",
+ .reg_rlc = 12,
+ .reg_en = VPU_REG_EN_DEC,
+ .reg_irq = VPU_DEC_INTERRUPT_REGISTER,
+ .reg_len = 12,
+ .reg_dir_mv = 41,
+ .reg_pps = -1,
+ .reg_pipe = VPU_PP_INTERRUPT_REGISTER,
+ .enable_mask = 0,
+ .gating_mask = 0,
+ .pipe_mask = VPU_PP_PIPELINE_MODE_BIT,
+ .irq_mask = VPU_DEC_INTERRUPT_BIT,
+ .ready_mask = VPU_DEC_READY_BIT,
+ .error_mask = VPU_DEC_ERR_MASK,
+ .get_fmt = vpu_dec_get_fmt,
+ },
+};
+
+static struct vpu_hw_info hw_vpu_8270 = {
+ .hw_id = VPU_ID_8270,
+
+ .enc_offset = 0x0,
+ .enc_reg_num = REG_NUM_ENC_8270,
+ .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,
+
+ .base_dec = 0,
+ .base_pp = VPU_PP_INTERRUPT_REGISTER,
+ .base_dec_pp = 0,
+ .end_dec = REG_NUM_9190_DEC,
+ .end_pp = REG_NUM_9190_DEC_PP,
+ .end_dec_pp = REG_NUM_9190_DEC_PP,
+};
+
+static struct vpu_hw_info hw_vpu_4831 = {
+ .hw_id = VPU_ID_4831,
+
+ .enc_offset = 0x0,
+ .enc_reg_num = REG_NUM_ENC_4831,
+ .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,
+
+ .base_dec = 0,
+ .base_pp = VPU_PP_INTERRUPT_REGISTER,
+ .base_dec_pp = 0,
+ .end_dec = REG_NUM_9190_DEC,
+ .end_pp = REG_NUM_9190_DEC_PP,
+ .end_dec_pp = REG_NUM_9190_DEC_PP,
+};
+
+static struct vpu_hw_info hw_vpu_9190 = {
+ .hw_id = VPU_DEC_ID_9190,
+
+ .enc_offset = 0x0,
+ .enc_reg_num = 0,
+ .enc_io_size = 0,
+
+ .dec_offset = 0,
+ .dec_reg_num = REG_NUM_9190_DEC_PP,
+ .dec_io_size = REG_NUM_9190_DEC_PP * 4,
+
+ .base_dec = 0,
+ .base_pp = VPU_PP_INTERRUPT_REGISTER,
+ .base_dec_pp = 0,
+ .end_dec = REG_NUM_9190_DEC,
+ .end_pp = REG_NUM_9190_DEC_PP,
+ .end_dec_pp = REG_NUM_9190_DEC_PP,
+};
+
+/*
+ * file handle translate information
+ */
+DEF_FMT_TRANS_TBL(vpu_jpegd,
+ 12, 13, 14, 40, 66, 67
+);
+
+DEF_FMT_TRANS_TBL(vpu_h264d,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 40, 41
+);
+
+DEF_FMT_TRANS_TBL(vpu_vp6d,
+ 12, 13, 14, 18, 27, 40
+);
+
+DEF_FMT_TRANS_TBL(vpu_vp8d,
+ 10, 12, 13, 14, 18, 19, 22, 23,
+ 24, 25, 26, 27, 28, 29, 40
+);
+
+DEF_FMT_TRANS_TBL(vpu_vc1d,
+ 12, 13, 14, 15, 16, 17, 27, 41
+);
+
+DEF_FMT_TRANS_TBL(vpu_avsd,
+ 12, 13, 14, 15, 16, 17, 40, 41, 45
+);
+
+DEF_FMT_TRANS_TBL(vpu_defaultd,
+ 12, 13, 14, 15, 16, 17, 40, 41
+);
+
+DEF_FMT_TRANS_TBL(vpu_default_pp,
+ 63, 64, 65, 66, 67, 73, 74
+);
+
+DEF_FMT_TRANS_TBL(vpu_vp8e,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 26, 51, 52, 58, 59
+);
+
+DEF_FMT_TRANS_TBL(vpu_defaulte,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 51
+);
+
+static const struct vpu_trans_info trans_vpu[FMT_TYPE_BUTT] = {
+ SETUP_FMT_TBL(FMT_JPEGD, vpu_jpegd),
+ SETUP_FMT_TBL(FMT_H263D, vpu_defaultd),
+ SETUP_FMT_TBL(FMT_H264D, vpu_h264d),
+ EMPTY_FMT_TBL(FMT_H265D),
+
+ SETUP_FMT_TBL(FMT_MPEG1D, vpu_defaultd),
+ SETUP_FMT_TBL(FMT_MPEG2D, vpu_defaultd),
+ SETUP_FMT_TBL(FMT_MPEG4D, vpu_defaultd),
+
+ SETUP_FMT_TBL(FMT_VP6D, vpu_vp6d),
+ SETUP_FMT_TBL(FMT_VP7D, vpu_defaultd),
+ SETUP_FMT_TBL(FMT_VP8D, vpu_vp8d),
+ EMPTY_FMT_TBL(FMT_VP9D),
+
+ SETUP_FMT_TBL(FMT_VC1D, vpu_vc1d),
+ SETUP_FMT_TBL(FMT_AVSD, vpu_avsd),
+
+ SETUP_FMT_TBL(FMT_PP, vpu_default_pp),
+
+ SETUP_FMT_TBL(FMT_JPEGE, vpu_defaulte),
+ SETUP_FMT_TBL(FMT_H264E, vpu_defaulte),
+ SETUP_FMT_TBL(FMT_VP8E, vpu_vp8e),
+};
+
+#endif
diff --git a/drivers/video/rk_vcodec/vcodec_hw_vpu2.h b/drivers/video/rk_vcodec/vcodec_hw_vpu2.h
new file mode 100644
index 0000000..86c1e16
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_hw_vpu2.h
@@ -0,0 +1,278 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ * Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU2_H
+#define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU2_H
+
+#include "vcodec_hw_info.h"
+
+/* hardware information */
+#define REG_NUM_VPU2_DEC (159)
+#define REG_NUM_VPU2_DEC_START (50)
+#define REG_NUM_VPU2_DEC_END (159)
+#define REG_NUM_VPU2_PP (41)
+#define REG_NUM_VPU2_DEC_PP (159)
+#define REG_NUM_VPU2_ENC (184)
+#define REG_NUM_VPU2_DEC_OFFSET (0x400)
+
+/* enable and gating register */
+#define VPU2_REG_EN_ENC 103
+#define VPU2_REG_ENC_GATE 109
+#define VPU2_REG_ENC_GATE_BIT BIT(4)
+
+#define VPU2_REG_EN_DEC 57
+#define VPU2_REG_DEC_GATE 57
+#define VPU2_REG_DEC_GATE_BIT BIT(4)
+#define VPU2_REG_EN_PP 41
+#define VPU2_REG_PP_GATE 1
+#define VPU2_REG_PP_GATE_BIT BIT(8)
+#define VPU2_REG_EN_DEC_PP 57
+#define VPU2_REG_DEC_PP_GATE 57
+#define VPU2_REG_DEC_PP_GATE_BIT BIT(4)
+
+/* interrupt and error status register */
+#define VPU2_DEC_INTERRUPT_REGISTER 55
+#define VPU2_DEC_INTERRUPT_BIT BIT(0)
+#define VPU2_DEC_READY_BIT BIT(4)
+#define VPU2_DEC_BUS_ERROR_BIT BIT(5)
+#define VPU2_DEC_BUFFER_EMPTY_BIT BIT(6)
+#define VPU2_DEC_ASO_ERROR_BIT BIT(8)
+#define VPU2_DEC_SLICE_DONE_BIT BIT(9)
+#define VPU2_DEC_STREAM_ERROR_BIT BIT(12)
+#define VPU2_DEC_TIMEOUT_BIT BIT(13)
+#define VPU2_DEC_ERR_MASK (VPU2_DEC_BUS_ERROR_BIT \
+ |VPU2_DEC_BUFFER_EMPTY_BIT \
+ |VPU2_DEC_STREAM_ERROR_BIT \
+ |VPU2_DEC_TIMEOUT_BIT)
+
+#define VPU2_PP_INTERRUPT_REGISTER 40
+#define VPU2_PP_INTERRUPT_BIT BIT(0)
+#define VPU2_PP_READY_BIT BIT(2)
+#define VPU2_PP_BUS_ERROR_BIT BIT(3)
+#define VPU2_PP_ERR_MASK VPU2_PP_BUS_ERROR_BIT
+#define VPU2_PP_PIPELINE_REGISTER 41
+#define VPU2_PP_PIPELINE_MODE_BIT BIT(4)
+
+#define VPU2_ENC_INTERRUPT_REGISTER 109
+#define VPU2_ENC_INTERRUPT_BIT BIT(0)
+#define VPU2_ENC_READY_BIT BIT(1)
+#define VPU2_ENC_BUS_ERROR_BIT BIT(4)
+#define VPU2_ENC_BUFFER_FULL_BIT BIT(5)
+#define VPU2_ENC_TIMEOUT_BIT BIT(6)
+#define VPU2_ENC_ERR_MASK (VPU2_ENC_BUS_ERROR_BIT \
+ |VPU2_ENC_BUFFER_FULL_BIT \
+ |VPU2_ENC_TIMEOUT_BIT)
+
+static const enum FORMAT_TYPE vpu2_dec_fmt_tbl[] = {
+ [0] = FMT_H264D,
+ [1] = FMT_MPEG4D,
+ [2] = FMT_H263D,
+ [3] = FMT_JPEGD,
+ [4] = FMT_VC1D,
+ [5] = FMT_MPEG2D,
+ [6] = FMT_MPEG1D,
+ [7] = FMT_VP6D,
+ [8] = FMT_TYPE_BUTT,
+ [9] = FMT_VP7D,
+ [10] = FMT_VP8D,
+ [11] = FMT_AVSD,
+ [12] = FMT_TYPE_BUTT,
+ [13] = FMT_TYPE_BUTT,
+ [14] = FMT_TYPE_BUTT,
+ [15] = FMT_TYPE_BUTT,
+};
+
+static enum FORMAT_TYPE vpu2_dec_get_fmt(u32 *regs)
+{
+ u32 fmt_id = regs[53] & 0xf;
+ enum FORMAT_TYPE type = vpu2_dec_fmt_tbl[fmt_id];
+ return type;
+}
+
+static enum FORMAT_TYPE vpu2_pp_get_fmt(u32 *regs)
+{
+ return FMT_PP;
+}
+
+static const enum FORMAT_TYPE vpu2_enc_fmt_tbl[] = {
+ [0] = FMT_TYPE_BUTT,
+ [1] = FMT_VP8E,
+ [2] = FMT_JPEGE,
+ [3] = FMT_H264E,
+};
+
+static enum FORMAT_TYPE vpu2_enc_get_fmt(u32 *regs)
+{
+ u32 fmt_id = (regs[VPU2_REG_EN_ENC] >> 4) & 0x3;
+ enum FORMAT_TYPE type = vpu2_enc_fmt_tbl[fmt_id];
+ return type;
+}
+
+static struct vpu_task_info task_vpu2[TASK_TYPE_BUTT] = {
+ {
+ .name = "vpu2_enc",
+ .reg_rlc = 48,
+ .reg_en = VPU2_REG_EN_ENC,
+ .reg_gating = VPU2_REG_ENC_GATE,
+ .reg_irq = VPU2_ENC_INTERRUPT_REGISTER,
+ .reg_len = -1,
+ .reg_dir_mv = -1,
+ .reg_pps = -1,
+ .reg_pipe = -1,
+ .enable_mask = 0x30,
+ .gating_mask = VPU2_REG_ENC_GATE_BIT,
+ .pipe_mask = 0,
+ .irq_mask = VPU2_ENC_INTERRUPT_BIT,
+ .ready_mask = VPU2_ENC_READY_BIT,
+ .error_mask = VPU2_ENC_ERR_MASK,
+ .get_fmt = vpu2_enc_get_fmt,
+ },
+ {
+ .name = "vpu2_dec",
+ .reg_rlc = 64,
+ .reg_en = VPU2_REG_EN_DEC,
+ .reg_irq = VPU2_DEC_INTERRUPT_REGISTER,
+ .reg_len = 64,
+ .reg_dir_mv = 62,
+ .reg_pps = -1,
+ .reg_pipe = VPU2_PP_PIPELINE_REGISTER,
+ .enable_mask = 0,
+ .gating_mask = VPU2_REG_DEC_GATE_BIT,
+ .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT,
+ .irq_mask = VPU2_DEC_INTERRUPT_BIT,
+ .ready_mask = VPU2_DEC_READY_BIT,
+ .error_mask = VPU2_DEC_ERR_MASK,
+ .get_fmt = vpu2_dec_get_fmt,
+ },
+ {
+ .name = "vpu2_pp",
+ .reg_en = VPU2_REG_EN_PP,
+ .reg_irq = VPU2_PP_INTERRUPT_REGISTER,
+ .reg_len = -1,
+ .reg_dir_mv = -1,
+ .reg_pps = -1,
+ .reg_pipe = VPU2_PP_PIPELINE_REGISTER,
+ .enable_mask = 0,
+ .gating_mask = VPU2_REG_PP_GATE_BIT,
+ .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT,
+ .irq_mask = VPU2_PP_INTERRUPT_BIT,
+ .ready_mask = VPU2_PP_READY_BIT,
+ .error_mask = VPU2_PP_ERR_MASK,
+ .get_fmt = vpu2_pp_get_fmt,
+ },
+ {
+ .name = "vpu2_dec_pp",
+ .reg_rlc = 64,
+ .reg_en = VPU2_REG_EN_DEC_PP,
+ .reg_irq = VPU2_DEC_INTERRUPT_REGISTER,
+ .reg_len = 64,
+ .reg_dir_mv = 62,
+ .reg_pps = -1,
+ .reg_pipe = VPU2_PP_PIPELINE_REGISTER,
+ .enable_mask = 0,
+ .gating_mask = VPU2_REG_DEC_GATE_BIT,
+ .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT,
+ .irq_mask = VPU2_DEC_INTERRUPT_BIT,
+ .ready_mask = VPU2_DEC_READY_BIT,
+ .error_mask = VPU2_DEC_ERR_MASK,
+ .get_fmt = vpu2_dec_get_fmt,
+ },
+};
+
+static struct vpu_hw_info hw_vpu2 = {
+ .hw_id = VPU2_ID,
+
+ .enc_offset = 0x0,
+ .enc_reg_num = REG_NUM_VPU2_ENC,
+ .enc_io_size = REG_NUM_VPU2_ENC * 4,
+
+ .dec_offset = REG_NUM_VPU2_DEC_OFFSET,
+ .dec_reg_num = REG_NUM_VPU2_DEC_PP,
+ .dec_io_size = REG_NUM_VPU2_DEC_PP * 4,
+
+ .base_dec = REG_NUM_VPU2_DEC_START,
+ .base_pp = 0,
+ .base_dec_pp = 0,
+ .end_dec = REG_NUM_VPU2_DEC_END,
+ .end_pp = REG_NUM_VPU2_PP,
+ .end_dec_pp = REG_NUM_VPU2_DEC_END,
+};
+
+/*
+ * file handle translate information
+ */
+DEF_FMT_TRANS_TBL(vpu2_jpegd,
+ 131, 64, 63, 61, 21, 22
+);
+
+DEF_FMT_TRANS_TBL(vpu2_h264d,
+ 64, 63, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 61, 62
+);
+
+DEF_FMT_TRANS_TBL(vpu2_vp6d,
+ 64, 63, 131, 136, 145, 61
+);
+
+DEF_FMT_TRANS_TBL(vpu2_vp8d,
+ 149, 64, 63, 131, 136, 137, 140, 141,
+ 142, 143, 144, 145, 146, 147, 61
+);
+
+DEF_FMT_TRANS_TBL(vpu2_vc1d,
+ 64, 63, 131, 148, 134, 135, 145, 62
+);
+
+DEF_FMT_TRANS_TBL(vpu2_default_dec,
+ 64, 63, 131, 148, 134, 135, 61, 62
+);
+
+DEF_FMT_TRANS_TBL(vpu2_default_pp,
+ 12, 13, 18, 19, 20, 21, 22
+);
+
+DEF_FMT_TRANS_TBL(vpu2_default_enc,
+ 77, 78, 56, 57, 63, 64, 48, 49,
+ 50, 81
+);
+
+const struct vpu_trans_info trans_vpu2[FMT_TYPE_BUTT] = {
+ SETUP_FMT_TBL(FMT_JPEGD , vpu2_jpegd),
+ SETUP_FMT_TBL(FMT_H263D , vpu2_default_dec),
+ SETUP_FMT_TBL(FMT_H264D , vpu2_h264d),
+ EMPTY_FMT_TBL(FMT_H265D),
+
+ SETUP_FMT_TBL(FMT_MPEG1D, vpu2_default_dec),
+ SETUP_FMT_TBL(FMT_MPEG2D, vpu2_default_dec),
+ SETUP_FMT_TBL(FMT_MPEG4D, vpu2_default_dec),
+
+ SETUP_FMT_TBL(FMT_VP6D , vpu2_vp6d),
+ SETUP_FMT_TBL(FMT_VP7D , vpu2_default_dec),
+ SETUP_FMT_TBL(FMT_VP8D , vpu2_vp8d),
+ EMPTY_FMT_TBL(FMT_VP9D),
+
+ SETUP_FMT_TBL(FMT_PP , vpu2_default_pp),
+
+ SETUP_FMT_TBL(FMT_VC1D , vpu2_vc1d),
+ SETUP_FMT_TBL(FMT_AVSD , vpu2_default_dec),
+
+ SETUP_FMT_TBL(FMT_JPEGE , vpu2_default_enc),
+ SETUP_FMT_TBL(FMT_H264E , vpu2_default_enc),
+ SETUP_FMT_TBL(FMT_VP8E , vpu2_default_enc),
+};
+
+#endif
diff --git a/drivers/video/rk_vcodec/vcodec_iommu_drm.c b/drivers/video/rk_vcodec/vcodec_iommu_drm.c
new file mode 100755
index 0000000..0bc5100
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_iommu_drm.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ * author: Jung Zhao jung.zhao@rock-chips.com
+ * Randy Li, randy.li@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/dma-buf.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#if 0
+#include <drm/drm_sync_helper.h>
+#include <drm/rockchip_drm.h>
+#endif
+#include <linux/dma-mapping.h>
+#include <asm/dma-iommu.h>
+#include <linux/rockchip-iovmm.h>
+#include <linux/pm_runtime.h>
+#include <linux/memblock.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/component.h>
+#if 0
+#include <linux/fence.h>
+#endif
+#include <linux/iommu.h>
+#include <linux/console.h>
+#include <linux/kref.h>
+#include <linux/fdtable.h>
+#include <linux/ktime.h>
+#include <linux/iova.h>
+#include <linux/dma-iommu.h>
+
+#include "vcodec_iommu_ops.h"
+
+struct vcodec_drm_buffer {
+ struct list_head list;
+ struct dma_buf *dma_buf;
+ union {
+ unsigned long iova;
+ unsigned long phys;
+ };
+ void *cpu_addr;
+ unsigned long size;
+ int index;
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
+ struct sg_table *copy_sgt;
+ struct page **pages;
+ struct kref ref;
+ struct vcodec_iommu_session_info *session_info;
+ ktime_t last_used;
+};
+
+struct vcodec_iommu_drm_info {
+ struct iommu_domain *domain;
+ bool attached;
+};
+
+static struct vcodec_drm_buffer *
+vcodec_drm_get_buffer_no_lock(struct vcodec_iommu_session_info *session_info,
+ int idx)
+{
+ struct vcodec_drm_buffer *drm_buffer = NULL, *n;
+
+ list_for_each_entry_safe(drm_buffer, n, &session_info->buffer_list,
+ list) {
+ if (drm_buffer->index == idx) {
+ drm_buffer->last_used = ktime_get();
+ return drm_buffer;
+ }
+ }
+
+ return NULL;
+}
+
+static struct vcodec_drm_buffer *
+vcodec_drm_get_buffer_fd_no_lock(struct vcodec_iommu_session_info *session_info,
+ int fd)
+{
+ struct vcodec_drm_buffer *drm_buffer = NULL, *n;
+ struct dma_buf *dma_buf = NULL;
+
+ dma_buf = dma_buf_get(fd);
+
+ list_for_each_entry_safe(drm_buffer, n, &session_info->buffer_list,
+ list) {
+ if (drm_buffer->dma_buf == dma_buf) {
+ drm_buffer->last_used = ktime_get();
+ dma_buf_put(dma_buf);
+ return drm_buffer;
+ }
+ }
+
+ dma_buf_put(dma_buf);
+
+ return NULL;
+}
+
+static void vcodec_drm_detach(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_drm_info *drm_info = iommu_info->private;
+ struct device *dev = iommu_info->dev;
+ struct iommu_domain *domain = drm_info->domain;
+
+ mutex_lock(&iommu_info->iommu_mutex);
+
+ if (!drm_info->attached) {
+ mutex_unlock(&iommu_info->iommu_mutex);
+ return;
+ }
+
+ iommu_detach_device(domain, dev);
+ drm_info->attached = false;
+
+ mutex_unlock(&iommu_info->iommu_mutex);
+}
+
+static int vcodec_drm_attach_unlock(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_drm_info *drm_info = iommu_info->private;
+ struct device *dev = iommu_info->dev;
+ struct iommu_domain *domain = drm_info->domain;
+ int ret = 0;
+
+ ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
+ ret = iommu_attach_device(domain, dev);
+ if (ret) {
+ dev_err(dev, "Failed to attach iommu device\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int vcodec_drm_attach(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_drm_info *drm_info = iommu_info->private;
+ int ret;
+
+ mutex_lock(&iommu_info->iommu_mutex);
+
+ if (drm_info->attached) {
+ mutex_unlock(&iommu_info->iommu_mutex);
+ return 0;
+ }
+
+ ret = vcodec_drm_attach_unlock(iommu_info);
+ if (ret) {
+ mutex_unlock(&iommu_info->iommu_mutex);
+ return ret;
+ }
+
+ drm_info->attached = true;
+
+ mutex_unlock(&iommu_info->iommu_mutex);
+
+ return ret;
+}
+
+static void *vcodec_drm_sgt_map_kernel(struct vcodec_drm_buffer *drm_buffer)
+{
+ struct vcodec_iommu_session_info *session_info =
+ drm_buffer->session_info;
+ struct device *dev = session_info->dev;
+ struct scatterlist *sgl, *sg;
+ int nr_pages = PAGE_ALIGN(drm_buffer->size) >> PAGE_SHIFT;
+ int i = 0, j = 0, k = 0;
+ struct page *page;
+
+ drm_buffer->pages = kmalloc_array(nr_pages, sizeof(*drm_buffer->pages),
+ GFP_KERNEL);
+ if (!(drm_buffer->pages)) {
+ dev_err(dev, "drm map can not alloc pages\n");
+
+ return NULL;
+ }
+
+ sgl = drm_buffer->sgt->sgl;
+
+ for_each_sg(sgl, sg, drm_buffer->sgt->nents, i) {
+ page = sg_page(sg);
+ for (j = 0; j < sg->length / PAGE_SIZE; j++)
+ drm_buffer->pages[k++] = page++;
+ }
+
+ return vmap(drm_buffer->pages, nr_pages, VM_MAP,
+ pgprot_noncached(PAGE_KERNEL));
+}
+
+static void vcodec_drm_sgt_unmap_kernel(struct vcodec_drm_buffer *drm_buffer)
+{
+ vunmap(drm_buffer->cpu_addr);
+ kfree(drm_buffer->pages);
+}
+
+static int vcodec_finalise_sg(struct scatterlist *sg,
+ int nents,
+ dma_addr_t dma_addr)
+{
+ struct scatterlist *s, *cur = sg;
+ unsigned long seg_mask = DMA_BIT_MASK(32);
+ unsigned int cur_len = 0, max_len = DMA_BIT_MASK(32);
+ int i, count = 0;
+
+ for_each_sg(sg, s, nents, i) {
+ /* Restore this segment's original unaligned fields first */
+ unsigned int s_iova_off = sg_dma_address(s);
+ unsigned int s_length = sg_dma_len(s);
+ unsigned int s_iova_len = s->length;
+
+ s->offset += s_iova_off;
+ s->length = s_length;
+ sg_dma_address(s) = ARM_MAPPING_ERROR;
+ sg_dma_len(s) = 0;
+
+ /*
+ * Now fill in the real DMA data. If...
+ * - there is a valid output segment to append to
+ * - and this segment starts on an IOVA page boundary
+ * - but doesn't fall at a segment boundary
+ * - and wouldn't make the resulting output segment too long
+ */
+ if (cur_len && !s_iova_off && (dma_addr & seg_mask) &&
+ (cur_len + s_length <= max_len)) {
+ /* ...then concatenate it with the previous one */
+ cur_len += s_length;
+ } else {
+ /* Otherwise start the next output segment */
+ if (i > 0)
+ cur = sg_next(cur);
+ cur_len = s_length;
+ count++;
+
+ sg_dma_address(cur) = dma_addr + s_iova_off;
+ }
+
+ sg_dma_len(cur) = cur_len;
+ dma_addr += s_iova_len;
+
+ if (s_length + s_iova_off < s_iova_len)
+ cur_len = 0;
+ }
+ return count;
+}
+
+static void vcodec_invalidate_sg(struct scatterlist *sg, int nents)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ if (sg_dma_address(s) != ARM_MAPPING_ERROR)
+ s->offset += sg_dma_address(s);
+ if (sg_dma_len(s))
+ s->length = sg_dma_len(s);
+ sg_dma_address(s) = ARM_MAPPING_ERROR;
+ sg_dma_len(s) = 0;
+ }
+}
+
+static dma_addr_t vcodec_dma_map_sg(struct iommu_domain *domain,
+ struct scatterlist *sg,
+ int nents, int prot)
+{
+ struct iova_domain *iovad = domain->iova_cookie;
+ struct iova *iova;
+ struct scatterlist *s, *prev = NULL;
+ dma_addr_t dma_addr;
+ size_t iova_len = 0;
+ unsigned long mask = DMA_BIT_MASK(32);
+ unsigned long shift = iova_shift(iovad);
+ int i;
+
+ /*
+ * Work out how much IOVA space we need, and align the segments to
+ * IOVA granules for the IOMMU driver to handle. With some clever
+ * trickery we can modify the list in-place, but reversibly, by
+ * stashing the unaligned parts in the as-yet-unused DMA fields.
+ */
+ for_each_sg(sg, s, nents, i) {
+ size_t s_iova_off = iova_offset(iovad, s->offset);
+ size_t s_length = s->length;
+ size_t pad_len = (mask - iova_len + 1) & mask;
+
+ sg_dma_address(s) = s_iova_off;
+ sg_dma_len(s) = s_length;
+ s->offset -= s_iova_off;
+ s_length = iova_align(iovad, s_length + s_iova_off);
+ s->length = s_length;
+
+ /*
+ * Due to the alignment of our single IOVA allocation, we can
+ * depend on these assumptions about the segment boundary mask:
+ * - If mask size >= IOVA size, then the IOVA range cannot
+ * possibly fall across a boundary, so we don't care.
+ * - If mask size < IOVA size, then the IOVA range must start
+ * exactly on a boundary, therefore we can lay things out
+ * based purely on segment lengths without needing to know
+ * the actual addresses beforehand.
+ * - The mask must be a power of 2, so pad_len == 0 if
+ * iova_len == 0, thus we cannot dereference prev the first
+ * time through here (i.e. before it has a meaningful value).
+ */
+ if (pad_len && pad_len < s_length - 1) {
+ prev->length += pad_len;
+ iova_len += pad_len;
+ }
+
+ iova_len += s_length;
+ prev = s;
+ }
+
+ iova = alloc_iova(iovad, iova_align(iovad, iova_len) >> shift,
+ mask >> shift, true);
+ if (!iova)
+ goto out_restore_sg;
+
+ /*
+ * We'll leave any physical concatenation to the IOMMU driver's
+ * implementation - it knows better than we do.
+ */
+ dma_addr = iova_dma_addr(iovad, iova);
+ if (iommu_map_sg(domain, dma_addr, sg, nents, prot) < iova_len)
+ goto out_free_iova;
+
+ return vcodec_finalise_sg(sg, nents, dma_addr);
+
+out_free_iova:
+ __free_iova(iovad, iova);
+out_restore_sg:
+ vcodec_invalidate_sg(sg, nents);
+ return 0;
+}
+
+static void vcodec_dma_unmap_sg(struct iommu_domain *domain,
+ dma_addr_t dma_addr)
+{
+ struct iova_domain *iovad = domain->iova_cookie;
+ unsigned long shift = iova_shift(iovad);
+ unsigned long pfn = dma_addr >> shift;
+ struct iova *iova = find_iova(iovad, pfn);
+ size_t size;
+
+ if (WARN_ON(!iova))
+ return;
+
+ size = iova_size(iova) << shift;
+ size -= iommu_unmap(domain, pfn << shift, size);
+ /* ...and if we can't, then something is horribly, horribly wrong */
+ WARN_ON(size > 0);
+ __free_iova(iovad, iova);
+}
+
+static void vcodec_drm_clear_map(struct kref *ref)
+{
+ struct vcodec_drm_buffer *drm_buffer =
+ container_of(ref, struct vcodec_drm_buffer, ref);
+ struct vcodec_iommu_session_info *session_info =
+ drm_buffer->session_info;
+ struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
+ struct vcodec_iommu_drm_info *drm_info = iommu_info->private;
+
+ mutex_lock(&iommu_info->iommu_mutex);
+ drm_info = session_info->iommu_info->private;
+
+ if (drm_buffer->cpu_addr) {
+ vcodec_drm_sgt_unmap_kernel(drm_buffer);
+ drm_buffer->cpu_addr = NULL;
+ }
+
+ if (drm_buffer->attach) {
+ vcodec_dma_unmap_sg(drm_info->domain, drm_buffer->iova);
+ sg_free_table(drm_buffer->copy_sgt);
+ kfree(drm_buffer->copy_sgt);
+ dma_buf_unmap_attachment(drm_buffer->attach, drm_buffer->sgt,
+ DMA_BIDIRECTIONAL);
+ dma_buf_detach(drm_buffer->dma_buf, drm_buffer->attach);
+ dma_buf_put(drm_buffer->dma_buf);
+ drm_buffer->attach = NULL;
+ }
+
+ mutex_unlock(&iommu_info->iommu_mutex);
+}
+
+static void vcdoec_drm_dump_info(struct vcodec_iommu_session_info *session_info)
+{
+ struct vcodec_drm_buffer *drm_buffer = NULL, *n;
+
+ vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_OPS_DUMP,
+ "still there are below buffers stored in list\n");
+ list_for_each_entry_safe(drm_buffer, n, &session_info->buffer_list,
+ list) {
+ vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_OPS_DUMP,
+ "index %d drm_buffer dma_buf %p cpu_addr %p\n",
+ drm_buffer->index,
+ drm_buffer->dma_buf, drm_buffer->cpu_addr);
+ }
+}
+
+static int vcodec_drm_free(struct vcodec_iommu_session_info *session_info,
+ int idx)
+{
+ struct device *dev = session_info->dev;
+ /* please double-check all maps have been release */
+ struct vcodec_drm_buffer *drm_buffer;
+
+ mutex_lock(&session_info->list_mutex);
+ drm_buffer = vcodec_drm_get_buffer_no_lock(session_info, idx);
+
+ if (!drm_buffer) {
+ dev_err(dev, "can not find %d buffer in list\n", idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ return -EINVAL;
+ }
+
+ if (refcount_read(&drm_buffer->ref.refcount) == 0) {
+ dma_buf_put(drm_buffer->dma_buf);
+ list_del_init(&drm_buffer->list);
+ kfree(drm_buffer);
+ session_info->buffer_nums--;
+ vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_NORMAL,
+ "buffer nums %d\n", session_info->buffer_nums);
+ }
+ mutex_unlock(&session_info->list_mutex);
+
+ return 0;
+}
+
+static int
+vcodec_drm_unmap_iommu(struct vcodec_iommu_session_info *session_info,
+ int idx)
+{
+ struct device *dev = session_info->dev;
+ struct vcodec_drm_buffer *drm_buffer;
+
+ /* Force to flush iommu table */
+ if (of_machine_is_compatible("rockchip,rk3288"))
+ rockchip_iovmm_invalidate_tlb(session_info->mmu_dev);
+
+ mutex_lock(&session_info->list_mutex);
+ drm_buffer = vcodec_drm_get_buffer_no_lock(session_info, idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ if (!drm_buffer) {
+ dev_err(dev, "can not find %d buffer in list\n", idx);
+ return -EINVAL;
+ }
+
+ kref_put(&drm_buffer->ref, vcodec_drm_clear_map);
+
+ return 0;
+}
+
+static int vcodec_drm_map_iommu(struct vcodec_iommu_session_info *session_info,
+ int idx,
+ unsigned long *iova,
+ unsigned long *size)
+{
+ struct device *dev = session_info->dev;
+ struct vcodec_drm_buffer *drm_buffer;
+
+ /* Force to flush iommu table */
+ if (of_machine_is_compatible("rockchip,rk3288"))
+ rockchip_iovmm_invalidate_tlb(session_info->mmu_dev);
+
+ mutex_lock(&session_info->list_mutex);
+ drm_buffer = vcodec_drm_get_buffer_no_lock(session_info, idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ if (!drm_buffer) {
+ dev_err(dev, "can not find %d buffer in list\n", idx);
+ return -EINVAL;
+ }
+
+ kref_get(&drm_buffer->ref);
+ if (iova)
+ *iova = drm_buffer->iova;
+ if (size)
+ *size = drm_buffer->size;
+ return 0;
+}
+
+static int
+vcodec_drm_unmap_kernel(struct vcodec_iommu_session_info *session_info, int idx)
+{
+ struct device *dev = session_info->dev;
+ struct vcodec_drm_buffer *drm_buffer;
+
+ mutex_lock(&session_info->list_mutex);
+ drm_buffer = vcodec_drm_get_buffer_no_lock(session_info, idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ if (!drm_buffer) {
+ dev_err(dev, "can not find %d buffer in list\n", idx);
+
+ return -EINVAL;
+ }
+
+ if (drm_buffer->cpu_addr) {
+ vcodec_drm_sgt_unmap_kernel(drm_buffer);
+ drm_buffer->cpu_addr = NULL;
+ }
+
+ kref_put(&drm_buffer->ref, vcodec_drm_clear_map);
+ return 0;
+}
+
+static int
+vcodec_drm_free_fd(struct vcodec_iommu_session_info *session_info, int fd)
+{
+ struct device *dev = session_info->dev;
+ /* please double-check all maps have been release */
+ struct vcodec_drm_buffer *drm_buffer = NULL;
+
+ mutex_lock(&session_info->list_mutex);
+ drm_buffer = vcodec_drm_get_buffer_fd_no_lock(session_info, fd);
+
+ if (!drm_buffer) {
+ dev_err(dev, "can not find %d buffer in list\n", fd);
+ mutex_unlock(&session_info->list_mutex);
+
+ return -EINVAL;
+ }
+ mutex_unlock(&session_info->list_mutex);
+
+ vcodec_drm_unmap_iommu(session_info, drm_buffer->index);
+
+ mutex_lock(&session_info->list_mutex);
+ if (refcount_read(&drm_buffer->ref.refcount) == 0) {
+ dma_buf_put(drm_buffer->dma_buf);
+ list_del_init(&drm_buffer->list);
+ kfree(drm_buffer);
+ session_info->buffer_nums--;
+ vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_NORMAL,
+ "buffer nums %d\n", session_info->buffer_nums);
+ }
+ mutex_unlock(&session_info->list_mutex);
+
+ return 0;
+}
+
+static void
+vcodec_drm_clear_session(struct vcodec_iommu_session_info *session_info)
+{
+ struct vcodec_drm_buffer *drm_buffer = NULL, *n;
+
+ list_for_each_entry_safe(drm_buffer, n, &session_info->buffer_list,
+ list) {
+ kref_put(&drm_buffer->ref, vcodec_drm_clear_map);
+ vcodec_drm_free(session_info, drm_buffer->index);
+ }
+}
+
+static void *
+vcodec_drm_map_kernel(struct vcodec_iommu_session_info *session_info, int idx)
+{
+ struct device *dev = session_info->dev;
+ struct vcodec_drm_buffer *drm_buffer;
+
+ mutex_lock(&session_info->list_mutex);
+ drm_buffer = vcodec_drm_get_buffer_no_lock(session_info, idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ if (!drm_buffer) {
+ dev_err(dev, "can not find %d buffer in list\n", idx);
+ return NULL;
+ }
+
+ if (!drm_buffer->cpu_addr)
+ drm_buffer->cpu_addr =
+ vcodec_drm_sgt_map_kernel(drm_buffer);
+
+ kref_get(&drm_buffer->ref);
+
+ return drm_buffer->cpu_addr;
+}
+
+static int vcodec_drm_import(struct vcodec_iommu_session_info *session_info,
+ int fd)
+{
+ struct vcodec_drm_buffer *drm_buffer = NULL, *n;
+ struct vcodec_drm_buffer *oldest_buffer = NULL, *loop_buffer = NULL;
+ struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
+ struct vcodec_iommu_drm_info *drm_info = iommu_info->private;
+ struct device *dev = session_info->dev;
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
+ struct dma_buf *dma_buf;
+ ktime_t oldest_time = ktime_set(0, 0);
+ struct scatterlist *sg, *s;
+ int i;
+ int ret = 0;
+
+ dma_buf = dma_buf_get(fd);
+ if (IS_ERR(dma_buf)) {
+ ret = PTR_ERR(dma_buf);
+ return ret;
+ }
+
+ list_for_each_entry_safe(drm_buffer, n,
+ &session_info->buffer_list, list) {
+ if (drm_buffer->dma_buf == dma_buf) {
+ dma_buf_put(dma_buf);
+ drm_buffer->last_used = ktime_get();
+ return drm_buffer->index;
+ }
+ }
+
+ drm_buffer = kzalloc(sizeof(*drm_buffer), GFP_KERNEL);
+ if (!drm_buffer) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ drm_buffer->dma_buf = dma_buf;
+ drm_buffer->session_info = session_info;
+ drm_buffer->last_used = ktime_get();
+
+ kref_init(&drm_buffer->ref);
+
+ mutex_lock(&iommu_info->iommu_mutex);
+ drm_info = session_info->iommu_info->private;
+
+ attach = dma_buf_attach(drm_buffer->dma_buf, dev);
+ if (IS_ERR(attach)) {
+ ret = PTR_ERR(attach);
+ goto fail_out;
+ }
+
+ get_dma_buf(drm_buffer->dma_buf);
+
+ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sgt)) {
+ ret = PTR_ERR(sgt);
+ goto fail_detach;
+ }
+
+ /*
+ * Since we call dma_buf_map_attachment outside attach/detach, this
+ * will cause incorrectly map. we have to re-build map table native
+ * and for avoiding destroy their origin map table, we need use a
+ * copy one sg_table.
+ */
+ drm_buffer->copy_sgt = kmalloc(sizeof(*drm_buffer->copy_sgt),
+ GFP_KERNEL);
+ if (!drm_buffer->copy_sgt) {
+ ret = -ENOMEM;
+ goto fail_detach;
+ }
+
+ ret = sg_alloc_table(drm_buffer->copy_sgt, sgt->nents, GFP_KERNEL);
+ s = drm_buffer->copy_sgt->sgl;
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ sg_set_page(s, sg_page(sg),
+ PAGE_SIZE << compound_order(sg_page(sg)), 0);
+ sg_dma_address(s) = page_to_phys(sg_page(sg));
+ s->offset = sg->offset;
+ s->length = sg->length;
+ s = sg_next(s);
+ }
+
+ ret = vcodec_dma_map_sg(drm_info->domain, drm_buffer->copy_sgt->sgl,
+ drm_buffer->copy_sgt->nents,
+ IOMMU_READ | IOMMU_WRITE);
+ if (!ret) {
+ ret = -ENOMEM;
+ goto fail_alloc;
+ }
+ drm_buffer->iova = sg_dma_address(drm_buffer->copy_sgt->sgl);
+ drm_buffer->size = drm_buffer->dma_buf->size;
+
+ drm_buffer->attach = attach;
+ drm_buffer->sgt = sgt;
+
+ mutex_unlock(&iommu_info->iommu_mutex);
+
+ INIT_LIST_HEAD(&drm_buffer->list);
+ mutex_lock(&session_info->list_mutex);
+ session_info->buffer_nums++;
+ vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_NORMAL,
+ "buffer nums %d\n", session_info->buffer_nums);
+ if (session_info->buffer_nums > BUFFER_LIST_MAX_NUMS) {
+ list_for_each_entry_safe(loop_buffer, n,
+ &session_info->buffer_list, list) {
+ if (ktime_to_ns(oldest_time) == 0 ||
+ ktime_after(oldest_time,
+ loop_buffer->last_used)) {
+ oldest_time = loop_buffer->last_used;
+ oldest_buffer = loop_buffer;
+ }
+ }
+ kref_put(&oldest_buffer->ref, vcodec_drm_clear_map);
+ dma_buf_put(oldest_buffer->dma_buf);
+ list_del_init(&oldest_buffer->list);
+ kfree(oldest_buffer);
+ session_info->buffer_nums--;
+ }
+ drm_buffer->index = session_info->max_idx;
+ list_add_tail(&drm_buffer->list, &session_info->buffer_list);
+ session_info->max_idx++;
+ if ((session_info->max_idx & 0xfffffff) == 0)
+ session_info->max_idx = 0;
+ mutex_unlock(&session_info->list_mutex);
+
+ return drm_buffer->index;
+
+fail_alloc:
+ sg_free_table(drm_buffer->copy_sgt);
+ kfree(drm_buffer->copy_sgt);
+ dma_buf_unmap_attachment(attach, sgt,
+ DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(drm_buffer->dma_buf, attach);
+ dma_buf_put(drm_buffer->dma_buf);
+fail_out:
+ kfree(drm_buffer);
+ mutex_unlock(&iommu_info->iommu_mutex);
+
+ return ret;
+}
+
+static int vcodec_drm_create(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_drm_info *drm_info;
+ struct iommu_group *group;
+ int ret;
+
+ iommu_info->private = kzalloc(sizeof(*drm_info),
+ GFP_KERNEL);
+ drm_info = iommu_info->private;
+ if (!drm_info)
+ return -ENOMEM;
+
+ drm_info->domain = iommu_domain_alloc(&platform_bus_type);
+ drm_info->attached = false;
+ if (!drm_info->domain)
+ return -ENOMEM;
+#ifdef CONFIG_IOMMU_DMA
+ ret = iommu_get_dma_cookie(drm_info->domain);
+ if (ret)
+ goto err_free_domain;
+#else
+ {
+ unsigned long order, base_pfn, end_pfn;
+ dma_addr_t base;
+ u64 size;
+
+ base = 0x10000000;
+ size = SZ_2G;
+
+ order = __ffs(drm_info->domain->ops->pgsize_bitmap);
+ base_pfn = max_t(unsigned long, 1, base >> order);
+ end_pfn = (base + size - 1) >> order;
+
+ /* Check the domain allows at least some access to the device... */
+ if (drm_info->domain->geometry.force_aperture) {
+ if (base > drm_info->domain->geometry.aperture_end ||
+ base + size <= drm_info->domain->geometry.aperture_start) {
+ pr_warn("specified DMA range outside IOMMU capability\n");
+ return -EFAULT;
+ }
+ /* ...then finally give it a kicking to make sure it fits */
+ base_pfn = max_t(unsigned long, base_pfn,
+ drm_info->domain->geometry.aperture_start >> order);
+ end_pfn = min_t(unsigned long, end_pfn,
+ drm_info->domain->geometry.aperture_end >> order);
+ }
+ drm_info->domain->iova_cookie = kzalloc(sizeof(struct iova_domain), GFP_KERNEL);
+ init_iova_domain(drm_info->domain->iova_cookie, 1UL << order, base_pfn, end_pfn);
+ iova_cache_get();
+ }
+#endif
+ group = iommu_group_get(iommu_info->dev);
+ if (!group) {
+ group = iommu_group_alloc();
+ if (IS_ERR(group)) {
+ dev_err(iommu_info->dev,
+ "Failed to allocate IOMMU group\n");
+ goto err_put_cookie;
+ }
+ ret = iommu_group_add_device(group, iommu_info->dev);
+ if (ret) {
+ dev_err(iommu_info->dev,
+ "failed to add device to IOMMU group\n");
+ goto err_put_cookie;
+ }
+ }
+#ifdef CONFIG_IOMMU_DMA
+ iommu_dma_init_domain(drm_info->domain, 0x10000000, SZ_2G, iommu_info->dev);
+#endif
+ iommu_group_put(group);
+
+ return 0;
+
+err_put_cookie:
+#ifdef CONFIG_IOMMU_DMA
+ iommu_put_dma_cookie(drm_info->domain);
+#endif
+err_free_domain:
+ iommu_domain_free(drm_info->domain);
+
+ return ret;
+}
+
+static int vcodec_drm_destroy(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_drm_info *drm_info = iommu_info->private;
+#ifdef CONFIG_IOMMU_DMA
+ iommu_put_dma_cookie(drm_info->domain);
+#else
+ iova_cache_put();
+#endif
+ iommu_domain_free(drm_info->domain);
+
+ kfree(drm_info);
+ iommu_info->private = NULL;
+
+ return 0;
+}
+
+static struct vcodec_iommu_ops drm_ops = {
+ .create = vcodec_drm_create,
+ .import = vcodec_drm_import,
+ .free = vcodec_drm_free,
+ .free_fd = vcodec_drm_free_fd,
+ .map_kernel = vcodec_drm_map_kernel,
+ .unmap_kernel = vcodec_drm_unmap_kernel,
+ .map_iommu = vcodec_drm_map_iommu,
+ .unmap_iommu = vcodec_drm_unmap_iommu,
+ .destroy = vcodec_drm_destroy,
+ .dump = vcdoec_drm_dump_info,
+ .attach = vcodec_drm_attach,
+ .detach = vcodec_drm_detach,
+ .clear = vcodec_drm_clear_session,
+};
+
+void vcodec_iommu_drm_set_ops(struct vcodec_iommu_info *iommu_info)
+{
+ if (!iommu_info)
+ return;
+ iommu_info->ops = &drm_ops;
+}
diff --git a/drivers/video/rk_vcodec/vcodec_iommu_ion.c b/drivers/video/rk_vcodec/vcodec_iommu_ion.c
new file mode 100644
index 0000000..658e9d6
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_iommu_ion.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ * author: Jung Zhao jung.zhao@rock-chips.com
+ * Randy Li, randy.li@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/rockchip_ion.h>
+#include <linux/rockchip-iovmm.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/memblock.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/component.h>
+#include <linux/fence.h>
+#include <linux/console.h>
+#include <linux/kref.h>
+#include <linux/fdtable.h>
+
+#include "vcodec_iommu_ops.h"
+
+struct vcodec_ion_buffer {
+ struct list_head list;
+ struct ion_handle *handle;
+ int index;
+};
+
+struct vcodec_iommu_ion_info {
+ struct ion_client *ion_client;
+ bool attached;
+};
+
+static struct vcodec_ion_buffer *
+vcodec_ion_get_buffer_no_lock(struct vcodec_iommu_session_info *session_info,
+ int idx)
+{
+ struct vcodec_ion_buffer *ion_buffer = NULL, *n;
+
+ list_for_each_entry_safe(ion_buffer, n,
+ &session_info->buffer_list, list) {
+ if (ion_buffer->index == idx)
+ return ion_buffer;
+ }
+
+ return NULL;
+}
+
+static void
+vcodec_ion_clear_session(struct vcodec_iommu_session_info *session_info)
+{
+ /* do nothing */
+}
+
+static int vcodec_ion_attach(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
+ int ret;
+
+ mutex_lock(&iommu_info->iommu_mutex);
+
+ if (ion_info->attached) {
+ mutex_unlock(&iommu_info->iommu_mutex);
+ return 0;
+ }
+
+ rockchip_iovmm_activate(iommu_info->dev);
+
+ ion_info->attached = true;
+
+ mutex_unlock(&iommu_info->iommu_mutex);
+
+ return ret;
+}
+
+static void vcodec_ion_detach(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
+
+ mutex_lock(&iommu_info->iommu_mutex);
+
+ if (!ion_info->attached) {
+ mutex_unlock(&iommu_info->iommu_mutex);
+ return;
+ }
+
+ rockchip_iovmm_deactivate(iommu_info->dev);
+ ion_info->attached = false;
+
+ mutex_unlock(&iommu_info->iommu_mutex);
+}
+
+static int vcodec_ion_destroy(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
+
+ vcodec_ion_detach(iommu_info);
+ kfree(ion_info);
+ iommu_info->private = NULL;
+
+ return 0;
+}
+
+static int
+vcodec_ion_free(struct vcodec_iommu_session_info *session_info, int idx)
+{
+ struct vcodec_ion_buffer *ion_buffer;
+
+ mutex_lock(&session_info->list_mutex);
+ ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
+
+ if (!ion_buffer) {
+ mutex_unlock(&session_info->list_mutex);
+ pr_err("%s can not find %d buffer in list\n", __func__, idx);
+
+ return -EINVAL;
+ }
+
+ list_del_init(&ion_buffer->list);
+ mutex_unlock(&session_info->list_mutex);
+ kfree(ion_buffer);
+
+ return 0;
+}
+
+static int
+vcodec_ion_unmap_iommu(struct vcodec_iommu_session_info *session_info, int idx)
+{
+ struct vcodec_ion_buffer *ion_buffer;
+ struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
+ struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
+
+ mutex_lock(&session_info->list_mutex);
+ ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ if (!ion_buffer) {
+ pr_err("%s can not find %d buffer in list\n", __func__, idx);
+
+ return -EINVAL;
+ }
+
+ ion_free(ion_info->ion_client, ion_buffer->handle);
+
+ return 0;
+}
+
+static int
+vcodec_ion_map_iommu(struct vcodec_iommu_session_info *session_info, int idx,
+ unsigned long *iova, unsigned long *size)
+{
+ struct vcodec_ion_buffer *ion_buffer;
+ struct device *dev = session_info->dev;
+ struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
+ struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
+ int ret = 0;
+
+ /* Force to flush iommu table */
+ rockchip_iovmm_invalidate_tlb(session_info->dev);
+
+ mutex_lock(&session_info->list_mutex);
+ ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ if (!ion_buffer) {
+ pr_err("%s can not find %d buffer in list\n", __func__, idx);
+
+ return -EINVAL;
+ }
+
+ if (session_info->mmu_dev)
+ ret = ion_map_iommu(dev, ion_info->ion_client,
+ ion_buffer->handle, iova, size);
+ else
+ ret = ion_phys(ion_info->ion_client, ion_buffer->handle,
+ iova, (size_t *)size);
+
+ return ret;
+}
+
+static int
+vcodec_ion_unmap_kernel(struct vcodec_iommu_session_info *session_info,
+ int idx)
+{
+ struct vcodec_ion_buffer *ion_buffer;
+
+ mutex_lock(&session_info->list_mutex);
+ ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ if (!ion_buffer) {
+ pr_err("%s can not find %d buffer in list\n", __func__, idx);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void *
+vcodec_ion_map_kernel(struct vcodec_iommu_session_info *session_info, int idx)
+{
+ struct vcodec_ion_buffer *ion_buffer;
+ struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
+ struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
+
+ rockchip_iovmm_invalidate_tlb(session_info->dev);
+
+ mutex_lock(&session_info->list_mutex);
+ ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
+ mutex_unlock(&session_info->list_mutex);
+
+ if (!ion_buffer) {
+ pr_err("%s can not find %d buffer in list\n", __func__, idx);
+
+ return NULL;
+ }
+
+ return ion_map_kernel(ion_info->ion_client, ion_buffer->handle);
+}
+
+static int
+vcodec_ion_import(struct vcodec_iommu_session_info *session_info, int fd)
+{
+ struct vcodec_ion_buffer *ion_buffer = NULL;
+ struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
+ struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
+
+ ion_buffer = kzalloc(sizeof(*ion_buffer), GFP_KERNEL);
+ if (!ion_buffer)
+ return -ENOMEM;
+
+ ion_buffer->handle = ion_import_dma_buf(ion_info->ion_client, fd);
+
+ INIT_LIST_HEAD(&ion_buffer->list);
+ mutex_lock(&session_info->list_mutex);
+ ion_buffer->index = session_info->max_idx;
+ list_add_tail(&ion_buffer->list, &session_info->buffer_list);
+ session_info->max_idx++;
+ if ((session_info->max_idx & 0xfffffff) == 0)
+ session_info->max_idx = 0;
+ mutex_unlock(&session_info->list_mutex);
+
+ return ion_buffer->index;
+}
+
+static int vcodec_ion_create(struct vcodec_iommu_info *iommu_info)
+{
+ struct vcodec_iommu_ion_info *ion_info;
+
+ iommu_info->private = kmalloc(sizeof(*ion_info), GFP_KERNEL);
+
+ ion_info = iommu_info->private;
+ if (!ion_info)
+ return -ENOMEM;
+
+ ion_info->ion_client = rockchip_ion_client_create("vpu");
+ ion_info->attached = false;
+
+ vcodec_ion_attach(iommu_info);
+
+ return IS_ERR(ion_info->ion_client) ? -1 : 0;
+}
+
+static struct vcodec_iommu_ops ion_ops = {
+ .create = vcodec_ion_create,
+ .destroy = vcodec_ion_destroy,
+ .import = vcodec_ion_import,
+ .free = vcodec_ion_free,
+ .free_fd = NULL,
+ .map_kernel = vcodec_ion_map_kernel,
+ .unmap_kernel = vcodec_ion_unmap_kernel,
+ .map_iommu = vcodec_ion_map_iommu,
+ .unmap_iommu = vcodec_ion_unmap_iommu,
+ .dump = NULL,
+ .attach = vcodec_ion_attach,
+ .detach = vcodec_ion_detach,
+ .clear = vcodec_ion_clear_session,
+};
+
+/*
+ * we do not manage the ref number ourselves,
+ * since ion will help us to do that. what we
+ * need to do is just map/unmap and import/free
+ * every time
+ */
+void vcodec_iommu_ion_set_ops(struct vcodec_iommu_info *iommu_info)
+{
+ if (!iommu_info)
+ return;
+ iommu_info->ops = &ion_ops;
+}
diff --git a/drivers/video/rk_vcodec/vcodec_iommu_ops.c b/drivers/video/rk_vcodec/vcodec_iommu_ops.c
new file mode 100644
index 0000000..bb25db4
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_iommu_ops.c
@@ -0,0 +1,256 @@
+/**
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ * author: Jung Zhao jung.zhao@rock-chips.com
+ * Randy Li, randy.li@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+
+#include "vcodec_iommu_ops.h"
+
+static
+struct vcodec_iommu_session_info *vcodec_iommu_get_session_info
+ (struct vcodec_iommu_info *iommu_info, struct vpu_session *session)
+{
+ struct vcodec_iommu_session_info *session_info = NULL, *n;
+
+ list_for_each_entry_safe(session_info, n, &iommu_info->session_list,
+ head) {
+ if (session_info->session == session)
+ return session_info;
+ }
+
+ return NULL;
+}
+
+int vcodec_iommu_create(struct vcodec_iommu_info *iommu_info)
+{
+ if (!iommu_info || !iommu_info->ops->create)
+ return -EINVAL;
+
+ return iommu_info->ops->create(iommu_info);
+}
+
+int vcodec_iommu_import(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int fd)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ if (!iommu_info || !iommu_info->ops->import || !session)
+ return -EINVAL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+ if (!session_info) {
+ session_info = kzalloc(sizeof(*session_info), GFP_KERNEL);
+ if (!session_info)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&session_info->head);
+ INIT_LIST_HEAD(&session_info->buffer_list);
+ mutex_init(&session_info->list_mutex);
+ session_info->max_idx = 0;
+ session_info->session = session;
+ session_info->mmu_dev = iommu_info->mmu_dev;
+ session_info->dev = iommu_info->dev;
+ session_info->iommu_info = iommu_info;
+ session_info->buffer_nums = 0;
+ mutex_lock(&iommu_info->list_mutex);
+ list_add_tail(&session_info->head, &iommu_info->session_list);
+ mutex_unlock(&iommu_info->list_mutex);
+ }
+
+ session_info->debug_level = iommu_info->debug_level;
+
+ return iommu_info->ops->import(session_info, fd);
+}
+
+int vcodec_iommu_free(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int idx)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+
+ if (!iommu_info || !iommu_info->ops->free || !session_info)
+ return -EINVAL;
+
+ return iommu_info->ops->free(session_info, idx);
+}
+
+int vcodec_iommu_free_fd(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int fd)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+
+ if (!iommu_info || !iommu_info->ops->free_fd || !session_info)
+ return -EINVAL;
+
+ return iommu_info->ops->free_fd(session_info, fd);
+}
+
+void *vcodec_iommu_map_kernel(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int idx)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+
+ if (!iommu_info || !iommu_info->ops->map_kernel || !session_info)
+ return NULL;
+
+ return iommu_info->ops->map_kernel(session_info, idx);
+}
+
+int vcodec_iommu_unmap_kernel(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int idx)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+
+ if (!iommu_info || !iommu_info->ops->unmap_kernel || !session_info)
+ return -EINVAL;
+
+ return iommu_info->ops->unmap_kernel(session_info, idx);
+}
+
+int vcodec_iommu_map_iommu(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session,
+ int idx, unsigned long *iova,
+ unsigned long *size)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+
+ if (!iommu_info || !iommu_info->ops->map_iommu || !session_info)
+ return -EINVAL;
+
+ return iommu_info->ops->map_iommu(session_info, idx, iova, size);
+}
+
+int vcodec_iommu_unmap_iommu(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int idx)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+
+ if (!iommu_info || !iommu_info->ops->unmap_iommu || !session_info)
+ return -EINVAL;
+
+ return iommu_info->ops->unmap_iommu(session_info, idx);
+}
+
+int vcodec_iommu_destroy(struct vcodec_iommu_info *iommu_info)
+{
+ if (!iommu_info || !iommu_info->ops->destroy)
+ return -EINVAL;
+
+ return iommu_info->ops->destroy(iommu_info);
+}
+
+void vcodec_iommu_dump(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+
+ if (!iommu_info || !iommu_info->ops->dump || !session_info)
+ return;
+
+ iommu_info->ops->dump(session_info);
+}
+
+void vcodec_iommu_clear(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session)
+{
+ struct vcodec_iommu_session_info *session_info = NULL;
+
+ session_info = vcodec_iommu_get_session_info(iommu_info, session);
+
+ if (!iommu_info || !iommu_info->ops->clear || !session_info)
+ return;
+
+ iommu_info->ops->clear(session_info);
+
+ mutex_lock(&iommu_info->list_mutex);
+ list_del_init(&session_info->head);
+ kfree(session_info);
+ mutex_unlock(&iommu_info->list_mutex);
+}
+
+int vcodec_iommu_attach(struct vcodec_iommu_info *iommu_info)
+{
+ if (!iommu_info || !iommu_info->ops->attach)
+ return 0;
+
+ return iommu_info->ops->attach(iommu_info);
+}
+
+void vcodec_iommu_detach(struct vcodec_iommu_info *iommu_info)
+{
+ if (!iommu_info || !iommu_info->ops->detach)
+ return;
+
+ return iommu_info->ops->detach(iommu_info);
+}
+
+struct vcodec_iommu_info *
+vcodec_iommu_info_create(struct device *dev,
+ struct device *mmu_dev,
+ int alloc_type)
+{
+ struct vcodec_iommu_info *iommu_info = NULL;
+
+ iommu_info = kzalloc(sizeof(*iommu_info), GFP_KERNEL);
+ if (!iommu_info)
+ return NULL;
+
+ iommu_info->dev = dev;
+ INIT_LIST_HEAD(&iommu_info->session_list);
+ mutex_init(&iommu_info->list_mutex);
+ mutex_init(&iommu_info->iommu_mutex);
+ switch (alloc_type) {
+#ifdef CONFIG_DRM
+ case ALLOCATOR_USE_DRM:
+ vcodec_iommu_drm_set_ops(iommu_info);
+ break;
+#endif
+#ifdef CONFIG_ION
+ case ALLOCATOR_USE_ION:
+ vcodec_iommu_ion_set_ops(iommu_info);
+ break;
+#endif
+ default:
+ iommu_info->ops = NULL;
+ break;
+ }
+
+ iommu_info->mmu_dev = mmu_dev;
+
+ vcodec_iommu_create(iommu_info);
+
+ return iommu_info;
+}
+
+int vcodec_iommu_info_destroy(struct vcodec_iommu_info *iommu_info)
+{
+ vcodec_iommu_destroy(iommu_info);
+ kfree(iommu_info);
+
+ return 0;
+}
diff --git a/drivers/video/rk_vcodec/vcodec_iommu_ops.h b/drivers/video/rk_vcodec/vcodec_iommu_ops.h
new file mode 100644
index 0000000..807ad2f
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_iommu_ops.h
@@ -0,0 +1,132 @@
+/**
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ * author: Jung Zhao jung.zhao@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __VCODEC_IOMMU_OPS_H__
+#define __VCODEC_IOMMU_OPS_H__
+
+#include <linux/platform_device.h>
+#include "vcodec_service.h"
+
+#define BUFFER_LIST_MAX_NUMS 30
+
+#define ALLOCATOR_USE_ION 0x00000000
+#define ALLOCATOR_USE_DRM 0x00000001
+
+#define DEBUG_IOMMU_OPS_DUMP 0x00020000
+#define DEBUG_IOMMU_NORMAL 0x00040000
+
+#define vpu_iommu_debug_func(debug_level, type, fmt, args...) \
+ do { \
+ if (unlikely(debug_level & type)) { \
+ pr_info("%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } \
+ } while (0)
+#define vpu_iommu_debug(debug_level, type, fmt, args...) \
+ do { \
+ if (unlikely(debug_level & type)) { \
+ pr_info(fmt, ##args); \
+ } \
+ } while (0)
+
+struct vcodec_iommu_info;
+struct vcodec_iommu_session_info;
+
+struct vcodec_iommu_ops {
+ int (*create)(struct vcodec_iommu_info *iommu_info);
+ int (*import)(struct vcodec_iommu_session_info *session_info, int fd);
+ int (*free)(struct vcodec_iommu_session_info *session_info, int idx);
+ int (*free_fd)(struct vcodec_iommu_session_info *session_info, int fd);
+ void *(*map_kernel)(struct vcodec_iommu_session_info *session_info,
+ int idx);
+ int (*unmap_kernel)(struct vcodec_iommu_session_info *session_info,
+ int idx);
+ int (*map_iommu)(struct vcodec_iommu_session_info *session_info,
+ int idx,
+ unsigned long *iova, unsigned long *size);
+ int (*unmap_iommu)(struct vcodec_iommu_session_info *session_info,
+ int idx);
+ int (*destroy)(struct vcodec_iommu_info *iommu_info);
+ void (*dump)(struct vcodec_iommu_session_info *session_info);
+ int (*attach)(struct vcodec_iommu_info *iommu_info);
+ void (*detach)(struct vcodec_iommu_info *iommu_info);
+ void (*clear)(struct vcodec_iommu_session_info *session_info);
+};
+
+struct vcodec_iommu_session_info {
+ struct list_head head;
+ struct vpu_session *session;
+ int buffer_nums;
+ struct list_head buffer_list;
+ struct mutex list_mutex;
+ int max_idx;
+ struct device *dev;
+ struct device *mmu_dev;
+ struct vcodec_iommu_info *iommu_info;
+ int debug_level;
+};
+
+struct vcodec_iommu_info {
+ struct list_head session_list;
+ struct mutex list_mutex;
+ struct mutex iommu_mutex;
+ struct device *dev;
+ struct device *mmu_dev;
+ struct vcodec_iommu_ops *ops;
+ int debug_level;
+ void *private;
+};
+
+#ifdef CONFIG_DRM
+void vcodec_iommu_drm_set_ops(struct vcodec_iommu_info *iommu_info);
+#endif
+#ifdef CONFIG_ION
+void vcodec_iommu_ion_set_ops(struct vcodec_iommu_info *iommu_info);
+#endif
+
+struct vcodec_iommu_info *vcodec_iommu_info_create(struct device *dev,
+ struct device *mmu_dev,
+ int alloc_type);
+int vcodec_iommu_info_destroy(struct vcodec_iommu_info *iommu_info);
+
+int vcodec_iommu_create(struct vcodec_iommu_info *iommu_info);
+int vcodec_iommu_import(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int fd);
+int vcodec_iommu_free(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int idx);
+int vcodec_iommu_free_fd(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int fd);
+void *vcodec_iommu_map_kernel(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int idx);
+int vcodec_iommu_unmap_kernel(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session, int idx);
+int vcodec_iommu_map_iommu(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session,
+ int idx,
+ unsigned long *iova,
+ unsigned long *size);
+int vcodec_iommu_unmap_iommu(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session,
+ int idx);
+int vcodec_iommu_destroy(struct vcodec_iommu_info *iommu_info);
+void vcodec_iommu_dump(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session);
+void vcodec_iommu_clear(struct vcodec_iommu_info *iommu_info,
+ struct vpu_session *session);
+
+int vcodec_iommu_attach(struct vcodec_iommu_info *iommu_info);
+void vcodec_iommu_detach(struct vcodec_iommu_info *iommu_info);
+
+#endif
diff --git a/drivers/video/rk_vcodec/vcodec_service.c b/drivers/video/rk_vcodec/vcodec_service.c
new file mode 100755
index 0000000..9d44f12
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_service.c
@@ -0,0 +1,3058 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming, chm@rock-chips.com
+ * Alpha Lin, alpha.lin@rock-chips.com
+ * Jung Zhao, jung.zhao@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/compat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#ifdef CONFIG_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+#include <linux/cdev.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
+
+#include <linux/rockchip/cru.h>
+#include <linux/rockchip/pmu.h>
+#include <linux/rockchip/grf.h>
+
+#include <linux/dma-buf.h>
+#include <linux/rockchip-iovmm.h>
+
+#include "vcodec_hw_info.h"
+#include "vcodec_hw_vpu.h"
+#include "vcodec_hw_rkv.h"
+#include "vcodec_hw_vpu2.h"
+
+#include "vcodec_service.h"
+
+#include "vcodec_iommu_ops.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 DEBUG_TASK_INFO 0x00000200
+
+#define DEBUG_SET_REG 0x00001000
+#define DEBUG_GET_REG 0x00002000
+#define DEBUG_PPS_FILL 0x00004000
+#define DEBUG_IRQ_CHECK 0x00008000
+#define DEBUG_CACHE_32B 0x00010000
+
+#define PRINT_FUNCTION 0x80000000
+#define PRINT_LINE 0x40000000
+
+#define MHZ (1000 * 1000)
+#define SIZE_REG(reg) ((reg) * 4)
+
+#define VCODEC_CLOCK_ENABLE 1
+#define EXTRA_INFO_MAGIC 0x4C4A46
+
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "bit switch for vcodec_service debug information");
+/*
+ * hardware information organization
+ *
+ * In order to support multiple hardware with different version the hardware
+ * information is organized as follow:
+ *
+ * 1. First, index hardware by register size / position.
+ * These information is fix for each hardware and do not relate to runtime
+ * work flow. It only related to resource allocation.
+ * Descriptor: struct vpu_hw_info
+ *
+ * 2. Then, index hardware by runtime configuration
+ * These information is related to runtime setting behave including enable
+ * register, irq register and other key control flag
+ * Descriptor: struct vpu_task_info
+ *
+ * 3. Final, on iommu case the fd translation is required
+ * Descriptor: struct vpu_trans_info
+ */
+
+enum VPU_FREQ {
+ VPU_FREQ_200M,
+ VPU_FREQ_266M,
+ VPU_FREQ_300M,
+ VPU_FREQ_400M,
+ VPU_FREQ_500M,
+ VPU_FREQ_600M,
+ VPU_FREQ_DEFAULT,
+ VPU_FREQ_BUT,
+};
+
+struct extra_info_elem {
+ u32 index;
+ u32 offset;
+};
+
+
+struct extra_info_for_iommu {
+ u32 magic;
+ u32 cnt;
+ struct extra_info_elem elem[20];
+};
+
+static const struct vcodec_info vcodec_info_set[] = {
+ {
+ .hw_id = VPU_ID_8270,
+ .hw_info = &hw_vpu_8270,
+ .task_info = task_vpu,
+ .trans_info = trans_vpu,
+ },
+ {
+ .hw_id = VPU_ID_4831,
+ .hw_info = &hw_vpu_4831,
+ .task_info = task_vpu,
+ .trans_info = trans_vpu,
+ },
+ {
+ .hw_id = VPU_DEC_ID_9190,
+ .hw_info = &hw_vpu_9190,
+ .task_info = task_vpu,
+ .trans_info = trans_vpu,
+ },
+ {
+ .hw_id = HEVC_ID,
+ .hw_info = &hw_rkhevc,
+ .task_info = task_rkv,
+ .trans_info = trans_rkv,
+ },
+ {
+ .hw_id = RKV_DEC_ID,
+ .hw_info = &hw_rkvdec,
+ .task_info = task_rkv,
+ .trans_info = trans_rkv,
+ },
+ {
+ .hw_id = VPU2_ID,
+ .hw_info = &hw_vpu2,
+ .task_info = task_vpu2,
+ .trans_info = trans_vpu2,
+ },
+ {
+ .hw_id = RKV_DEC_ID2,
+ .hw_info = &hw_rkvdec,
+ .task_info = task_rkv,
+ .trans_info = trans_rkv,
+ },
+};
+
+/* Both VPU1 and VPU2 */
+static const struct vcodec_device_info vpu_device_info = {
+ .device_type = VCODEC_DEVICE_TYPE_VPUX,
+ .name = "vpu-service",
+};
+
+static const struct vcodec_device_info vpu_combo_device_info = {
+ .device_type = VCODEC_DEVICE_TYPE_VPUC,
+ .name = "vpu-combo",
+};
+
+static const struct vcodec_device_info hevc_device_info = {
+ .device_type = VCODEC_DEVICE_TYPE_HEVC,
+ .name = "hevc-service",
+};
+
+static const struct vcodec_device_info rkvd_device_info = {
+ .device_type = VCODEC_DEVICE_TYPE_RKVD,
+ .name = "rkvdec",
+};
+
+#define DEBUG
+#ifdef DEBUG
+#define vpu_debug_func(type, fmt, args...) \
+ do { \
+ 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_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)
+
+enum VPU_DEC_FMT {
+ VPU_DEC_FMT_H264,
+ VPU_DEC_FMT_MPEG4,
+ VPU_DEC_FMT_H263,
+ VPU_DEC_FMT_JPEG,
+ VPU_DEC_FMT_VC1,
+ VPU_DEC_FMT_MPEG2,
+ VPU_DEC_FMT_MPEG1,
+ VPU_DEC_FMT_VP6,
+ VPU_DEC_FMT_RESERV0,
+ VPU_DEC_FMT_VP7,
+ VPU_DEC_FMT_VP8,
+ VPU_DEC_FMT_AVS,
+ VPU_DEC_FMT_RES
+};
+
+/**
+ * struct for process session which connect to vpu
+ *
+ * @author ChenHengming (2011-5-3)
+ */
+struct vpu_session {
+ enum VPU_CLIENT_TYPE type;
+ /* a linked list of data so we can access them for debugging */
+ struct list_head list_session;
+ /* a linked list of register data waiting for process */
+ struct list_head waiting;
+ /* a linked list of register data in processing */
+ struct list_head running;
+ /* a linked list of register data processed */
+ struct list_head done;
+ wait_queue_head_t wait;
+ pid_t pid;
+ atomic_t task_running;
+};
+
+/**
+ * struct for process register set
+ *
+ * @author ChenHengming (2011-5-4)
+ */
+struct vpu_reg {
+ enum VPU_CLIENT_TYPE type;
+ enum VPU_FREQ freq;
+ struct vpu_session *session;
+ struct vpu_subdev_data *data;
+ struct vpu_task_info *task;
+ const struct vpu_trans_info *trans;
+
+ /* link to vpu service session */
+ struct list_head session_link;
+ /* link to register set list */
+ struct list_head status_link;
+
+ unsigned long size;
+ struct list_head mem_region_list;
+ u32 dec_base;
+ u32 *reg;
+};
+
+struct vpu_device {
+ atomic_t irq_count_codec;
+ atomic_t irq_count_pp;
+ unsigned int iosize;
+ u32 *regs;
+};
+
+enum vcodec_device_id {
+ VCODEC_DEVICE_ID_VPU,
+ VCODEC_DEVICE_ID_HEVC,
+ VCODEC_DEVICE_ID_COMBO,
+ VCODEC_DEVICE_ID_RKVDEC,
+ VCODEC_DEVICE_ID_BUTT
+};
+
+enum VCODEC_RUNNING_MODE {
+ VCODEC_RUNNING_MODE_NONE = -1,
+ VCODEC_RUNNING_MODE_VPU,
+ VCODEC_RUNNING_MODE_HEVC,
+ VCODEC_RUNNING_MODE_RKVDEC
+};
+
+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;
+ u32 reg_idx;
+ int hdl;
+};
+
+enum vpu_ctx_state {
+ MMU_ACTIVATED = BIT(0)
+};
+
+struct vpu_subdev_data {
+ struct cdev cdev;
+ dev_t dev_t;
+ struct class *cls;
+ struct device *child_dev;
+
+ int irq_enc;
+ int irq_dec;
+ struct vpu_service_info *pservice;
+
+ u32 *regs;
+ enum VCODEC_RUNNING_MODE mode;
+ struct list_head lnk_service;
+
+ struct device *dev;
+
+ struct vpu_device enc_dev;
+ struct vpu_device dec_dev;
+
+ enum VPU_HW_ID hw_id;
+ struct vpu_hw_info *hw_info;
+ struct vpu_task_info *task_info;
+ const struct vpu_trans_info *trans_info;
+
+ u32 reg_size;
+ unsigned long state;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_file_regs;
+#endif
+
+ struct device *mmu_dev;
+ struct vcodec_iommu_info *iommu_info;
+ struct work_struct set_work;
+};
+
+struct vpu_service_info {
+#ifdef CONFIG_WAKELOCK
+ struct wake_lock wake_lock;
+ struct wake_lock set_wake_lock;
+#endif
+
+ struct delayed_work power_off_work;
+ struct workqueue_struct *set_workq;
+ ktime_t last; /* record previous power-on time */
+ /* vpu service structure global lock */
+ struct mutex lock;
+ /* link to link_reg in struct vpu_reg */
+ struct list_head waiting;
+ /* link to link_reg in struct vpu_reg */
+ struct list_head running;
+ /* link to link_reg in struct vpu_reg */
+ struct list_head done;
+ /* link to list_session in struct vpu_session */
+ struct list_head session;
+ atomic_t total_running;
+ atomic_t enabled;
+ atomic_t power_on_cnt;
+ atomic_t power_off_cnt;
+ atomic_t service_on;
+ struct mutex shutdown_lock;
+ struct vpu_reg *reg_codec;
+ struct vpu_reg *reg_pproc;
+ struct vpu_reg *reg_resev;
+ struct vpu_dec_config dec_config;
+ struct vpu_enc_config enc_config;
+
+ bool auto_freq;
+ 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;
+
+#ifdef CONFIG_RESET_CONTROLLER
+ struct reset_control *rst_a;
+ struct reset_control *rst_h;
+ struct reset_control *rst_v;
+ struct reset_control *rst_niu_a;
+ struct reset_control *rst_niu_h;
+#endif
+ struct device *dev;
+
+ u32 irq_status;
+ atomic_t reset_request;
+ struct list_head mem_region_list;
+
+ enum vcodec_device_id dev_id;
+
+ enum VCODEC_RUNNING_MODE curr_mode;
+ u32 prev_mode;
+
+ struct delayed_work simulate_work;
+
+ u32 mode_bit;
+ u32 mode_ctrl;
+ u32 *reg_base;
+ u32 ioaddr;
+ struct regmap *grf;
+ u32 *grf_base;
+
+ char *name;
+
+ u32 subcnt;
+ struct list_head subdev_list;
+
+ u32 alloc_type;
+};
+
+struct vpu_request {
+ u32 *req;
+ u32 size;
+};
+
+#ifdef CONFIG_COMPAT
+struct compat_vpu_request {
+ compat_uptr_t req;
+ u32 size;
+};
+#endif
+
+#define VDPU_SOFT_RESET_REG 101
+#define VDPU_CLEAN_CACHE_REG 516
+#define VEPU_CLEAN_CACHE_REG 772
+#define HEVC_CLEAN_CACHE_REG 260
+
+#define VPU_REG_ENABLE(base, reg) writel_relaxed(1, base + reg)
+
+#define VDPU_SOFT_RESET(base) VPU_REG_ENABLE(base, VDPU_SOFT_RESET_REG)
+#define VDPU_CLEAN_CACHE(base) VPU_REG_ENABLE(base, VDPU_CLEAN_CACHE_REG)
+#define VEPU_CLEAN_CACHE(base) VPU_REG_ENABLE(base, VEPU_CLEAN_CACHE_REG)
+#define HEVC_CLEAN_CACHE(base) VPU_REG_ENABLE(base, HEVC_CLEAN_CACHE_REG)
+
+#define VPU_POWER_OFF_DELAY (4 * HZ) /* 4s */
+#define VPU_TIMEOUT_DELAY (2 * HZ) /* 2s */
+
+static void *vcodec_get_drv_data(struct platform_device *pdev);
+
+static void vpu_service_power_on(struct vpu_subdev_data *data,
+ struct vpu_service_info *pservice);
+
+static void time_record(struct vpu_task_info *task, int is_end)
+{
+ if (unlikely(debug & DEBUG_TIMING) && task)
+ do_gettimeofday((is_end) ? (&task->end) : (&task->start));
+}
+
+static void time_diff(struct vpu_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 inline int try_reset_assert(struct reset_control *rst)
+{
+ if (rst)
+ return reset_control_assert(rst);
+ return -EINVAL;
+}
+
+static inline int try_reset_deassert(struct reset_control *rst)
+{
+ if (rst)
+ return reset_control_deassert(rst);
+ return -EINVAL;
+}
+
+static inline int grf_combo_switch(const struct vpu_subdev_data *data)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ int bits;
+ u32 raw = 0;
+
+ bits = 1 << pservice->mode_bit;
+#ifdef CONFIG_MFD_SYSCON
+ if (pservice->grf) {
+ regmap_read(pservice->grf, pservice->mode_ctrl, &raw);
+
+ 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) {
+ u32 *grf_base = pservice->grf_base;
+
+ raw = readl_relaxed(grf_base + pservice->mode_ctrl / 4);
+ if (data->mode == VCODEC_RUNNING_MODE_HEVC)
+ writel_relaxed(raw | bits | (bits << 16),
+ grf_base + pservice->mode_ctrl / 4);
+ else
+ writel_relaxed((raw & (~bits)) | (bits << 16),
+ grf_base + pservice->mode_ctrl / 4);
+ } else {
+ vpu_err("no grf resource define, switch decoder failed\n");
+ return -EINVAL;
+ }
+#else
+ if (pservice->grf_base) {
+ u32 *grf_base = pservice->grf_base;
+
+ raw = readl_relaxed(grf_base + pservice->mode_ctrl / 4);
+ if (data->mode == VCODEC_RUNNING_MODE_HEVC)
+ writel_relaxed(raw | bits | (bits << 16),
+ grf_base + pservice->mode_ctrl / 4);
+ else
+ writel_relaxed((raw & (~bits)) | (bits << 16),
+ grf_base + pservice->mode_ctrl / 4);
+ } else {
+ vpu_err("no grf resource define, switch decoder failed\n");
+ return -EINVAL;
+ }
+#endif
+ return 0;
+}
+
+static void vcodec_enter_mode(struct vpu_subdev_data *data)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_subdev_data *subdata, *n;
+
+ if (pservice->subcnt < 2 || pservice->mode_ctrl == 0) {
+ if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
+ set_bit(MMU_ACTIVATED, &data->state);
+
+ if (atomic_read(&pservice->enabled)) {
+ if (vcodec_iommu_attach(data->iommu_info))
+ dev_err(data->dev,
+ "vcodec service attach failed\n"
+ );
+ else
+ /* Stop here is enough */
+ return;
+ }
+ }
+ return;
+ }
+
+ if (pservice->curr_mode == data->mode)
+ return;
+
+ vpu_debug(DEBUG_IOMMU, "vcodec enter mode %d\n", data->mode);
+ list_for_each_entry_safe(subdata, n,
+ &pservice->subdev_list, lnk_service) {
+ if (data != subdata && subdata->mmu_dev &&
+ test_bit(MMU_ACTIVATED, &subdata->state)) {
+ clear_bit(MMU_ACTIVATED, &subdata->state);
+ vcodec_iommu_detach(subdata->iommu_info);
+ }
+ }
+
+ /*
+ * For the RK3228H, it is not necessary to write a register to
+ * switch vpu combo mode, it is unsafe to write the grf.
+ */
+ if (pservice->mode_ctrl)
+ if (grf_combo_switch(data))
+ return;
+
+ if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
+ set_bit(MMU_ACTIVATED, &data->state);
+ if (atomic_read(&pservice->enabled))
+ vcodec_iommu_attach(data->iommu_info);
+ else
+ /* FIXME BUG_ON should not be used in mass produce */
+ BUG_ON(!atomic_read(&pservice->enabled));
+ }
+
+ pservice->prev_mode = pservice->curr_mode;
+ pservice->curr_mode = data->mode;
+}
+
+static void vcodec_exit_mode(struct vpu_subdev_data *data)
+{
+ /*
+ * In case of VPU Combo, it require HW switch its running mode
+ * before the other HW component start work. set current HW running
+ * mode to none, can ensure HW switch to its reqired mode properly.
+ */
+ data->pservice->curr_mode = VCODEC_RUNNING_MODE_NONE;
+}
+
+static int vpu_get_clk(struct vpu_service_info *pservice)
+{
+#if VCODEC_CLOCK_ENABLE
+ struct device *dev = pservice->dev;
+
+ switch (pservice->dev_id) {
+ case VCODEC_DEVICE_ID_HEVC:
+ /* We won't regard the power domain as clocks at 4.4 */
+ pservice->pd_video = devm_clk_get(dev, "pd_hevc");
+ if (IS_ERR(pservice->pd_video)) {
+ pservice->pd_video = NULL;
+ dev_dbg(dev, "failed on clk_get pd_hevc\n");
+ }
+ case VCODEC_DEVICE_ID_COMBO:
+ case VCODEC_DEVICE_ID_RKVDEC:
+ pservice->clk_cabac = devm_clk_get(dev, "clk_cabac");
+ if (IS_ERR(pservice->clk_cabac)) {
+ dev_err(dev, "failed on clk_get clk_cabac\n");
+ pservice->clk_cabac = NULL;
+ }
+ pservice->clk_core = devm_clk_get(dev, "clk_core");
+ if (IS_ERR(pservice->clk_core)) {
+ dev_err(dev, "failed on clk_get clk_core\n");
+ pservice->clk_core = NULL;
+ /* The VDPU and AVSD combo doesn't need those clocks */
+ if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC)
+ return -1;
+ }
+ case VCODEC_DEVICE_ID_VPU:
+ pservice->aclk_vcodec = devm_clk_get(dev, "aclk_vcodec");
+ if (IS_ERR(pservice->aclk_vcodec)) {
+ dev_err(dev, "failed on clk_get aclk_vcodec\n");
+ pservice->aclk_vcodec = NULL;
+ return -1;
+ }
+
+ pservice->hclk_vcodec = devm_clk_get(dev, "hclk_vcodec");
+ if (IS_ERR(pservice->hclk_vcodec)) {
+ dev_err(dev, "failed on clk_get hclk_vcodec\n");
+ pservice->hclk_vcodec = NULL;
+ return -1;
+ }
+ if (pservice->pd_video == NULL) {
+ pservice->pd_video = devm_clk_get(dev, "pd_video");
+ if (IS_ERR(pservice->pd_video)) {
+ pservice->pd_video = NULL;
+ dev_dbg(dev, "do not have pd_video\n");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+#else
+ return 0;
+#endif
+}
+
+static void _vpu_reset(struct vpu_subdev_data *data)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ unsigned long rate = 0;
+
+ dev_info(pservice->dev, "resetting...\n");
+ 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;
+
+#ifdef CONFIG_RESET_CONTROLLER
+ rockchip_pmu_set_idle_request(pservice->dev, true);
+
+ rate = clk_get_rate(pservice->aclk_vcodec);
+ /*
+ * Some old platforms can't run at 300MHZ, they don't request
+ * decrease the frequency at resetting either. It is safe to
+ * keep here in 200 MHZ.
+ */
+ clk_set_rate(pservice->aclk_vcodec, 200 * MHZ);
+
+ try_reset_assert(pservice->rst_niu_a);
+ try_reset_assert(pservice->rst_niu_h);
+ try_reset_assert(pservice->rst_v);
+ try_reset_assert(pservice->rst_a);
+ try_reset_assert(pservice->rst_h);
+ udelay(5);
+
+ try_reset_deassert(pservice->rst_h);
+ try_reset_deassert(pservice->rst_a);
+ try_reset_deassert(pservice->rst_v);
+ try_reset_deassert(pservice->rst_niu_h);
+ try_reset_deassert(pservice->rst_niu_a);
+
+#if 0
+ rockchip_pmu_set_idle_request(pservice->dev, false);
+#endif
+ clk_set_rate(pservice->aclk_vcodec, rate);
+ dev_info(pservice->dev, "reset done\n");
+#endif
+}
+
+static void vpu_reset(struct vpu_subdev_data *data)
+{
+ struct vpu_service_info *pservice = data->pservice;
+
+ _vpu_reset(data);
+ if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
+ clear_bit(MMU_ACTIVATED, &data->state);
+ if (atomic_read(&pservice->enabled)) {
+ /* Need to reset iommu */
+ vcodec_iommu_detach(data->iommu_info);
+ } else {
+ /* FIXME BUG_ON should not be used in mass produce */
+ BUG_ON(!atomic_read(&pservice->enabled));
+ }
+ }
+
+ atomic_set(&pservice->reset_request, 0);
+ dev_info(pservice->dev, "reset done\n");
+}
+
+static void reg_deinit(struct vpu_subdev_data *data, struct vpu_reg *reg);
+static void vpu_service_session_clear(struct vpu_subdev_data *data,
+ struct vpu_session *session)
+{
+ struct vpu_reg *reg, *n;
+
+ list_for_each_entry_safe(reg, n, &session->waiting, session_link) {
+ reg_deinit(data, reg);
+ }
+ list_for_each_entry_safe(reg, n, &session->running, session_link) {
+ reg_deinit(data, reg);
+ }
+ list_for_each_entry_safe(reg, n, &session->done, session_link) {
+ reg_deinit(data, reg);
+ }
+}
+
+static void vpu_service_clear(struct vpu_subdev_data *data)
+{
+ struct vpu_reg *reg, *n;
+ struct vpu_session *session, *s;
+ struct vpu_service_info *pservice = data->pservice;
+
+ list_for_each_entry_safe(reg, n, &pservice->waiting, status_link) {
+ reg_deinit(reg->data, reg);
+ }
+
+ /* wake up session wait event to prevent the timeout hw reset
+ * during reboot procedure.
+ */
+ list_for_each_entry_safe(session, s,
+ &pservice->session, list_session)
+ wake_up(&session->wait);
+}
+
+static void vpu_service_dump(struct vpu_service_info *pservice)
+{
+}
+
+
+static void vpu_service_power_off(struct vpu_service_info *pservice)
+{
+ int total_running;
+ struct vpu_subdev_data *data = NULL, *n;
+ int ret = atomic_add_unless(&pservice->enabled, -1, 0);
+
+ if (!ret)
+ return;
+
+ 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);
+ }
+
+ dev_dbg(pservice->dev, "power off...\n");
+
+ udelay(5);
+
+ list_for_each_entry_safe(data, n, &pservice->subdev_list, lnk_service) {
+ if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
+ clear_bit(MMU_ACTIVATED, &data->state);
+ vcodec_iommu_detach(data->iommu_info);
+ }
+ }
+ pservice->curr_mode = VCODEC_RUNNING_MODE_NONE;
+ pm_runtime_put(pservice->dev);
+#if VCODEC_CLOCK_ENABLE
+ 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->clk_core)
+ clk_disable_unprepare(pservice->clk_core);
+ if (pservice->clk_cabac)
+ clk_disable_unprepare(pservice->clk_cabac);
+#endif
+
+ atomic_add(1, &pservice->power_off_cnt);
+#ifdef CONFIG_WAKELOCK
+ wake_unlock(&pservice->wake_lock);
+#endif
+ dev_dbg(pservice->dev, "power off done\n");
+}
+
+static inline void vpu_queue_power_off_work(struct vpu_service_info *pservice)
+{
+ queue_delayed_work(system_wq, &pservice->power_off_work,
+ VPU_POWER_OFF_DELAY);
+}
+
+static void vpu_power_off_work(struct work_struct *work_s)
+{
+ struct delayed_work *dlwork = container_of(work_s,
+ struct delayed_work, work);
+ struct vpu_service_info *pservice = container_of(dlwork,
+ struct vpu_service_info, power_off_work);
+
+ if (mutex_trylock(&pservice->lock)) {
+ vpu_service_power_off(pservice);
+ mutex_unlock(&pservice->lock);
+ } else {
+ /* Come back later if the device is busy... */
+ vpu_queue_power_off_work(pservice);
+ }
+}
+
+static void vpu_service_power_on(struct vpu_subdev_data *data,
+ struct vpu_service_info *pservice)
+{
+ int ret;
+ ktime_t now = ktime_get();
+
+ if (ktime_to_ns(ktime_sub(now, pservice->last)) > NSEC_PER_SEC ||
+ atomic_read(&pservice->power_on_cnt)) {
+ /* NSEC_PER_SEC */
+ cancel_delayed_work_sync(&pservice->power_off_work);
+ vpu_queue_power_off_work(pservice);
+ pservice->last = now;
+ }
+ ret = atomic_add_unless(&pservice->enabled, 1, 1);
+ if (!ret)
+ return;
+
+ dev_dbg(pservice->dev, "power on\n");
+
+#define BIT_VCODEC_CLK_SEL (1<<10)
+ if (of_machine_is_compatible("rockchip,rk3126"))
+ writel_relaxed(readl_relaxed(RK_GRF_VIRT + RK312X_GRF_SOC_CON1)
+ | BIT_VCODEC_CLK_SEL | (BIT_VCODEC_CLK_SEL << 16),
+ RK_GRF_VIRT + RK312X_GRF_SOC_CON1);
+#if VCODEC_CLOCK_ENABLE
+ if (pservice->aclk_vcodec)
+ clk_prepare_enable(pservice->aclk_vcodec);
+ if (pservice->hclk_vcodec)
+ clk_prepare_enable(pservice->hclk_vcodec);
+ if (pservice->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
+ pm_runtime_get_sync(pservice->dev);
+
+ udelay(5);
+ atomic_add(1, &pservice->power_on_cnt);
+#ifdef CONFIG_WAKELOCK
+ wake_lock(&pservice->wake_lock);
+#endif
+}
+
+static inline bool reg_check_interlace(struct vpu_reg *reg)
+{
+ u32 type = (reg->reg[3] & (1 << 23));
+
+ return (type > 0);
+}
+
+static inline enum VPU_DEC_FMT reg_check_fmt(struct vpu_reg *reg)
+{
+ enum VPU_DEC_FMT type = (enum VPU_DEC_FMT)((reg->reg[3] >> 28) & 0xf);
+
+ return type;
+}
+
+static inline int reg_probe_width(struct vpu_reg *reg)
+{
+ int width_in_mb = reg->reg[4] >> 23;
+
+ return width_in_mb * 16;
+}
+
+static inline int reg_probe_hevc_y_stride(struct vpu_reg *reg)
+{
+ int y_virstride = reg->reg[8];
+
+ return y_virstride;
+}
+
+static int vcodec_fd_to_iova(struct vpu_subdev_data *data,
+ struct vpu_session *session,
+ struct vpu_reg *reg,
+ int fd)
+{
+ int hdl;
+ int ret = 0;
+ struct vcodec_mem_region *mem_region;
+
+ hdl = vcodec_iommu_import(data->iommu_info, session, fd);
+ if (hdl < 0)
+ return hdl;
+
+ mem_region = kzalloc(sizeof(*mem_region), GFP_KERNEL);
+ if (mem_region == NULL) {
+ vpu_err("allocate memory for iommu memory region failed\n");
+ vcodec_iommu_free(data->iommu_info, session, hdl);
+ return -ENOMEM;
+ }
+
+ mem_region->hdl = hdl;
+ ret = vcodec_iommu_map_iommu(data->iommu_info, session, mem_region->hdl,
+ &mem_region->iova, &mem_region->len);
+ if (ret < 0) {
+ vpu_err("fd %d ion map iommu failed\n", fd);
+ kfree(mem_region);
+ vcodec_iommu_free(data->iommu_info, session, hdl);
+
+ return -EFAULT;
+ }
+ INIT_LIST_HEAD(&mem_region->reg_lnk);
+ list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);
+ return mem_region->iova;
+}
+
+/*
+ * NOTE: rkvdec/rkhevc put scaling list address in pps buffer hardware will read
+ * it by pps id in video stream data.
+ *
+ * So we need to translate the address in iommu case. The address data is also
+ * 10bit fd + 22bit offset mode.
+ * Because userspace decoder do not give the pps id in the register file sets
+ * kernel driver need to translate each scaling list address in pps buffer which
+ * means 256 pps for H.264, 64 pps for H.265.
+ *
+ * In order to optimize the performance kernel driver ask userspace decoder to
+ * set all scaling list address in pps buffer to the same one which will be used
+ * on current decoding task. Then kernel driver can only translate the first
+ * address then copy it all pps buffer.
+ */
+static int fill_scaling_list_addr_in_pps(
+ struct vpu_subdev_data *data,
+ struct vpu_reg *reg,
+ char *pps,
+ int pps_info_count,
+ int pps_info_size,
+ int scaling_list_addr_offset)
+{
+ int base = scaling_list_addr_offset;
+ int scaling_fd = 0;
+ u32 scaling_offset;
+
+ scaling_offset = (u32)pps[base + 0];
+ scaling_offset += (u32)pps[base + 1] << 8;
+ scaling_offset += (u32)pps[base + 2] << 16;
+ scaling_offset += (u32)pps[base + 3] << 24;
+
+ scaling_fd = scaling_offset & 0x3ff;
+ scaling_offset = scaling_offset >> 10;
+
+ if (scaling_fd > 0) {
+ int i = 0;
+ u32 tmp = vcodec_fd_to_iova(data, reg->session, reg,
+ scaling_fd);
+
+ if (IS_ERR_VALUE(tmp))
+ return -1;
+ tmp += scaling_offset;
+
+ for (i = 0; i < pps_info_count; i++, base += pps_info_size) {
+ pps[base + 0] = (tmp >> 0) & 0xff;
+ pps[base + 1] = (tmp >> 8) & 0xff;
+ pps[base + 2] = (tmp >> 16) & 0xff;
+ pps[base + 3] = (tmp >> 24) & 0xff;
+ }
+ }
+
+ return 0;
+}
+
+static int vcodec_bufid_to_iova(struct vpu_subdev_data *data,
+ struct vpu_session *session,
+ const u8 *tbl,
+ int size, struct vpu_reg *reg,
+ struct extra_info_for_iommu *ext_inf)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_task_info *task = reg->task;
+ enum FORMAT_TYPE type;
+ int hdl;
+ int ret = 0;
+ struct vcodec_mem_region *mem_region;
+ int i;
+ int offset = 0;
+
+ if (tbl == NULL || size <= 0) {
+ dev_err(pservice->dev, "input arguments invalidate\n");
+ return -EINVAL;
+ }
+
+ if (task->get_fmt)
+ type = task->get_fmt(reg->reg);
+ else {
+ dev_err(pservice->dev, "invalid task with NULL get_fmt\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i++) {
+ int usr_fd = reg->reg[tbl[i]] & 0x3FF;
+
+ /* if userspace do not set the fd at this register, skip */
+ if (usr_fd == 0)
+ continue;
+
+ /*
+ * for avoiding cache sync issue, we need to map/unmap
+ * input buffer every time. FIX ME, if it is unnecessary
+ */
+ if (task->reg_rlc == tbl[i])
+ vcodec_iommu_free_fd(data->iommu_info, session, usr_fd);
+ /*
+ * special offset scale case
+ *
+ * This translation is for fd + offset translation.
+ * One register has 32bits. We need to transfer both buffer file
+ * handle and the start address offset so we packet file handle
+ * and offset together using below format.
+ *
+ * 0~9 bit for buffer file handle range 0 ~ 1023
+ * 10~31 bit for offset range 0 ~ 4M
+ *
+ * But on 4K case the offset can be larger the 4M
+ * So on H.264 4K vpu/vpu2 decoder we scale the offset by 16
+ * But MPEG4 will use the same register for colmv and it do not
+ * need scale.
+ *
+ * RKVdec do not have this issue.
+ */
+ if ((type == FMT_H264D || type == FMT_VP9D) &&
+ task->reg_dir_mv > 0 && task->reg_dir_mv == tbl[i])
+ offset = reg->reg[tbl[i]] >> 10 << 4;
+ else
+ offset = reg->reg[tbl[i]] >> 10;
+
+ vpu_debug(DEBUG_IOMMU, "pos %3d fd %3d offset %10d i %d\n",
+ tbl[i], usr_fd, offset, i);
+
+ hdl = vcodec_iommu_import(data->iommu_info, session, usr_fd);
+
+ if (task->reg_pps > 0 && task->reg_pps == tbl[i]) {
+ int pps_info_offset;
+ int pps_info_count;
+ int pps_info_size;
+ int scaling_list_addr_offset;
+
+ switch (type) {
+ case FMT_H264D: {
+ pps_info_offset = offset;
+ pps_info_count = 256;
+ pps_info_size = 32;
+ scaling_list_addr_offset = 23;
+ } break;
+ case FMT_H265D: {
+ pps_info_offset = 0;
+ pps_info_count = 64;
+ pps_info_size = 80;
+ scaling_list_addr_offset = 74;
+ } break;
+ default: {
+ pps_info_offset = 0;
+ pps_info_count = 0;
+ pps_info_size = 0;
+ scaling_list_addr_offset = 0;
+ } break;
+ }
+
+ vpu_debug(DEBUG_PPS_FILL,
+ "scaling list filling parameter:\n");
+ vpu_debug(DEBUG_PPS_FILL,
+ "pps_info_offset %d\n", pps_info_offset);
+ vpu_debug(DEBUG_PPS_FILL,
+ "pps_info_count %d\n", pps_info_count);
+ vpu_debug(DEBUG_PPS_FILL,
+ "pps_info_size %d\n", pps_info_size);
+ vpu_debug(DEBUG_PPS_FILL,
+ "scaling_list_addr_offset %d\n",
+ scaling_list_addr_offset);
+
+ if (pps_info_count) {
+ u8 *pps;
+
+ pps = vcodec_iommu_map_kernel
+ (data->iommu_info, session, hdl);
+
+ vpu_debug(DEBUG_PPS_FILL,
+ "scaling list setting pps %p\n", pps);
+ pps += pps_info_offset;
+
+ fill_scaling_list_addr_in_pps
+ (data, reg, pps, pps_info_count,
+ pps_info_size,
+ scaling_list_addr_offset);
+
+ vcodec_iommu_unmap_kernel
+ (data->iommu_info, session, hdl);
+ }
+ }
+
+ mem_region = kzalloc(sizeof(*mem_region), GFP_KERNEL);
+
+ if (!mem_region) {
+ vcodec_iommu_free(data->iommu_info, session, hdl);
+ return -ENOMEM;
+ }
+
+ mem_region->hdl = hdl;
+ mem_region->reg_idx = tbl[i];
+
+ ret = vcodec_iommu_map_iommu(data->iommu_info, session,
+ mem_region->hdl, &mem_region->iova,
+ &mem_region->len);
+ if (ret < 0) {
+ dev_err(pservice->dev,
+ "reg %d fd %d ion map iommu failed\n",
+ tbl[i], usr_fd);
+ kfree(mem_region);
+ vcodec_iommu_free(data->iommu_info, session, 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 (task->reg_len > 0 && task->reg_len == tbl[i]) {
+ 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, &reg->mem_region_list);
+ }
+
+ if (ext_inf != NULL && ext_inf->magic == EXTRA_INFO_MAGIC) {
+ for (i = 0; i < ext_inf->cnt; i++) {
+ 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] +=
+ ext_inf->elem[i].offset;
+ }
+ }
+
+ return 0;
+}
+
+static int vcodec_reg_address_translate(struct vpu_subdev_data *data,
+ struct vpu_session *session,
+ struct vpu_reg *reg,
+ struct extra_info_for_iommu *ext_inf)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ enum FORMAT_TYPE type = reg->task->get_fmt(reg->reg);
+
+ if (type < FMT_TYPE_BUTT) {
+ const struct vpu_trans_info *info = &reg->trans[type];
+ const u8 *tbl = info->table;
+ int size = info->count;
+
+ return vcodec_bufid_to_iova(data, session, tbl, size, reg,
+ ext_inf);
+ }
+
+ dev_err(pservice->dev, "found invalid format type!\n");
+ return -EINVAL;
+}
+
+static void get_reg_freq(struct vpu_subdev_data *data, struct vpu_reg *reg)
+{
+
+ if (!of_machine_is_compatible("rockchip,rk2928g")) {
+ if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {
+ if (reg_check_fmt(reg) == VPU_DEC_FMT_H264) {
+ if (reg_probe_width(reg) > 3200) {
+ /*raise frequency for 4k avc.*/
+ reg->freq = VPU_FREQ_600M;
+ }
+ } else {
+ if (reg_check_interlace(reg))
+ reg->freq = VPU_FREQ_400M;
+ }
+ }
+ if (data->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;
+ }
+}
+
+static struct vpu_reg *reg_init(struct vpu_subdev_data *data,
+ struct vpu_session *session,
+ void __user *src, u32 size)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ int extra_size = 0;
+ struct extra_info_for_iommu extra_info;
+ struct vpu_reg *reg = kzalloc(sizeof(*reg) + data->reg_size,
+ GFP_KERNEL);
+
+ vpu_debug_enter();
+
+ if (!reg) {
+ vpu_err("error: kzalloc failed\n");
+ return NULL;
+ }
+
+ if (size > data->reg_size) {
+ extra_size = size - data->reg_size;
+ size = data->reg_size;
+ }
+ reg->session = session;
+ reg->data = data;
+ reg->type = session->type;
+ reg->size = size;
+ reg->freq = VPU_FREQ_DEFAULT;
+ reg->task = &data->task_info[session->type];
+ reg->trans = data->trans_info;
+ reg->reg = (u32 *)&reg[1];
+ INIT_LIST_HEAD(&reg->session_link);
+ INIT_LIST_HEAD(&reg->status_link);
+
+ INIT_LIST_HEAD(&reg->mem_region_list);
+
+ if (copy_from_user(&reg->reg[0], (void __user *)src, size)) {
+ vpu_err("error: copy_from_user failed\n");
+ kfree(reg);
+ return NULL;
+ }
+
+ if (copy_from_user(&extra_info, (u8 *)src + size, extra_size)) {
+ vpu_err("error: copy_from_user failed\n");
+ kfree(reg);
+ return NULL;
+ }
+
+ if (vcodec_reg_address_translate(data, session, reg, &extra_info) < 0) {
+ int i = 0;
+
+ vpu_err("error: translate reg address failed, dumping regs\n");
+ for (i = 0; i < size >> 2; i++)
+ dev_err(pservice->dev, "reg[%02d]: %08x\n",
+ i, *((u32 *)src + i));
+
+ kfree(reg);
+ return NULL;
+ }
+
+ mutex_lock(&pservice->lock);
+ list_add_tail(&reg->status_link, &pservice->waiting);
+ list_add_tail(&reg->session_link, &session->waiting);
+ mutex_unlock(&pservice->lock);
+
+ if (pservice->auto_freq)
+ get_reg_freq(data, reg);
+
+ vpu_debug_leave();
+
+ return reg;
+}
+
+static void reg_deinit(struct vpu_subdev_data *data, struct vpu_reg *reg)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ struct vcodec_mem_region *mem_region = NULL, *n;
+
+ list_del_init(&reg->session_link);
+ list_del_init(&reg->status_link);
+ if (reg == pservice->reg_codec)
+ pservice->reg_codec = NULL;
+ if (reg == pservice->reg_pproc)
+ pservice->reg_pproc = NULL;
+
+ /* release memory region attach to this registers table. */
+ list_for_each_entry_safe(mem_region, n,
+ &reg->mem_region_list, reg_lnk) {
+ vcodec_iommu_unmap_iommu(data->iommu_info, reg->session,
+ mem_region->hdl);
+ vcodec_iommu_free(data->iommu_info, reg->session,
+ mem_region->hdl);
+ list_del_init(&mem_region->reg_lnk);
+ kfree(mem_region);
+ }
+
+ kfree(reg);
+}
+
+static void reg_from_wait_to_run(struct vpu_service_info *pservice,
+ struct vpu_reg *reg)
+{
+ vpu_debug_enter();
+ list_del_init(&reg->status_link);
+ list_add_tail(&reg->status_link, &pservice->running);
+
+ list_del_init(&reg->session_link);
+ list_add_tail(&reg->session_link, &reg->session->running);
+ vpu_debug_leave();
+}
+
+static void reg_copy_from_hw(struct vpu_reg *reg, u32 *src, u32 count)
+{
+ int i;
+ u32 *dst = reg->reg;
+
+ vpu_debug_enter();
+ for (i = 0; i < count; i++, src++)
+ *dst++ = readl_relaxed(src);
+
+ dst = (u32 *)&reg->reg[0];
+ for (i = 0; i < count; i++)
+ vpu_debug(DEBUG_GET_REG, "get reg[%02d] %08x\n", i, dst[i]);
+
+ vpu_debug_leave();
+}
+
+static void reg_from_run_to_done(struct vpu_subdev_data *data,
+ struct vpu_reg *reg)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_hw_info *hw_info = data->hw_info;
+ struct vpu_task_info *task = reg->task;
+
+ vpu_debug_enter();
+
+ list_del_init(&reg->status_link);
+ list_add_tail(&reg->status_link, &pservice->done);
+
+ list_del_init(&reg->session_link);
+ list_add_tail(&reg->session_link, &reg->session->done);
+
+ switch (reg->type) {
+ case VPU_ENC: {
+ pservice->reg_codec = NULL;
+ reg_copy_from_hw(reg, data->enc_dev.regs, hw_info->enc_reg_num);
+ reg->reg[task->reg_irq] = pservice->irq_status;
+ } break;
+ case VPU_DEC: {
+ pservice->reg_codec = NULL;
+ reg_copy_from_hw(reg, data->dec_dev.regs, hw_info->dec_reg_num);
+
+ /* revert hack for decoded length */
+ if (task->reg_len > 0) {
+ int reg_len = task->reg_len;
+ u32 dec_get = reg->reg[reg_len];
+ 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[reg_len] = dec_length << 10;
+ }
+
+ reg->reg[task->reg_irq] = pservice->irq_status;
+ } break;
+ case VPU_PP: {
+ pservice->reg_pproc = NULL;
+ reg_copy_from_hw(reg, data->dec_dev.regs, hw_info->dec_reg_num);
+ writel_relaxed(0, data->dec_dev.regs + task->reg_irq);
+ } break;
+ case VPU_DEC_PP: {
+ u32 pipe_mode;
+ u32 *regs = data->dec_dev.regs;
+
+ pservice->reg_codec = NULL;
+ pservice->reg_pproc = NULL;
+
+ reg_copy_from_hw(reg, data->dec_dev.regs, hw_info->dec_reg_num);
+
+ /* NOTE: remove pp pipeline mode flag first */
+ pipe_mode = readl_relaxed(regs + task->reg_pipe);
+ pipe_mode &= ~task->pipe_mask;
+ writel_relaxed(pipe_mode, regs + task->reg_pipe);
+
+ /* revert hack for decoded length */
+ if (task->reg_len > 0) {
+ int reg_len = task->reg_len;
+ u32 dec_get = reg->reg[reg_len];
+ 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[reg_len] = dec_length << 10;
+ }
+
+ reg->reg[task->reg_irq] = pservice->irq_status;
+ } break;
+ default: {
+ vpu_err("error: copy reg from hw with unknown type %d\n",
+ reg->type);
+ } break;
+ }
+ vcodec_exit_mode(data);
+
+ atomic_sub(1, &reg->session->task_running);
+ atomic_sub(1, &pservice->total_running);
+ wake_up(&reg->session->wait);
+
+ vpu_debug_leave();
+}
+
+static void vpu_service_set_freq(struct vpu_service_info *pservice,
+ struct vpu_reg *reg)
+{
+ enum VPU_FREQ curr = atomic_read(&pservice->freq_status);
+
+ if (curr == reg->freq)
+ return;
+
+ atomic_set(&pservice->freq_status, reg->freq);
+ switch (reg->freq) {
+ case VPU_FREQ_200M: {
+ clk_set_rate(pservice->aclk_vcodec, 200*MHZ);
+ } break;
+ case VPU_FREQ_266M: {
+ clk_set_rate(pservice->aclk_vcodec, 266*MHZ);
+ } break;
+ case VPU_FREQ_300M: {
+ clk_set_rate(pservice->aclk_vcodec, 300*MHZ);
+ } break;
+ case VPU_FREQ_400M: {
+ clk_set_rate(pservice->aclk_vcodec, 400*MHZ);
+ } break;
+ case VPU_FREQ_500M: {
+ clk_set_rate(pservice->aclk_vcodec, 500*MHZ);
+ } break;
+ case VPU_FREQ_600M: {
+ clk_set_rate(pservice->aclk_vcodec, 600*MHZ);
+ } break;
+ default: {
+ unsigned long rate = 300*MHZ;
+
+ if (of_machine_is_compatible("rockchip,rk2928g"))
+ rate = 400*MHZ;
+
+ clk_set_rate(pservice->aclk_vcodec, rate);
+ } break;
+ }
+}
+
+static void reg_copy_to_hw(struct vpu_subdev_data *data, struct vpu_reg *reg)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_task_info *task = reg->task;
+ struct vpu_hw_info *hw_info = data->hw_info;
+ int i;
+ u32 *src = (u32 *)&reg->reg[0];
+ u32 enable_mask = task->enable_mask;
+ u32 gating_mask = task->gating_mask;
+ u32 reg_en = task->reg_en;
+
+ vpu_debug_enter();
+
+ atomic_add(1, &pservice->total_running);
+ atomic_add(1, &reg->session->task_running);
+
+ if (pservice->auto_freq)
+ vpu_service_set_freq(pservice, reg);
+
+ vcodec_enter_mode(data);
+
+ switch (reg->type) {
+ case VPU_ENC: {
+ u32 *dst = data->enc_dev.regs;
+ u32 base = 0;
+ u32 end = hw_info->enc_reg_num;
+ /* u32 reg_gating = task->reg_gating; */
+
+ pservice->reg_codec = reg;
+
+ vpu_debug(DEBUG_TASK_INFO,
+ "reg: base %3d end %d en %2d mask: en %x gate %x\n",
+ base, end, reg_en, enable_mask, gating_mask);
+
+ VEPU_CLEAN_CACHE(dst);
+
+ if (debug & DEBUG_SET_REG)
+ for (i = base; i < end; i++)
+ vpu_debug(DEBUG_SET_REG, "set reg[%02d] %08x\n",
+ i, src[i]);
+
+ /*
+ * NOTE: encoder need to setup mode first
+ */
+ writel_relaxed(src[reg_en] & enable_mask, dst + reg_en);
+
+ /* NOTE: encoder gating is not on enable register */
+ /* src[reg_gating] |= gating_mask; */
+
+ for (i = base; i < end; i++) {
+ if (i != reg_en)
+ writel_relaxed(src[i], dst + i);
+ }
+
+ writel(src[reg_en], dst + reg_en);
+ dsb(sy);
+
+ time_record(reg->task, 0);
+ } break;
+ case VPU_DEC: {
+ u32 *dst = data->dec_dev.regs;
+ u32 len = hw_info->dec_reg_num;
+ u32 base = hw_info->base_dec;
+ u32 end = hw_info->end_dec;
+
+ pservice->reg_codec = reg;
+
+ vpu_debug(DEBUG_TASK_INFO,
+ "reg: base %3d end %d en %2d mask: en %x gate %x\n",
+ base, end, reg_en, enable_mask, gating_mask);
+
+ VDPU_CLEAN_CACHE(dst);
+
+ /* on rkvdec set cache size to 64byte */
+ if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC) {
+ u32 *cache_base = dst + 0x100;
+ u32 val = (debug & DEBUG_CACHE_32B) ? (0x3) : (0x13);
+ writel_relaxed(val, cache_base + 0x07);
+ writel_relaxed(val, cache_base + 0x17);
+ }
+
+ if (debug & DEBUG_SET_REG)
+ for (i = 0; i < len; i++)
+ vpu_debug(DEBUG_SET_REG, "set reg[%02d] %08x\n",
+ i, src[i]);
+ /*
+ * NOTE: The end register is invalid. Do NOT write to it
+ * Also the base register must be written
+ */
+ for (i = base; i < end; i++) {
+ if (i != reg_en)
+ writel_relaxed(src[i], dst + i);
+ }
+
+ writel(src[reg_en] | gating_mask, dst + reg_en);
+ dsb(sy);
+
+ time_record(reg->task, 0);
+ } break;
+ case VPU_PP: {
+ u32 *dst = data->dec_dev.regs;
+ u32 base = hw_info->base_pp;
+ u32 end = hw_info->end_pp;
+
+ pservice->reg_pproc = reg;
+
+ vpu_debug(DEBUG_TASK_INFO,
+ "reg: base %3d end %d en %2d mask: en %x gate %x\n",
+ base, end, reg_en, enable_mask, gating_mask);
+
+ if (debug & DEBUG_SET_REG)
+ for (i = base; i < end; i++)
+ vpu_debug(DEBUG_SET_REG, "set reg[%02d] %08x\n",
+ i, src[i]);
+
+ for (i = base; i < end; i++) {
+ if (i != reg_en)
+ writel_relaxed(src[i], dst + i);
+ }
+
+ writel(src[reg_en] | gating_mask, dst + reg_en);
+ dsb(sy);
+
+ time_record(reg->task, 0);
+ } break;
+ case VPU_DEC_PP: {
+ u32 *dst = data->dec_dev.regs;
+ u32 base = hw_info->base_dec_pp;
+ u32 end = hw_info->end_dec_pp;
+
+ pservice->reg_codec = reg;
+ pservice->reg_pproc = reg;
+
+ vpu_debug(DEBUG_TASK_INFO,
+ "reg: base %3d end %d en %2d mask: en %x gate %x\n",
+ base, end, reg_en, enable_mask, gating_mask);
+
+ /* VDPU_SOFT_RESET(dst); */
+ VDPU_CLEAN_CACHE(dst);
+
+ if (debug & DEBUG_SET_REG)
+ for (i = base; i < end; i++)
+ vpu_debug(DEBUG_SET_REG, "set reg[%02d] %08x\n",
+ i, src[i]);
+
+ for (i = base; i < end; i++) {
+ if (i != reg_en)
+ writel_relaxed(src[i], dst + i);
+ }
+
+ /* NOTE: dec output must be disabled */
+
+ writel(src[reg_en] | gating_mask, dst + reg_en);
+ dsb(sy);
+
+ time_record(reg->task, 0);
+ } break;
+ default: {
+ vpu_err("error: unsupport session type %d", reg->type);
+ atomic_sub(1, &pservice->total_running);
+ atomic_sub(1, &reg->session->task_running);
+ } break;
+ }
+
+ vpu_debug_leave();
+}
+
+static void try_set_reg(struct vpu_subdev_data *data)
+{
+ struct vpu_service_info *pservice = data->pservice;
+
+ vpu_debug_enter();
+
+ mutex_lock(&pservice->shutdown_lock);
+ if (atomic_read(&pservice->service_on) == 0) {
+ mutex_unlock(&pservice->shutdown_lock);
+ return;
+ }
+ if (!list_empty(&pservice->waiting)) {
+ struct vpu_reg *reg_codec = pservice->reg_codec;
+ struct vpu_reg *reg_pproc = pservice->reg_pproc;
+ int can_set = 0;
+ bool change_able = (reg_codec == NULL) && (reg_pproc == NULL);
+ int reset_request = atomic_read(&pservice->reset_request);
+ struct vpu_reg *reg = list_entry(pservice->waiting.next,
+ struct vpu_reg, status_link);
+
+ vpu_service_power_on(data, pservice);
+
+ if (change_able || !reset_request) {
+ switch (reg->type) {
+ case VPU_ENC: {
+ if (change_able)
+ can_set = 1;
+ } break;
+ case VPU_DEC: {
+ if (reg_codec == NULL)
+ can_set = 1;
+ if (pservice->auto_freq && (reg_pproc != NULL))
+ can_set = 0;
+ } break;
+ case VPU_PP: {
+ if (reg_codec == NULL) {
+ if (reg_pproc == NULL)
+ can_set = 1;
+ } else {
+ if ((reg_codec->type == VPU_DEC) &&
+ (reg_pproc == NULL))
+ can_set = 1;
+
+ /*
+ * NOTE:
+ * 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: {
+ dev_err(pservice->dev,
+ "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);
+ }
+ }
+
+ mutex_unlock(&pservice->shutdown_lock);
+ vpu_debug_leave();
+}
+
+static void vpu_set_register_work(struct work_struct *work_s)
+{
+ struct vpu_subdev_data *data = container_of(work_s,
+ struct vpu_subdev_data,
+ set_work);
+ struct vpu_service_info *pservice = data->pservice;
+
+ mutex_lock(&pservice->lock);
+ try_set_reg(data);
+ mutex_unlock(&pservice->lock);
+}
+
+static int return_reg(struct vpu_subdev_data *data,
+ struct vpu_reg *reg, u32 __user *dst)
+{
+ struct vpu_hw_info *hw_info = data->hw_info;
+ size_t size = reg->size;
+ u32 base;
+
+ vpu_debug_enter();
+ switch (reg->type) {
+ case VPU_ENC: {
+ base = 0;
+ } break;
+ case VPU_DEC: {
+ base = hw_info->base_dec_pp;
+ } break;
+ case VPU_PP: {
+ base = hw_info->base_pp;
+ } break;
+ case VPU_DEC_PP: {
+ base = hw_info->base_dec_pp;
+ } break;
+ default: {
+ vpu_err("error: copy reg to user with unknown type %d\n",
+ reg->type);
+ return -EFAULT;
+ } break;
+ }
+
+ if (copy_to_user(dst, &reg->reg[base], size)) {
+ vpu_err("error: copy_to_user failed\n");
+ return -EFAULT;
+ }
+
+ reg_deinit(data, reg);
+ vpu_debug_leave();
+ return 0;
+}
+
+static long vpu_service_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct vpu_subdev_data *data =
+ container_of(filp->f_path.dentry->d_inode->i_cdev,
+ struct vpu_subdev_data, cdev);
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_session *session = (struct vpu_session *)filp->private_data;
+
+ vpu_debug_enter();
+ if (NULL == session)
+ return -EINVAL;
+
+ switch (cmd) {
+ case VPU_IOC_SET_CLIENT_TYPE: {
+ session->type = (enum VPU_CLIENT_TYPE)arg;
+ vpu_debug(DEBUG_IOCTL, "pid %d set client type %d\n",
+ session->pid, session->type);
+ } break;
+ case VPU_IOC_GET_HW_FUSE_STATUS: {
+ struct vpu_request req;
+
+ vpu_debug(DEBUG_IOCTL, "pid %d get hw status %d\n",
+ session->pid, session->type);
+ if (copy_from_user(&req, (void __user *)arg, sizeof(req))) {
+ vpu_err("error: get hw status copy_from_user failed\n");
+ return -EFAULT;
+ } else {
+ void *config = (session->type != VPU_ENC) ?
+ ((void *)&pservice->dec_config) :
+ ((void *)&pservice->enc_config);
+ size_t size = (session->type != VPU_ENC) ?
+ (sizeof(struct vpu_dec_config)) :
+ (sizeof(struct vpu_enc_config));
+ if (copy_to_user((void __user *)req.req,
+ config, size)) {
+ vpu_err("error: get hw status copy_to_user failed type %d\n",
+ session->type);
+ return -EFAULT;
+ }
+ }
+ } break;
+ case VPU_IOC_SET_REG: {
+ struct vpu_request req;
+ struct vpu_reg *reg;
+
+ vpu_debug(DEBUG_IOCTL, "pid %d set reg type %d\n",
+ session->pid, session->type);
+ if (copy_from_user(&req, (void __user *)arg,
+ sizeof(struct vpu_request))) {
+ vpu_err("error: set reg copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ reg = reg_init(data, session, (void __user *)req.req, req.size);
+ if (NULL == reg) {
+ return -EFAULT;
+ } else {
+ queue_work(pservice->set_workq, &data->set_work);
+ }
+ } break;
+ case VPU_IOC_GET_REG: {
+ struct vpu_request req;
+ struct vpu_reg *reg;
+ int ret;
+
+ vpu_debug(DEBUG_IOCTL, "pid %d get reg type %d\n",
+ session->pid, session->type);
+ if (copy_from_user(&req, (void __user *)arg,
+ sizeof(struct vpu_request))) {
+ vpu_err("error: get reg copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ ret = wait_event_timeout(session->wait,
+ !list_empty(&session->done),
+ VPU_TIMEOUT_DELAY);
+
+ if (!list_empty(&session->done)) {
+ if (ret < 0)
+ vpu_err("warning: pid %d wait task error ret %d\n",
+ session->pid, ret);
+ ret = 0;
+ } else {
+ if (unlikely(ret < 0)) {
+ vpu_err("error: pid %d wait task ret %d\n",
+ session->pid, ret);
+ } else if (ret == 0) {
+ vpu_err("error: pid %d wait %d task done timeout\n",
+ session->pid,
+ atomic_read(&session->task_running));
+ ret = -ETIMEDOUT;
+ }
+ }
+
+ if (ret < 0) {
+ int task_running = atomic_read(&session->task_running);
+
+ mutex_lock(&pservice->lock);
+ vpu_service_dump(pservice);
+ if (task_running) {
+ atomic_set(&session->task_running, 0);
+ atomic_sub(task_running,
+ &pservice->total_running);
+ dev_err(pservice->dev,
+ "%d task is running but not return, reset hardware...",
+ task_running);
+ vpu_reset(data);
+ dev_err(pservice->dev, "done\n");
+ }
+ vpu_service_session_clear(data, session);
+ mutex_unlock(&pservice->lock);
+
+ return ret;
+ }
+ mutex_lock(&pservice->lock);
+ reg = list_entry(session->done.next,
+ struct vpu_reg, session_link);
+ return_reg(data, reg, (u32 __user *)req.req);
+ mutex_unlock(&pservice->lock);
+ } break;
+ case VPU_IOC_PROBE_IOMMU_STATUS: {
+ int iommu_enable = 1;
+
+ vpu_debug(DEBUG_IOCTL, "VPU_IOC_PROBE_IOMMU_STATUS\n");
+
+ if (copy_to_user((void __user *)arg,
+ &iommu_enable, sizeof(int))) {
+ vpu_err("error: iommu status copy_to_user failed\n");
+ return -EFAULT;
+ }
+ } break;
+ default: {
+ vpu_err("error: unknow vpu service ioctl cmd %x\n", cmd);
+ } break;
+ }
+ vpu_debug_leave();
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long compat_vpu_service_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct vpu_subdev_data *data =
+ container_of(filp->f_path.dentry->d_inode->i_cdev,
+ struct vpu_subdev_data, cdev);
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_session *session = (struct vpu_session *)filp->private_data;
+
+ vpu_debug_enter();
+ vpu_debug(3, "cmd %x, COMPAT_VPU_IOC_SET_CLIENT_TYPE %x\n", cmd,
+ (u32)COMPAT_VPU_IOC_SET_CLIENT_TYPE);
+ if (NULL == session)
+ return -EINVAL;
+
+ switch (cmd) {
+ case COMPAT_VPU_IOC_SET_CLIENT_TYPE: {
+ session->type = (enum VPU_CLIENT_TYPE)arg;
+ vpu_debug(DEBUG_IOCTL, "compat set client type %d\n",
+ session->type);
+ } break;
+ case COMPAT_VPU_IOC_GET_HW_FUSE_STATUS: {
+ struct compat_vpu_request req;
+
+ vpu_debug(DEBUG_IOCTL, "compat get hw status %d\n",
+ session->type);
+ if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
+ sizeof(struct compat_vpu_request))) {
+ vpu_err("error: compat get hw status copy_from_user failed\n");
+ return -EFAULT;
+ } else {
+ void *config = (session->type != VPU_ENC) ?
+ ((void *)&pservice->dec_config) :
+ ((void *)&pservice->enc_config);
+ size_t size = (session->type != VPU_ENC) ?
+ (sizeof(struct vpu_dec_config)) :
+ (sizeof(struct vpu_enc_config));
+
+ if (copy_to_user(compat_ptr((compat_uptr_t)req.req),
+ config, size)) {
+ vpu_err("error: compat get hw status copy_to_user failed type %d\n",
+ session->type);
+ return -EFAULT;
+ }
+ }
+ } break;
+ case COMPAT_VPU_IOC_SET_REG: {
+ struct compat_vpu_request req;
+ struct vpu_reg *reg;
+
+ vpu_debug(DEBUG_IOCTL, "compat 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("compat set_reg copy_from_user failed\n");
+ return -EFAULT;
+ }
+ reg = reg_init(data, session,
+ compat_ptr((compat_uptr_t)req.req), req.size);
+ if (NULL == reg) {
+ return -EFAULT;
+ } else {
+ queue_work(pservice->set_workq, &data->set_work);
+ }
+ } break;
+ case COMPAT_VPU_IOC_GET_REG: {
+ struct compat_vpu_request req;
+ struct vpu_reg *reg;
+ int ret;
+
+ vpu_debug(DEBUG_IOCTL, "compat 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("compat get reg copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ ret = wait_event_timeout(session->wait,
+ !list_empty(&session->done),
+ VPU_TIMEOUT_DELAY);
+
+ if (!list_empty(&session->done)) {
+ if (ret < 0)
+ vpu_err("warning: pid %d wait task error ret %d\n",
+ session->pid, ret);
+ ret = 0;
+ } else {
+ if (unlikely(ret < 0)) {
+ vpu_err("error: pid %d wait task ret %d\n",
+ session->pid, ret);
+ } else if (ret == 0) {
+ vpu_err("error: pid %d wait %d task done timeout\n",
+ session->pid,
+ atomic_read(&session->task_running));
+ ret = -ETIMEDOUT;
+ }
+ }
+
+ if (ret < 0) {
+ int task_running = atomic_read(&session->task_running);
+
+ mutex_lock(&pservice->lock);
+ vpu_service_dump(pservice);
+ if (task_running) {
+ atomic_set(&session->task_running, 0);
+ atomic_sub(task_running,
+ &pservice->total_running);
+ dev_err(pservice->dev,
+ "%d task is running but not return, reset hardware...",
+ task_running);
+ vpu_reset(data);
+ dev_err(pservice->dev, "done\n");
+ }
+ vpu_service_session_clear(data, session);
+ mutex_unlock(&pservice->lock);
+ return ret;
+ }
+
+ mutex_lock(&pservice->lock);
+ reg = list_entry(session->done.next,
+ struct vpu_reg, session_link);
+ return_reg(data, reg, compat_ptr((compat_uptr_t)req.req));
+ mutex_unlock(&pservice->lock);
+ } break;
+ case COMPAT_VPU_IOC_PROBE_IOMMU_STATUS: {
+ int iommu_enable = 1;
+
+ vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_PROBE_IOMMU_STATUS\n");
+
+ if (copy_to_user(compat_ptr((compat_uptr_t)arg),
+ &iommu_enable, sizeof(int))) {
+ vpu_err("error: VPU_IOC_PROBE_IOMMU_STATUS copy_to_user failed\n");
+ return -EFAULT;
+ }
+ } break;
+ default: {
+ vpu_err("error: unknow vpu service ioctl cmd %x\n", cmd);
+ } break;
+ }
+ vpu_debug_leave();
+ return 0;
+}
+#endif
+
+static int vpu_service_check_hw(struct vpu_subdev_data *data)
+{
+ int ret = -EINVAL, i = 0;
+ u32 hw_id = readl_relaxed(data->regs);
+
+ hw_id = (hw_id >> 16) & 0xFFFF;
+ dev_info(data->dev, "checking hw id %x\n", hw_id);
+ data->hw_info = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(vcodec_info_set); i++) {
+ const struct vcodec_info *info = &vcodec_info_set[i];
+
+ if (hw_id == info->hw_id) {
+ data->hw_id = info->hw_id;
+ data->hw_info = info->hw_info;
+ data->task_info = info->task_info;
+ data->trans_info = info->trans_info;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int vpu_service_open(struct inode *inode, struct file *filp)
+{
+ struct vpu_subdev_data *data = container_of(
+ inode->i_cdev, struct vpu_subdev_data, cdev);
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_session *session = NULL;
+
+ vpu_debug_enter();
+
+ session = kzalloc(sizeof(*session), GFP_KERNEL);
+ if (!session) {
+ vpu_err("error: unable to allocate memory for vpu_session.");
+ return -ENOMEM;
+ }
+
+ data->iommu_info->debug_level = debug;
+
+ session->type = VPU_TYPE_BUTT;
+ session->pid = current->pid;
+ INIT_LIST_HEAD(&session->waiting);
+ INIT_LIST_HEAD(&session->running);
+ INIT_LIST_HEAD(&session->done);
+ INIT_LIST_HEAD(&session->list_session);
+ init_waitqueue_head(&session->wait);
+ atomic_set(&session->task_running, 0);
+ mutex_lock(&pservice->lock);
+ list_add_tail(&session->list_session, &pservice->session);
+ filp->private_data = (void *)session;
+ mutex_unlock(&pservice->lock);
+
+ dev_dbg(pservice->dev, "dev opened\n");
+ vpu_debug_leave();
+ return nonseekable_open(inode, filp);
+}
+
+static int vpu_service_release(struct inode *inode, struct file *filp)
+{
+ struct vpu_subdev_data *data = container_of(
+ inode->i_cdev, struct vpu_subdev_data, cdev);
+ struct vpu_service_info *pservice = data->pservice;
+ int task_running;
+ struct vpu_session *session = (struct vpu_session *)filp->private_data;
+
+ vpu_debug_enter();
+ if (NULL == session)
+ return -EINVAL;
+
+ task_running = atomic_read(&session->task_running);
+ if (task_running) {
+ dev_err(pservice->dev,
+ "error: session %d still has %d task running when closing\n",
+ session->pid, task_running);
+ msleep(50);
+ }
+ wake_up(&session->wait);
+
+ mutex_lock(&pservice->lock);
+ /* remove this filp from the asynchronusly notified filp's */
+ list_del_init(&session->list_session);
+ vpu_service_session_clear(data, session);
+ vcodec_iommu_clear(data->iommu_info, session);
+ kfree(session);
+ filp->private_data = NULL;
+ mutex_unlock(&pservice->lock);
+
+ dev_info(pservice->dev, "closed\n");
+ vpu_debug_leave();
+ return 0;
+}
+
+static const struct file_operations vpu_service_fops = {
+ .unlocked_ioctl = vpu_service_ioctl,
+ .open = vpu_service_open,
+ .release = vpu_service_release,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_vpu_service_ioctl,
+#endif
+};
+
+static irqreturn_t vdpu_irq(int irq, void *dev_id);
+static irqreturn_t vdpu_isr(int irq, void *dev_id);
+static irqreturn_t vepu_irq(int irq, void *dev_id);
+static irqreturn_t vepu_isr(int irq, void *dev_id);
+static void get_hw_info(struct vpu_subdev_data *data);
+
+static struct device *rockchip_get_sysmmu_dev(const char *compt)
+{
+ struct device_node *dn = NULL;
+ struct platform_device *pd = NULL;
+ struct device *ret = NULL;
+
+ dn = of_find_compatible_node(NULL, NULL, compt);
+ if (!dn) {
+ pr_err("can't find device node %s \r\n", compt);
+ return NULL;
+ }
+
+ pd = of_find_device_by_node(dn);
+ if (!pd) {
+ pr_err("can't find platform device in device node %s\n", compt);
+ return NULL;
+ }
+ ret = &pd->dev;
+
+ return ret;
+}
+
+#ifdef CONFIG_IOMMU_API
+static inline void platform_set_sysmmu(struct device *iommu,
+ struct device *dev)
+{
+ dev->archdata.iommu = iommu;
+}
+#else
+static inline void platform_set_sysmmu(struct device *iommu,
+ struct device *dev)
+{
+}
+#endif
+
+int vcodec_sysmmu_fault_hdl(struct device *dev,
+ enum rk_iommu_inttype itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr, unsigned int status)
+{
+ struct platform_device *pdev;
+ struct vpu_service_info *pservice;
+ struct vpu_subdev_data *data;
+
+ vpu_debug_enter();
+
+ if (dev == NULL) {
+ pr_err("invalid NULL dev\n");
+ return 0;
+ }
+
+ pdev = container_of(dev, struct platform_device, dev);
+ if (pdev == NULL) {
+ pr_err("invalid NULL platform_device\n");
+ return 0;
+ }
+
+ data = platform_get_drvdata(pdev);
+ if (data == NULL) {
+ pr_err("invalid NULL vpu_subdev_data\n");
+ return 0;
+ }
+
+ pservice = data->pservice;
+ if (pservice == NULL) {
+ pr_err("invalid NULL vpu_service_info\n");
+ return 0;
+ }
+
+ if (pservice->reg_codec) {
+ struct vpu_reg *reg = pservice->reg_codec;
+ struct vcodec_mem_region *mem, *n;
+ int i = 0;
+
+ pr_err("vcodec, fault addr 0x%08lx\n", fault_addr);
+ if (!list_empty(&reg->mem_region_list)) {
+ list_for_each_entry_safe(mem, n, &reg->mem_region_list,
+ reg_lnk) {
+ pr_err("vcodec, reg[%02u] mem region [%02d] 0x%lx %lx\n",
+ mem->reg_idx, i, mem->iova, mem->len);
+ i++;
+ }
+ } else {
+ pr_err("no memory region mapped\n");
+ }
+
+ if (reg->data) {
+ struct vpu_subdev_data *data = reg->data;
+ u32 *base = (u32 *)data->dec_dev.regs;
+ u32 len = data->hw_info->dec_reg_num;
+
+ pr_err("current errror register set:\n");
+
+ for (i = 0; i < len; i++)
+ pr_err("reg[%02d] %08x\n",
+ i, readl_relaxed(base + i));
+ }
+
+ pr_alert("vcodec, page fault occur, reset hw\n");
+
+ /* reg->reg[101] = 1; */
+ _vpu_reset(data);
+ }
+
+ return 0;
+}
+
+static int vcodec_subdev_probe(struct platform_device *pdev,
+ struct vpu_service_info *pservice)
+{
+ uint8_t *regs = NULL;
+ int32_t ret = 0;
+ uint32_t ioaddr = 0;
+ struct resource *res = NULL;
+ struct vpu_hw_info *hw_info = NULL;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct vpu_subdev_data *data = NULL;
+ struct platform_device *sub_dev = NULL;
+ struct device_node *sub_np = NULL;
+ const char *name = np->name;
+ char mmu_dev_dts_name[40];
+
+ dev_info(dev, "probe device");
+
+ data = devm_kzalloc(dev, sizeof(struct vpu_subdev_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->pservice = pservice;
+ data->dev = dev;
+
+ INIT_WORK(&data->set_work, vpu_set_register_work);
+
+ switch (pservice->dev_id) {
+ case VCODEC_DEVICE_ID_VPU:
+ data->mode = VCODEC_RUNNING_MODE_VPU;
+ break;
+ case VCODEC_DEVICE_ID_HEVC:
+ data->mode = VCODEC_RUNNING_MODE_HEVC;
+ break;
+ case VCODEC_DEVICE_ID_RKVDEC:
+ data->mode = VCODEC_RUNNING_MODE_RKVDEC;
+ break;
+ case VCODEC_DEVICE_ID_COMBO:
+ default:
+ of_property_read_u32(np, "dev_mode", (u32 *)&data->mode);
+ break;
+ }
+
+ if (pservice->reg_base == 0) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->regs)) {
+ ret = PTR_ERR(data->regs);
+ goto err;
+ }
+ ioaddr = res->start;
+ } else {
+ data->regs = pservice->reg_base;
+ ioaddr = pservice->ioaddr;
+ }
+
+ sub_np = of_parse_phandle(np, "iommus", 0);
+ if (sub_np) {
+ sub_dev = of_find_device_by_node(sub_np);
+ data->mmu_dev = &sub_dev->dev;
+ }
+
+ /* Back to legacy iommu probe */
+ if (!data->mmu_dev) {
+ switch (data->mode) {
+ case VCODEC_RUNNING_MODE_VPU:
+ sprintf(mmu_dev_dts_name,
+ VPU_IOMMU_COMPATIBLE_NAME);
+ break;
+ case VCODEC_RUNNING_MODE_RKVDEC:
+ sprintf(mmu_dev_dts_name,
+ VDEC_IOMMU_COMPATIBLE_NAME);
+ break;
+ case VCODEC_RUNNING_MODE_HEVC:
+ default:
+ sprintf(mmu_dev_dts_name,
+ HEVC_IOMMU_COMPATIBLE_NAME);
+ break;
+ }
+
+ data->mmu_dev =
+ rockchip_get_sysmmu_dev(mmu_dev_dts_name);
+ if (data->mmu_dev)
+ platform_set_sysmmu(data->mmu_dev, dev);
+
+ rockchip_iovmm_set_fault_handler
+ (dev, vcodec_sysmmu_fault_hdl);
+ }
+
+ dev_info(dev, "vpu mmu dec %p\n", data->mmu_dev);
+
+ clear_bit(MMU_ACTIVATED, &data->state);
+ vpu_service_power_on(data, pservice);
+
+ of_property_read_u32(np, "allocator", (u32 *)&pservice->alloc_type);
+ data->iommu_info = vcodec_iommu_info_create(dev, data->mmu_dev,
+ pservice->alloc_type);
+ dev_info(dev, "allocator is %s\n", pservice->alloc_type == 1 ? "drm" :
+ (pservice->alloc_type == 2 ? "ion" : "null"));
+ vcodec_enter_mode(data);
+ ret = vpu_service_check_hw(data);
+ if (ret < 0) {
+ dev_err(dev, "error: hw info check failed\n");
+ goto err;
+ }
+ vcodec_exit_mode(data);
+
+ hw_info = data->hw_info;
+ regs = (u8 *)data->regs;
+
+ if (hw_info->dec_reg_num) {
+ data->dec_dev.iosize = hw_info->dec_io_size;
+ data->dec_dev.regs = (u32 *)(regs + hw_info->dec_offset);
+ }
+
+ if (hw_info->enc_reg_num) {
+ data->enc_dev.iosize = hw_info->enc_io_size;
+ data->enc_dev.regs = (u32 *)(regs + hw_info->enc_offset);
+ }
+
+ data->reg_size = max(hw_info->dec_io_size, hw_info->enc_io_size);
+
+ data->irq_enc = platform_get_irq_byname(pdev, "irq_enc");
+ if (data->irq_enc > 0) {
+ ret = devm_request_threaded_irq(dev, data->irq_enc,
+ vepu_irq, vepu_isr,
+ IRQF_SHARED, dev_name(dev),
+ (void *)data);
+ if (ret) {
+ dev_err(dev, "error: can't request vepu irq %d\n",
+ data->irq_enc);
+ goto err;
+ }
+ }
+
+ data->irq_dec = platform_get_irq_byname(pdev, "irq_dec");
+ if (data->irq_dec > 0) {
+ ret = devm_request_threaded_irq(dev, data->irq_dec,
+ vdpu_irq, vdpu_isr,
+ IRQF_SHARED, dev_name(dev),
+ (void *)data);
+ if (ret) {
+ dev_err(dev, "error: can't request vdpu irq %d\n",
+ data->irq_dec);
+ goto err;
+ }
+ }
+ atomic_set(&data->dec_dev.irq_count_codec, 0);
+ atomic_set(&data->dec_dev.irq_count_pp, 0);
+ atomic_set(&data->enc_dev.irq_count_codec, 0);
+ atomic_set(&data->enc_dev.irq_count_pp, 0);
+
+ get_hw_info(data);
+ pservice->auto_freq = true;
+
+ /* create device node */
+ ret = alloc_chrdev_region(&data->dev_t, 0, 1, name);
+ if (ret) {
+ dev_err(dev, "alloc dev_t failed\n");
+ goto err;
+ }
+
+ cdev_init(&data->cdev, &vpu_service_fops);
+
+ data->cdev.owner = THIS_MODULE;
+ data->cdev.ops = &vpu_service_fops;
+
+ ret = cdev_add(&data->cdev, data->dev_t, 1);
+
+ if (ret) {
+ dev_err(dev, "add dev_t failed\n");
+ goto err;
+ }
+
+ data->cls = class_create(THIS_MODULE, name);
+
+ if (IS_ERR(data->cls)) {
+ ret = PTR_ERR(data->cls);
+ dev_err(dev, "class_create err:%d\n", ret);
+ goto err;
+ }
+
+ data->child_dev = device_create(data->cls, dev,
+ data->dev_t, NULL, "%s", name);
+
+ platform_set_drvdata(pdev, data);
+
+ INIT_LIST_HEAD(&data->lnk_service);
+ list_add_tail(&data->lnk_service, &pservice->subdev_list);
+
+ /* After the subdev was appened to the list of pservice */
+ vpu_service_power_off(pservice);
+
+ return 0;
+err:
+ dev_err(dev, "probe err:%d\n", ret);
+ if (data->child_dev) {
+ device_destroy(data->cls, data->dev_t);
+ cdev_del(&data->cdev);
+ unregister_chrdev_region(data->dev_t, 1);
+ }
+
+ if (data->cls)
+ class_destroy(data->cls);
+ vpu_service_power_off(pservice);
+ return -1;
+}
+
+static void vcodec_subdev_remove(struct vpu_subdev_data *data)
+{
+ struct vpu_service_info *pservice = data->pservice;
+
+ vcodec_iommu_info_destroy(data->iommu_info);
+ data->iommu_info = NULL;
+
+ mutex_lock(&pservice->lock);
+ cancel_delayed_work_sync(&pservice->power_off_work);
+ vpu_service_power_off(pservice);
+ mutex_unlock(&pservice->lock);
+
+ device_destroy(data->cls, data->dev_t);
+ class_destroy(data->cls);
+ cdev_del(&data->cdev);
+ unregister_chrdev_region(data->dev_t, 1);
+
+#ifdef CONFIG_DEBUG_FS
+ if (!IS_ERR_OR_NULL(data->debugfs_dir))
+ debugfs_remove_recursive(data->debugfs_dir);
+#endif
+}
+
+static void vcodec_read_property(struct device_node *np,
+ struct vpu_service_info *pservice)
+{
+ pservice->mode_bit = 0;
+ pservice->mode_ctrl = 0;
+ pservice->subcnt = 0;
+ pservice->grf_base = NULL;
+
+ of_property_read_u32(np, "subcnt", &pservice->subcnt);
+
+ if (pservice->subcnt > 1) {
+ of_property_read_u32(np, "mode_bit", &pservice->mode_bit);
+ of_property_read_u32(np, "mode_ctrl", &pservice->mode_ctrl);
+ }
+#ifdef CONFIG_MFD_SYSCON
+ 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
+ vpu_err("can't find vpu grf property\n");
+ 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");
+ pservice->rst_niu_a = devm_reset_control_get(pservice->dev, "niu_a");
+ pservice->rst_niu_h = devm_reset_control_get(pservice->dev, "niu_h");
+
+ if (IS_ERR_OR_NULL(pservice->rst_a)) {
+ dev_dbg(pservice->dev, "No aclk reset resource define\n");
+ pservice->rst_a = NULL;
+ }
+
+ if (IS_ERR_OR_NULL(pservice->rst_h)) {
+ dev_dbg(pservice->dev, "No hclk reset resource define\n");
+ pservice->rst_h = NULL;
+ }
+
+ if (IS_ERR_OR_NULL(pservice->rst_v)) {
+ dev_dbg(pservice->dev, "No core reset resource define\n");
+ pservice->rst_v = NULL;
+ }
+
+ if (IS_ERR_OR_NULL(pservice->rst_niu_a)) {
+ dev_dbg(pservice->dev, "No NIU aclk reset resource define\n");
+ pservice->rst_niu_a = NULL;
+ }
+
+ if (IS_ERR_OR_NULL(pservice->rst_niu_h)) {
+ dev_dbg(pservice->dev, "No NIU hclk reset resource define\n");
+ pservice->rst_niu_h = NULL;
+ }
+#endif
+
+ of_property_read_string(np, "name", (const char **)&pservice->name);
+}
+
+static void vcodec_init_drvdata(struct vpu_service_info *pservice)
+{
+ pservice->dev_id = VCODEC_DEVICE_ID_VPU;
+ pservice->curr_mode = -1;
+#ifdef CONFIG_WAKELOCK
+ wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu");
+#endif
+ INIT_LIST_HEAD(&pservice->waiting);
+ INIT_LIST_HEAD(&pservice->running);
+ mutex_init(&pservice->lock);
+ mutex_init(&pservice->shutdown_lock);
+ atomic_set(&pservice->service_on, 1);
+
+ INIT_LIST_HEAD(&pservice->done);
+ INIT_LIST_HEAD(&pservice->session);
+ INIT_LIST_HEAD(&pservice->subdev_list);
+
+ pservice->reg_pproc = NULL;
+ atomic_set(&pservice->total_running, 0);
+ 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);
+ pservice->last = 0;
+
+ pservice->alloc_type = 0;
+}
+
+static int vcodec_probe(struct platform_device *pdev)
+{
+ int i;
+ int ret = 0;
+ struct resource *res = NULL;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct vpu_service_info *pservice = NULL;
+ struct vcodec_device_info *driver_data;
+
+ pservice = devm_kzalloc(dev, sizeof(struct vpu_service_info),
+ GFP_KERNEL);
+ if (!pservice)
+ return -ENOMEM;
+ pservice->dev = dev;
+
+ pservice->set_workq = create_singlethread_workqueue("vcodec");
+ if (!pservice->set_workq) {
+ dev_err(dev, "failed to create workqueue\n");
+ return -ENOMEM;
+ }
+
+ driver_data = vcodec_get_drv_data(pdev);
+ if (!driver_data)
+ return -EINVAL;
+
+ vcodec_read_property(np, pservice);
+ vcodec_init_drvdata(pservice);
+
+ /* Underscore for label, hyphens for name */
+ switch (driver_data->device_type) {
+ case VCODEC_DEVICE_TYPE_VPUX:
+ pservice->dev_id = VCODEC_DEVICE_ID_VPU;
+ break;
+ case VCODEC_DEVICE_TYPE_VPUC:
+ pservice->dev_id = VCODEC_DEVICE_ID_COMBO;
+ break;
+ case VCODEC_DEVICE_TYPE_HEVC:
+ pservice->dev_id = VCODEC_DEVICE_ID_HEVC;
+ break;
+ case VCODEC_DEVICE_TYPE_RKVD:
+ pservice->dev_id = VCODEC_DEVICE_ID_RKVDEC;
+ break;
+ default:
+ dev_err(dev, "unsupported device type\n");
+ return -ENODEV;
+ }
+
+ if (0 > vpu_get_clk(pservice))
+ goto err;
+
+ if (of_property_read_bool(np, "reg")) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ pservice->reg_base = devm_ioremap_resource(pservice->dev, res);
+ if (IS_ERR(pservice->reg_base)) {
+ vpu_err("ioremap registers base failed\n");
+ ret = PTR_ERR(pservice->reg_base);
+ goto err;
+ }
+ pservice->ioaddr = res->start;
+ } else {
+ pservice->reg_base = 0;
+ }
+
+ pm_runtime_enable(dev);
+
+ if (of_property_read_bool(np, "subcnt")) {
+ struct vpu_subdev_data *data = NULL;
+
+ data = devm_kzalloc(dev, sizeof(struct vpu_subdev_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ for (i = 0; i < pservice->subcnt; i++) {
+ struct device_node *sub_np;
+ struct platform_device *sub_pdev;
+
+ sub_np = of_parse_phandle(np, "rockchip,sub", i);
+ sub_pdev = of_find_device_by_node(sub_np);
+
+ vcodec_subdev_probe(sub_pdev, pservice);
+ }
+ data->pservice = pservice;
+ platform_set_drvdata(pdev, data);
+ } else {
+ vcodec_subdev_probe(pdev, pservice);
+ }
+
+ dev_info(dev, "init success\n");
+
+ return 0;
+
+err:
+ dev_info(dev, "init failed\n");
+ destroy_workqueue(pservice->set_workq);
+#ifdef CONFIG_WAKELOCK
+ wake_lock_destroy(&pservice->wake_lock);
+#endif
+ return ret;
+}
+
+static int vcodec_remove(struct platform_device *pdev)
+{
+ struct vpu_subdev_data *data = platform_get_drvdata(pdev);
+
+ vcodec_subdev_remove(data);
+
+ pm_runtime_disable(data->pservice->dev);
+
+ return 0;
+}
+
+static void vcodec_shutdown(struct platform_device *pdev)
+{
+ struct vpu_subdev_data *data = platform_get_drvdata(pdev);
+ struct vpu_service_info *pservice = data->pservice;
+ struct device_node *np = pdev->dev.of_node;
+ int val;
+ int ret;
+ int i;
+
+ dev_info(&pdev->dev, "vcodec shutdown");
+
+ mutex_lock(&pservice->shutdown_lock);
+ atomic_set(&pservice->service_on, 0);
+ mutex_unlock(&pservice->shutdown_lock);
+
+ ret = readx_poll_timeout(atomic_read,
+ &pservice->total_running,
+ val, val == 0, 20000, 200000);
+ if (ret == -ETIMEDOUT)
+ dev_err(&pdev->dev, "wait total running time out\n");
+
+ vcodec_exit_mode(data);
+ vpu_service_clear(data);
+ if (of_property_read_bool(np, "subcnt")) {
+ for (i = 0; i < pservice->subcnt; i++) {
+ struct device_node *sub_np;
+ struct platform_device *sub_pdev;
+
+ sub_np = of_parse_phandle(np, "rockchip,sub", i);
+ sub_pdev = of_find_device_by_node(sub_np);
+ vcodec_subdev_remove(platform_get_drvdata(sub_pdev));
+ }
+
+ } else {
+ vcodec_subdev_remove(data);
+ }
+
+ pm_runtime_disable(&pdev->dev);
+}
+
+static const struct of_device_id vcodec_service_dt_ids[] = {
+ {
+ .compatible = "rockchip,vpu_service",
+ .data = &vpu_device_info,
+ },
+ {
+ .compatible = "rockchip,hevc_service",
+ .data = &hevc_device_info,
+ },
+ {
+ .compatible = "rockchip,vpu_combo",
+ .data = &vpu_combo_device_info,
+ },
+ {
+ .compatible = "rockchip,rkvdec",
+ .data = &rkvd_device_info,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, vcodec_service_dt_ids);
+
+static void *vcodec_get_drv_data(struct platform_device *pdev)
+{
+ struct vcodec_device_info *driver_data = NULL;
+ const struct of_device_id *match;
+
+ match = of_match_node(vcodec_service_dt_ids, pdev->dev.of_node);
+ if (match)
+ driver_data = (struct vcodec_device_info *)match->data;
+
+ return driver_data;
+}
+
+static struct platform_driver vcodec_driver = {
+ .probe = vcodec_probe,
+ .remove = vcodec_remove,
+ .shutdown = vcodec_shutdown,
+ .driver = {
+ .name = "rk-vcodec",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(vcodec_service_dt_ids),
+ },
+};
+
+static void get_hw_info(struct vpu_subdev_data *data)
+{
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_dec_config *dec = &pservice->dec_config;
+ struct vpu_enc_config *enc = &pservice->enc_config;
+
+ if (of_machine_is_compatible("rockchip,rk2928") ||
+ of_machine_is_compatible("rockchip,rk3036") ||
+ of_machine_is_compatible("rockchip,rk3066") ||
+ of_machine_is_compatible("rockchip,rk3126") ||
+ of_machine_is_compatible("rockchip,rk3188"))
+ dec->max_dec_pic_width = 1920;
+ else
+ dec->max_dec_pic_width = 4096;
+
+ if (data->mode == VCODEC_RUNNING_MODE_VPU) {
+ dec->h264_support = 3;
+ dec->jpeg_support = 1;
+ dec->mpeg4_support = 2;
+ dec->vc1_support = 3;
+ dec->mpeg2_support = 1;
+ dec->pp_support = 1;
+ dec->sorenson_support = 1;
+ dec->ref_buf_support = 3;
+ dec->vp6_support = 1;
+ dec->vp7_support = 1;
+ dec->vp8_support = 1;
+ dec->avs_support = 1;
+ dec->jpeg_ext_support = 0;
+ dec->custom_mpeg4_support = 1;
+ dec->reserve = 0;
+ dec->mvc_support = 1;
+
+ if (data->enc_dev.regs) {
+ u32 config_reg = readl_relaxed(data->enc_dev.regs + 63);
+
+ enc->max_encoded_width = config_reg & ((1 << 11) - 1);
+ enc->h264_enabled = 1;
+ enc->mpeg4_enabled = (config_reg >> 26) & 1;
+ enc->jpeg_enabled = 1;
+ enc->vs_enabled = (config_reg >> 24) & 1;
+ enc->rgb_enabled = (config_reg >> 28) & 1;
+ enc->reg_size = data->reg_size;
+ enc->reserv[0] = 0;
+ enc->reserv[1] = 0;
+ }
+
+ pservice->auto_freq = true;
+ 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 = of_machine_is_compatible
+ ("rockchip,rk30xx");
+ } else if (data->mode == VCODEC_RUNNING_MODE_RKVDEC) {
+ pservice->auto_freq = true;
+ atomic_set(&pservice->freq_status, VPU_FREQ_BUT);
+ } else {
+ /* disable frequency switch in hevc.*/
+ pservice->auto_freq = false;
+ }
+}
+
+static bool check_irq_err(struct vpu_task_info *task, u32 irq_status)
+{
+ vpu_debug(DEBUG_IRQ_CHECK, "task %s status %08x mask %08x\n",
+ task->name, irq_status, task->error_mask);
+
+ 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;
+ struct vpu_task_info *task = NULL;
+ struct vpu_device *dev = &data->dec_dev;
+ u32 hw_id = data->hw_info->hw_id;
+ u32 raw_status;
+ u32 dec_status;
+
+ task = &data->task_info[TASK_DEC];
+
+ raw_status = readl_relaxed(dev->regs + task->reg_irq);
+ dec_status = raw_status;
+
+ vpu_debug(DEBUG_TASK_INFO,
+ "vdpu_irq reg %d status %x mask: irq %x ready %x error %0x\n",
+ task->reg_irq, dec_status,
+ task->irq_mask, task->ready_mask, task->error_mask);
+
+ if (dec_status & task->irq_mask) {
+ time_record(task, 1);
+ vpu_debug(DEBUG_IRQ_STATUS, "vdpu_irq dec status %08x\n",
+ dec_status);
+ if ((dec_status & 0x40001) == 0x40001) {
+ do {
+ dec_status = readl_relaxed(dev->regs +
+ task->reg_irq);
+ } while ((dec_status & 0x40001) == 0x40001);
+ }
+
+ if (check_irq_err(task, dec_status))
+ atomic_add(1, &pservice->reset_request);
+
+ writel_relaxed(0, dev->regs + task->reg_irq);
+
+ /* set clock gating to save power */
+ writel(task->gating_mask, dev->regs + task->reg_en);
+
+ atomic_add(1, &dev->irq_count_codec);
+ time_diff(task);
+ pservice->irq_status = raw_status;
+ }
+
+ task = &data->task_info[TASK_PP];
+ if (hw_id != HEVC_ID && hw_id != RKV_DEC_ID) {
+ u32 pp_status = readl_relaxed(dev->regs + task->irq_mask);
+
+ if (pp_status & task->irq_mask) {
+ time_record(task, 1);
+ vpu_debug(DEBUG_IRQ_STATUS, "vdpu_irq pp status %08x\n",
+ pp_status);
+
+ if (check_irq_err(task, dec_status))
+ atomic_add(1, &pservice->reset_request);
+
+ /* clear pp IRQ */
+ writel_relaxed(pp_status & (~task->reg_irq),
+ dev->regs + task->irq_mask);
+ atomic_add(1, &dev->irq_count_pp);
+ time_diff(task);
+ }
+ }
+
+ if (atomic_read(&dev->irq_count_pp) ||
+ atomic_read(&dev->irq_count_codec))
+ return IRQ_WAKE_THREAD;
+ else
+ return IRQ_NONE;
+}
+
+static irqreturn_t vdpu_isr(int irq, void *dev_id)
+{
+ struct vpu_subdev_data *data = (struct vpu_subdev_data *)dev_id;
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_device *dev = &data->dec_dev;
+
+ mutex_lock(&pservice->lock);
+ if (atomic_read(&dev->irq_count_codec)) {
+ atomic_sub(1, &dev->irq_count_codec);
+ if (pservice->reg_codec == NULL) {
+ vpu_err("error: dec isr with no task waiting\n");
+ } else {
+ reg_from_run_to_done(data, pservice->reg_codec);
+ /* avoid vpu timeout and can't recover problem */
+ if (data->mode == VCODEC_RUNNING_MODE_VPU)
+ VDPU_SOFT_RESET(data->regs);
+ }
+ }
+
+ if (atomic_read(&dev->irq_count_pp)) {
+ atomic_sub(1, &dev->irq_count_pp);
+ if (pservice->reg_pproc == NULL)
+ vpu_err("error: pp isr with no task waiting\n");
+ else
+ reg_from_run_to_done(data, pservice->reg_pproc);
+ }
+
+ queue_work(pservice->set_workq, &data->set_work);
+ mutex_unlock(&pservice->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t vepu_irq(int irq, void *dev_id)
+{
+ struct vpu_subdev_data *data = (struct vpu_subdev_data *)dev_id;
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_task_info *task = &data->task_info[TASK_ENC];
+ struct vpu_device *dev = &data->enc_dev;
+ u32 irq_status;
+
+ irq_status = readl_relaxed(dev->regs + task->reg_irq);
+
+ vpu_debug(DEBUG_TASK_INFO,
+ "vepu_irq reg %d status %x mask: irq %x ready %x error %0x\n",
+ task->reg_irq, irq_status,
+ task->irq_mask, task->ready_mask, task->error_mask);
+
+ vpu_debug(DEBUG_IRQ_STATUS, "vepu_irq enc status %08x\n", irq_status);
+
+ if (likely(irq_status & task->irq_mask)) {
+ time_record(task, 1);
+
+ if (check_irq_err(task, irq_status))
+ atomic_add(1, &pservice->reset_request);
+
+ /* clear enc IRQ */
+ writel_relaxed(irq_status & (~task->irq_mask),
+ dev->regs + task->reg_irq);
+
+ atomic_add(1, &dev->irq_count_codec);
+ time_diff(task);
+ }
+
+ pservice->irq_status = irq_status;
+
+ if (atomic_read(&dev->irq_count_codec))
+ return IRQ_WAKE_THREAD;
+ else
+ return IRQ_NONE;
+}
+
+static irqreturn_t vepu_isr(int irq, void *dev_id)
+{
+ struct vpu_subdev_data *data = (struct vpu_subdev_data *)dev_id;
+ struct vpu_service_info *pservice = data->pservice;
+ struct vpu_device *dev = &data->enc_dev;
+
+ mutex_lock(&pservice->lock);
+ if (atomic_read(&dev->irq_count_codec)) {
+ atomic_sub(1, &dev->irq_count_codec);
+ if (NULL == pservice->reg_codec)
+ vpu_err("error: enc isr with no task waiting\n");
+ else
+ reg_from_run_to_done(data, pservice->reg_codec);
+ }
+ queue_work(pservice->set_workq, &data->set_work);
+ mutex_unlock(&pservice->lock);
+
+ return IRQ_HANDLED;
+}
+
+module_platform_driver(vcodec_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/rk_vcodec/vcodec_service.h b/drivers/video/rk_vcodec/vcodec_service.h
new file mode 100644
index 0000000..956c692
--- /dev/null
+++ b/drivers/video/rk_vcodec/vcodec_service.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ * Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_RK29_VCODEC_SERVICE_H
+#define __ARCH_ARM_MACH_RK29_VCODEC_SERVICE_H
+
+#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */
+#include "config.h"
+
+/*
+ * Ioctl definitions
+ */
+
+/* Use 'k' as magic number */
+#define VPU_IOC_MAGIC 'l'
+
+#define VPU_IOC_SET_CLIENT_TYPE _IOW(VPU_IOC_MAGIC, 1, unsigned long)
+#define VPU_IOC_GET_HW_FUSE_STATUS _IOW(VPU_IOC_MAGIC, 2, unsigned long)
+
+#define VPU_IOC_SET_REG _IOW(VPU_IOC_MAGIC, 3, unsigned long)
+#define VPU_IOC_GET_REG _IOW(VPU_IOC_MAGIC, 4, unsigned long)
+
+#define VPU_IOC_PROBE_IOMMU_STATUS _IOR(VPU_IOC_MAGIC, 5, unsigned long)
+
+#ifdef CONFIG_COMPAT
+#define COMPAT_VPU_IOC_SET_CLIENT_TYPE _IOW(VPU_IOC_MAGIC, 1, u32)
+#define COMPAT_VPU_IOC_GET_HW_FUSE_STATUS _IOW(VPU_IOC_MAGIC, 2, u32)
+
+#define COMPAT_VPU_IOC_SET_REG _IOW(VPU_IOC_MAGIC, 3, u32)
+#define COMPAT_VPU_IOC_GET_REG _IOW(VPU_IOC_MAGIC, 4, u32)
+
+#define COMPAT_VPU_IOC_PROBE_IOMMU_STATUS _IOR(VPU_IOC_MAGIC, 5, u32)
+#endif
+
+enum VPU_CLIENT_TYPE {
+ VPU_ENC = 0x0,
+ VPU_DEC = 0x1,
+ VPU_PP = 0x2,
+ VPU_DEC_PP = 0x3,
+ VPU_TYPE_BUTT,
+};
+
+/* Hardware decoder configuration description */
+struct vpu_dec_config {
+ /* Maximum video decoding width supported */
+ u32 max_dec_pic_width;
+ /* Maximum output width of Post-Processor */
+ u32 max_pp_out_pic_width;
+ /* HW supports h.264 */
+ u32 h264_support;
+ /* HW supports JPEG */
+ u32 jpeg_support;
+ /* HW supports MPEG-4 */
+ u32 mpeg4_support;
+ /* HW supports custom MPEG-4 features */
+ u32 custom_mpeg4_support;
+ /* HW supports VC-1 Simple */
+ u32 vc1_support;
+ /* HW supports MPEG-2 */
+ u32 mpeg2_support;
+ /* HW supports post-processor */
+ u32 pp_support;
+ /* HW post-processor functions bitmask */
+ u32 pp_config;
+ /* HW supports Sorenson Spark */
+ u32 sorenson_support;
+ /* HW supports reference picture buffering */
+ u32 ref_buf_support;
+ /* HW supports VP6 */
+ u32 vp6_support;
+ /* HW supports VP7 */
+ u32 vp7_support;
+ /* HW supports VP8 */
+ u32 vp8_support;
+ /* HW supports AVS */
+ u32 avs_support;
+ /* HW supports JPEG extensions */
+ u32 jpeg_ext_support;
+ u32 reserve;
+ /* HW supports H264 MVC extension */
+ u32 mvc_support;
+};
+
+/* Hardware encoder configuration description */
+struct vpu_enc_config {
+ /* Maximum supported width for video encoding (not JPEG) */
+ u32 max_encoded_width;
+ /* HW supports H.264 */
+ u32 h264_enabled;
+ /* HW supports JPEG */
+ u32 jpeg_enabled;
+ /* HW supports MPEG-4 */
+ u32 mpeg4_enabled;
+ /* HW supports video stabilization */
+ u32 vs_enabled;
+ /* HW supports RGB input */
+ u32 rgb_enabled;
+ u32 reg_size;
+ u32 reserv[2];
+};
+
+#endif
+
diff --git a/include/dt-bindings/clock/rockchip,rk3036.h b/include/dt-bindings/clock/rockchip,rk3036.h
new file mode 100644
index 0000000..019550c
--- /dev/null
+++ b/include/dt-bindings/clock/rockchip,rk3036.h
@@ -0,0 +1,155 @@
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_RK3036_H
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_RK3036_H
+
+#include "rockchip.h"
+
+/* pll id */
+#define RK3036_APLL_ID 0
+#define RK3036_DPLL_ID 1
+#define RK3036_GPLL_ID 2
+#define RK3036_END_PLL_ID 3
+
+/* reset id */
+#define RK3036_RST_CORE0 0
+#define RK3036_RST_CORE1 1
+#define RK3036_RST_0RES2 2
+#define RK3036_RST_0RES3 3
+#define RK3036_RST_CORE0_DBG 4
+#define RK3036_RST_CORE1_DBG 5
+#define RK3036_RST_0RES6 6
+#define RK3036_RST_0RES7 7
+#define RK3036_RST_CORE0_POR 8
+#define RK3036_RST_CORE1_POR 9
+#define RK3036_RST_0RES10 10
+#define RK3036_RST_0RES11 11
+#define RK3036_RST_L2C 12
+#define RK3036_RST_TOPDBG 13
+#define RK3036_RST_STRC_SYS_A 14
+#define RK3036_RST_PD_CORE_NIU 15
+
+#define RK3036_RST_TIMER2 16
+#define RK3036_RST_CPUSYS_H 17
+#define RK3036_RST_1RES2 18
+#define RK3036_RST_AHB2APB_H 19
+#define RK3036_RST_TIMER3 20
+#define RK3036_RST_INTMEM 21
+#define RK3036_RST_ROM 22
+#define RK3036_RST_PERI_NIU 23
+#define RK3036_RST_I2S 24
+#define RK3036_RST_DDR_PLL 25
+#define RK3036_RST_GPU_DLL 26
+#define RK3036_RST_TIMER0 27
+#define RK3036_RST_TIMER1 28
+#define RK3036_RST_CORE_DLL 29
+#define RK3036_RST_EFUSE_P 30
+#define RK3036_RST_ACODEC_P 31
+
+#define RK3036_RST_GPIO0 32
+#define RK3036_RST_GPIO1 33
+#define RK3036_RST_GPIO2 34
+#define RK3036_RST_2RES3 35
+#define RK3036_RST_2RES4 36
+#define RK3036_RST_2RES5 37
+#define RK3036_RST_2RES6 38
+#define RK3036_RST_UART0 39
+#define RK3036_RST_UART1 40
+#define RK3036_RST_UART2 41
+#define RK3036_RST_2RES10 42
+#define RK3036_RST_I2C0 43
+#define RK3036_RST_I2C1 44
+#define RK3036_RST_I2C2 45
+#define RK3036_RST_2RES14 46
+#define RK3036_RST_SFC 47
+
+#define RK3036_RST_PWM0 48
+#define RK3036_RST_3RES1 49
+#define RK3036_RST_3RES2 50
+#define RK3036_RST_DAP 51
+#define RK3036_RST_DAP_SYS 52
+#define RK3036_RST_3RES5 53
+#define RK3036_RST_3RES6 54
+#define RK3036_RST_GRF 55
+#define RK3036_RST_3RES8 56
+#define RK3036_RST_PERIPHSYS_A 57
+#define RK3036_RST_PERIPHSYS_H 58
+#define RK3036_RST_PERIPHSYS_P 59
+#define RK3036_RST_3RES12 60
+#define RK3036_RST_CPU_PERI 61
+#define RK3036_RST_EMEM_PERI 62
+#define RK3036_RST_USB_PERI 63
+
+#define RK3036_RST_DMA2 64
+#define RK3036_RST_4RES1 65
+#define RK3036_RST_MAC 66
+#define RK3036_RST_4RES3 67
+#define RK3036_RST_NANDC 68
+#define RK3036_RST_USBOTG0 69
+#define RK3036_RST_4RES6 70
+#define RK3036_RST_OTGC0 71
+#define RK3036_RST_USBOTG1 72
+#define RK3036_RST_4RES9 73
+#define RK3036_RST_OTGC1 74
+#define RK3036_RST_4RES11 75
+#define RK3036_RST_4RES12 76
+#define RK3036_RST_4RES13 77
+#define RK3036_RST_4RES14 78
+#define RK3036_RST_DDRMSCH 79
+
+#define RK3036_RST_5RES0 80
+#define RK3036_RST_MMC0 81
+#define RK3036_RST_SDIO 82
+#define RK3036_RST_EMMC 83
+#define RK3036_RST_SPI0 84
+#define RK3036_RST_5RES5 85
+#define RK3036_RST_WDT 86
+#define RK3036_RST_5RES7 87
+#define RK3036_RST_DDRPHY 88
+#define RK3036_RST_DDRPHY_P 89
+#define RK3036_RST_DDRCTRL 90
+#define RK3036_RST_DDRCTRL_P 91
+#define RK3036_RST_5RES12 92
+#define RK3036_RST_5RES13 93
+#define RK3036_RST_5RES14 94
+#define RK3036_RST_5RES15 95
+
+#define RK3036_RST_HDMI_P 96
+#define RK3036_RST_6RES1 97
+#define RK3036_RST_6RES2 98
+#define RK3036_RST_VIO_BUS_H 99
+#define RK3036_RST_6RES4 100
+#define RK3036_RST_6RES5 101
+#define RK3036_RST_6RES6 102
+#define RK3036_RST_UTMI0 103
+#define RK3036_RST_UTMI1 104
+#define RK3036_RST_USBPOR 105
+#define RK3036_RST_6RES10 106
+#define RK3036_RST_6RES11 107
+#define RK3036_RST_6RES12 108
+#define RK3036_RST_6RES13 109
+#define RK3036_RST_6RES14 110
+#define RK3036_RST_6RES15 111
+
+#define RK3036_RST_VCODEC_A 112
+#define RK3036_RST_VCODEC_H 113
+#define RK3036_RST_VIO1_A 114
+#define RK3036_RST_HEVC 115
+#define RK3036_RST_VCODEC_NIU_A 116
+#define RK3036_RST_LCDC1_A 117
+#define RK3036_RST_LCDC1_H 118
+#define RK3036_RST_LCDC1_D 119
+#define RK3036_RST_GPU 120
+#define RK3036_RST_7RES9 121
+#define RK3036_RST_GPU_NIU_A 122
+#define RK3036_RST_7RES11 123
+#define RK3036_RST_7RES12 124
+#define RK3036_RST_7RES13 125
+#define RK3036_RST_7RES14 126
+#define RK3036_RST_7RES15 127
+
+#define RK3036_RST_8RES0 128
+#define RK3036_RST_8RES1 129
+#define RK3036_RST_8RES2 130
+#define RK3036_RST_DBG_P 131
+/* con8[15:4] is reserved */
+
+#endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_RK3036_H */
diff --git a/include/dt-bindings/clock/rockchip,rk312x.h b/include/dt-bindings/clock/rockchip,rk312x.h
new file mode 100755
index 0000000..0af5abc
--- /dev/null
+++ b/include/dt-bindings/clock/rockchip,rk312x.h
@@ -0,0 +1,167 @@
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_RK3128_H
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_RK3128_H
+
+#include "rockchip.h"
+
+/* pll id */
+#define RK3128_APLL_ID 0
+#define RK3128_DPLL_ID 1
+#define RK3128_CPLL_ID 2
+#define RK3128_GPLL_ID 3
+#define RK3128_END_PLL_ID 4
+
+/* reset id */
+#define RK3128_RST_CORE0_PO 0
+#define RK3128_RST_CORE1_PO 1
+#define RK3128_RST_CORE2_PO 2
+#define RK3128_RST_CORE3_PO 3
+#define RK3128_RST_CORE0 4
+#define RK3128_RST_CORE1 5
+#define RK3128_RST_CORE2 6
+#define RK3128_RST_CORE3 7
+#define RK3128_RST_CORE0_DBG 8
+#define RK3128_RST_CORE1_DBG 9
+#define RK3128_RST_CORE2_DBG 10
+#define RK3128_RST_CORE3_DBG 11
+#define RK3128_RST_TOPDBG 12
+#define RK3128_RST_ACLK_CORE 13
+#define RK3128_RST_STRC_SYS_A 14
+#define RK3128_RST_L2C 15
+
+#define RK3128_RST_1RES0 16
+#define RK3128_RST_1RES1 17
+#define RK3128_RST_CPUSYS_H 18
+#define RK3128_RST_AHB2APB_H 19
+#define RK3128_RST_SPDIF 20
+#define RK3128_RST_INTMEM 21
+#define RK3128_RST_ROM 22
+#define RK3128_RST_PERI_NIU 23
+#define RK3128_RST_I2S_2CH 24
+#define RK3128_RST_I2S_8CH 25
+#define RK3128_RST_GPU_PVTM 26
+#define RK3128_RST_FUNC_PVTM 27
+#define RK3128_RST_1RES12 28
+#define RK3128_RST_CORE_PVTM 29
+#define RK3128_RST_EFUSE_P 30
+#define RK3128_RST_ACODEC_P 31
+
+#define RK3128_RST_GPIO0 32
+#define RK3128_RST_GPIO1 33
+#define RK3128_RST_GPIO2 34
+#define RK3128_RST_GPIO3 35
+#define RK3128_RST_MIPIPHY 36
+#define RK3128_RST_2RES5 37
+#define RK3128_RST_2RES6 38
+#define RK3128_RST_UART0 39
+#define RK3128_RST_UART1 40
+#define RK3128_RST_UART2 41
+#define RK3128_RST_2RES10 42
+#define RK3128_RST_I2C0 43
+#define RK3128_RST_I2C1 44
+#define RK3128_RST_I2C2 45
+#define RK3128_RST_I2C3 46
+#define RK3128_RST_SFC 47
+
+#define RK3128_RST_PWM0 48
+#define RK3128_RST_3RES1 49
+#define RK3128_RST_DAP_P 50
+#define RK3128_RST_DAP 51
+#define RK3128_RST_DAP_SYS 52
+#define RK3128_RST_CRYPTO 53
+#define RK3128_RST_3RES6 54
+#define RK3128_RST_GRF 55
+#define RK3128_RST_GMAC 56
+#define RK3128_RST_PERIPHSYS_A 57
+#define RK3128_RST_PERIPHSYS_H 58
+#define RK3128_RST_PERIPHSYS_P 59
+#define RK3128_RST_SMART_CARD 60
+#define RK3128_RST_CPU_PERI 61
+#define RK3128_RST_EMEM_PERI 62
+#define RK3128_RST_USB_PERI 63
+
+#define RK3128_RST_DMA2 64
+#define RK3128_RST_4RES1 65
+#define RK3128_RST_4RES2 66
+#define RK3128_RST_GPS 67
+#define RK3128_RST_NANDC 68
+#define RK3128_RST_USBOTG0 69
+#define RK3128_RST_4RES6 70
+#define RK3128_RST_OTGC0 71
+#define RK3128_RST_USBOTG1 72
+#define RK3128_RST_4RES9 73
+#define RK3128_RST_OTGC1 74
+#define RK3128_RST_4RES11 75
+#define RK3128_RST_4RES12 76
+#define RK3128_RST_4RES13 77
+#define RK3128_RST_4RES14 78
+#define RK3128_RST_DDRMSCH 79
+
+#define RK3128_RST_5RES0 80
+#define RK3128_RST_MMC0 81
+#define RK3128_RST_SDIO 82
+#define RK3128_RST_EMMC 83
+#define RK3128_RST_SPI0 84
+#define RK3128_RST_5RES5 85
+#define RK3128_RST_WDT 86
+#define RK3128_RST_SARADC 87
+#define RK3128_RST_DDRPHY 88
+#define RK3128_RST_DDRPHY_P 89
+#define RK3128_RST_DDRCTRL 90
+#define RK3128_RST_DDRCTRL_P 91
+#define RK3128_RST_TSP 92
+#define RK3128_RST_TSP_CLKIN0 93
+#define RK3128_RST_USBHOST0_EHCI 94
+#define RK3128_RST_5RES15 95
+
+#define RK3128_RST_HDMI_P 96
+#define RK3128_RST_VIO_ARBI_H 97
+#define RK3128_RST_VIO_A 98
+#define RK3128_RST_VIO_BUS_H 99
+#define RK3128_RST_LCDC0_A 100
+#define RK3128_RST_LCDC0_H 101
+#define RK3128_RST_LCDC0_D 102
+#define RK3128_RST_UTMI0 103
+#define RK3128_RST_UTMI1 104
+#define RK3128_RST_USBPOR 105
+#define RK3128_RST_IEP_A 106
+#define RK3128_RST_IEP_H 107
+#define RK3128_RST_RGA_A 108
+#define RK3128_RST_RGA_H 109
+#define RK3128_RST_CIF0 110
+#define RK3128_RST_PMU 111
+
+#define RK3128_RST_VCODEC_A 112
+#define RK3128_RST_VCODEC_H 113
+#define RK3128_RST_VIO1_A 114
+#define RK3128_RST_HEVC 115
+#define RK3128_RST_VCODEC_NIU_A 116
+#define RK3128_RST_PMU_NIU 117
+#define RK3128_RST_7RES6 118
+#define RK3128_RST_LCDC0_S 119
+#define RK3128_RST_GPU 120
+#define RK3128_RST_7RES9 121
+#define RK3128_RST_GPU_NIU_A 122
+#define RK3128_RST_EBC_A 123
+#define RK3128_RST_EBC_H 124
+#define RK3128_RST_7RES13 125
+#define RK3128_RST_7RES14 126
+#define RK3128_RST_7RES15 127
+
+#define RK3128_RST_CORE_DBG 128
+#define RK3128_RST_DBG_P 129
+#define RK3128_RST_TIMER0 130
+#define RK3128_RST_TIMER1 131
+#define RK3128_RST_TIMER2 132
+#define RK3128_RST_TIMER3 133
+#define RK3128_RST_TIMER4 134
+#define RK3128_RST_TIMER5 135
+#define RK3128_RST_VIO_H2P 136
+#define RK3128_RST_VIO_MIPI_DSI 137
+#define RK3128_RST_8RES10 138
+#define RK3128_RST_8RES11 139
+#define RK3128_RST_8RES12 140
+#define RK3128_RST_8RES13 141
+#define RK3128_RST_8RES14 142
+#define RK3128_RST_8RES15 143
+
+#endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_RK3128_H */
diff --git a/include/dt-bindings/clock/rockchip,rk3188.h b/include/dt-bindings/clock/rockchip,rk3188.h
new file mode 100644
index 0000000..b8c57e1
--- /dev/null
+++ b/include/dt-bindings/clock/rockchip,rk3188.h
@@ -0,0 +1,13 @@
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_RK3188_H
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_RK3188_H
+
+#include "rockchip.h"
+
+/* pll id */
+#define RK3188_APLL_ID 0
+#define RK3188_DPLL_ID 1
+#define RK3188_CPLL_ID 2
+#define RK3188_GPLL_ID 3
+#define RK3188_END_PLL_ID 4
+
+#endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_RK3188_H */
diff --git a/include/dt-bindings/clock/rockchip,rk3228.h b/include/dt-bindings/clock/rockchip,rk3228.h
new file mode 100644
index 0000000..b86e445
--- /dev/null
+++ b/include/dt-bindings/clock/rockchip,rk3228.h
@@ -0,0 +1,167 @@
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_RK3228_H
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_RK3228_H
+
+#include "rockchip.h"
+
+/* pll id */
+#define RK3228_APLL_ID 0
+#define RK3228_DPLL_ID 1
+#define RK3228_CPLL_ID 2
+#define RK3228_GPLL_ID 3
+#define RK3228_END_PLL_ID 4
+
+/* reset id */
+#define RK3228_RST_CORE0_PO 0
+#define RK3228_RST_CORE1_PO 1
+#define RK3228_RST_CORE2_PO 2
+#define RK3228_RST_CORE3_PO 3
+#define RK3228_RST_CORE0 4
+#define RK3228_RST_CORE1 5
+#define RK3228_RST_CORE2 6
+#define RK3228_RST_CORE3 7
+#define RK3228_RST_CORE0_DBG 8
+#define RK3228_RST_CORE1_DBG 9
+#define RK3228_RST_CORE2_DBG 10
+#define RK3228_RST_CORE3_DBG 11
+#define RK3228_RST_TOPDBG 12
+#define RK3228_RST_ACLK_CORE 13
+#define RK3228_RST_NOC_A 14
+#define RK3228_RST_L2C 15
+
+#define RK3228_RST_1RES0 16
+#define RK3228_RST_1RES1 17
+#define RK3228_RST_CPUSYS_H 18
+#define RK3228_RST_BUSSYS_H 19
+#define RK3228_RST_SPDIF 20
+#define RK3228_RST_INTMEM 21
+#define RK3228_RST_ROM 22
+#define RK3228_RST_OTG_ADP 23
+#define RK3228_RST_I2S0 24
+#define RK3228_RST_I2S1 25
+#define RK3228_RST_I2S2 26
+#define RK3228_RST_ACODEC_P 27
+#define RK3228_RST_DFIMON 28
+#define RK3228_RST_MSCH 29
+#define RK3228_RST_EFUSE_1024 30
+#define RK3228_RST_EFUSE_256 31
+
+#define RK3228_RST_GPIO0 32
+#define RK3228_RST_GPIO1 33
+#define RK3228_RST_GPIO2 34
+#define RK3228_RST_GPIO3 35
+#define RK3228_RST_PERIPH_NOC_A 36
+#define RK3228_RST_PERIPH_NOC_H 37
+#define RK3228_RST_PERIPH_NOC_P 38
+#define RK3228_RST_UART0 39
+#define RK3228_RST_UART1 40
+#define RK3228_RST_UART2 41
+#define RK3228_RST_PHYNOC 42
+#define RK3228_RST_I2C0 43
+#define RK3228_RST_I2C1 44
+#define RK3228_RST_I2C2 45
+#define RK3228_RST_I2C3 46
+#define RK3228_RST_2RES15 47
+
+#define RK3228_RST_PWM0 48
+#define RK3228_RST_A53_GIC 49
+#define RK3228_RST_3RES2 50
+#define RK3228_RST_DAP 51
+#define RK3228_RST_DAP_NOC 52
+#define RK3228_RST_CRYPTO 53
+#define RK3228_RST_SGRF 54
+#define RK3228_RST_GRF 55
+#define RK3228_RST_GMAC 56
+#define RK3228_RST_3RES9 57
+#define RK3228_RST_PERIPHSYS_A 58
+#define RK3228_RST_3RES11 59
+#define RK3228_RST_3RES12 60
+#define RK3228_RST_3RES13 61
+#define RK3228_RST_3RES14 62
+#define RK3228_RST_MACPHY 63
+
+#define RK3228_RST_4RES0 64
+#define RK3228_RST_4RES1 65
+#define RK3228_RST_4RES2 66
+#define RK3228_RST_4RES3 67
+#define RK3228_RST_NANDC 68
+#define RK3228_RST_USBOTG0 69
+#define RK3228_RST_OTGC0 70
+#define RK3228_RST_USBHOST0 71
+#define RK3228_RST_HOST_CTRL0 72
+#define RK3228_RST_USBHOST1 73
+#define RK3228_RST_HOST_CTRL1 74
+#define RK3228_RST_USBHOST2 75
+#define RK3228_RST_HOST_CTRL2 76
+#define RK3228_RST_USBPOR0 77
+#define RK3228_RST_USBPOR1 78
+#define RK3228_RST_DDRMSCH 79
+
+#define RK3228_RST_SMART_CARD 80
+#define RK3228_RST_SDMMC0 81
+#define RK3228_RST_SDIO 82
+#define RK3228_RST_EMMC 83
+#define RK3228_RST_SPI0 84
+#define RK3228_RST_TSP_H 85
+#define RK3228_RST_TSP 86
+#define RK3228_RST_TSADC 87
+#define RK3228_RST_DDRPHY 88
+#define RK3228_RST_DDRPHY_P 89
+#define RK3228_RST_DDRCTRL 90
+#define RK3228_RST_DDRCTRL_P 91
+#define RK3228_RST_HOST0_ECHI 92
+#define RK3228_RST_HOST1_ECHI 93
+#define RK3228_RST_HOST2_ECHI 94
+#define RK3228_RST_VOP 95
+
+#define RK3228_RST_HDMI_P 96
+#define RK3228_RST_VIO_ARBI_H 97
+#define RK3228_RST_IEP_NOC_A 98
+#define RK3228_RST_VIO_NOC_H 99
+#define RK3228_RST_VOP_A 100
+#define RK3228_RST_VOP_H 101
+#define RK3228_RST_VOP_D 102
+#define RK3228_RST_UTMI0 103
+#define RK3228_RST_UTMI1 104
+#define RK3228_RST_UTMI2 105
+#define RK3228_RST_UTMI3 106
+#define RK3228_RST_RGA 107
+#define RK3228_RST_RGA_NOC_A 108
+#define RK3228_RST_RGA_A 109
+#define RK3228_RST_RGA_H 110
+#define RK3228_RST_HDCP_A 111
+
+#define RK3228_RST_VPU_A 112
+#define RK3228_RST_VPU_H 113
+#define RK3228_RST_7RES2 114
+#define RK3228_RST_7RES3 115
+#define RK3228_RST_VPU_NOC_A 116
+#define RK3228_RST_VPU_NOC_H 117
+#define RK3228_RST_RKVDEC_A 118
+#define RK3228_RST_RKVDEC_NOC_A 119
+#define RK3228_RST_RKVDEC_H 120
+#define RK3228_RST_RKVDEC_NOC_H 121
+#define RK3228_RST_RKVDEC_CORE 122
+#define RK3228_RST_RKVDEC_CABAC 123
+#define RK3228_RST_IEP_A 124
+#define RK3228_RST_IEP_H 125
+#define RK3228_RST_GPU_A 126
+#define RK3228_RST_GPU_NOC_A 127
+
+#define RK3228_RST_CORE_DBG 128
+#define RK3228_RST_DBG_P 129
+#define RK3228_RST_TIMER0 130
+#define RK3228_RST_TIMER1 131
+#define RK3228_RST_TIMER2 132
+#define RK3228_RST_TIMER3 133
+#define RK3228_RST_TIMER4 134
+#define RK3228_RST_TIMER5 135
+#define RK3228_RST_VIO_H2P 136
+#define RK3228_RST_8RES9 137
+#define RK3228_RST_8RES10 138
+#define RK3228_RST_HDMIPHY 139
+#define RK3228_RST_VDAC 140
+#define RK3228_RST_TIMER_6CH 141
+#define RK3228_RST_8RES14 142
+#define RK3228_RST_8RES15 143
+
+#endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_RK3228_H */
diff --git a/include/dt-bindings/clock/rockchip,rk3288.h b/include/dt-bindings/clock/rockchip,rk3288.h
new file mode 100644
index 0000000..1a2803c
--- /dev/null
+++ b/include/dt-bindings/clock/rockchip,rk3288.h
@@ -0,0 +1,220 @@
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_RK3288_H
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_RK3288_H
+
+#include "rockchip.h"
+
+/* pll id */
+#define RK3288_APLL_ID 0
+#define RK3288_DPLL_ID 1
+#define RK3288_CPLL_ID 2
+#define RK3288_GPLL_ID 3
+#define RK3288_NPLL_ID 4
+#define RK3288_END_PLL_ID 5
+
+/* reset id */
+#define RK3288_SOFT_RST_CORE0 0
+#define RK3288_SOFT_RST_CORE1 1
+#define RK3288_SOFT_RST_CORE2 2
+#define RK3288_SOFT_RST_CORE3 3
+#define RK3288_SOFT_RST_CORE0_PO 4
+#define RK3288_SOFT_RST_CORE1_PO 5
+#define RK3288_SOFT_RST_CORE2_PO 6
+#define RK3288_SOFT_RST_CORE3_PO 7
+#define RK3288_SOFT_RST_PD_CORE_STR_SYS_A 8
+#define RK3288_SOFT_RST_PD_BUS_STR_SYS_A 9
+#define RK3288_SOFT_RST_L2C 10
+#define RK3288_SOFT_RST_TOPDBG 11
+#define RK3288_SOFT_RST_CORE0_DBG 12
+#define RK3288_SOFT_RST_CORE1_DBG 13
+#define RK3288_SOFT_RST_CORE2_DBG 14
+#define RK3288_SOFT_RST_CORE3_DBG 15
+
+#define RK3288_SOFT_RST_PD_BUS_AHB_ARBITOR 16
+#define RK3288_SOFT_RST_EFUSE_256BIT_P 17
+#define RK3288_SOFT_RST_DMA1 18
+#define RK3288_SOFT_RST_INTMEM 19
+#define RK3288_SOFT_RST_ROM 20
+#define RK3288_SOFT_RST_SPDIF_8CH 21
+#define RK3288_SOFT_RST_TIMER_P 22
+#define RK3288_SOFT_RST_I2S 23
+#define RK3288_SOFT_RST_SPDIF 24
+#define RK3288_SOFT_RST_TIMER0 25
+#define RK3288_SOFT_RST_TIMER1 26
+#define RK3288_SOFT_RST_TIMER2 27
+#define RK3288_SOFT_RST_TIMER3 28
+#define RK3288_SOFT_RST_TIMER4 29
+#define RK3288_SOFT_RST_TIMER5 30
+#define RK3288_SOFT_RST_EFUSE_P 31
+
+#define RK3288_SOFT_RST_GPIO0 32
+#define RK3288_SOFT_RST_GPIO1 33
+#define RK3288_SOFT_RST_GPIO2 34
+#define RK3288_SOFT_RST_GPIO3 35
+#define RK3288_SOFT_RST_GPIO4 36
+#define RK3288_SOFT_RST_GPIO5 37
+#define RK3288_SOFT_RST_GPIO6 38
+#define RK3288_SOFT_RST_GPIO7 39
+#define RK3288_SOFT_RST_GPIO8 40
+#define RK3288_SOFT_RST_2RES9 41
+#define RK3288_SOFT_RST_I2C0 42
+#define RK3288_SOFT_RST_I2C1 43
+#define RK3288_SOFT_RST_I2C2 44
+#define RK3288_SOFT_RST_I2C3 45
+#define RK3288_SOFT_RST_I2C4 46
+#define RK3288_SOFT_RST_I2C5 47
+
+#define RK3288_SOFT_RST_DW_PWM 48
+#define RK3288_SOFT_RST_MMC_PERI 49
+#define RK3288_SOFT_RST_PERIPH_MMU 50
+#define RK3288_SOFT_RST_DAP 51
+#define RK3288_SOFT_RST_DAP_SYS 52
+#define RK3288_SOFT_RST_TPIU_AT 53
+#define RK3288_SOFT_RST_PMU_P 54
+#define RK3288_SOFT_RST_GRF 55
+#define RK3288_SOFT_RST_PMU 56
+#define RK3288_SOFT_RST_PERIPHSYS_A 57
+#define RK3288_SOFT_RST_PERIPHSYS_H 58
+#define RK3288_SOFT_RST_PERIPHSYS_P 59
+#define RK3288_SOFT_RST_PERIPH_NIU 60
+#define RK3288_SOFT_RST_PD_PERI_AHB_ARBITOR 61
+#define RK3288_SOFT_RST_EMEM_PERI 62
+#define RK3288_SOFT_RST_USB_PERI 63
+
+#define RK3288_SOFT_RST_DMA2 64
+#define RK3288_SOFT_RST_4RES1 65
+#define RK3288_SOFT_RST_MAC 66
+#define RK3288_SOFT_RST_GPS 67
+#define RK3288_SOFT_RST_4RES4 68
+#define RK3288_SOFT_RST_RK_PWM 69
+#define RK3288_SOFT_RST_4RES6 70
+#define RK3288_SOFT_RST_CCP 71
+#define RK3288_SOFT_RST_USB_HOST0 72
+#define RK3288_SOFT_RST_EHCI1 73
+#define RK3288_SOFT_RST_EHCI1_AUX 74
+#define RK3288_SOFT_RST_EHCI1PHY 75
+#define RK3288_SOFT_RST_HSADC 76
+#define RK3288_SOFT_RST_NANDC0 77
+#define RK3288_SOFT_RST_NANDC1 78
+#define RK3288_SOFT_RST_4RES15 79
+
+#define RK3288_SOFT_RST_TZPC 80
+#define RK3288_SOFT_RST_5RES1 81
+#define RK3288_SOFT_RST_5RES2 82
+#define RK3288_SOFT_RST_SPI0 83
+#define RK3288_SOFT_RST_SPI1 84
+#define RK3288_SOFT_RST_SPI2 85
+#define RK3288_SOFT_RST_5RES6 86
+#define RK3288_SOFT_RST_SARADC 87
+#define RK3288_SOFT_RST_PD_ALIVE_NIU_P 88
+#define RK3288_SOFT_RST_PD_PMU_INTMEM_P 89
+#define RK3288_SOFT_RST_PD_PMU_NIU_P 90
+#define RK3288_SOFT_RST_SECURITY_GRF_P 91
+#define RK3288_SOFT_RST_5RES12 92
+#define RK3288_SOFT_RST_5RES13 93
+#define RK3288_SOFT_RST_5RES14 94
+#define RK3288_SOFT_RST_5RES15 95
+
+#define RK3288_SOFT_RST_VIO_ARBI_H 96
+#define RK3288_SOFT_RST_RGA_NIU_A 97
+#define RK3288_SOFT_RST_VIO0_NIU_A 98
+#define RK3288_SOFT_RST_VIO_NIU_H 99
+#define RK3288_SOFT_RST_LCDC0_A 100
+#define RK3288_SOFT_RST_LCDC0_H 101
+#define RK3288_SOFT_RST_LCDC0_D 102
+#define RK3288_SOFT_RST_VIO1_NIU_A 103
+#define RK3288_SOFT_RST_VIP 104
+#define RK3288_SOFT_RST_RGA_CORE 105
+#define RK3288_SOFT_RST_IEP_A 106
+#define RK3288_SOFT_RST_IEP_H 107
+#define RK3288_SOFT_RST_RGA_A 108
+#define RK3288_SOFT_RST_RGA_H 109
+#define RK3288_SOFT_RST_ISP 110
+#define RK3288_SOFT_RST_EDP 111
+
+#define RK3288_SOFT_RST_VCODEC_A 112
+#define RK3288_SOFT_RST_VCODEC_H 113
+#define RK3288_SOFT_RST_VIO_H2P_H 114
+#define RK3288_SOFT_RST_MIPIDSI0_P 115
+#define RK3288_SOFT_RST_MIPIDSI1_P 116
+#define RK3288_SOFT_RST_MIPICSI_P 117
+#define RK3288_SOFT_RST_LVDS_PHY_P 118
+#define RK3288_SOFT_RST_LVDS_CON 119
+#define RK3288_SOFT_RST_GPU 120
+#define RK3288_SOFT_RST_HDMI 121
+#define RK3288_SOFT_RST_7RES10 122
+#define RK3288_SOFT_RST_7RES11 123
+#define RK3288_SOFT_RST_CORE_PVTM 124
+#define RK3288_SOFT_RST_GPU_PVTM 125
+#define RK3288_SOFT_RST_7RES14 126
+#define RK3288_SOFT_RST_7RES15 127
+
+#define RK3288_SOFT_RST_MMC0 128
+#define RK3288_SOFT_RST_SDIO0 129
+#define RK3288_SOFT_RST_SDIO1 130
+#define RK3288_SOFT_RST_EMMC 131
+#define RK3288_SOFT_RST_USBOTG_H 132
+#define RK3288_SOFT_RST_USBOTGPHY 133
+#define RK3288_SOFT_RST_USBOTGC 134
+#define RK3288_SOFT_RST_USBHOST0_H 135
+#define RK3288_SOFT_RST_USBHOST0PHY 136
+#define RK3288_SOFT_RST_USBHOST0C 137
+#define RK3288_SOFT_RST_USBHOST1_H 138
+#define RK3288_SOFT_RST_USBHOST1PHY 139
+#define RK3288_SOFT_RST_USBHOST1C 140
+#define RK3288_SOFT_RST_USB_ADP 141
+#define RK3288_SOFT_RST_ACC_EFUSE 142
+#define RK3288_SOFT_RST_8RES15 143
+
+#define RK3288_SOFT_RST_CORESIGHT 144
+#define RK3288_SOFT_RST_PD_CORE_AHB_NOC 145
+#define RK3288_SOFT_RST_PD_CORE_APB_NOC 146
+#define RK3288_SOFT_RST_PD_CORE_MP_AXI 147
+#define RK3288_SOFT_RST_GIC 148
+#define RK3288_SOFT_RST_LCDCPWM0 149
+#define RK3288_SOFT_RST_LCDCPWM1 150
+#define RK3288_SOFT_RST_VIO0_H2P_BRG 151
+#define RK3288_SOFT_RST_VIO1_H2P_BRG 152
+#define RK3288_SOFT_RST_RGA_H2P_BRG 153
+#define RK3288_SOFT_RST_HEVC 154
+#define RK3288_SOFT_RST_9RES11 155
+#define RK3288_SOFT_RST_9RES12 156
+#define RK3288_SOFT_RST_9RES13 157
+#define RK3288_SOFT_RST_9RES14 158
+#define RK3288_SOFT_RST_TSADC_P 159
+
+#define RK3288_SOFT_RST_DDRPHY0 160
+#define RK3288_SOFT_RST_DDRPHY0_P 161
+#define RK3288_SOFT_RST_DDRCTRL0 162
+#define RK3288_SOFT_RST_DDRCTRL0_P 163
+#define RK3288_SOFT_RST_DDRPHY0_CTL 164
+#define RK3288_SOFT_RST_DDRPHY1 165
+#define RK3288_SOFT_RST_DDRPHY1_P 166
+#define RK3288_SOFT_RST_DDRCTRL1 167
+#define RK3288_SOFT_RST_DDRCTRL1_P 168
+#define RK3288_SOFT_RST_DDRPHY1_CTL 169
+#define RK3288_SOFT_RST_DDRMSCH0 170
+#define RK3288_SOFT_RST_DDRMSCH1 171
+#define RK3288_SOFT_RST_10RES12 172
+#define RK3288_SOFT_RST_10RES13 173
+#define RK3288_SOFT_RST_CRYPTO 174
+#define RK3288_SOFT_RST_C2C_HOST 175
+
+#define RK3288_SOFT_RST_LCDC1_A 176
+#define RK3288_SOFT_RST_LCDC1_H 177
+#define RK3288_SOFT_RST_LCDC1_D 178
+#define RK3288_SOFT_RST_UART0 179
+#define RK3288_SOFT_RST_UART1 180
+#define RK3288_SOFT_RST_UART2 181
+#define RK3288_SOFT_RST_UART3 182
+#define RK3288_SOFT_RST_UART4 183
+#define RK3288_SOFT_RST_11RES8 184
+#define RK3288_SOFT_RST_11RES9 185
+#define RK3288_SOFT_RST_SIMC 186
+#define RK3288_SOFT_RST_PS2C 187
+#define RK3288_SOFT_RST_TSP 188
+#define RK3288_SOFT_RST_TSP_CLKIN0 189
+#define RK3288_SOFT_RST_TSP_CLKIN1 190
+#define RK3288_SOFT_RST_TSP_27M 191
+
+
+#endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_RK3288_H */
diff --git a/include/dt-bindings/clock/rockchip,rk3368.h b/include/dt-bindings/clock/rockchip,rk3368.h
new file mode 100644
index 0000000..9ebf185
--- /dev/null
+++ b/include/dt-bindings/clock/rockchip,rk3368.h
@@ -0,0 +1,262 @@
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_RK3368_H
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_RK3368_H
+
+#include "rockchip.h"
+
+/* reset id */
+#define RK3368_SRST_CORE_B_0_SC 0
+#define RK3368_SRST_CORE_B_1 1
+#define RK3368_SRST_CORE_B_2 2
+#define RK3368_SRST_CORE_B_3 3
+#define RK3368_SRST_CORE_B_PO0_SC 4
+#define RK3368_SRST_CORE_B_PO1 5
+#define RK3368_SRST_CORE_B_PO2 6
+#define RK3368_SRST_CORE_B_PO3 7
+#define RK3368_SRST_L2_B_SC 8
+#define RK3368_SRST_ADB_B_SC 9
+#define RK3368_SRST_PD_CORE_B_NIU 10
+#define RK3368_SRST_STRC_SYS_A_SC 11
+#define RK3368_SRST_0RES12 12
+#define RK3368_SRST_0RES13 13
+#define RK3368_SRST_SOCDBG_B 14
+#define RK3368_SRST_CORE_B_DBG 15
+
+#define RK3368_SRST_1RES0 16
+#define RK3368_SRST_1RES1 17
+#define RK3368_SRST_DMA1 18
+#define RK3368_SRST_INTMEM 19
+#define RK3368_SRST_ROM 20
+#define RK3368_SRST_SPDIF_8CH 21
+#define RK3368_SRST_1RES6 22
+#define RK3368_SRST_I2S 23
+#define RK3368_SRST_MAILBOX 24
+#define RK3368_SRST_I2S_2CH 25
+#define RK3368_SRST_EFUSE_256_P 26
+#define RK3368_SRST_1RES11 27
+#define RK3368_SRST_MCU_SYS 28
+#define RK3368_SRST_MCU_PO 29
+#define RK3368_SRST_MCU_NOC_H 30
+#define RK3368_SRST_EFUSE_P 31
+
+#define RK3368_SRST_GPIO0 32
+#define RK3368_SRST_GPIO1 33
+#define RK3368_SRST_GPIO2 34
+#define RK3368_SRST_GPIO3 35
+#define RK3368_SRST_GPIO4 36
+#define RK3368_SRST_2RES5 37
+#define RK3368_SRST_2RES6 38
+#define RK3368_SRST_2RES7 39
+#define RK3368_SRST_2RES8 40
+#define RK3368_SRST_PMUGRF_P 41
+#define RK3368_SRST_I2C0 42
+#define RK3368_SRST_I2C1 43
+#define RK3368_SRST_I2C2 44
+#define RK3368_SRST_I2C3 45
+#define RK3368_SRST_I2C4 46
+#define RK3368_SRST_I2C5 47
+
+#define RK3368_SRST_DW_PWM 48
+#define RK3368_SRST_MMC_PERI 49
+#define RK3368_SRST_PERIPH_MMU 50
+#define RK3368_SRST_3RES3 51
+#define RK3368_SRST_3RES4 52
+#define RK3368_SRST_3RES5 53
+#define RK3368_SRST_3RES6 54
+#define RK3368_SRST_GRF 55
+#define RK3368_SRST_PMU 56
+#define RK3368_SRST_PERIPH_SYS_A 57
+#define RK3368_SRST_PERIPH_SYS_H 58
+#define RK3368_SRST_PERIPH_SYS_P 59
+#define RK3368_SRST_PERIPH_NIU 60
+#define RK3368_SRST_PD_PERI_AHB_ARBITOR 61
+#define RK3368_SRST_EMEM_PERI 62
+#define RK3368_SRST_USB_PERI 63
+
+#define RK3368_SRST_DMA2 64
+#define RK3368_SRST_4RES1 65
+#define RK3368_SRST_MAC 66
+#define RK3368_SRST_GPS 67
+#define RK3368_SRST_4RES4 68
+#define RK3368_SRST_RK_PWM 69
+#define RK3368_SRST_4RES6 70
+#define RK3368_SRST_4RES7 71
+#define RK3368_SRST_HOST0_H 72
+#define RK3368_SRST_EHCI1 73
+#define RK3368_SRST_EHCI1_AUX 74
+#define RK3368_SRST_EHCI1PHY 75
+#define RK3368_SRST_HSADC_H 76
+#define RK3368_SRST_NANDC0 77
+#define RK3368_SRST_4RES14 78
+#define RK3368_SRST_SFC 79
+
+#define RK3368_SRST_5RES0 80
+#define RK3368_SRST_5RES1 81
+#define RK3368_SRST_5RES2 82
+#define RK3368_SRST_SPI0 83
+#define RK3368_SRST_SPI1 84
+#define RK3368_SRST_SPI2 85
+#define RK3368_SRST_5RES6 86
+#define RK3368_SRST_SARADC 87
+#define RK3368_SRST_PD_ALIVE_NIU_P 88
+#define RK3368_SRST_PD_PMU_INTMEM_P 89
+#define RK3368_SRST_PD_PMU_NIU_P 90
+#define RK3368_SRST_SGRF_P 91
+#define RK3368_SRST_5RES12 92
+#define RK3368_SRST_5RES13 93
+#define RK3368_SRST_5RES14 94
+#define RK3368_SRST_5RES15 95
+
+#define RK3368_SRST_VIO_ARBI_H 96
+#define RK3368_SRST_RGA_NIU_A 97
+#define RK3368_SRST_VIO0_NIU_A 98
+#define RK3368_SRST_VIO0_BUS_H 99
+#define RK3368_SRST_LCDC0_A 100
+#define RK3368_SRST_LCDC0_H 101
+#define RK3368_SRST_LCDC0_D 102
+#define RK3368_SRST_6RES7 103
+#define RK3368_SRST_VIP 104
+#define RK3368_SRST_RGA_CORE 105
+#define RK3368_SRST_IEP_A 106
+#define RK3368_SRST_IEP_H 107
+#define RK3368_SRST_RGA_A 108
+#define RK3368_SRST_RGA_H 109
+#define RK3368_SRST_ISP 110
+#define RK3368_SRST_EDP_24M 111
+
+#define RK3368_SRST_VIDEO_A 112
+#define RK3368_SRST_VIDEO_H 113
+#define RK3368_SRST_MIPIDPHYTX_P 114
+#define RK3368_SRST_MIPIDSI0_P 115
+#define RK3368_SRST_MIPIDPHYRX_P 116
+#define RK3368_SRST_MIPICSI_P 117
+#define RK3368_SRST_7RES6 118
+#define RK3368_SRST_7RES7 119
+#define RK3368_SRST_GPU_CORE 120
+#define RK3368_SRST_HDMI 121
+#define RK3368_SRST_EDP_P 122
+#define RK3368_SRST_PMU_PVTM 123
+#define RK3368_SRST_CORE_PVTM 124
+#define RK3368_SRST_GPU_PVTM 125
+#define RK3368_SRST_GPU_SYS_A 126
+#define RK3368_SRST_GPU_MEM_NIU_A 127
+
+#define RK3368_SRST_MMC0 128
+#define RK3368_SRST_SDIO0 129
+#define RK3368_SRST_8RES2 130
+#define RK3368_SRST_EMMC 131
+#define RK3368_SRST_USBOTG0_H 132
+#define RK3368_SRST_USBOTGPHY0 133
+#define RK3368_SRST_USBOTGC0 134
+#define RK3368_SRST_USBHOSTC0_H 135
+#define RK3368_SRST_USBOTGPHY1 136
+#define RK3368_SRST_USBHOSTC0 137
+#define RK3368_SRST_USBPHY0_UTMI 138
+#define RK3368_SRST_USBPHY1_UTMI 139
+#define RK3368_SRST_8RES12 140
+#define RK3368_SRST_USB_ADP 141
+#define RK3368_SRST_8RES14 142
+#define RK3368_SRST_8RES15 143
+
+#define RK3368_SRST_DBG 144
+#define RK3368_SRST_PD_CORE_AHB_NOC 145
+#define RK3368_SRST_PD_CORE_APB_NOC 146
+#define RK3368_SRST_9RES3 147
+#define RK3368_SRST_GIC 148
+#define RK3368_SRST_LCDCPWM0 149
+#define RK3368_SRST_9RES6 150
+#define RK3368_SRST_9RES7 151
+#define RK3368_SRST_9RES8 152
+#define RK3368_SRST_RGA_H2P_BRG 153
+#define RK3368_SRST_VIDEO 154
+#define RK3368_SRST_9RES11 155
+#define RK3368_SRST_9RES12 156
+#define RK3368_SRST_GPU_CFG_NIU_A 157
+#define RK3368_SRST_9RES14 158
+#define RK3368_SRST_TSADC_P 159
+
+#define RK3368_SRST_DDRPHY0 160
+#define RK3368_SRST_DDRPHY0_P 161
+#define RK3368_SRST_DDRCTRL0 162
+#define RK3368_SRST_DDRCTRL0_P 163
+#define RK3368_SRST_10RES4 164
+#define RK3368_SRST_VIDEO_NIU_A 165
+#define RK3368_SRST_10RES6 166
+#define RK3368_SRST_VIDEO_NIU_H 167
+#define RK3368_SRST_10RES8 168
+#define RK3368_SRST_10RES9 169
+#define RK3368_SRST_DDRMSCH0 170
+#define RK3368_SRST_10RES11 171
+#define RK3368_SRST_10RES12 172
+#define RK3368_SRST_SYS_BUS 173
+#define RK3368_SRST_CRYPTO 174
+#define RK3368_SRST_10RES15 175
+
+#define RK3368_SRST_11RES0 176
+#define RK3368_SRST_11RES1 177
+#define RK3368_SRST_11RES2 178
+#define RK3368_SRST_UART0 179
+#define RK3368_SRST_UART1 180
+#define RK3368_SRST_UART2 181
+#define RK3368_SRST_UART3 182
+#define RK3368_SRST_UART4 183
+#define RK3368_SRST_11RES8 184
+#define RK3368_SRST_11RES9 185
+#define RK3368_SRST_SIMC_P 186
+#define RK3368_SRST_11RES11 187
+#define RK3368_SRST_TSP_H 188
+#define RK3368_SRST_TSP_CLKIN0 189
+#define RK3368_SRST_11RES14 190
+#define RK3368_SRST_11RES15 191
+
+#define RK3368_SRST_CORE_L_0_SC 192
+#define RK3368_SRST_CORE_L_1 193
+#define RK3368_SRST_CORE_L_2 194
+#define RK3368_SRST_CORE_L_3 195
+#define RK3368_SRST_CORE_L_PO0_SC 196
+#define RK3368_SRST_CORE_L_PO1 197
+#define RK3368_SRST_CORE_L_PO2 198
+#define RK3368_SRST_CORE_L_PO3 199
+#define RK3368_SRST_L2_L_SC 200
+#define RK3368_SRST_ADB_L_SC 201
+#define RK3368_SRST_PD_CORE_L_NIU_A_SC 202
+#define RK3368_SRST_CCI400_SYS_SC 203
+#define RK3368_SRST_CCI400_DDR_SC 204
+#define RK3368_SRST_CCI400_SC 205
+#define RK3368_SRST_SOCDBG_L 206
+#define RK3368_SRST_CORE_L_DBG 207
+
+#define RK3368_SRST_CORE_B_0 208
+#define RK3368_SRST_CORE_B_PO0 209
+#define RK3368_SRST_L2_B 210
+#define RK3368_SRST_ADB_B 211
+#define RK3368_SRST_PD_CORE_B_NIU_A 212
+#define RK3368_SRST_STRC_SYS_A 213
+#define RK3368_SRST_CORE_L_0 214
+#define RK3368_SRST_CORE_L_PO0 215
+#define RK3368_SRST_L2_L 216
+#define RK3368_SRST_ADB_L 217
+#define RK3368_SRST_PD_CORE_L_NIU_A 218
+#define RK3368_SRST_CCI400_SYS 219
+#define RK3368_SRST_CCI400_DDR 220
+#define RK3368_SRST_CCI400 221
+#define RK3368_SRST_TRACE 222
+#define RK3368_SRST_13RES15 223
+
+#define RK3368_SRST_TIMER00 224
+#define RK3368_SRST_TIMER01 225
+#define RK3368_SRST_TIMER02 226
+#define RK3368_SRST_TIMER03 227
+#define RK3368_SRST_TIMER04 228
+#define RK3368_SRST_TIMER05 229
+#define RK3368_SRST_TIMER10 230
+#define RK3368_SRST_TIMER11 231
+#define RK3368_SRST_TIMER12 232
+#define RK3368_SRST_TIMER13 233
+#define RK3368_SRST_TIMER14 234
+#define RK3368_SRST_TIMER15 235
+#define RK3368_SRST_TIMER0_P 236
+#define RK3368_SRST_TIMER1_P 237
+#define RK3368_SRST_14RES14 238
+#define RK3368_SRST_14RES15 239
+
+#endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_RK3368_H */
diff --git a/include/dt-bindings/clock/rockchip.h b/include/dt-bindings/clock/rockchip.h
new file mode 100644
index 0000000..a7c8c5c
--- /dev/null
+++ b/include/dt-bindings/clock/rockchip.h
@@ -0,0 +1,100 @@
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_H
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_H
+
+#ifndef BIT
+#define BIT(nr) (1 << (nr))
+#endif
+
+#define CLK_DIVIDER_PLUS_ONE (0)
+#define CLK_DIVIDER_ONE_BASED BIT(0)
+#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
+#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
+#define CLK_DIVIDER_HIWORD_MASK BIT(3)
+
+/* Rockchip special defined */
+//#define CLK_DIVIDER_FIXED BIT(6)
+#define CLK_DIVIDER_USER_DEFINE BIT(7)
+
+/*
+ * flags used across common struct clk. these flags should only affect the
+ * top-level framework. custom flags for dealing with hardware specifics
+ * belong in struct clk_foo
+ */
+#define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */
+#define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */
+#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */
+#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
+#define CLK_IS_ROOT BIT(4) /* root clk, has no parent */
+#define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */
+#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
+#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
+#define CLK_SET_RATE_PARENT_IN_ORDER BIT(8) /* consider the order of re-parent
+ and set_div on rate change */
+
+
+
+/* Rockchip pll flags */
+#define CLK_PLL_3188 BIT(0)
+#define CLK_PLL_3188_APLL BIT(1)
+#define CLK_PLL_3188PLUS BIT(2)
+#define CLK_PLL_3188PLUS_APLL BIT(3)
+#define CLK_PLL_3288_APLL BIT(4)
+#define CLK_PLL_3188PLUS_AUTO BIT(5)
+#define CLK_PLL_3036_APLL BIT(6)
+#define CLK_PLL_3036PLUS_AUTO BIT(7)
+#define CLK_PLL_312XPLUS BIT(8)
+#define CLK_PLL_3368_APLLB BIT(9)
+#define CLK_PLL_3368_APLLL BIT(10)
+#define CLK_PLL_3368_LOW_JITTER BIT(11)
+
+
+/* rate_ops index */
+#define CLKOPS_RATE_MUX_DIV 1
+#define CLKOPS_RATE_EVENDIV 2
+#define CLKOPS_RATE_MUX_EVENDIV 3
+#define CLKOPS_RATE_I2S_FRAC 4
+#define CLKOPS_RATE_FRAC 5
+#define CLKOPS_RATE_I2S 6
+#define CLKOPS_RATE_CIFOUT 7
+#define CLKOPS_RATE_UART 8
+#define CLKOPS_RATE_HSADC 9
+#define CLKOPS_RATE_MAC_REF 10
+#define CLKOPS_RATE_CORE 11
+#define CLKOPS_RATE_CORE_CHILD 12
+#define CLKOPS_RATE_DDR 13
+#define CLKOPS_RATE_RK3288_I2S 14
+#define CLKOPS_RATE_RK3288_USB480M 15
+#define CLKOPS_RATE_RK3288_DCLK_LCDC0 16
+#define CLKOPS_RATE_RK3288_DCLK_LCDC1 17
+#define CLKOPS_RATE_DDR_DIV2 18
+#define CLKOPS_RATE_DDR_DIV4 19
+#define CLKOPS_RATE_RK3368_MUX_DIV_NPLL 20
+#define CLKOPS_RATE_RK3368_DCLK_LCDC 21
+#define CLKOPS_RATE_RK3368_DDR 22
+
+#define CLKOPS_TABLE_END (~0)
+
+/* pd id */
+#define CLK_PD_BCPU 0
+#define CLK_PD_BDSP 1
+#define CLK_PD_BUS 2
+#define CLK_PD_CPU_0 3
+#define CLK_PD_CPU_1 4
+#define CLK_PD_CPU_2 5
+#define CLK_PD_CPU_3 6
+#define CLK_PD_CS 7
+#define CLK_PD_GPU 8
+#define CLK_PD_HEVC 9
+#define CLK_PD_PERI 10
+#define CLK_PD_SCU 11
+#define CLK_PD_VIDEO 12
+#define CLK_PD_VIO 13
+#define CLK_PD_GPU_0 14
+#define CLK_PD_GPU_1 15
+
+#define CLK_PD_VIRT 255
+
+/* reset flag */
+#define ROCKCHIP_RESET_HIWORD_MASK BIT(0)
+
+#endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_H */
diff --git a/include/linux/rockchip-iovmm.h b/include/linux/rockchip-iovmm.h
new file mode 100644
index 0000000..73e2ff1
--- /dev/null
+++ b/include/linux/rockchip-iovmm.h
@@ -0,0 +1,156 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_PLAT_IOVMM_H
+#define __ASM_PLAT_IOVMM_H
+
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <linux/spinlock.h>
+
+#define IEP_IOMMU_COMPATIBLE_NAME "rockchip,iep_mmu"
+#define VIP_IOMMU_COMPATIBLE_NAME "rockchip,vip_mmu"
+#define ISP_IOMMU_COMPATIBLE_NAME "rockchip,isp_mmu"
+#define ISP0_IOMMU_COMPATIBLE_NAME "rockchip,isp0_mmu"
+#define ISP1_IOMMU_COMPATIBLE_NAME "rockchip,isp1_mmu"
+#define VOPB_IOMMU_COMPATIBLE_NAME "rockchip,vopb_mmu"
+#define VOPL_IOMMU_COMPATIBLE_NAME "rockchip,vopl_mmu"
+#define VOP_IOMMU_COMPATIBLE_NAME "rockchip,vop_mmu"
+#define HEVC_IOMMU_COMPATIBLE_NAME "rockchip,hevc_mmu"
+#define VPU_IOMMU_COMPATIBLE_NAME "rockchip,vpu_mmu"
+#define VDEC_IOMMU_COMPATIBLE_NAME "rockchip,vdec_mmu"
+
+enum rk_iommu_inttype {
+ IOMMU_PAGEFAULT,
+ IOMMU_BUSERROR,
+ IOMMU_FAULT_UNKNOWN,
+ IOMMU_FAULTS_NUM
+};
+
+struct iommu_drvdata;
+
+/*
+ * @itype: type of fault.
+ * @pgtable_base: the physical address of page table base. This is 0 if @itype
+ * is IOMMU_BUSERROR.
+ * @fault_addr: the device (virtual) address that the System MMU tried to
+ * translated. This is 0 if @itype is IOMMU_BUSERROR.
+ */
+typedef int (*rockchip_iommu_fault_handler_t)(struct device *dev,
+ enum rk_iommu_inttype itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr,
+ unsigned int statu
+ );
+
+
+struct scatterlist;
+struct device;
+
+#ifdef CONFIG_RK_IOVMM
+
+int rockchip_iovmm_activate(struct device *dev);
+void rockchip_iovmm_deactivate(struct device *dev);
+
+/* rockchip_iovmm_map() - Maps a list of physical memory chunks
+ * @dev: the owner of the IO address space where the mapping is created
+ * @sg: list of physical memory chunks to map
+ * @offset: length in bytes where the mapping starts
+ * @size: how much memory to map in bytes. @offset + @size must not exceed
+ * total size of @sg
+ *
+ * This function returns mapped IO address in the address space of @dev.
+ * Returns minus error number if mapping fails.
+ * Caller must check its return code with IS_ERROR_VALUE() if the function
+ * succeeded.
+ *
+ * The caller of this function must ensure that iovmm_cleanup() is not called
+ * while this function is called.
+ *
+ */
+dma_addr_t rockchip_iovmm_map(struct device *dev, struct scatterlist *sg,
+ off_t offset, size_t size);
+
+/* rockchip_iovmm_unmap() - unmaps the given IO address
+ * @dev: the owner of the IO address space where @iova belongs
+ * @iova: IO address that needs to be unmapped and freed.
+ *
+ * The caller of this function must ensure that iovmm_cleanup() is not called
+ * while this function is called.
+ */
+void rockchip_iovmm_unmap(struct device *dev, dma_addr_t iova);
+
+/* rockchip_iovmm_map_oto - create one to one mapping for the given physical address
+ * @dev: the owner of the IO address space to map
+ * @phys: physical address to map
+ * @size: size of the mapping to create
+ *
+ * This function return 0 if mapping is successful. Otherwise, minus error
+ * value.
+ */
+int rockchip_iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size);
+
+/* rockchip_iovmm_unmap_oto - remove one to one mapping
+ * @dev: the owner ofthe IO address space
+ * @phys: physical address to remove mapping
+ */
+void rockchip_iovmm_unmap_oto(struct device *dev, phys_addr_t phys);
+
+void rockchip_iovmm_set_fault_handler(struct device *dev,
+ rockchip_iommu_fault_handler_t handler);
+/** rockchip_iovmm_set_fault_handler() - Fault handler for IOMMUs
+ * Called when interrupt occurred by the IOMMUs
+ * The device drivers of peripheral devices that has a IOMMU can implement
+ * a fault handler to resolve address translation fault by IOMMU.
+ * The meanings of return value and parameters are described below.
+ *
+ * return value: non-zero if the fault is correctly resolved.
+ * zero if the fault is not handled.
+ */
+
+int rockchip_iovmm_invalidate_tlb(struct device *dev);
+#else
+static inline int rockchip_iovmm_activate(struct device *dev)
+{
+ return -ENOSYS;
+}
+
+static inline void rockchip_iovmm_deactivate(struct device *dev)
+{
+}
+
+static inline dma_addr_t rockchip_iovmm_map(struct device *dev,
+ struct scatterlist *sg, off_t offset, size_t size)
+{
+ return -ENOSYS;
+}
+
+static inline void rockchip_iovmm_unmap(struct device *dev, dma_addr_t iova)
+{
+}
+
+static inline int rockchip_iovmm_map_oto(struct device *dev, phys_addr_t phys,
+ size_t size)
+{
+ return -ENOSYS;
+}
+
+static inline void rockchip_iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
+{
+}
+
+static inline void rockchip_iovmm_set_fault_handler(struct device *dev,
+ rockchip_iommu_fault_handler_t handler)
+{
+}
+static inline int rockchip_iovmm_invalidate_tlb(struct device *dev)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_RK_IOVMM */
+
+#endif /*__ASM_PLAT_IOVMM_H*/
diff --git a/include/linux/rockchip/common.h b/include/linux/rockchip/common.h
new file mode 100644
index 0000000..006d52d
--- /dev/null
+++ b/include/linux/rockchip/common.h
@@ -0,0 +1,100 @@
+#ifndef __MACH_ROCKCHIP_COMMON_H
+#define __MACH_ROCKCHIP_COMMON_H
+
+#include <linux/notifier.h>
+
+#define RK_DEVICE(VIRT, PHYS, SIZE) \
+ { \
+ .virtual = (unsigned long)(VIRT), \
+ .pfn = __phys_to_pfn(PHYS), \
+ .length = SIZE, \
+ .type = MT_DEVICE, \
+ }
+
+extern bool rockchip_jtag_enabled;
+extern unsigned long rockchip_boot_fn;
+extern struct smp_operations rockchip_smp_ops;
+
+struct ddr_bw_info {
+ u32 ddr_wr;
+ u32 ddr_rd;
+ u32 ddr_act;
+ u32 ddr_time;
+ u32 ddr_total;
+ u32 ddr_percent;
+
+ u32 cpum;
+ u32 gpu;
+ u32 peri;
+ u32 video;
+ u32 vio0;
+ u32 vio1;
+ u32 vio2;
+};
+extern void (*ddr_bandwidth_get)(struct ddr_bw_info *ddr_bw_ch0,
+ struct ddr_bw_info *ddr_bw_ch1);
+extern int (*ddr_change_freq)(uint32_t mhz);
+extern long (*ddr_round_rate)(uint32_t mhz);
+extern void (*ddr_set_auto_self_refresh)(bool en);
+extern int (*ddr_recalc_rate)(void);
+
+int rockchip_cpu_kill(unsigned int cpu);
+void rockchip_cpu_die(unsigned int cpu);
+int rockchip_cpu_disable(unsigned int cpu);
+
+#define BOOT_MODE_NORMAL 0
+#define BOOT_MODE_FACTORY2 1
+#define BOOT_MODE_RECOVERY 2
+#define BOOT_MODE_CHARGE 3
+#define BOOT_MODE_POWER_TEST 4
+#define BOOT_MODE_OFFMODE_CHARGING 5
+#define BOOT_MODE_REBOOT 6
+#define BOOT_MODE_PANIC 7
+#define BOOT_MODE_WATCHDOG 8
+#define BOOT_MODE_TSADC 9
+
+int rockchip_boot_mode(void);
+void __init rockchip_boot_mode_init(u32 flag, u32 mode);
+void rockchip_restart_get_boot_mode(const char *cmd, u32 *flag, u32 *mode);
+void __init rockchip_efuse_init(void);
+void __init rockchip_suspend_init(void);
+void __init rockchip_ion_reserve(void);
+void __init rockchip_uboot_mem_reserve(void);
+
+enum rockchip_pm_policy {
+ ROCKCHIP_PM_POLICY_PERFORMANCE = 0,
+ ROCKCHIP_PM_POLICY_NORMAL,
+ ROCKCHIP_PM_POLICY_POWERSAVE,
+ ROCKCHIP_PM_NR_POLICYS,
+};
+
+enum rockchip_pm_policy rockchip_pm_get_policy(void);
+int rockchip_pm_set_policy(enum rockchip_pm_policy policy);
+int rockchip_pm_policy_register_notifier(struct notifier_block *nb);
+int rockchip_pm_policy_unregister_notifier(struct notifier_block *nb);
+
+int rockchip_register_system_status_notifier(struct notifier_block *nb);
+int rockchip_unregister_system_status_notifier(struct notifier_block *nb);
+int rockchip_set_system_status(unsigned long status);
+int rockchip_clear_system_status(unsigned long status);
+unsigned long rockchip_get_system_status(void);
+u32 pvtm_get_value(u32 ch, u32 time_us);
+
+#define INVALID_TEMP INT_MAX
+#if IS_ENABLED(CONFIG_ROCKCHIP_THERMAL)
+int rockchip_tsadc_get_temp(int chn, int voltage);
+#else
+#if IS_ENABLED(CONFIG_SENSORS_ROCKCHIP_TSADC)
+int rockchip_tsadc_get_temp(int chn);
+#else
+static inline int rockchip_tsadc_get_temp(int chn) { return INVALID_TEMP; }
+#endif
+#endif
+
+#ifdef CONFIG_RK_LAST_LOG
+void rk_last_log_text(char *text, size_t size);
+#else
+static inline void rk_last_log_text(char *text, size_t size) {}
+#endif
+
+#endif
diff --git a/include/linux/rockchip/cpu.h b/include/linux/rockchip/cpu.h
new file mode 100644
index 0000000..ad6cdc4
--- /dev/null
+++ b/include/linux/rockchip/cpu.h
@@ -0,0 +1,135 @@
+#ifndef __MACH_ROCKCHIP_CPU_H
+#define __MACH_ROCKCHIP_CPU_H
+
+#ifdef CONFIG_ROCKCHIP_CPUINFO
+
+extern unsigned long rockchip_soc_id;
+
+static inline bool cpu_is_rockchip(void)
+{
+ return rockchip_soc_id;
+}
+
+#define ROCKCHIP_CPU_VERION_MASK 0x0000f000
+#define ROCKCHIP_CPU_VERION_SHIFT 12
+
+static inline unsigned long rockchip_get_cpu_version(void)
+{
+ return (rockchip_soc_id & ROCKCHIP_CPU_VERION_MASK)
+ >> ROCKCHIP_CPU_VERION_SHIFT;
+}
+
+static inline void rockchip_set_cpu_version(unsigned long ver)
+{
+ rockchip_soc_id &= ~ROCKCHIP_CPU_VERION_MASK;
+ rockchip_soc_id |=
+ (ver << ROCKCHIP_CPU_VERION_SHIFT) & ROCKCHIP_CPU_VERION_MASK;
+}
+
+#else
+
+static inline bool cpu_is_rockchip(void)
+{
+ return true;
+}
+
+static inline unsigned long rockchip_get_cpu_version(void)
+{
+ return 0;
+}
+
+static inline void rockchip_set_cpu_version(unsigned long ver)
+{
+}
+
+#endif
+
+#define ROCKCHIP_CPU_MASK 0xffff0000
+#define ROCKCHIP_CPU_RK2928 0x29280000
+#define ROCKCHIP_CPU_RK3026 0x30260000
+#define ROCKCHIP_CPU_RK312X 0x31260000
+#define ROCKCHIP_CPU_RK3036 0x30360000
+#define ROCKCHIP_CPU_RK30XX 0x30660000
+#define ROCKCHIP_CPU_RK3066B 0x31680000
+#define ROCKCHIP_CPU_RK3188 0x31880000
+#define ROCKCHIP_CPU_RK319X 0x31900000
+#define ROCKCHIP_CPU_RK3288 0x32880000
+#define ROCKCHIP_CPU_RK3228 0x32280000
+
+#ifdef CONFIG_ROCKCHIP_CPUINFO
+#define ROCKCHIP_CPU(id, ID) \
+static inline bool cpu_is_rk##id(void) \
+{ \
+ return (rockchip_soc_id & ROCKCHIP_CPU_MASK) == ROCKCHIP_CPU_RK ##ID; \
+}
+#else
+#define ROCKCHIP_CPU(id, ID) \
+static inline bool cpu_is_rk##id(void) { return false; }
+#endif
+
+ROCKCHIP_CPU(2928, 2928)
+ROCKCHIP_CPU(3026, 3026)
+ROCKCHIP_CPU(3036, 3036)
+ROCKCHIP_CPU(30xx, 30XX)
+ROCKCHIP_CPU(3066b, 3066B)
+ROCKCHIP_CPU(312x, 312X)
+ROCKCHIP_CPU(3188, 3188)
+ROCKCHIP_CPU(319x, 319X)
+ROCKCHIP_CPU(3288, 3288)
+ROCKCHIP_CPU(3228, 3228)
+
+#define ROCKCHIP_SOC_MASK (ROCKCHIP_CPU_MASK | 0xff)
+#define ROCKCHIP_SOC_RK2926 (ROCKCHIP_CPU_RK2928 | 0x00)
+#define ROCKCHIP_SOC_RK2928G (ROCKCHIP_CPU_RK2928 | 0x01)
+#define ROCKCHIP_SOC_RK2928L (ROCKCHIP_CPU_RK2928 | 0x02)
+#define ROCKCHIP_SOC_RK3028A (ROCKCHIP_CPU_RK3026 | 0x03)
+#define ROCKCHIP_SOC_RK3026 (ROCKCHIP_CPU_RK3026 | 0x04)
+#define ROCKCHIP_SOC_RK3126 (ROCKCHIP_CPU_RK312X | 0x00)
+#define ROCKCHIP_SOC_RK3126B (ROCKCHIP_CPU_RK312X | 0x10)
+#define ROCKCHIP_SOC_RK3128 (ROCKCHIP_CPU_RK312X | 0x01)
+#define ROCKCHIP_SOC_RK3036 (ROCKCHIP_CPU_RK3036 | 0x00)
+#define ROCKCHIP_SOC_RK3000 (ROCKCHIP_CPU_RK30XX | 0x00)
+#define ROCKCHIP_SOC_RK3066 (ROCKCHIP_CPU_RK30XX | 0x01)
+#define ROCKCHIP_SOC_RK3068 (ROCKCHIP_CPU_RK30XX | 0x02)
+#define ROCKCHIP_SOC_RK3066B (ROCKCHIP_CPU_RK3066B| 0x00)
+#define ROCKCHIP_SOC_RK3168 (ROCKCHIP_CPU_RK3066B| 0x01)
+#define ROCKCHIP_SOC_RK3028 (ROCKCHIP_CPU_RK3066B| 0x03)
+#define ROCKCHIP_SOC_RK3188 (ROCKCHIP_CPU_RK3188 | 0x00)
+#define ROCKCHIP_SOC_RK3188PLUS (ROCKCHIP_CPU_RK3188 | 0x10)
+#define ROCKCHIP_SOC_RK3190 (ROCKCHIP_CPU_RK319X | 0x00)
+#define ROCKCHIP_SOC_RK3288 (ROCKCHIP_CPU_RK3288 | 0x00)
+#define ROCKCHIP_SOC_RK3228 (ROCKCHIP_CPU_RK3228 | 0x00)
+
+#ifdef CONFIG_ROCKCHIP_CPUINFO
+#define ROCKCHIP_SOC(id, ID) \
+static inline bool soc_is_rk##id(void) \
+{ \
+ return (rockchip_soc_id & ROCKCHIP_SOC_MASK) == ROCKCHIP_SOC_RK ##ID; \
+}
+#else
+#define ROCKCHIP_SOC(id, ID) \
+static inline bool soc_is_rk##id(void) { return false; }
+#endif
+
+ROCKCHIP_SOC(2926, 2926)
+ROCKCHIP_SOC(2928g, 2928G)
+ROCKCHIP_SOC(2928l, 2928L)
+ROCKCHIP_SOC(3028a, 3028A)
+ROCKCHIP_SOC(3026, 3026)
+ROCKCHIP_SOC(3126, 3126)
+ROCKCHIP_SOC(3126b, 3126B)
+ROCKCHIP_SOC(3128, 3128)
+ROCKCHIP_SOC(3036, 3036)
+ROCKCHIP_SOC(3000, 3000)
+ROCKCHIP_SOC(3066, 3066)
+ROCKCHIP_SOC(3068, 3068)
+ROCKCHIP_SOC(3066b, 3066B)
+ROCKCHIP_SOC(3168, 3168)
+ROCKCHIP_SOC(3028, 3028)
+ROCKCHIP_SOC(3188, 3188)
+ROCKCHIP_SOC(3188plus, 3188PLUS)
+ROCKCHIP_SOC(3190, 3190)
+ROCKCHIP_SOC(3288, 3288)
+ROCKCHIP_SOC(3228, 3228)
+
+#endif
diff --git a/include/linux/rockchip/cru.h b/include/linux/rockchip/cru.h
new file mode 100755
index 0000000..ee33f5a
--- /dev/null
+++ b/include/linux/rockchip/cru.h
@@ -0,0 +1,281 @@
+#ifndef __MACH_ROCKCHIP_CRU_H
+#define __MACH_ROCKCHIP_CRU_H
+
+#include <dt-bindings/clock/rockchip,rk3188.h>
+#include <dt-bindings/clock/rockchip,rk3288.h>
+#include <linux/rockchip/iomap.h>
+
+
+/*******************CRU BITS*******************************/
+
+#define CRU_W_MSK(bits_shift, msk) ((msk) << ((bits_shift) + 16))
+
+#define CRU_SET_BITS(val, bits_shift, msk) (((val)&(msk)) << (bits_shift))
+
+#define CRU_W_MSK_SETBITS(val, bits_shift,msk) \
+ (CRU_W_MSK(bits_shift, msk) | CRU_SET_BITS(val, bits_shift, msk))
+
+/*******************RK3188********************************/
+/*******************CRU OFFSET*********************/
+#define RK3188_CRU_MODE_CON 0x40
+#define RK3188_CRU_CLKSEL_CON 0x44
+#define RK3188_CRU_CLKGATE_CON 0xd0
+#define RK3188_CRU_GLB_SRST_FST 0x100
+#define RK3188_CRU_GLB_SRST_SND 0x104
+#define RK3188_CRU_SOFTRST_CON 0x110
+
+#define RK3188_PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4))
+
+#define RK3188_CRU_CLKSELS_CON_CNT (35)
+#define RK3188_CRU_CLKSELS_CON(i) (RK3188_CRU_CLKSEL_CON + ((i) * 4))
+
+#define RK3188_CRU_CLKGATES_CON_CNT (10)
+#define RK3188_CRU_CLKGATES_CON(i) (RK3188_CRU_CLKGATE_CON + ((i) * 4))
+
+#define RK3188_CRU_SOFTRSTS_CON_CNT (9)
+#define RK3188_CRU_SOFTRSTS_CON(i) (RK3188_CRU_SOFTRST_CON + ((i) * 4))
+
+#define RK3188_CRU_MISC_CON (0x134)
+#define RK3188_CRU_GLB_CNT_TH (0x140)
+
+/******************PLL MODE BITS*******************/
+#define RK3188_PLL_MODE_MSK(id) (0x3 << ((id) * 4))
+#define RK3188_PLL_MODE_SLOW(id) ((0x0<<((id)*4))|(0x3<<(16+(id)*4)))
+#define RK3188_PLL_MODE_NORM(id) ((0x1<<((id)*4))|(0x3<<(16+(id)*4)))
+#define RK3188_PLL_MODE_DEEP(id) ((0x2<<((id)*4))|(0x3<<(16+(id)*4)))
+
+/******************CRU GATINGS**********************************/
+#define RK3188_CRU_GATEID_CONS(ID) (RK3188_CRU_CLKGATE_CON+(ID/16)*4)
+
+/*************************RK3288********************************/
+
+/*******************CRU OFFSET*********************/
+#define RK3288_CRU_MODE_CON 0x50
+#define RK3288_CRU_CLKSEL_CON 0x60
+#define RK3288_CRU_CLKGATE_CON 0x160
+
+#define RK3288_PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4))
+#define RK3288_CRU_CLKSELS_CON(i) (RK3288_CRU_CLKSEL_CON + ((i) * 4))
+#define RK3288_CRU_CLKGATES_CON(i) (RK3288_CRU_CLKGATE_CON + ((i) * 4))
+
+/******************PLL MODE BITS*******************/
+/*************apll dpll,cpll,gpll,npll 0~4************/
+#define RK3288_PLLS_MODE_OFFSET(id) ((id)<=3 ? (id*4) : 14)
+#define RK3288_PLL_MODE_MSK(id) (0x3 << RK3288_PLLS_MODE_OFFSET(id))
+#define RK3288_PLL_MODE_SLOW(id) ((0x0<<RK3288_PLLS_MODE_OFFSET(id))|(0x3<<(16+RK3288_PLLS_MODE_OFFSET(id))))
+#define RK3288_PLL_MODE_NORM(id) ((0x1<<RK3288_PLLS_MODE_OFFSET(id))|(0x3<<(16+RK3288_PLLS_MODE_OFFSET(id))))
+#define RK3288_PLL_MODE_DEEP(id) ((0x2<<RK3288_PLLS_MODE_OFFSET(id))|(0x3<<(16+RK3288_PLLS_MODE_OFFSET(id))))
+
+/*******************CRU GATING*********************/
+#define RK3288_CRU_CLKGATES_CON_CNT (19)
+#define RK3288_CRU_CONS_GATEID(i) (16 * (i))
+#define RK3288_CRU_GATEID_CONS(ID) (RK3288_CRU_CLKGATE_CON+(ID/16)*4)
+
+enum rk3288_cru_clk_gate {
+ /* SCU CLK GATE 0 CON */
+ RK3288_CLKGATE_UART0_SRC = (RK3288_CRU_CONS_GATEID(1)+8),
+
+ RK3288_CLKGATE_UART4_SRC = (RK3288_CRU_CONS_GATEID(2)+12),
+
+ RK3288_CLKGATE_PCLK_UART0= (RK3288_CRU_CONS_GATEID(6)+8),
+ RK3288_CLKGATE_PCLK_UART1,
+ RK3288_CLKGATE6_DUMP1,
+ RK3288_CLKGATE_PCLK_UART3,
+ RK3288_CLKGATE_PCLK_I2C2,
+ RK3288_CLKGATE_PCLK_I2C3,
+ RK3288_CLKGATE_PCLK_I2C4,
+
+ RK3288_CLKGATE_PCLK_I2C0 = (RK3288_CRU_CONS_GATEID(10)+2),
+ RK3288_CLKGATE_PCLK_I2C1,
+
+ RK3288_CLKGATE_PCLK_UART2 = (RK3288_CRU_CONS_GATEID(11)+9),
+
+
+ RK3288_CLKGATE_PCLK_GPIO1 = (RK3288_CRU_CONS_GATEID(14)+1),
+
+ RK3288_CLKGATE_PCLK_GPIO0 = (RK3288_CRU_CONS_GATEID(17)+4),
+ //gate6
+};
+
+#define RK3288_CRU_GLB_SRST_FST_VALUE 0x1b0
+#define RK3288_CRU_GLB_SRST_SND_VALUE 0x1b4
+#define RK3288_CRU_SOFTRST_CON 0x1b8
+#define RK3288_CRU_MISC_CON 0x1e8
+#define RK3288_CRU_GLB_CNT_TH 0x1ec
+#define RK3288_CRU_GLB_RST_CON 0x1f0
+#define RK3288_CRU_GLB_RST_ST 0x1f8
+#define RK3288_CRU_SDMMC_CON0 0x200
+#define RK3288_CRU_SDMMC_CON1 0x204
+#define RK3288_CRU_SDIO0_CON0 0x208
+#define RK3288_CRU_SDIO0_CON1 0x20c
+#define RK3288_CRU_SDIO1_CON0 0x210
+#define RK3288_CRU_SDIO1_CON1 0x214
+#define RK3288_CRU_EMMC_CON0 0x218
+#define RK3288_CRU_EMMC_CON1 0x21c
+
+#define RK3288_CRU_SOFTRSTS_CON_CNT (12)
+#define RK3288_CRU_SOFTRSTS_CON(i) (RK3288_CRU_SOFTRST_CON + ((i) * 4))
+
+static inline void rk3288_cru_set_soft_reset(u32 idx, bool on)
+{
+ void __iomem *reg = RK_CRU_VIRT + RK3288_CRU_SOFTRSTS_CON(idx >> 4);
+ u32 val = on ? 0x10001U << (idx & 0xf) : 0x10000U << (idx & 0xf);
+ writel_relaxed(val, reg);
+ dsb(sy);
+}
+
+#define RK3036_CRU_MODE_CON 0x0040
+
+/******************PLL MODE BITS*******************/
+/****************apll dpll,gpll 0~2******************/
+#define RK3036_PLLS_MODE_OFFSET(id) ((id) < 2 ? (id*4) : 12)
+
+#define RK3036_PLL_MODE_SLOW(id) ((0x0 << RK3036_PLLS_MODE_OFFSET(id)) \
+ | (((id) < 2 ? 0x1 : 0x3) << (16 + RK3036_PLLS_MODE_OFFSET(id))))
+
+#define RK3036_PLL_MODE_MSK(id) (0x1 << RK3036_PLLS_MODE_OFFSET(id))
+
+#define RK3036_APLL_MODE_SLOW ((0x0<<0x00)|(0x1<<(16+0x00)))
+#define RK3036_DPLL_MODE_SLOW ((0x0<<0x04)|(0x1<<(16+0x04)))
+#define RK3036_GPLL_MODE_SLOW ((0x0<<0x12)|(0x3<<(16+0x12)))
+
+#define RK3036_APLL_MODE_NORM ((0x1<<0x00)|(0x1<<(16+0x00)))
+#define RK3036_DPLL_MODE_NORM ((0x1<<0x04)|(0x1<<(16+0x04)))
+#define RK3036_GPLL_MODE_NORM ((0x1<<0x12)|(0x3<<(16+0x12)))
+
+#define RK3036_GPLL_MODE_DEEP ((0x10<<0x12)|(0x3<<(16+0x12)))
+
+#define RK3036_PLL_CONS(id, i) (((id) < 2 ? id : (id + 1)) * 0x10 + ((i) * 4))
+
+#define RK3036_CRU_GLB_SRST_FST_VALUE 0x00100
+#define RK3036_CRU_GLB_SRST_SND_VALUE 0x00104
+#define RK3036_CRU_SOFTRST0_CON 0x00110
+#define RK3036_CRU_SOFTRST1_CON 0x00114
+#define RK3036_CRU_SOFTRST2_CON 0x00118
+#define RK3036_CRU_SOFTRST3_CON 0x0011c
+#define RK3036_CRU_SOFTRST4_CON 0x00120
+#define RK3036_CRU_SOFTRST5_CON 0x00124
+#define RK3036_CRU_SOFTRST6_CON 0x00128
+#define RK3036_CRU_SOFTRST7_CON 0x0012c
+#define RK3036_CRU_SOFTRST8_CON 0x00130
+#define RK3036_CRU_MISC_CON 0x00134
+#define RK3036_CRU_GLB_CNT_TH 0x00140
+#define RK3036_CRU_SDMMC_CON0 0x00144
+#define RK3036_CRU_SDMMC_CON1 0x00148
+#define RK3036_CRU_SDIO_CON0 0x0014c
+#define RK3036_CRU_SDIO_CON1 0x00150
+#define RK3036_CRU_EMMC_CON0 0x00154
+#define RK3036_CRU_EMMC_CON1 0x00158
+#define RK3036_CRU_RST_ST 0x00160
+#define RK3036_CRU_PLL_MASK_CON 0x001f0
+
+#define RK3036_CRU_CLKSEL_CON 0x44
+#define RK3036_CRU_CLKGATE_CON 0xd0
+
+#define RK3036_CRU_CLKSELS_CON_CNT (35)
+#define RK3036_CRU_CLKSELS_CON(i) (RK3036_CRU_CLKSEL_CON + ((i) * 4))
+
+#define RK3036_CRU_CLKGATES_CON_CNT (11)
+#define RK3036_CRU_CLKGATES_CON(i) (RK3036_CRU_CLKGATE_CON + ((i) * 4))
+
+#define RK3036_CRU_SOFTRSTS_CON_CNT (9)
+#define RK3036_CRU_SOFTRSTS_CON(i) (RK3036_CRU_SOFTRST_CON + ((i) * 4))
+
+/*******************CRU GATING*********************/
+#define RK3036_CRU_UART_GATE 0xd4
+#define RK3036_CLKGATE_UART0_SRC 8
+#define RK3036_CLKGATE_UART0_PCLK 9
+
+#define RK312X_PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4))
+
+#define RK312X_CRU_GLB_SRST_FST_VALUE 0x00100
+#define RK312X_CRU_GLB_SRST_SND_VALUE 0x00104
+#define RK312X_CRU_MISC_CON 0x00134
+#define RK312X_CRU_GLB_CNT_TH 0x00140
+#define RK312X_CRU_GLB_RST_ST 0x00150
+#define RK312X_CRU_SDMMC_CON0 0x01c0
+#define RK312X_CRU_SDMMC_CON1 0x01c4
+#define RK312X_CRU_SDIO_CON0 0x01c8
+#define RK312X_CRU_SDIO_CON1 0x01cc
+#define RK312X_CRU_EMMC_CON0 0x01d8
+#define RK312X_CRU_EMMC_CON1 0x01dc
+#define RK312X_CRU_PLL_PRG_EN 0x01f0
+#define RK312X_CRU_MODE_CON 0x40
+#define RK312X_CRU_RST_ST 0x00160
+#define RK312X_CRU_PLL_MASK_CON 0x001f0
+
+#define RK312X_CRU_CLKSEL_CON 0x44
+#define RK312X_CRU_CLKGATE_CON 0xd0
+
+#define RK312X_PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4))
+
+/******************PLL MODE BITS*******************/
+#define RK312X_PLLS_MODE_OFFSET(id) ((id) <= 3 ? (id * 4) : 14)
+#define RK312X_PLL_MODE_MSK(id) (0x1 << RK312X_PLLS_MODE_OFFSET(id))
+#define RK312X_PLL_MODE_SLOW(id) ((0x0 << RK312X_PLLS_MODE_OFFSET(id))\
+| (0x1 << (16 + RK312X_PLLS_MODE_OFFSET(id))))
+#define RK312X_PLL_MODE_NORM(id) ((0x1 << RK312X_PLLS_MODE_OFFSET(id))\
+| (0x1 << (16 + RK312X_PLLS_MODE_OFFSET(id))))
+
+
+#define RK312X_CRU_SOFTRST_CON 0x110
+
+#define RK312X_CRU_CLKSELS_CON_CNT (35)
+#define RK312X_CRU_CLKSELS_CON(i) (RK3036_CRU_CLKSEL_CON + ((i) * 4))
+
+#define RK312X_CRU_CLKGATES_CON_CNT (11)
+#define RK312X_CRU_CLKGATES_CON(i) (RK3036_CRU_CLKGATE_CON + ((i) * 4))
+
+#define RK312X_CRU_SOFTRSTS_CON_CNT (9)
+#define RK312X_CRU_SOFTRSTS_CON(i) (RK312X_CRU_SOFTRST_CON + ((i) * 4))
+
+/*******************CRU GATING*********************/
+#define RK312X_CRU_CONS_GATEID(i) (16 * (i))
+#define RK312X_CRU_GATEID_CONS(ID) (RK312X_CRU_CLKGATE_CON\
+ + ((ID) / 16) * 4)
+
+enum rk312x_cru_clk_gate {
+ /* SCU CLK GATE 0 CON */
+ RK312X_CLKGATE_UART0_SRC = (RK312X_CRU_CONS_GATEID(1) + 8),
+ RK312X_CLKGATE_PCLK_UART0 = (RK312X_CRU_CONS_GATEID(8) + 0),
+ RK312X_CLKGATE_PCLK_UART1,
+ RK312X_CLKGATE_PCLK_UART2,
+};
+
+#define RK3228_PLL_CONS(id, i) RK312X_PLL_CONS(id, i)
+#define RK3228_CRU_MODE_CON RK312X_CRU_MODE_CON
+#define RK3228_CRU_CLKSELS_CON_CNT RK312X_CRU_CLKSELS_CON_CNT
+#define RK3228_CRU_CLKSELS_CON(i) RK312X_CRU_CLKSELS_CON(i)
+#define RK3228_CRU_CLKGATES_CON_CNT (16)
+#define RK3228_CRU_CLKGATES_CON(i) RK312X_CRU_CLKGATES_CON(i)
+#define RK3228_CRU_SOFTRSTS_CON_CNT RK312X_CRU_SOFTRSTS_CON_CNT
+#define RK3228_CRU_SOFTRSTS_CON(i) RK312X_CRU_SOFTRSTS_CON(i)
+#define RK3228_CRU_MISC_CON RK312X_CRU_MISC_CON
+#define RK3228_CRU_GLB_CNT_TH RK312X_CRU_GLB_CNT_TH
+#define RK3228_CRU_GLB_RST_ST RK312X_CRU_GLB_RST_ST
+#define RK3228_CRU_SDMMC_CON0 RK312X_CRU_SDMMC_CON0
+#define RK3228_CRU_SDMMC_CON1 RK312X_CRU_SDMMC_CON1
+#define RK3228_CRU_SDIO_CON0 RK312X_CRU_SDIO_CON0
+#define RK3228_CRU_SDIO_CON1 RK312X_CRU_SDIO_CON1
+#define RK3228_CRU_EMMC_CON0 RK312X_CRU_EMMC_CON0
+#define RK3228_CRU_EMMC_CON1 RK312X_CRU_EMMC_CON1
+#define RK3228_CRU_GLB_SRST_FST_VALUE 0x001f0
+#define RK3228_CRU_GLB_SRST_SND_VALUE 0x001f4
+#define RK3228_CRU_PLL_MASK_CON 0x001f8
+
+/*************************RK3368********************************/
+
+/*******************CRU OFFSET*********************/
+#define RK3368_CRU_CLKSEL_CON 0x100
+#define RK3368_CRU_CLKGATE_CON 0x200
+#define RK3368_CRU_CLKGATES_CON_CNT 25
+
+#define RK3368_PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4))
+#define RK3368_CRU_CLKSELS_CON(i) (RK3368_CRU_CLKSEL_CON + ((i) * 4))
+#define RK3368_CRU_CLKGATES_CON(i) (RK3368_CRU_CLKGATE_CON + ((i) * 4))
+
+#define RK3368_CRU_SOFTRSTS_CON_CNT (15)
+#define RK3368_CRU_SOFTRST_CON 0x300
+#define RK3368_CRU_SOFTRSTS_CON(i) (RK3368_CRU_SOFTRST_CON + ((i) * 4))
+
+#endif
diff --git a/include/linux/rockchip/dvfs.h b/include/linux/rockchip/dvfs.h
new file mode 100644
index 0000000..1aaffbd
--- /dev/null
+++ b/include/linux/rockchip/dvfs.h
@@ -0,0 +1,258 @@
+/* arch/arm/mach-rk30/rk30_dvfs.h
+ *
+ * Copyright (C) 2012 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _RK30_DVFS_H_
+#define _RK30_DVFS_H_
+
+#include <linux/device.h>
+#include <linux/clk-provider.h>
+
+#define ARM_DVFS_CH 0
+#define GPU_DVFS_CH 1
+#define LOG_DVFS_CH 2
+
+struct dvfs_node;
+typedef int (*dvfs_set_rate_callback)(struct dvfs_node *clk_dvfs_node, unsigned long rate);
+typedef int (*clk_set_rate_callback)(struct clk *clk, unsigned long rate);
+
+/**
+ * struct vd_node: To Store All Voltage Domains' info
+ * @name: Voltage Domain's Name
+ * @regulator_name: Voltage domain's regulator name
+ * @cur_volt: Voltage Domain's Current Voltage
+ * @regulator: Voltage Domain's regulator point
+ * @node: Point of he Voltage Domain List Node
+ * @pd_list: Head of Power Domain List Belongs to This Voltage Domain
+ * @req_volt_list: The list of clocks requests
+ * @dvfs_mutex: Lock
+ * @vd_dvfs_target: Callback function
+ */
+ #define VD_VOL_LIST_CNT (200)
+ #define VD_LIST_RELATION_L 0
+ #define VD_LIST_RELATION_H 1
+
+struct vd_node {
+ const char *name;
+ const char *regulator_name;
+ int volt_time_flag;// =0 ,is no initing checking ,>0 ,support,<0 not support
+ int mode_flag;// =0 ,is no initing checking ,>0 ,support,<0 not support;
+ int cur_volt;
+ int volt_set_flag;
+ int suspend_volt;
+ struct regulator *regulator;
+ struct list_head node;
+ struct list_head pd_list;
+ struct mutex mutex;
+ dvfs_set_rate_callback vd_dvfs_target;
+ unsigned int n_voltages;
+ int volt_list[VD_VOL_LIST_CNT];
+ unsigned int regu_mode;
+};
+
+/**
+ * struct pd_node: To Store All Power Domains' info
+ * @name: Power Domain's Name
+ * @cur_volt: Power Domain's Current Voltage
+ * @pd_status: Power Domain's status
+ * @vd: Voltage Domain the power domain belongs to
+ * @pd_clk: Look power domain as a clock
+ * @node: List node to Voltage Domain
+ * @clk_list: Head of Power Domain's Clocks List
+ */
+struct pd_node {
+ const char *name;
+ int cur_volt;
+ unsigned char pd_status;
+ struct vd_node *vd;
+ struct list_head node;
+ struct list_head clk_list;
+ unsigned int regu_mode;
+};
+
+struct pvtm_info {
+ const char *compatible;
+ struct cpufreq_frequency_table *pvtm_table;
+ int channel;
+ int process_version;
+ int scan_rate_hz;
+ int sample_time_us;
+ int volt_step_uv;
+ int delta_pvtm_by_volt;
+ int delta_pvtm_by_temp;
+ int volt_margin_uv;
+ int min_volt_uv;
+ int max_volt_uv;
+ int cluster;
+};
+
+struct lkg_adjust_volt_table {
+ int lkg;
+ int dlt_volt;
+};
+
+struct lkg_info {
+ int def_table_lkg;
+ int min_adjust_freq;
+ struct lkg_adjust_volt_table *table;
+};
+
+/**
+ * struct dvfs_node: To Store All dvfs clocks' info
+ * @name: Dvfs clock's Name
+ * @set_freq: Dvfs clock's Current Frequency
+ * @set_volt: Dvfs clock's Current Voltage
+ * @enable_dvfs: Sign if DVFS clock enable
+ * @clk: System clk's point
+ * @pd: Power Domains dvfs clock belongs to
+ * @vd: Voltage Domains dvfs clock belongs to
+ * @dvfs_nb: Notify list
+ * @dvfs_table: Frequency and voltage table for dvfs
+ * @clk_dvfs_target: Callback function
+ */
+struct dvfs_node {
+ struct device dev; //for opp
+ const char *name;
+ int set_freq; //KHZ
+ int set_volt; //MV
+ int enable_count;
+ int freq_limit_en; //sign if use limit frequency
+ int support_pvtm;
+ unsigned int min_rate; //limit min frequency
+ unsigned int max_rate; //limit max frequency
+ unsigned long last_set_rate;
+ unsigned int channel;
+ unsigned int temp_channel;
+ unsigned long temp_limit_rate;
+ unsigned int target_temp;
+ unsigned int temp_limit_enable;
+ unsigned int min_temp_limit;
+ int old_temp;
+ struct clk *clk;
+ struct pd_node *pd;
+ struct vd_node *vd;
+ struct list_head node;
+ struct notifier_block *dvfs_nb;
+ struct cpufreq_frequency_table *dvfs_table;
+ struct cpufreq_frequency_table *pvtm_table;
+ struct cpufreq_frequency_table *per_temp_limit_table;
+ struct cpufreq_frequency_table *nor_temp_limit_table;
+ struct cpufreq_frequency_table *virt_temp_limit_table[4];
+ clk_set_rate_callback clk_dvfs_target;
+ struct cpufreq_frequency_table *regu_mode_table;
+ int regu_mode_en;
+ unsigned int regu_mode;
+ struct pvtm_info *pvtm_info;
+ int lkg_adjust_volt_en;
+ struct lkg_info lkg_info;
+ unsigned int cluster;
+ unsigned int max_limit_freq;
+ unsigned int pvtm_min_temp;
+};
+
+
+
+#define DVFS_MHZ (1000*1000)
+#define DVFS_KHZ (1000)
+
+#define DVFS_V (1000*1000)
+#define DVFS_MV (1000)
+#if 0
+#define DVFS_DBG(fmt, args...) printk(KERN_INFO "DVFS DBG:\t"fmt, ##args)
+#else
+#define DVFS_DBG(fmt, args...) {while(0);}
+#endif
+
+#define DVFS_ERR(fmt, args...) printk(KERN_ERR "DVFS ERR:\t"fmt, ##args)
+#define DVFS_LOG(fmt, args...) printk(KERN_DEBUG "DVFS LOG:\t"fmt, ##args)
+#define DVFS_WARNING(fmt, args...) printk(KERN_WARNING "DVFS WARNING:\t"fmt, ##args)
+
+#define DVFS_SET_VOLT_FAILURE 1
+#define DVFS_SET_VOLT_SUCCESS 0
+
+#define dvfs_regulator_get(dev,id) regulator_get((dev),(id))
+#define dvfs_regulator_put(regu) regulator_put((regu))
+#define dvfs_regulator_set_voltage(regu,min_uV,max_uV) regulator_set_voltage((regu),(min_uV),(max_uV))
+#define dvfs_regulator_get_voltage(regu) regulator_get_voltage((regu))
+#define dvfs_regulator_set_voltage_time(regu, old_uV, new_uV) regulator_set_voltage_time((regu), (old_uV), (new_uV))
+#define dvfs_regulator_set_mode(regu, mode) regulator_set_mode((regu), (mode))
+#define dvfs_regulator_get_mode(regu) regulator_get_mode((regu))
+#define dvfs_regulator_list_voltage(regu,selector) regulator_list_voltage((regu),(selector))
+#define dvfs_regulator_count_voltages(regu) regulator_count_voltages((regu))
+
+#define clk_dvfs_node_get(a,b) clk_get((a),(b))
+#define clk_dvfs_node_get_rate_kz(a) (clk_get_rate((a))/1000)
+#define clk_dvfs_node_set_rate(a,b) clk_set_rate((a),(b))
+
+typedef void (*avs_init_fn)(void);
+typedef u8 (*avs_get_val_fn)(void);
+struct avs_ctr_st {
+ avs_init_fn avs_init;
+ avs_get_val_fn avs_get_val;
+};
+
+#ifdef CONFIG_DVFS
+struct dvfs_node *clk_get_dvfs_node(char *clk_name);
+void clk_put_dvfs_node(struct dvfs_node *clk_dvfs_node);
+unsigned long dvfs_clk_get_rate(struct dvfs_node *clk_dvfs_node);
+unsigned long dvfs_clk_get_last_set_rate(struct dvfs_node *clk_dvfs_node);
+unsigned long dvfs_clk_round_rate(struct dvfs_node *clk_dvfs_node, unsigned long rate);
+int dvfs_clk_set_rate(struct dvfs_node *clk_dvfs_node, unsigned long rate);
+int dvfs_clk_enable(struct dvfs_node *clk_dvfs_node);
+void dvfs_clk_disable(struct dvfs_node *clk_dvfs_node);
+int dvfs_clk_prepare_enable(struct dvfs_node *clk_dvfs_node);
+void dvfs_clk_disable_unprepare(struct dvfs_node *clk_dvfs_node);
+int dvfs_set_freq_volt_table(struct dvfs_node *clk_dvfs_node, struct cpufreq_frequency_table *table);
+int dvfs_clk_register_set_rate_callback(struct dvfs_node *clk_dvfs_node, clk_set_rate_callback clk_dvfs_target);
+int dvfs_clk_enable_limit(struct dvfs_node *clk_dvfs_node, unsigned int min_rate, unsigned max_rate);
+int dvfs_clk_get_limit(struct dvfs_node *clk_dvfs_node, unsigned int *min_rate, unsigned int *max_rate) ;
+int dvfs_clk_disable_limit(struct dvfs_node *clk_dvfs_node);
+int clk_disable_dvfs(struct dvfs_node *clk_dvfs_node);
+int clk_enable_dvfs(struct dvfs_node *clk_dvfs_node);
+void dvfs_disable_temp_limit(void);
+struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct dvfs_node *clk_dvfs_node);
+int rk_regist_vd(struct vd_node *vd);
+int rk_regist_pd(struct pd_node *pd);
+int rk_regist_clk(struct dvfs_node *clk_dvfs_node);
+struct regulator *dvfs_get_regulator(char *regulator_name);
+int of_dvfs_init(void);
+
+#else
+
+static inline struct dvfs_node *clk_get_dvfs_node(char *clk_name){ return NULL; };
+static inline void clk_put_dvfs_node(struct dvfs_node *clk_dvfs_node){ return; };
+static inline unsigned long dvfs_clk_get_rate(struct dvfs_node *clk_dvfs_node){ return 0; };
+static inline unsigned long dvfs_clk_get_last_set_rate(struct dvfs_node *clk_dvfs_node){ return 0; };
+static inline unsigned long dvfs_clk_round_rate(struct dvfs_node *clk_dvfs_node, unsigned long rate) { return 0; };
+static inline int dvfs_clk_set_rate(struct dvfs_node *clk_dvfs_node, unsigned long rate){ return 0; };
+static inline int dvfs_clk_enable(struct dvfs_node *clk_dvfs_node){ return 0; };
+static inline void dvfs_clk_disable(struct dvfs_node *clk_dvfs_node){ };
+static inline int dvfs_clk_prepare_enable(struct dvfs_node *clk_dvfs_node){ return 0; };
+static inline void dvfs_clk_disable_unprepare(struct dvfs_node *clk_dvfs_node){ };
+static inline int dvfs_set_freq_volt_table(struct dvfs_node *clk_dvfs_node, struct cpufreq_frequency_table *table){ return 0; };
+static inline int dvfs_clk_register_set_rate_callback(struct dvfs_node *clk_dvfs_node, clk_set_rate_callback clk_dvfs_target){ return 0; };
+static inline int dvfs_clk_enable_limit(struct dvfs_node *clk_dvfs_node, unsigned int min_rate, unsigned max_rate){ return 0; };
+static inline int dvfs_clk_get_limit(struct dvfs_node *clk_dvfs_node, unsigned int *min_rate, unsigned int *max_rate) { return 0; };
+static inline int dvfs_clk_disable_limit(struct dvfs_node *clk_dvfs_node){ return 0; };
+static inline int clk_disable_dvfs(struct dvfs_node *clk_dvfs_node){ return 0; };
+static inline int clk_enable_dvfs(struct dvfs_node *clk_dvfs_node){ return 0; };
+static inline void dvfs_disable_temp_limit(void) {};
+static inline struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct dvfs_node *clk_dvfs_node){ return NULL; };
+static inline int rk_regist_vd(struct vd_node *vd){ return 0; };
+static inline int rk_regist_pd(struct pd_node *pd){ return 0; };
+static inline int rk_regist_clk(struct dvfs_node *clk_dvfs_node){ return 0; };
+static inline struct regulator *dvfs_get_regulator(char *regulator_name){ return NULL; };
+static inline int of_dvfs_init(void){ return 0; };
+#endif
+
+#endif
diff --git a/include/linux/rockchip/grf.h b/include/linux/rockchip/grf.h
new file mode 100755
index 0000000..ab03372
--- /dev/null
+++ b/include/linux/rockchip/grf.h
@@ -0,0 +1,699 @@
+#ifndef __MACH_ROCKCHIP_GRF_H
+#define __MACH_ROCKCHIP_GRF_H
+
+#define RK3188_GRF_GPIO0L_DIR 0x0000
+#define RK3188_GRF_GPIO0H_DIR 0x0004
+#define RK3188_GRF_GPIO1L_DIR 0x0008
+#define RK3188_GRF_GPIO1H_DIR 0x000c
+#define RK3188_GRF_GPIO2L_DIR 0x0010
+#define RK3188_GRF_GPIO2H_DIR 0x0014
+#define RK3188_GRF_GPIO3L_DIR 0x0018
+#define RK3188_GRF_GPIO3H_DIR 0x001c
+#define RK3188_GRF_GPIO0L_DO 0x0020
+#define RK3188_GRF_GPIO0H_DO 0x0024
+#define RK3188_GRF_GPIO1L_DO 0x0028
+#define RK3188_GRF_GPIO1H_DO 0x002c
+#define RK3188_GRF_GPIO2L_DO 0x0030
+#define RK3188_GRF_GPIO2H_DO 0x0034
+#define RK3188_GRF_GPIO3L_DO 0x0038
+#define RK3188_GRF_GPIO3H_DO 0x003c
+#define RK3188_GRF_GPIO0L_EN 0x0040
+#define RK3188_GRF_GPIO0H_EN 0x0044
+#define RK3188_GRF_GPIO1L_EN 0x0048
+#define RK3188_GRF_GPIO1H_EN 0x004c
+#define RK3188_GRF_GPIO2L_EN 0x0050
+#define RK3188_GRF_GPIO2H_EN 0x0054
+#define RK3188_GRF_GPIO3L_EN 0x0058
+#define RK3188_GRF_GPIO3H_EN 0x005c
+
+#define RK3188_GRF_GPIO0C_IOMUX 0x0068
+#define RK3188_GRF_GPIO0D_IOMUX 0x006c
+#define RK3188_GRF_GPIO1A_IOMUX 0x0070
+#define RK3188_GRF_GPIO1B_IOMUX 0x0074
+#define RK3188_GRF_GPIO1C_IOMUX 0x0078
+#define RK3188_GRF_GPIO1D_IOMUX 0x007c
+#define RK3188_GRF_GPIO2A_IOMUX 0x0080
+#define RK3188_GRF_GPIO2B_IOMUX 0x0084
+#define RK3188_GRF_GPIO2C_IOMUX 0x0088
+#define RK3188_GRF_GPIO2D_IOMUX 0x008c
+#define RK3188_GRF_GPIO3A_IOMUX 0x0090
+#define RK3188_GRF_GPIO3B_IOMUX 0x0094
+#define RK3188_GRF_GPIO3C_IOMUX 0x0098
+#define RK3188_GRF_GPIO3D_IOMUX 0x009c
+#define RK3188_GRF_SOC_CON0 0x00a0
+#define RK3188_GRF_SOC_CON1 0x00a4
+#define RK3188_GRF_SOC_CON2 0x00a8
+#define RK3188_GRF_SOC_STATUS0 0x00ac
+#define RK3188_GRF_DMAC1_CON0 0x00b0
+#define RK3188_GRF_DMAC1_CON1 0x00b4
+#define RK3188_GRF_DMAC1_CON2 0x00b8
+#define RK3188_GRF_DMAC2_CON0 0x00bc
+#define RK3188_GRF_DMAC2_CON1 0x00c0
+#define RK3188_GRF_DMAC2_CON2 0x00c4
+#define RK3188_GRF_DMAC2_CON3 0x00c8
+#define RK3188_GRF_CPU_CON0 0x00cc
+#define RK3188_GRF_CPU_CON1 0x00d0
+#define RK3188_GRF_CPU_CON2 0x00d4
+#define RK3188_GRF_CPU_CON3 0x00d8
+#define RK3188_GRF_CPU_CON4 0x00dc
+#define RK3188_GRF_CPU_CON5 0x00e0
+
+#define RK3188_GRF_DDRC_CON0 0x00ec
+#define RK3188_GRF_DDRC_STAT 0x00f0
+#define RK3188_GRF_IO_CON0 0x00f4
+#define RK3188_GRF_IO_CON1 0x00f8
+#define RK3188_GRF_IO_CON2 0x00fc
+#define RK3188_GRF_IO_CON3 0x0100
+#define RK3188_GRF_IO_CON4 0x0104
+#define RK3188_GRF_SOC_STATUS1 0x0108
+#define RK3188_GRF_UOC0_CON0 0x010c
+#define RK3188_GRF_UOC0_CON1 0x0110
+#define RK3188_GRF_UOC0_CON2 0x0114
+#define RK3188_GRF_UOC0_CON3 0x0118
+#define RK3188_GRF_UOC1_CON0 0x011c
+#define RK3188_GRF_UOC1_CON1 0x0120
+#define RK3188_GRF_UOC1_CON2 0x0124
+#define RK3188_GRF_UOC1_CON3 0x0128
+#define RK3188_GRF_UOC2_CON0 0x012c
+#define RK3188_GRF_UOC2_CON1 0x0130
+
+#define RK3188_GRF_UOC3_CON0 0x0138
+#define RK3188_GRF_UOC3_CON1 0x013c
+#define RK3188_GRF_EHCI_STAT 0x0140
+#define RK3188_GRF_OS_REG0 0x0144
+#define RK3188_GRF_OS_REG1 0x0148
+#define RK3188_GRF_OS_REG2 0x014c
+#define RK3188_GRF_OS_REG3 0x0150
+#define RK3188_GRF_OS_REG4 0x0154
+#define RK3188_GRF_OS_REG5 0x0158
+#define RK3188_GRF_OS_REG6 0x015c
+#define RK3188_GRF_OS_REG7 0x0160
+#define RK3188_GRF_GPIO0B_PULL 0x0164
+#define RK3188_GRF_GPIO0C_PULL 0x0168
+#define RK3188_GRF_GPIO0D_PULL 0x016c
+#define RK3188_GRF_GPIO1A_PULL 0x0170
+#define RK3188_GRF_GPIO1B_PULL 0x0174
+#define RK3188_GRF_GPIO1C_PULL 0x0178
+#define RK3188_GRF_GPIO1D_PULL 0x017c
+#define RK3188_GRF_GPIO2A_PULL 0x0180
+#define RK3188_GRF_GPIO2B_PULL 0x0184
+#define RK3188_GRF_GPIO2C_PULL 0x0188
+#define RK3188_GRF_GPIO2D_PULL 0x018c
+#define RK3188_GRF_GPIO3A_PULL 0x0190
+#define RK3188_GRF_GPIO3B_PULL 0x0194
+#define RK3188_GRF_GPIO3C_PULL 0x0198
+#define RK3188_GRF_GPIO3D_PULL 0x019c
+#define RK3188_GRF_FLASH_DATA_PULL 0x01a0
+#define RK3188_GRF_FLASH_CMD_PULL 0x01a4
+
+
+#define RK3288_GRF_GPIO0_A_IOMUX 0x0084
+#define RK3288_GRF_GPIO0_B_IOMUX 0x0088
+#define RK3288_GRF_GPIO0_C_IOMUX 0x008c
+
+#define RK3288_GRF_GPIO1D_IOMUX 0x000c
+#define RK3288_GRF_GPIO2A_IOMUX 0x0010
+#define RK3288_GRF_GPIO2B_IOMUX 0x0014
+#define RK3288_GRF_GPIO2C_IOMUX 0x0018
+
+#define RK3288_GRF_GPIO3A_IOMUX 0x0020
+#define RK3288_GRF_GPIO3B_IOMUX 0x0024
+#define RK3288_GRF_GPIO3C_IOMUX 0x0028
+#define RK3288_GRF_GPIO3DL_IOMUX 0x002c
+#define RK3288_GRF_GPIO3DH_IOMUX 0x0030
+#define RK3288_GRF_GPIO4AL_IOMUX 0x0034
+#define RK3288_GRF_GPIO4AH_IOMUX 0x0038
+#define RK3288_GRF_GPIO4BL_IOMUX 0x003c
+
+#define RK3288_GRF_GPIO4C_IOMUX 0x0044
+#define RK3288_GRF_GPIO4D_IOMUX 0x0048
+
+#define RK3288_GRF_GPIO5B_IOMUX 0x0050
+#define RK3288_GRF_GPIO5C_IOMUX 0x0054
+
+#define RK3288_GRF_GPIO6A_IOMUX 0x005c
+#define RK3288_GRF_GPIO6B_IOMUX 0x0060
+#define RK3288_GRF_GPIO6C_IOMUX 0x0064
+
+#define RK3288_GRF_GPIO7A_IOMUX 0x006c
+#define RK3288_GRF_GPIO7B_IOMUX 0x0070
+#define RK3288_GRF_GPIO7CL_IOMUX 0x0074
+#define RK3288_GRF_GPIO7CH_IOMUX 0x0078
+
+#define RK3288_GRF_GPIO8A_IOMUX 0x0080
+#define RK3288_GRF_GPIO8B_IOMUX 0x0084
+
+#define RK3288_GRF_GPIO1H_SR 0x0104
+#define RK3288_GRF_GPIO2L_SR 0x0108
+#define RK3288_GRF_GPIO2H_SR 0x010c
+#define RK3288_GRF_GPIO3L_SR 0x0110
+#define RK3288_GRF_GPIO3H_SR 0x0114
+#define RK3288_GRF_GPIO4L_SR 0x0118
+#define RK3288_GRF_GPIO4H_SR 0x011c
+#define RK3288_GRF_GPIO5L_SR 0x0120
+#define RK3288_GRF_GPIO5H_SR 0x0124
+#define RK3288_GRF_GPIO6L_SR 0x0128
+#define RK3288_GRF_GPIO6H_SR 0x012c
+#define RK3288_GRF_GPIO7L_SR 0x0130
+#define RK3288_GRF_GPIO7H_SR 0x0134
+#define RK3288_GRF_GPIO8L_SR 0x0138
+
+#define RK3288_GRF_GPIO1D_P 0x014c
+#define RK3288_GRF_GPIO2A_P 0x0150
+#define RK3288_GRF_GPIO2B_P 0x0154
+#define RK3288_GRF_GPIO2C_P 0x0158
+
+#define RK3288_GRF_GPIO3A_P 0x0160
+#define RK3288_GRF_GPIO3B_P 0x0164
+#define RK3288_GRF_GPIO3C_P 0x0168
+#define RK3288_GRF_GPIO3D_P 0x016c
+#define RK3288_GRF_GPIO4A_P 0x0170
+#define RK3288_GRF_GPIO4B_P 0x0174
+#define RK3288_GRF_GPIO4C_P 0x0178
+#define RK3288_GRF_GPIO4D_P 0x017c
+
+#define RK3288_GRF_GPIO5B_P 0x0184
+#define RK3288_GRF_GPIO5C_P 0x0188
+
+#define RK3288_GRF_GPIO6A_P 0x0190
+#define RK3288_GRF_GPIO6B_P 0x0194
+#define RK3288_GRF_GPIO6C_P 0x0198
+
+#define RK3288_GRF_GPIO7A_P 0x01a0
+#define RK3288_GRF_GPIO7B_P 0x01a4
+#define RK3288_GRF_GPIO7C_P 0x01a8
+
+#define RK3288_GRF_GPIO8A_P 0x01b0
+#define RK3288_GRF_GPIO8B_P 0x01b4
+
+#define RK3288_GRF_GPIO1D_E 0x01cc
+#define RK3288_GRF_GPIO2A_E 0x01d0
+#define RK3288_GRF_GPIO2B_E 0x01d4
+#define RK3288_GRF_GPIO2C_E 0x01d8
+
+#define RK3288_GRF_GPIO3A_E 0x01e0
+#define RK3288_GRF_GPIO3B_E 0x01e4
+#define RK3288_GRF_GPIO3C_E 0x01e8
+#define RK3288_GRF_GPIO3D_E 0x01ec
+#define RK3288_GRF_GPIO4A_E 0x01f0
+#define RK3288_GRF_GPIO4B_E 0x01f4
+#define RK3288_GRF_GPIO4C_E 0x01f8
+#define RK3288_GRF_GPIO4D_E 0x01fc
+
+#define RK3288_GRF_GPIO5B_E 0x0204
+#define RK3288_GRF_GPIO5C_E 0x0208
+
+#define RK3288_GRF_GPIO6A_E 0x0210
+#define RK3288_GRF_GPIO6B_E 0x0214
+#define RK3288_GRF_GPIO6C_E 0x0218
+
+#define RK3288_GRF_GPIO7A_E 0x0220
+#define RK3288_GRF_GPIO7B_E 0x0224
+#define RK3288_GRF_GPIO7C_E 0x0228
+
+#define RK3288_GRF_GPIO8A_E 0x0230
+#define RK3288_GRF_GPIO8B_E 0x0234
+
+#define RK3288_GRF_GPIO_SMT 0x0240
+#define RK3288_GRF_SOC_CON0 0x0244
+#define RK3288_GRF_SOC_CON1 0x0248
+#define RK3288_GRF_SOC_CON2 0x024c
+#define RK3288_GRF_SOC_CON3 0x0250
+#define RK3288_GRF_SOC_CON4 0x0254
+#define RK3288_GRF_SOC_CON5 0x0258
+#define RK3288_GRF_SOC_CON6 0x025c
+#define RK3288_GRF_SOC_CON7 0x0260
+#define RK3288_GRF_SOC_CON8 0x0264
+#define RK3288_GRF_SOC_CON9 0x0268
+#define RK3288_GRF_SOC_CON10 0x026c
+#define RK3288_GRF_SOC_CON11 0x0270
+#define RK3288_GRF_SOC_CON12 0x0274
+#define RK3288_GRF_SOC_CON13 0x0278
+#define RK3288_GRF_SOC_CON14 0x027c
+#define RK3288_GRF_SOC_STATUS0 0x0280
+#define RK3288_GRF_SOC_STATUS1 0x0284
+#define RK3288_GRF_SOC_STATUS2 0x0288
+#define RK3288_GRF_SOC_STATUS3 0x028c
+#define RK3288_GRF_SOC_STATUS4 0x0290
+#define RK3288_GRF_SOC_STATUS5 0x0294
+#define RK3288_GRF_SOC_STATUS6 0x0298
+#define RK3288_GRF_SOC_STATUS7 0x029c
+#define RK3288_GRF_SOC_STATUS8 0x02a0
+#define RK3288_GRF_SOC_STATUS9 0x02a4
+#define RK3288_GRF_SOC_STATUS10 0x02a8
+#define RK3288_GRF_SOC_STATUS11 0x02ac
+#define RK3288_GRF_SOC_STATUS12 0x02b0
+#define RK3288_GRF_SOC_STATUS13 0x02b4
+#define RK3288_GRF_SOC_STATUS14 0x02b8
+#define RK3288_GRF_SOC_STATUS15 0x02bc
+#define RK3288_GRF_SOC_STATUS16 0x02c0
+#define RK3288_GRF_SOC_STATUS17 0x02c4
+#define RK3288_GRF_SOC_STATUS18 0x02c8
+#define RK3288_GRF_SOC_STATUS19 0x02cc
+#define RK3288_GRF_SOC_STATUS20 0x02d0
+#define RK3288_GRF_SOC_STATUS21 0x02d4
+
+#define RK3288_GRF_PERIDMAC_CON0 0x02e0
+#define RK3288_GRF_PERIDMAC_CON1 0x02e4
+#define RK3288_GRF_PERIDMAC_CON2 0x02e8
+#define RK3288_GRF_PERIDMAC_CON3 0x02ec
+#define RK3288_GRF_DDRC0_CON0 0x02f0
+#define RK3288_GRF_DDRC1_CON0 0x02f4
+#define RK3288_GRF_CPU_CON0 0x02f8
+#define RK3288_GRF_CPU_CON1 0x02fc
+#define RK3288_GRF_CPU_CON2 0x0300
+#define RK3288_GRF_CPU_CON3 0x0304
+#define RK3288_GRF_CPU_CON4 0x0308
+
+#define RK3288_GRF_CPU_STATUS0 0x0318
+
+#define RK3288_GRF_UOC0_CON0 0x0320
+#define RK3288_GRF_UOC0_CON1 0x0324
+#define RK3288_GRF_UOC0_CON2 0x0328
+#define RK3288_GRF_UOC0_CON3 0x032c
+#define RK3288_GRF_UOC0_CON4 0x0330
+#define RK3288_GRF_UOC1_CON0 0x0334
+#define RK3288_GRF_UOC1_CON1 0x0338
+#define RK3288_GRF_UOC1_CON2 0x033c
+#define RK3288_GRF_UOC1_CON3 0x0340
+#define RK3288_GRF_UOC1_CON4 0x0344
+#define RK3288_GRF_UOC2_CON0 0x0348
+#define RK3288_GRF_UOC2_CON1 0x034c
+#define RK3288_GRF_UOC2_CON2 0x0350
+#define RK3288_GRF_UOC2_CON3 0x0354
+#define RK3288_GRF_UOC3_CON0 0x0358
+#define RK3288_GRF_UOC3_CON1 0x035c
+#define RK3288_GRF_UOC4_CON0 0x0360
+#define RK3288_GRF_UOC4_CON1 0x0364
+#define RK3288_GRF_PVTM_CON0 0x0368
+#define RK3288_GRF_PVTM_CON1 0x036c
+#define RK3288_GRF_PVTM_CON2 0x0370
+#define RK3288_GRF_PVTM_STATUS0 0x0374
+#define RK3288_GRF_PVTM_STATUS1 0x0378
+#define RK3288_GRF_PVTM_STATUS2 0x037c
+#define RK3288_GRF_IO_VSEL 0x0380
+#define RK3288_GRF_SARADC_TESTBIT 0x0384
+#define RK3288_GRF_TSADC_TESTBIT_L 0x0388
+#define RK3288_GRF_TSADC_TESTBIT_H 0x038c
+#define RK3288_GRF_OS_REG0 0x0390
+#define RK3288_GRF_OS_REG1 0x0394
+#define RK3288_GRF_OS_REG2 0x0398
+#define RK3288_GRF_OS_REG3 0x039c
+
+#define RK3288_GRF_SOC_CON15 0x03a4
+#define RK3288_GRF_SOC_CON16 0x03a8
+
+#define RK3288_SGRF_SOC_CON0 0x0000
+#define RK3288_SGRF_SOC_CON1 0x0004
+#define RK3288_SGRF_SOC_CON2 0x0008
+#define RK3288_SGRF_SOC_CON3 0x000c
+#define RK3288_SGRF_SOC_CON4 0x0010
+#define RK3288_SGRF_SOC_CON5 0x0014
+
+#define RK3288_SGRF_BUSDMAC_CON0 0x0020
+#define RK3288_SGRF_BUSDMAC_CON1 0x0024
+
+#define RK3288_SGRF_CPU_CON0 0x0040
+#define RK3288_SGRF_CPU_CON1 0x0044
+#define RK3288_SGRF_CPU_CON2 0x0048
+
+#define RK3288_SGRF_SOC_CON6 0x0050
+#define RK3288_SGRF_SOC_CON7 0x0054
+#define RK3288_SGRF_SOC_CON8 0x0058
+#define RK3288_SGRF_SOC_CON9 0x005c
+#define RK3288_SGRF_SOC_CON10 0x0060
+#define RK3288_SGRF_SOC_CON11 0x0064
+#define RK3288_SGRF_SOC_CON12 0x0068
+#define RK3288_SGRF_SOC_CON13 0x006c
+#define RK3288_SGRF_SOC_CON14 0x0070
+#define RK3288_SGRF_SOC_CON15 0x0074
+#define RK3288_SGRF_SOC_CON16 0x0078
+#define RK3288_SGRF_SOC_CON17 0x007c
+#define RK3288_SGRF_SOC_CON18 0x0080
+#define RK3288_SGRF_SOC_CON19 0x0084
+#define RK3288_SGRF_SOC_CON20 0x0088
+#define RK3288_SGRF_SOC_CON21 0x008c
+
+#define RK3288_SGRF_SOC_STATUS0 0x0100
+#define RK3288_SGRF_SOC_STATUS1 0x0104
+
+#define RK3288_SGRF_FAST_BOOT_ADDR 0x0120
+
+
+#define RK3036_GRF_GPIO0A_IOMUX 0x000a8
+#define RK3036_GRF_GPIO0B_IOMUX 0x000ac
+#define RK3036_GRF_GPIO0C_IOMUX 0x000b0
+#define RK3036_GRF_GPIO0D_IOMUX 0x000b4
+#define RK3036_GRF_GPIO1A_IOMUX 0x000b8
+#define RK3036_GRF_GPIO1B_IOMUX 0x000bc
+#define RK3036_GRF_GPIO1C_IOMUX 0x000c0
+#define RK3036_GRF_GPIO1D_IOMUX 0x000c4
+#define RK3036_GRF_GPIO2A_IOMUX 0x000c8
+#define RK3036_GRF_GPIO2B_IOMUX 0x000cc
+#define RK3036_GRF_GPIO2C_IOMUX 0x000d0
+#define RK3036_GRF_GPIO2D_IOMUX 0x000d4
+#define RK3036_GRF_GPIO_DS 0x00100
+#define RK3036_GRF_GPIO0L_PULL 0x00118
+#define RK3036_GRF_GPIO0H_PULL 0x0011c
+#define RK3036_GRF_GPIO1L_PULL 0x00120
+#define RK3036_GRF_GPIO1H_PULL 0x00124
+
+#define RK3036_GRF_GPIO2L_PULL 0x00128
+#define RK3036_GRF_GPIO2H_PULL 0x0012c
+#define RK3036_GRF_SOC_CON0 0x00140
+#define RK3036_GRF_SOC_CON1 0x00144
+#define RK3036_GRF_SOC_CON2 0x00148
+#define RK3036_GRF_SOC_STATUS0 0x0014c
+#define RK3036_GRF_SOC_CON3 0x00154
+#define RK3036_GRF_DMAC_CON0 0x0015c
+#define RK3036_GRF_DMAC_CON1 0x00160
+#define RK3036_GRF_DMAC_CON2 0x00164
+#define RK3036_GRF_UOC0_CON5 0x0017c
+#define RK3036_GRF_UOC1_CON4 0x00190
+#define RK3036_GRF_UOC1_CON5 0x00194
+#define RK3036_GRF_DDRC_STAT 0x0019c
+#define RK3036_GRF_UOC_CON6 0x001a0
+#define RK3036_GRF_SOC_STATUS1 0x001a4
+#define RK3036_GRF_CPU_CON0 0x001a8
+#define RK3036_GRF_CPU_CON1 0x001ac
+#define RK3036_GRF_CPU_CON2 0x001b0
+#define RK3036_GRF_CPU_CON3 0x001b4
+#define RK3036_GRF_CPU_STATUS0 0x001c0
+#define RK3036_GRF_CPU_STATUS1 0x001c4
+#define RK3036_GRF_OS_REG0 0x001c8
+#define RK3036_GRF_OS_REG1 0x001cc
+#define RK3036_GRF_OS_REG2 0x001d0
+#define RK3036_GRF_OS_REG3 0x001d4
+#define RK3036_GRF_OS_REG4 0x001d8
+#define RK3036_GRF_OS_REG5 0x001dc
+#define RK3036_GRF_OS_REG6 0x001e0
+#define RK3036_GRF_OS_REG7 0x001e4
+#define RK3036_GRF_DLL_CON0 0x00200
+#define RK3036_GRF_DLL_CON1 0x00204
+#define RK3036_GRF_DLL_CON2 0x00208
+#define RK3036_GRF_DLL_CON3 0x0020c
+#define RK3036_GRF_DLL_STATUS0 0x00210
+#define RK3036_GRF_DLL_STATUS1 0x00214
+
+#define RK3036_GRF_DLL_STATUS2 0x00218
+#define RK3036_GRF_DLL_STATUS3 0x0021c
+#define RK3036_GRF_DFI_WRNUM 0x00220
+#define RK3036_GRF_DFI_RDNUM 0x00224
+#define RK3036_GRF_DFI_ACTNUM 0x00228
+#define RK3036_GRF_DFI_TIMERVAL 0x0022c
+#define RK3036_GRF_NIF_FIFO0 0x00230
+#define RK3036_GRF_NIF_FIFO1 0x00234
+#define RK3036_GRF_NIF_FIFO2 0x00238
+#define RK3036_GRF_NIF_FIFO3 0x0023c
+#define RK3036_GRF_USBPHY0_CON0 0x00280
+#define RK3036_GRF_USBPHY0_CON1 0x00284
+#define RK3036_GRF_USBPHY0_CON2 0x00288
+#define RK3036_GRF_USBPHY0_CON3 0x0028c
+#define RK3036_GRF_USBPHY0_CON4 0x00290
+#define RK3036_GRF_USBPHY0_CON5 0x00294
+#define RK3036_GRF_USBPHY0_CON6 0x00298
+#define RK3036_GRF_USBPHY0_CON7 0x0029c
+#define RK3036_GRF_USBPHY1_CON0 0x002a0
+#define RK3036_GRF_USBPHY1_CON1 0x002a4
+#define RK3036_GRF_USBPHY1_CON2 0x002a8
+#define RK3036_GRF_USBPHY1_CON3 0x002ac
+#define RK3036_GRF_USBPHY1_CON4 0x002b0
+#define RK3036_GRF_USBPHY1_CON5 0x002b4
+#define RK3036_GRF_USBPHY1_CON6 0x002b8
+
+#define RK3036_GRF_USBPHY1_CON7 0x002bc
+#define RK3036_GRF_CHIP_TAG 0x00300
+#define RK3036_GRF_SDMMC_DET_CNT 0x00304
+
+#define RK312X_GRF_GPIO0A_IOMUX 0x000a8
+#define RK312X_GRF_GPIO0B_IOMUX 0x000ac
+#define RK312X_GRF_GPIO0C_IOMUX 0x000b0
+#define RK312X_GRF_GPIO0D_IOMUX 0x000b4
+#define RK312X_GRF_GPIO1A_IOMUX 0x000b8
+#define RK312X_GRF_GPIO1B_IOMUX 0x000bc
+#define RK312X_GRF_GPIO1C_IOMUX 0x000c0
+#define RK312X_GRF_GPIO1D_IOMUX 0x000c4
+#define RK312X_GRF_GPIO2A_IOMUX 0x000c8
+#define RK312X_GRF_GPIO2B_IOMUX 0x000cc
+#define RK312X_GRF_GPIO2C_IOMUX 0x000d0
+#define RK312X_GRF_GPIO2D_IOMUX 0x000d4
+#define RK312X_GRF_GPIO3A_IOMUX 0x000d8
+#define RK312X_GRF_GPIO3B_IOMUX 0x000dc
+#define RK312X_GRF_GPIO3C_IOMUX 0x000e0
+#define RK312X_GRF_GPIO3D_IOMUX 0x000e4
+#define RK312X_GRF_CIF_IOMUX 0x000ec
+#define RK312X_GRF_CIF_IOMUX1 0x000f0
+#define RK312X_GRF_GPIO_DS 0x00100
+#define RK312X_GRF_GPIO0L_PULL 0x00118
+#define RK312X_GRF_GPIO0H_PULL 0x0011c
+#define RK312X_GRF_GPIO1L_PULL 0x00120
+#define RK312X_GRF_GPIO1H_PULL 0x00124
+#define RK312X_GRF_GPIO2L_PULL 0x00128
+#define RK312X_GRF_GPIO2H_PULL 0x0012c
+#define RK312X_GRF_GPIO3L_PULL 0x00130
+#define RK312X_GRF_GPIO3H_PULL 0x00134
+#define RK312X_GRF_ACODEC_CON 0x0013c
+
+#define RK312X_GRF_SOC_CON0 0x00140
+#define RK312X_GRF_SOC_CON1 0x00144
+#define RK312X_GRF_SOC_CON2 0x00148
+#define RK312X_GRF_SOC_STATUS0 0x0014c
+#define RK312X_GRF_LVDS_CON0 0x00150
+#define RK312X_GRF_SOC_CON3 0x00154
+#define RK312X_GRF_DMAC_CON0 0x0015c
+#define RK312X_GRF_DMAC_CON1 0x00160
+#define RK312X_GRF_DMAC_CON2 0x00164
+#define RK312X_GRF_MAC_CON0 0x00168
+#define RK312X_GRF_MAC_CON1 0x0016c
+#define RK312X_GRF_TVE_CON 0x00170
+#define RK312X_GRF_UOC0_CON0 0x0017c
+#define RK312X_GRF_UOC1_CON1 0x00184
+#define RK312X_GRF_UOC1_CON2 0x00188
+#define RK312X_GRF_UOC1_CON3 0x0018c
+#define RK312X_GRF_UOC1_CON4 0x00190
+#define RK312X_GRF_UOC1_CON5 0x00194
+#define RK312X_GRF_DDRC_STAT 0x0019c
+#define RK312X_GRF_SOC_STATUS1 0x001a4
+#define RK312X_GRF_CPU_CON0 0x001a8
+#define RK312X_GRF_CPU_CON1 0x001ac
+#define RK312X_GRF_CPU_CON2 0x001b0
+#define RK312X_GRF_CPU_CON3 0x001b4
+#define RK312X_GRF_CPU_STATUS0 0x001c0
+#define RK312X_GRF_CPU_STATUS1 0x001c4
+#define RK312X_GRF_OS_REG0 0x001c8
+#define RK312X_GRF_OS_REG1 0x001cc
+#define RK312X_GRF_OS_REG2 0x001d0
+#define RK312X_GRF_OS_REG3 0x001d4
+#define RK312X_GRF_OS_REG4 0x001d8
+#define RK312X_GRF_OS_REG5 0x001dc
+#define RK312X_GRF_OS_REG6 0x001e0
+#define RK312X_GRF_OS_REG7 0x001e4
+#define RK312X_GRF_PVTM_CON0 0x00200
+#define RK312X_GRF_PVTM_CON1 0x00204
+#define RK312X_GRF_PVTM_CON2 0x00208
+#define RK312X_GRF_PVTM_CON3 0x0020c
+#define RK312X_GRF_PVTM_STATUS0 0x00210
+#define RK312X_GRF_PVTM_STATUS1 0x00214
+#define RK312X_GRF_PVTM_STATUS2 0x00218
+#define RK312X_GRF_PVTM_STATUS3 0x0021c
+#define RK312X_GRF_DFI_WRNUM 0x00220
+#define RK312X_GRF_DFI_RDNUM 0x00224
+#define RK312X_GRF_DFI_ACTNUM 0x00228
+#define RK312X_GRF_DFI_TIMERVAL 0x0022c
+#define RK312X_GRF_NIF_FIFO0 0x00230
+#define RK312X_GRF_NIF_FIFO1 0x00234
+#define RK312X_GRF_NIF_FIFO2 0x00238
+#define RK312X_GRF_NIF_FIFO3 0x0023c
+#define RK312X_GRF_USBPHY0_CON0 0x00280
+#define RK312X_GRF_USBPHY0_CON1 0x00284
+#define RK312X_GRF_USBPHY0_CON2 0x00288
+#define RK312X_GRF_USBPHY0_CON3 0x0028c
+#define RK312X_GRF_USBPHY0_CON4 0x00290
+#define RK312X_GRF_USBPHY0_CON5 0x00294
+#define RK312X_GRF_USBPHY0_CON6 0x00298
+#define RK312X_GRF_USBPHY0_CON7 0x0029c
+#define RK312X_GRF_USBPHY1_CON0 0x002a0
+#define RK312X_GRF_USBPHY1_CON1 0x002a4
+#define RK312X_GRF_USBPHY1_CON2 0x002a8
+#define RK312X_GRF_USBPHY1_CON3 0x002ac
+#define RK312X_GRF_USBPHY1_CON4 0x002b0
+#define RK312X_GRF_USBPHY1_CON5 0x002b4
+#define RK312X_GRF_USBPHY1_CON6 0x002b8
+#define RK312X_GRF_USBPHY1_CON7 0x002bc
+#define RK312X_GRF_UOC_STATUS0 0x002c0
+#define RK312X_GRF_CHIP_TAG 0x00300
+#define RK312X_GRF_SDMMC_DET_CNT 0x00304
+#define RK312X_GRF_EFUSE_PRG_EN 0x0037c
+
+#define RK3228_GRF_GPIO0A_IOMUX 0x0000
+#define RK3228_GRF_GPIO0B_IOMUX 0x0004
+#define RK3228_GRF_GPIO0C_IOMUX 0x0008
+#define RK3228_GRF_GPIO0D_IOMUX 0x000c
+#define RK3228_GRF_GPIO1A_IOMUX 0x0010
+#define RK3228_GRF_GPIO1B_IOMUX 0x0014
+#define RK3228_GRF_GPIO1C_IOMUX 0x0018
+#define RK3228_GRF_GPIO1D_IOMUX 0x001c
+#define RK3228_GRF_GPIO2A_IOMUX 0x0020
+#define RK3228_GRF_GPIO2B_IOMUX 0x0024
+#define RK3228_GRF_GPIO2C_IOMUX 0x0028
+#define RK3228_GRF_GPIO2D_IOMUX 0x002c
+#define RK3228_GRF_GPIO3A_IOMUX 0x0030
+#define RK3228_GRF_GPIO3B_IOMUX 0x0034
+#define RK3228_GRF_GPIO3C_IOMUX 0x0038
+#define RK3228_GRF_GPIO3D_IOMUX 0x003c
+#define RK3228_GRF_COM_IOMUX 0x0050
+#define RK3228_GRF_GPIO0A_P 0x0100
+#define RK3228_GRF_GPIO0B_P 0x0104
+#define RK3228_GRF_GPIO0C_P 0x0108
+#define RK3228_GRF_GPIO0D_P 0x010c
+#define RK3228_GRF_GPIO1A_P 0x0110
+#define RK3228_GRF_GPIO1B_P 0x0114
+#define RK3228_GRF_GPIO1C_P 0x0118
+#define RK3228_GRF_GPIO1D_P 0x011c
+#define RK3228_GRF_GPIO2A_P 0x0120
+#define RK3228_GRF_GPIO2B_P 0x0124
+#define RK3228_GRF_GPIO2C_P 0x0128
+#define RK3228_GRF_GPIO2D_P 0x012c
+#define RK3228_GRF_GPIO3A_P 0x0130
+#define RK3228_GRF_GPIO3B_P 0x0134
+#define RK3228_GRF_GPIO3C_P 0x0138
+#define RK3228_GRF_GPIO3D_P 0x013c
+#define RK3228_GRF_GPIO0A_E 0x0200
+#define RK3228_GRF_GPIO0B_E 0x0204
+#define RK3228_GRF_GPIO0C_E 0x0208
+#define RK3228_GRF_GPIO0D_E 0x020c
+#define RK3228_GRF_GPIO1A_E 0x0210
+#define RK3228_GRF_GPIO1B_E 0x0214
+#define RK3228_GRF_GPIO1C_E 0x0218
+#define RK3228_GRF_GPIO1D_E 0x021c
+#define RK3228_GRF_GPIO2A_E 0x0220
+#define RK3228_GRF_GPIO2B_E 0x0224
+#define RK3228_GRF_GPIO2C_E 0x0228
+#define RK3228_GRF_GPIO2D_E 0x022c
+#define RK3228_GRF_GPIO3A_E 0x0230
+#define RK3228_GRF_GPIO3B_E 0x0234
+#define RK3228_GRF_GPIO3C_E 0x0238
+#define RK3228_GRF_GPIO3D_E 0x023c
+#define RK3228_GRF_GPIO0L_SR 0x0300
+#define RK3228_GRF_GPIO0H_SR 0x0304
+#define RK3228_GRF_GPIO1L_SR 0x0308
+#define RK3228_GRF_GPIO1H_SR 0x030c
+#define RK3228_GRF_GPIO2L_SR 0x0310
+#define RK3228_GRF_GPIO2H_SR 0x0314
+#define RK3228_GRF_GPIO3L_SR 0x0318
+#define RK3228_GRF_GPIO3H_SR 0x031c
+#define RK3228_GRF_GPIO0L_SMT 0x0380
+#define RK3228_GRF_GPIO0H_SMT 0x0384
+#define RK3228_GRF_GPIO1L_SMT 0x0388
+#define RK3228_GRF_GPIO1H_SMT 0x038c
+#define RK3228_GRF_GPIO2L_SMT 0x0390
+#define RK3228_GRF_GPIO2H_SMT 0x0394
+#define RK3228_GRF_GPIO3L_SMT 0x0398
+#define RK3228_GRF_GPIO3H_SMT 0x039c
+#define RK3228_GRF_SOC_CON0 0x0400
+#define RK3228_GRF_SOC_CON1 0x0404
+#define RK3228_GRF_SOC_CON2 0x0408
+#define RK3228_GRF_SOC_CON3 0x040c
+#define RK3228_GRF_SOC_CON4 0x0410
+#define RK3228_GRF_SOC_CON5 0x0414
+#define RK3228_GRF_SOC_CON6 0x0418
+#define RK3228_GRF_SOC_STATUS0 0x0480
+#define RK3228_GRF_SOC_STATUS1 0x0484
+#define RK3228_GRF_SOC_STATUS2 0x0488
+#define RK3228_GRF_CHIP_ID 0x048c
+#define RK3228_GRF_CPU_CON0 0x0500
+#define RK3228_GRF_CPU_CON1 0x0504
+#define RK3228_GRF_CPU_CON2 0x0508
+#define RK3228_GRF_CPU_CON3 0x050c
+#define RK3228_GRF_CPU_STATUS0 0x0520
+#define RK3228_GRF_CPU_STATUS1 0x0524
+#define RK3228_GRF_OS_REG0 0x05c8
+#define RK3228_GRF_OS_REG1 0x05cc
+#define RK3228_GRF_OS_REG2 0x05d0
+#define RK3228_GRF_OS_REG3 0x05d4
+#define RK3228_GRF_OS_REG4 0x05d8
+#define RK3228_GRF_OS_REG5 0x05dc
+#define RK3228_GRF_OS_REG6 0x05e0
+#define RK3228_GRF_OS_REG7 0x05e4
+#define RK3228_GRF_DDRC_STAT 0x0604
+#define RK3228_GRF_SIG_DETECT_CON 0x0680
+#define RK3228_GRF_SIG_DETECT_CON1 0x0684
+#define RK3228_GRF_SIG_DETECT_STATUS 0x0690
+#define RK3228_GRF_SIG_DETECT_STATUS1 0x0694
+#define RK3228_GRF_SIG_DETECT_CLR 0x06a0
+#define RK3228_GRF_SIG_DETECT_CLR1 0x06a4
+#define RK3228_GRF_EMMC_DET 0x06b0
+#define RK3228_GRF_HOST0_CON0 0x0700
+#define RK3228_GRF_HOST0_CON1 0x0704
+#define RK3228_GRF_HOST0_CON2 0x0708
+#define RK3228_GRF_HOST1_CON0 0x0710
+#define RK3228_GRF_HOST1_CON1 0x0714
+#define RK3228_GRF_HOST1_CON2 0x0718
+#define RK3228_GRF_HOST2_CON0 0x0720
+#define RK3228_GRF_HOST2_CON1 0x0724
+#define RK3228_GRF_HOST2_CON2 0x0728
+#define RK3228_GRF_USBPHY0_CON0 0x0760
+#define RK3228_GRF_USBPHY0_CON1 0x0764
+#define RK3228_GRF_USBPHY0_CON2 0x0768
+#define RK3228_GRF_USBPHY0_CON3 0x076c
+#define RK3228_GRF_USBPHY0_CON4 0x0770
+#define RK3228_GRF_USBPHY0_CON5 0x0774
+#define RK3228_GRF_USBPHY0_CON6 0x0778
+#define RK3228_GRF_USBPHY0_CON7 0x077c
+#define RK3228_GRF_USBPHY0_CON8 0x0780
+#define RK3228_GRF_USBPHY0_CON9 0x0784
+#define RK3228_GRF_USBPHY0_CON10 0x0788
+#define RK3228_GRF_USBPHY0_CON11 0x078c
+#define RK3228_GRF_USBPHY0_CON12 0x0790
+#define RK3228_GRF_USBPHY0_CON13 0x0794
+#define RK3228_GRF_USBPHY0_CON14 0x0798
+#define RK3228_GRF_USBPHY0_CON15 0x079c
+#define RK3228_GRF_USBPHY0_CON16 0x07a0
+#define RK3228_GRF_USBPHY0_CON17 0x07a4
+#define RK3228_GRF_USBPHY0_CON18 0x07a8
+#define RK3228_GRF_USBPHY0_CON19 0x07ac
+#define RK3228_GRF_USBPHY0_CON20 0x07b0
+#define RK3228_GRF_USBPHY0_CON21 0x07b4
+#define RK3228_GRF_USBPHY0_CON22 0x07b8
+#define RK3228_GRF_USBPHY0_CON23 0x07bc
+#define RK3228_GRF_USBPHY0_CON24 0x07c0
+#define RK3228_GRF_USBPHY0_CON25 0x07c4
+#define RK3228_GRF_USBPHY0_CON26 0x07c8
+#define RK3228_GRF_USBPHY1_CON0 0x0800
+#define RK3228_GRF_USBPHY1_CON1 0x0804
+#define RK3228_GRF_USBPHY1_CON2 0x0808
+#define RK3228_GRF_USBPHY1_CON3 0x080c
+#define RK3228_GRF_USBPHY1_CON4 0x0810
+#define RK3228_GRF_USBPHY1_CON5 0x0814
+#define RK3228_GRF_USBPHY1_CON6 0x0818
+#define RK3228_GRF_USBPHY1_CON7 0x081c
+#define RK3228_GRF_USBPHY1_CON8 0x0820
+#define RK3228_GRF_USBPHY1_CON9 0x0824
+#define RK3228_GRF_USBPHY1_CON10 0x0828
+#define RK3228_GRF_USBPHY1_CON11 0x082c
+#define RK3228_GRF_USBPHY1_CON12 0x0830
+#define RK3228_GRF_USBPHY1_CON13 0x0834
+#define RK3228_GRF_USBPHY1_CON14 0x0838
+#define RK3228_GRF_USBPHY1_CON15 0x083c
+#define RK3228_GRF_USBPHY1_CON16 0x0840
+#define RK3228_GRF_USBPHY1_CON17 0x0844
+#define RK3228_GRF_USBPHY1_CON18 0x0848
+#define RK3228_GRF_USBPHY1_CON19 0x084c
+#define RK3228_GRF_USBPHY1_CON20 0x0850
+#define RK3228_GRF_USBPHY1_CON21 0x0854
+#define RK3228_GRF_USBPHY1_CON22 0x0858
+#define RK3228_GRF_USBPHY1_CON23 0x085c
+#define RK3228_GRF_USBPHY1_CON24 0x0860
+#define RK3228_GRF_USBPHY1_CON25 0x0864
+#define RK3228_GRF_USBPHY1_CON26 0x0868
+#define RK3228_GRF_OTG_CON0 0x0880
+#define RK3228_GRF_UOC_CON0 0x0884
+#define RK3228_GRF_MAC_CON0 0x0900
+#define RK3228_GRF_MAC_CON1 0x0904
+#define RK3228_GRF_MACPHY_CON0 0x0b00
+#define RK3228_GRF_MACPHY_CON1 0x0b04
+#define RK3228_GRF_MACPHY_CON2 0x0b08
+#define RK3228_GRF_MACPHY_CON3 0x0b0c
+#define RK3228_GRF_MACPHY_STATUS 0x0b10
+
+#endif
diff --git a/include/linux/rockchip/iomap.h b/include/linux/rockchip/iomap.h
new file mode 100755
index 0000000..e6ffe50
--- /dev/null
+++ b/include/linux/rockchip/iomap.h
@@ -0,0 +1,228 @@
+#ifndef __MACH_ROCKCHIP_IOMAP_H
+#define __MACH_ROCKCHIP_IOMAP_H
+
+#ifndef __ASSEMBLY__
+#include <asm/io.h>
+#endif
+
+#ifdef IOMEM
+#define RK_IO_ADDRESS(x) IOMEM(0xFED00000 + x)
+#else
+#define RK_IO_ADDRESS(x) ((void __force __iomem *)(0xFED00000 + x))
+#endif
+
+#define RK_CRU_VIRT RK_IO_ADDRESS(0x00000000)
+#define RK_GRF_VIRT RK_IO_ADDRESS(0x00010000)
+#define RK_SGRF_VIRT (RK_GRF_VIRT + 0x1000)
+#define RK_PMU_VIRT RK_IO_ADDRESS(0x00020000)
+#define RK_ROM_VIRT RK_IO_ADDRESS(0x00030000)
+#define RK_EFUSE_VIRT RK_IO_ADDRESS(0x00040000)
+#define RK_GPIO_VIRT(n) RK_IO_ADDRESS(0x00050000 + (n) * 0x1000)
+#define RK_DEBUG_UART_VIRT RK_IO_ADDRESS(0x00060000)
+#define RK_CPU_AXI_BUS_VIRT RK_IO_ADDRESS(0x00070000)
+#define RK_TIMER_VIRT RK_IO_ADDRESS(0x00080000)
+#define RK_PWM_VIRT RK_IO_ADDRESS(0x00088000)
+#define RK_GIC_VIRT RK_IO_ADDRESS(0x00090000)
+#define RK_BOOTRAM_VIRT RK_IO_ADDRESS(0x000a0000)
+#define RK_DDR_VIRT RK_IO_ADDRESS(0x000d0000)
+
+#define RK3188_CRU_PHYS 0x20000000
+#define RK3188_CRU_SIZE SZ_4K
+#define RK3188_GRF_PHYS 0x20008000
+#define RK3188_GRF_SIZE SZ_4K
+#define RK3188_PMU_PHYS 0x20004000
+#define RK3188_PMU_SIZE SZ_4K
+#define RK3188_ROM_PHYS 0x10120000
+#define RK3188_ROM_SIZE SZ_16K
+#define RK3188_EFUSE_PHYS 0x20010000
+#define RK3188_EFUSE_SIZE SZ_4K
+#define RK3188_GPIO0_PHYS 0x2000a000
+#define RK3188_GPIO1_PHYS 0x2003c000
+#define RK3188_GPIO2_PHYS 0x2003e000
+#define RK3188_GPIO3_PHYS 0x20080000
+#define RK3188_GPIO_SIZE SZ_4K
+#define RK3188_CPU_AXI_BUS_PHYS 0x10128000
+#define RK3188_CPU_AXI_BUS_SIZE SZ_32K
+#define RK3188_TIMER0_PHYS 0x20038000
+#define RK3188_TIMER3_PHYS 0x2000e000
+#define RK3188_TIMER_SIZE SZ_4K
+#define RK3188_DDR_PCTL_PHYS 0x20020000
+#define RK3188_DDR_PCTL_SIZE SZ_4K
+#define RK3188_DDR_PUBL_PHYS 0x20040000
+#define RK3188_DDR_PUBL_SIZE SZ_4K
+#define RK3188_UART0_PHYS 0x10124000
+#define RK3188_UART1_PHYS 0x10126000
+#define RK3188_UART2_PHYS 0x20064000
+#define RK3188_UART3_PHYS 0x20068000
+#define RK3188_UART_SIZE SZ_4K
+
+#define RK3288_CRU_PHYS 0xFF760000
+#define RK3288_CRU_SIZE SZ_4K
+#define RK3288_GRF_PHYS 0xFF770000
+#define RK3288_GRF_SIZE SZ_4K
+#define RK3288_SGRF_PHYS 0xFF740000
+#define RK3288_SGRF_SIZE SZ_4K
+#define RK3288_PMU_PHYS 0xFF730000
+#define RK3288_PMU_SIZE SZ_4K
+#define RK3288_ROM_PHYS 0xFFFD0000
+#define RK3288_ROM_SIZE (SZ_16K + SZ_4K)
+#define RK3288_EFUSE_PHYS 0xFFB40000
+#define RK3288_EFUSE_SIZE SZ_4K
+#define RK3288_GPIO0_PHYS 0xFF750000
+#define RK3288_GPIO1_PHYS 0xFF780000
+#define RK3288_GPIO2_PHYS 0xFF790000
+#define RK3288_GPIO3_PHYS 0xFF7A0000
+#define RK3288_GPIO4_PHYS 0xFF7B0000
+#define RK3288_GPIO5_PHYS 0xFF7C0000
+#define RK3288_GPIO6_PHYS 0xFF7D0000
+#define RK3288_GPIO7_PHYS 0xFF7E0000
+#define RK3288_GPIO8_PHYS 0xFF7F0000
+#define RK3288_GPIO_SIZE SZ_4K
+#define RK3288_SERVICE_CORE_PHYS 0XFFA80000
+#define RK3288_SERVICE_CORE_SIZE SZ_4K
+#define RK3288_SERVICE_DMAC_PHYS 0XFFA90000
+#define RK3288_SERVICE_DMAC_SIZE SZ_4K
+#define RK3288_SERVICE_GPU_PHYS 0XFFAA0000
+#define RK3288_SERVICE_GPU_SIZE SZ_4K
+#define RK3288_SERVICE_PERI_PHYS 0XFFAB0000
+#define RK3288_SERVICE_PERI_SIZE SZ_4K
+#define RK3288_SERVICE_BUS_PHYS 0XFFAC0000
+#define RK3288_SERVICE_BUS_SIZE SZ_16K
+#define RK3288_SERVICE_VIO_PHYS 0XFFAD0000
+#define RK3288_SERVICE_VIO_SIZE SZ_4K
+#define RK3288_SERVICE_VIDEO_PHYS 0XFFAE0000
+#define RK3288_SERVICE_VIDEO_SIZE SZ_4K
+#define RK3288_SERVICE_HEVC_PHYS 0XFFAF0000
+#define RK3288_SERVICE_HEVC_SIZE SZ_4K
+#define RK3288_TIMER0_PHYS 0xFF6B0000
+#define RK3288_TIMER6_PHYS 0xFF810000
+#define RK3288_TIMER_SIZE SZ_4K
+#define RK3288_DDR_PCTL0_PHYS 0xFF610000
+#define RK3288_DDR_PCTL1_PHYS 0xFF630000
+#define RK3288_DDR_PCTL_SIZE SZ_4K
+#define RK3288_DDR_PUBL0_PHYS 0xFF620000
+#define RK3288_DDR_PUBL1_PHYS 0xFF640000
+#define RK3288_DDR_PUBL_SIZE SZ_4K
+#define RK3288_UART_BT_PHYS 0xFF180000
+#define RK3288_UART_BB_PHYS 0xFF190000
+#define RK3288_UART_DBG_PHYS 0xFF690000
+#define RK3288_UART_GPS_PHYS 0xFF1B0000
+#define RK3288_UART_EXP_PHYS 0xFF1C0000
+#define RK3288_UART_SIZE SZ_4K
+#define RK3288_GIC_DIST_PHYS 0xFFC01000
+#define RK3288_GIC_DIST_SIZE SZ_4K
+#define RK3288_GIC_CPU_PHYS 0xFFC02000
+#define RK3288_GIC_CPU_SIZE SZ_4K
+#define RK3288_BOOTRAM_PHYS 0xFF720000
+#define RK3288_BOOTRAM_SIZE SZ_4K
+#define RK3288_IMEM_PHYS 0xFF700000
+#define RK3288_IMEM_SZIE 0x00018000
+
+#define RK3036_IMEM_PHYS 0x10080000
+#define RK3036_IMEM_SIZE SZ_8K
+#define RK3036_ROM_PHYS 0x10100000
+#define RK3036_ROM_SIZE SZ_16K
+#define RK3036_CPU_AXI_BUS_PHYS 0x10128000
+#define RK3036_CPU_AXI_BUS_SIZE SZ_32K
+#define RK3036_GIC_DIST_PHYS 0x10139000
+#define RK3036_GIC_DIST_SIZE SZ_4K
+#define RK3036_GIC_CPU_PHYS 0x1013a000
+#define RK3036_GIC_CPU_SIZE SZ_4K
+#define RK3036_CRU_PHYS 0x20000000
+#define RK3036_CRU_SIZE SZ_4K
+#define RK3036_DDR_PCTL_PHYS 0x20004000
+#define RK3036_DDR_PCTL_SIZE SZ_4K
+#define RK3036_GRF_PHYS 0x20008000
+#define RK3036_GRF_SIZE SZ_4K
+#define RK3036_DDR_PHY_PHYS 0x2000a000
+#define RK3036_DDR_PHY_SIZE SZ_4K
+#define RK3036_TIMER_PHYS 0x20044000
+#define RK3036_TIMER_SIZE SZ_4K
+#define RK3036_UART0_PHYS 0x20060000
+#define RK3036_UART1_PHYS 0x20064000
+#define RK3036_UART2_PHYS 0x20068000
+#define RK3036_UART_SIZE SZ_4K
+#define RK3036_GPIO0_PHYS 0x2007c000
+#define RK3036_GPIO1_PHYS 0x20080000
+#define RK3036_GPIO2_PHYS 0x20084000
+#define RK3036_GPIO_SIZE SZ_4K
+#define RK3036_EFUSE_PHYS 0x20090000
+#define RK3036_EFUSE_SIZE SZ_4K
+#define RK3036_PWM_PHYS 0x20050000
+#define RK3036_PWM_SIZE SZ_16K
+
+#define RK312X_IMEM_PHYS RK3036_IMEM_PHYS
+#define RK312X_IMEM_SIZE RK3036_IMEM_SIZE
+#define RK312X_ROM_PHYS RK3036_ROM_PHYS
+#define RK312X_ROM_SIZE RK3036_ROM_SIZE
+#define RK312X_CPU_AXI_BUS_PHYS RK3036_CPU_AXI_BUS_PHYS
+#define RK312X_CPU_AXI_BUS_SIZE RK3036_CPU_AXI_BUS_SIZE
+#define RK312X_GIC_DIST_PHYS RK3036_GIC_DIST_PHYS
+#define RK312X_GIC_DIST_SIZE RK3036_GIC_DIST_SIZE
+#define RK312X_GIC_CPU_PHYS RK3036_GIC_CPU_PHYS
+#define RK312X_GIC_CPU_SIZE RK3036_GIC_CPU_SIZE
+#define RK312X_CRU_PHYS RK3036_CRU_PHYS
+#define RK312X_CRU_SIZE RK3036_CRU_SIZE
+#define RK312X_DDR_PCTL_PHYS RK3036_DDR_PCTL_PHYS
+#define RK312X_DDR_PCTL_SIZE RK3036_DDR_PCTL_SIZE
+#define RK312X_GRF_PHYS RK3036_GRF_PHYS
+#define RK312X_GRF_SIZE RK3036_GRF_SIZE
+#define RK312X_DDR_PHY_PHYS RK3036_DDR_PHY_PHYS
+#define RK312X_DDR_PHY_SIZE RK3036_DDR_PHY_SIZE
+#define RK312X_TIMER_PHYS RK3036_TIMER_PHYS
+#define RK312X_TIMER_SIZE RK3036_TIMER_SIZE
+#define RK312X_UART0_PHYS RK3036_UART0_PHYS
+#define RK312X_UART1_PHYS RK3036_UART1_PHYS
+#define RK312X_UART2_PHYS RK3036_UART2_PHYS
+#define RK312X_UART_SIZE RK3036_UART_SIZE
+#define RK312X_GPIO0_PHYS RK3036_GPIO0_PHYS
+#define RK312X_GPIO1_PHYS RK3036_GPIO1_PHYS
+#define RK312X_GPIO2_PHYS RK3036_GPIO2_PHYS
+#define RK312X_GPIO3_PHYS 0x20088000
+#define RK312X_GPIO_SIZE RK3036_GPIO_SIZE
+#define RK312X_EFUSE_PHYS RK3036_EFUSE_PHYS
+#define RK312X_EFUSE_SIZE RK3036_EFUSE_SIZE
+#define RK312X_PMU_PHYS 0x100a0000
+#define RK312X_PMU_SIZE SZ_64K
+#define RK312X_PWM_PHYS 0x20050000
+#define RK312X_PWM_SIZE SZ_16K
+
+#define RK3228_IMEM_PHYS RK3036_IMEM_PHYS
+#define RK3228_IMEM_SIZE SZ_32K
+#define RK3228_ROM_PHYS RK3036_ROM_PHYS
+#define RK3228_ROM_SIZE RK3036_ROM_SIZE
+#define RK3228_CPU_AXI_BUS_PHYS 0x31000000
+#define RK3228_CPU_AXI_BUS_SIZE SZ_32K
+#define RK3228_GIC_DIST_PHYS 0x32011000
+#define RK3228_GIC_DIST_SIZE SZ_4K
+#define RK3228_GIC_CPU_PHYS 0x32012000
+#define RK3228_GIC_CPU_SIZE SZ_4K
+#define RK3228_CRU_PHYS 0x110e0000
+#define RK3228_CRU_SIZE SZ_4K
+#define RK3228_DDR_PCTL_PHYS 0x11200000
+#define RK3228_DDR_PCTL_SIZE SZ_4K
+#define RK3228_GRF_PHYS 0x11000000
+#define RK3228_GRF_SIZE SZ_4K
+#define RK3228_SGRF_PHYS 0x10140000
+#define RK3228_SGRF_SIZE SZ_4K
+#define RK3228_DDR_PHY_PHYS 0x12000000
+#define RK3228_DDR_PHY_SIZE SZ_4K
+#define RK3228_TIMER_PHYS 0x110c0000
+#define RK3228_TIMER_SIZE SZ_4K
+#define RK3228_STIMER_PHYS 0x110d0000
+#define RK3228_STIMER_SIZE SZ_4K
+#define RK3228_UART0_PHYS 0x11010000
+#define RK3228_UART1_PHYS 0x11020000
+#define RK3228_UART2_PHYS 0x11030000
+#define RK3228_UART_SIZE SZ_4K
+#define RK3228_GPIO0_PHYS 0x11110000
+#define RK3228_GPIO1_PHYS 0x11120000
+#define RK3228_GPIO2_PHYS 0x11130000
+#define RK3228_GPIO3_PHYS 0x11140000
+#define RK3228_GPIO_SIZE SZ_4K
+#define RK3228_EFUSE_PHYS 0x11040000
+#define RK3228_EFUSE_SIZE SZ_4K
+#define RK3228_PWM_PHYS 0x110b0000
+#define RK3228_PWM_SIZE SZ_16K
+
+#endif
diff --git a/include/linux/rockchip/pmu.h b/include/linux/rockchip/pmu.h
new file mode 100644
index 0000000..0092edf
--- /dev/null
+++ b/include/linux/rockchip/pmu.h
@@ -0,0 +1,140 @@
+#ifndef __MACH_ROCKCHIP_PMU_H
+#define __MACH_ROCKCHIP_PMU_H
+
+#define RK3188_PMU_WAKEUP_CFG0 0x00
+#define RK3188_PMU_WAKEUP_CFG1 0x04
+#define RK3188_PMU_PWRDN_CON 0x08
+#define RK3188_PMU_PWRDN_ST 0x0c
+#define RK3188_PMU_INT_CON 0x10
+#define RK3188_PMU_INT_ST 0x14
+#define RK3188_PMU_MISC_CON 0x18
+#define RK3188_PMU_OSC_CNT 0x1c
+#define RK3188_PMU_PLL_CNT 0x20
+#define RK3188_PMU_PMU_CNT 0x24
+#define RK3188_PMU_DDRIO_PWRON_CNT 0x28
+#define RK3188_PMU_WAKEUP_RST_CLR_CNT 0x2c
+#define RK3188_PMU_SCU_PWRDWN_CNT 0x30
+#define RK3188_PMU_SCU_PWRUP_CNT 0x34
+#define RK3188_PMU_MISC_CON1 0x38
+#define RK3188_PMU_GPIO0_CON 0x3c
+#define RK3188_PMU_SYS_REG0 0x40
+#define RK3188_PMU_SYS_REG1 0x44
+#define RK3188_PMU_SYS_REG2 0x48
+#define RK3188_PMU_SYS_REG3 0x4c
+#define RK3188_PMU_STOP_INT_DLY 0x60
+#define RK3188_PMU_GPIO0A_PULL 0x64
+#define RK3188_PMU_GPIO0B_PULL 0x68
+
+#define RK3288_PMU_WAKEUP_CFG0 0x00
+#define RK3288_PMU_WAKEUP_CFG1 0x04
+#define RK3288_PMU_PWRDN_CON 0x08
+#define RK3288_PMU_PWRDN_ST 0x0c
+#define RK3288_PMU_IDLE_REQ 0x10
+#define RK3288_PMU_IDLE_ST 0x14
+#define RK3288_PMU_PWRMODE_CON 0x18
+#define RK3288_PMU_PWR_STATE 0x1c
+#define RK3288_PMU_OSC_CNT 0x20
+#define RK3288_PMU_PLL_CNT 0x24
+#define RK3288_PMU_STABL_CNT 0x28
+#define RK3288_PMU_DDR0IO_PWRON_CNT 0x2c
+#define RK3288_PMU_DDR1IO_PWRON_CNT 0x30
+#define RK3288_PMU_CORE_PWRDWN_CNT 0x34
+#define RK3288_PMU_CORE_PWRUP_CNT 0x38
+#define RK3288_PMU_GPU_PWRDWN_CNT 0x3c
+#define RK3288_PMU_GPU_PWRUP_CNT 0x40
+#define RK3288_PMU_WAKEUP_RST_CLR_CNT 0x44
+#define RK3288_PMU_SFT_CON 0x48
+#define RK3288_PMU_DDR_SREF_ST 0x4c
+#define RK3288_PMU_INT_CON 0x50
+#define RK3288_PMU_INT_ST 0x54
+#define RK3288_PMU_BOOT_ADDR_SEL 0x58
+#define RK3288_PMU_GRF_CON 0x5c
+#define RK3288_PMU_GPIO_SR 0x60
+#define RK3288_PMU_GPIO0_A_PULL 0x64
+#define RK3288_PMU_GPIO0_B_PULL 0x68
+#define RK3288_PMU_GPIO0_C_PULL 0x6c
+#define RK3288_PMU_GPIO0_A_DRV 0x70
+#define RK3288_PMU_GPIO0_B_DRV 0x74
+#define RK3288_PMU_GPIO0_C_DRV 0x78
+#define RK3288_PMU_GPIO_OP 0x7c
+#define RK3288_PMU_GPIO0_SEL18 0x80
+#define RK3288_PMU_GPIO0_A_IOMUX 0x84
+#define RK3288_PMU_GPIO0_B_IOMUX 0x88
+#define RK3288_PMU_GPIO0_C_IOMUX 0x8c
+#define RK3288_PMU_PWRMODE_CON1 0x90
+#define RK3288_PMU_SYS_REG0 0x94
+#define RK3288_PMU_SYS_REG1 0x98
+#define RK3288_PMU_SYS_REG2 0x9c
+#define RK3288_PMU_SYS_REG3 0xa0
+
+#define RK312X_PMU_WAKEUP_CFG 0x00
+#define RK312X_PMU_PWRDN_CON 0x04
+#define RK312X_PMU_PWRDN_ST 0x08
+#define RK312X_PMU_IDLE_REQ 0x0C
+#define RK312X_PMU_IDLE_ST 0x10
+#define RK312X_PMU_PWRMODE_CON 0x14
+#define RK312X_PMU_PWR_STATE 0x18
+#define RK312X_PMU_OSC_CNT 0x1C
+#define RK312X_PMU_CORE_PWRDWN_CNT 0x20
+#define RK312X_PMU_CORE_PWRUP_CNT 0x24
+#define RK312X_PMU_SFT_CON 0x28
+#define RK312X_PMU_DDR_SREF_ST 0x2C
+#define RK312X_PMU_INT_CON 0x30
+#define RK312X_PMU_INT_ST 0x34
+#define RK312X_PMU_SYS_REG0 0x38
+#define RK312X_PMU_SYS_REG1 0x3C
+#define RK312X_PMU_SYS_REG2 0x40
+#define RK312X_PMU_SYS_REG3 0x44
+
+#define RK3368_PMU_PWRDN_CON 0x0c
+#define RK3368_PMU_PWRDN_ST 0x10
+#define RK3368_PMU_IDLE_REQ 0x3c
+#define RK3368_PMU_IDLE_ST 0x40
+
+enum pmu_power_domain {
+ PD_BCPU,
+ PD_BDSP,
+ PD_BUS,
+ PD_CPU_0,
+ PD_CPU_1,
+ PD_CPU_2,
+ PD_CPU_3,
+ PD_CS,
+ PD_GPU,
+ PD_HEVC,
+ PD_PERI,
+ PD_SCU,
+ PD_VIDEO,
+ PD_VIO,
+ PD_GPU_0,
+ PD_GPU_1,
+};
+
+enum pmu_idle_req {
+ IDLE_REQ_ALIVE,
+ IDLE_REQ_AP2BP,
+ IDLE_REQ_BP2AP,
+ IDLE_REQ_BUS,
+ IDLE_REQ_CORE,
+ IDLE_REQ_CPUP,
+ IDLE_REQ_DMA,
+ IDLE_REQ_GPU,
+ IDLE_REQ_HEVC,
+ IDLE_REQ_PERI,
+ IDLE_REQ_VIDEO,
+ IDLE_REQ_VIO,
+ IDLE_REQ_SYS,
+ IDLE_REQ_MSCH,
+ IDLE_REQ_CRYPTO,
+};
+
+struct rockchip_pmu_operations {
+ int (*set_power_domain)(enum pmu_power_domain pd, bool on);
+ bool (*power_domain_is_on)(enum pmu_power_domain pd);
+ int (*set_idle_request)(enum pmu_idle_req req, bool idle);
+};
+
+int rockchip_pmu_set_idle_request(struct device *dev, bool idle);
+extern struct rockchip_pmu_operations rockchip_pmu_ops;
+
+#endif
diff --git a/include/linux/rockchip/psci.h b/include/linux/rockchip/psci.h
new file mode 100644
index 0000000..7a3eed6
--- /dev/null
+++ b/include/linux/rockchip/psci.h
@@ -0,0 +1,75 @@
+#ifndef __ROCKCHIP_PSCI_H
+#define __ROCKCHIP_PSCI_H
+
+#define SEC_REG_RD (0x0)
+#define SEC_REG_WR (0x1)
+
+/*
+ * trust firmware verison
+ */
+#define RKTF_VER_MAJOR(ver) (((ver) >> 16) & 0xffff)
+#define RKTF_VER_MINOR(ver) ((ver) & 0xffff)
+
+/*
+ * pcsi smc funciton id
+ */
+#define PSCI_SIP_RKTF_VER (0x82000001)
+#define PSCI_SIP_ACCESS_REG (0x82000002)
+#define PSCI_SIP_ACCESS_REG64 (0xc2000002)
+#define PSCI_SIP_SUSPEND_WR_CTRBITS (0x82000003)
+#define PSCI_SIP_PENDING_CPUS (0x82000004)
+#define PSCI_SIP_UARTDBG_CFG (0x82000005)
+#define PSCI_SIP_UARTDBG_CFG64 (0xc2000005)
+#define PSCI_SIP_EL3FIQ_CFG (0x82000006)
+#define PSCI_SIP_SMEM_CONFIG (0x82000007)
+
+/*
+ * pcsi smc funciton err code
+ */
+#define PSCI_SMC_FUNC_UNK 0xffffffff
+
+/*
+ * define PSCI_SIP_UARTDBG_CFG call type
+ */
+#define UARTDBG_CFG_INIT 0xf0
+#define UARTDBG_CFG_OSHDL_TO_OS 0xf1
+#define UARTDBG_CFG_OSHDL_CPUSW 0xf3
+#define UARTDBG_CFG_OSHDL_DEBUG_ENABLE 0xf4
+#define UARTDBG_CFG_OSHDL_DEBUG_DISABLE 0xf5
+
+/*
+ * rockchip psci function call interface
+ */
+
+u32 rockchip_psci_smc_read(u32 function_id, u32 arg0, u32 arg1, u32 arg2,
+ u32 *val);
+u32 rockchip_psci_smc_write(u32 function_id, u32 arg0, u32 arg1, u32 arg2);
+
+u32 rockchip_psci_smc_get_tf_ver(void);
+u32 rockchip_secure_reg_read(u32 addr_phy);
+u32 rockchip_secure_reg_write(u32 addr_phy, u32 val);
+
+#ifdef CONFIG_ARM64
+u32 rockchip_psci_smc_write64(u64 function_id, u64 arg0, u64 arg1, u64 arg2);
+u32 rockchip_psci_smc_read64(u64 function_id, u64 arg0, u64 arg1, u64 arg2,
+ u64 *val);
+u64 rockchip_secure_reg_read64(u64 addr_phy);
+u32 rockchip_secure_reg_write64(u64 addr_phy, u64 val);
+
+void psci_fiq_debugger_uart_irq_tf_cb(u64 sp_el1, u64 offset);
+#endif
+
+u32 psci_fiq_debugger_switch_cpu(u32 cpu);
+void psci_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback);
+void psci_fiq_debugger_enable_debug(bool val);
+
+#if defined(CONFIG_ARM_PSCI) || defined(CONFIG_ARM64)
+u32 psci_set_memory_secure(bool val);
+#else
+static inline u32 psci_set_memory_secure(bool val)
+{
+ return 0;
+}
+#endif
+
+#endif /* __ROCKCHIP_PSCI_H */
diff --git a/include/linux/rockchip/rockchip_sip.h b/include/linux/rockchip/rockchip_sip.h
new file mode 100644
index 0000000..3b853d8
--- /dev/null
+++ b/include/linux/rockchip/rockchip_sip.h
@@ -0,0 +1,223 @@
+/* Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ROCKCHIP_SIP_H
+#define __ROCKCHIP_SIP_H
+
+#include <linux/arm-smccc.h>
+#include <linux/io.h>
+
+/* SMC function IDs for SiP Service queries, compatible with kernel-3.10 */
+#define SIP_ATF_VERSION 0x82000001
+#define SIP_ACCESS_REG 0x82000002
+#define SIP_SUSPEND_MODE 0x82000003
+#define SIP_PENDING_CPUS 0x82000004
+#define SIP_UARTDBG_CFG 0x82000005
+#define SIP_UARTDBG_CFG64 0xc2000005
+#define SIP_MCU_EL3FIQ_CFG 0x82000006
+#define SIP_ACCESS_CHIP_STATE64 0xc2000006
+#define SIP_SECURE_MEM_CONFIG 0x82000007
+#define SIP_ACCESS_CHIP_EXTRA_STATE64 0xc2000007
+#define SIP_DRAM_CONFIG 0x82000008
+#define SIP_SHARE_MEM 0x82000009
+#define SIP_SIP_VERSION 0x8200000a
+#define SIP_REMOTECTL_CFG 0x8200000b
+
+/* Rockchip Sip version */
+#define SIP_IMPLEMENT_V1 (1)
+#define SIP_IMPLEMENT_V2 (2)
+
+/* Trust firmware version */
+#define ATF_VER_MAJOR(ver) (((ver) >> 16) & 0xffff)
+#define ATF_VER_MINOR(ver) (((ver) >> 0) & 0xffff)
+
+/* SIP_ACCESS_REG: read or write */
+#define SECURE_REG_RD 0x0
+#define SECURE_REG_WR 0x1
+
+/* Fiq debugger share memory: 8KB enough */
+#define FIQ_UARTDBG_PAGE_NUMS 2
+#define FIQ_UARTDBG_SHARE_MEM_SIZE ((FIQ_UARTDBG_PAGE_NUMS) * 4096)
+
+/* Error return code */
+#define IS_SIP_ERROR(x) (!!(x))
+
+#define SIP_RET_SUCCESS 0
+#define SIP_RET_SMC_UNKNOWN -1
+#define SIP_RET_NOT_SUPPORTED -2
+#define SIP_RET_INVALID_PARAMS -3
+#define SIP_RET_INVALID_ADDRESS -4
+#define SIP_RET_DENIED -5
+
+/* SIP_UARTDBG_CFG64 call types */
+#define UARTDBG_CFG_INIT 0xf0
+#define UARTDBG_CFG_OSHDL_TO_OS 0xf1
+#define UARTDBG_CFG_OSHDL_CPUSW 0xf3
+#define UARTDBG_CFG_OSHDL_DEBUG_ENABLE 0xf4
+#define UARTDBG_CFG_OSHDL_DEBUG_DISABLE 0xf5
+#define UARTDBG_CFG_PRINT_PORT 0xf7
+#define UARTDBG_CFG_FIQ_ENABEL 0xf8
+#define UARTDBG_CFG_FIQ_DISABEL 0xf9
+
+/* SIP_SUSPEND_MODE32 call types */
+#define SUSPEND_MODE_CONFIG 0x01
+#define WKUP_SOURCE_CONFIG 0x02
+#define PWM_REGULATOR_CONFIG 0x03
+#define GPIO_POWER_CONFIG 0x04
+#define SUSPEND_DEBUG_ENABLE 0x05
+#define APIOS_SUSPEND_CONFIG 0x06
+#define VIRTUAL_POWEROFF 0x07
+
+/* SIP_REMOTECTL_CFG call types */
+#define REMOTECTL_SET_IRQ 0xf0
+#define REMOTECTL_SET_PWM_CH 0xf1
+#define REMOTECTL_SET_PWRKEY 0xf2
+#define REMOTECTL_GET_WAKEUP_STATE 0xf3
+#define REMOTECTL_ENABLE 0xf4
+/* wakeup state */
+#define REMOTECTL_PWRKEY_WAKEUP 0xdeadbeaf
+
+/* Share mem page types */
+typedef enum {
+ SHARE_PAGE_TYPE_INVALID = 0,
+ SHARE_PAGE_TYPE_UARTDBG,
+ SHARE_PAGE_TYPE_DDR,
+ SHARE_PAGE_TYPE_MAX,
+} share_page_type_t;
+
+/*
+ * Rules: struct arm_smccc_res contains result and data, details:
+ *
+ * a0: error code(0: success, !0: error);
+ * a1~a3: data
+ */
+#ifdef CONFIG_ROCKCHIP_SIP
+struct arm_smccc_res sip_smc_get_atf_version(void);
+struct arm_smccc_res sip_smc_get_sip_version(void);
+struct arm_smccc_res sip_smc_dram(u32 arg0, u32 arg1, u32 arg2);
+struct arm_smccc_res sip_smc_request_share_mem(u32 page_num,
+ share_page_type_t page_type);
+struct arm_smccc_res sip_smc_mcu_el3fiq(u32 arg0, u32 arg1, u32 arg2);
+
+int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2);
+int sip_smc_virtual_poweroff(void);
+
+int sip_smc_secure_reg_write(u32 addr_phy, u32 val);
+u32 sip_smc_secure_reg_read(u32 addr_phy);
+
+/***************************fiq debugger **************************************/
+void sip_fiq_debugger_enable_fiq(bool enable, uint32_t tgt_cpu);
+void sip_fiq_debugger_enable_debug(bool enable);
+int sip_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback_fn);
+int sip_fiq_debugger_set_print_port(u32 port_phyaddr, u32 baudrate);
+int sip_fiq_debugger_request_share_memory(void);
+int sip_fiq_debugger_get_target_cpu(void);
+int sip_fiq_debugger_switch_cpu(u32 cpu);
+int sip_fiq_debugger_is_enabled(void);
+#else
+static inline struct arm_smccc_res sip_smc_get_atf_version(void)
+{
+ struct arm_smccc_res tmp = {0};
+ return tmp;
+}
+
+static inline struct arm_smccc_res sip_smc_get_sip_version(void)
+{
+ struct arm_smccc_res tmp = {0};
+ return tmp;
+}
+
+static inline struct arm_smccc_res sip_smc_dram(u32 arg0, u32 arg1, u32 arg2)
+{
+ struct arm_smccc_res tmp = {0};
+ return tmp;
+}
+
+static inline struct arm_smccc_res sip_smc_request_share_mem
+ (u32 page_num, share_page_type_t page_type)
+{
+ struct arm_smccc_res tmp = {0};
+ return tmp;
+}
+
+static inline struct arm_smccc_res sip_smc_mcu_el3fiq
+ (u32 arg0, u32 arg1, u32 arg2)
+{
+ struct arm_smccc_res tmp = {0};
+ return tmp;
+}
+
+static inline int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2)
+{
+ return 0;
+}
+
+static inline int sip_smc_virtual_poweroff(void) { return 0; }
+static inline u32 sip_smc_secure_reg_read(u32 addr_phy) { return 0; }
+static inline int sip_smc_secure_reg_write(u32 addr_phy, u32 val) { return 0; }
+
+/***************************fiq debugger **************************************/
+static inline void sip_fiq_debugger_enable_fiq
+ (bool enable, uint32_t tgt_cpu) { return; }
+
+static inline void sip_fiq_debugger_enable_debug(bool enable) { return; }
+static inline int sip_fiq_debugger_uart_irq_tf_init(u32 irq_id,
+ void *callback_fn)
+{
+ return 0;
+}
+
+static inline int sip_fiq_debugger_set_print_port(u32 port_phyaddr,
+ u32 baudrate)
+{
+ return 0;
+}
+
+static inline int sip_fiq_debugger_request_share_memory(void) { return 0; }
+static inline int sip_fiq_debugger_get_target_cpu(void) { return 0; }
+static inline int sip_fiq_debugger_switch_cpu(u32 cpu) { return 0; }
+static inline int sip_fiq_debugger_is_enabled(void) { return 0; }
+#endif
+
+/* optee cpu_context */
+struct sm_nsec_ctx {
+ u32 usr_sp;
+ u32 usr_lr;
+ u32 irq_spsr;
+ u32 irq_sp;
+ u32 irq_lr;
+ u32 svc_spsr;
+ u32 svc_sp;
+ u32 svc_lr;
+ u32 abt_spsr;
+ u32 abt_sp;
+ u32 abt_lr;
+ u32 und_spsr;
+ u32 und_sp;
+ u32 und_lr;
+ u32 mon_lr;
+ u32 mon_spsr;
+ u32 r4;
+ u32 r5;
+ u32 r6;
+ u32 r7;
+ u32 r8;
+ u32 r9;
+ u32 r10;
+ u32 r11;
+ u32 r12;
+ u32 r0;
+ u32 r1;
+ u32 r2;
+ u32 r3;
+};
+
+#endif