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