From 2574313c2e3f2cfaba142ba84a65480a10fc2a10 Mon Sep 17 00:00:00 2001 From: Tonymac32 Date: Sun, 30 Jul 2017 14:36:04 -0400 Subject: [PATCH] Rockchip DEV VPU driver --- .../rockchip-dev/8000_VPU_driver_load.patch | 36 + .../rockchip-dev/8001_rk_vcodec_driver.patch | 9483 +++++++++++++++++ 2 files changed, 9519 insertions(+) create mode 100644 patch/kernel/rockchip-dev/8000_VPU_driver_load.patch create mode 100644 patch/kernel/rockchip-dev/8001_rk_vcodec_driver.patch diff --git a/patch/kernel/rockchip-dev/8000_VPU_driver_load.patch b/patch/kernel/rockchip-dev/8000_VPU_driver_load.patch new file mode 100644 index 0000000000..9c8e19e98e --- /dev/null +++ b/patch/kernel/rockchip-dev/8000_VPU_driver_load.patch @@ -0,0 +1,36 @@ +From 3a4f9e972d9723594d020b2785e3ec3ac148d02e Mon Sep 17 00:00:00 2001 +From: Myy +Date: Tue, 17 Jan 2017 19:55:25 +0000 +Subject: [PATCH 12/12] Export rockchip_pmu_set_idle_request for out-of-tree + VPU code + +In order to compile the Rockchip VPU modules "out-of-tree", it is +necessary to export rockchip_pmu_set_idle_request. + +I do not know why the "out-of-tree" VPU code needs it, though. There +might be way to avoid calling this function, and avoid exporting this +function. + +Or, in reverse, it might be extremely useful for external modules to +be able to use the Rockchip Power Management interface directly and, +therefore, export all the functions in rockchip/pw_domains.c + +Signed-off-by: Myy +--- + drivers/soc/rockchip/pm_domains.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c +index 796c46a..63a186b 100644 +--- a/drivers/soc/rockchip/pm_domains.c ++++ b/drivers/soc/rockchip/pm_domains.c +@@ -178,6 +178,7 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, + + return 0; + } ++EXPORT_SYMBOL(rockchip_pmu_set_idle_request); + + static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) + { +-- +2.10.2 diff --git a/patch/kernel/rockchip-dev/8001_rk_vcodec_driver.patch b/patch/kernel/rockchip-dev/8001_rk_vcodec_driver.patch new file mode 100644 index 0000000000..efb116c129 --- /dev/null +++ b/patch/kernel/rockchip-dev/8001_rk_vcodec_driver.patch @@ -0,0 +1,9483 @@ +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 ++#include ++#include ++#include ++#include ++#if 0 ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if 0 ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ ++#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 ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_WAKELOCK ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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, ®->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, ®->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 = ®->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 *)®[1]; ++ INIT_LIST_HEAD(®->session_link); ++ INIT_LIST_HEAD(®->status_link); ++ ++ INIT_LIST_HEAD(®->mem_region_list); ++ ++ if (copy_from_user(®->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(®->status_link, &pservice->waiting); ++ list_add_tail(®->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(®->session_link); ++ list_del_init(®->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, ++ ®->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(®->status_link); ++ list_add_tail(®->status_link, &pservice->running); ++ ++ list_del_init(®->session_link); ++ list_add_tail(®->session_link, ®->session->running); ++ vpu_debug_leave(); ++} ++ ++static void reg_copy_from_hw(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[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(®->status_link); ++ list_add_tail(®->status_link, &pservice->done); ++ ++ list_del_init(®->session_link); ++ list_add_tail(®->session_link, ®->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, ®->session->task_running); ++ atomic_sub(1, &pservice->total_running); ++ wake_up(®->session->wait); ++ ++ vpu_debug_leave(); ++} ++ ++static void vpu_service_set_freq(struct vpu_service_info *pservice, ++ 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[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, ®->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, ®->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[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(®->mem_region_list)) { ++ list_for_each_entry_safe(mem, n, ®->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 /* 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 ++#include ++#include ++ ++#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 ++ ++#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 ++#include ++#include ++ ++ ++/*******************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<> 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 ++#include ++ ++#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 ++#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 ++#include ++ ++/* 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