├── concept_documents ├── rk3288-chapter-26-hevc.pdf └── rk3288-chapter-25-video-encoder-decoder-unit-(vcodec).pdf ├── Kconfig ├── .gitignore ├── README.md ├── vcodec_iommu_dma.h ├── vcodec_service.h ├── Makefile ├── include └── video │ └── rk_vpu_service.h ├── vcodec_hw_info.h ├── vcodec_hw_rkv.h ├── vcodec_hw_vpu2.h ├── vcodec_iommu_dma.c ├── vcodec_hw_vpu.h └── vcodec_service.c /concept_documents/rk3288-chapter-26-hevc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miouyouyou/rockchip-vcodec/HEAD/concept_documents/rk3288-chapter-26-hevc.pdf -------------------------------------------------------------------------------- /Kconfig: -------------------------------------------------------------------------------- 1 | menu "VCODEC" 2 | depends on ARCH_ROCKCHIP 3 | 4 | config RK_VCODEC 5 | tristate "VCODEC (VPU HEVC) service driver in kernel" 6 | depends on ARCH_ROCKCHIP 7 | default n 8 | 9 | endmenu 10 | -------------------------------------------------------------------------------- /concept_documents/rk3288-chapter-25-video-encoder-decoder-unit-(vcodec).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miouyouyou/rockchip-vcodec/HEAD/concept_documents/rk3288-chapter-25-video-encoder-decoder-unit-(vcodec).pdf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.o 3 | *.ko 4 | *.mod.c 5 | *.install 6 | *.cmd 7 | Module.symvers 8 | *~ 9 | *# 10 | \#* 11 | .*~ 12 | .\#* 13 | .*# 14 | *.kate-swp 15 | .tmp_versions 16 | modules.order 17 | .cproject 18 | .kdev4 19 | .project 20 | .settings 21 | *.kdev4 22 | kernel/ 23 | linux/ 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OUTDATED 2 | 3 | This project is outdated. 4 | Use the latest 5.8 kernels and enable **rkvdec** (`VIDEO_ROCKCHIP_VDEC`) in the staging drivers, for good support on RK3399 boards. 5 | You can also try Kwiboo's kernel branch here : https://github.com/Kwiboo/linux-rockchip 6 | 7 | For FFMPEG support, try this branch : https://github.com/Kwiboo/FFmpeg/commits/v4l2-request-hwaccel-4.2.2 8 | -------------------------------------------------------------------------------- /vcodec_iommu_dma.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 - 2017 Fuzhou Rockchip Electronics Co., Ltd 3 | * Randy Li, 4 | * 5 | * This software is licensed under the terms of the GNU General Public 6 | * License version 2, as published by the Free Software Foundation, and 7 | * may be copied, distributed, and modified under those terms. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | */ 15 | 16 | #ifndef __VCODEC_IOMMU_DMA_H__ 17 | #define __VCODEC_IOMMU_DMA_H__ 18 | 19 | #include 20 | 21 | struct vcodec_iommu_info; 22 | struct vcodec_dma_session; 23 | 24 | struct vcodec_dma_session *vcodec_dma_session_create(struct device *dev); 25 | void vcodec_dma_destroy_session(struct vcodec_dma_session *session); 26 | 27 | dma_addr_t vcodec_dma_import_fd(struct vcodec_dma_session *session, int fd); 28 | int vcodec_dma_release_fd(struct vcodec_dma_session *session, int fd); 29 | 30 | struct vcodec_iommu_info *vcodec_iommu_probe(struct device *dev); 31 | int vcodec_iommu_remove(struct vcodec_iommu_info *info); 32 | 33 | int vcodec_iommu_attach(struct vcodec_iommu_info *info); 34 | void vcodec_iommu_detach(struct vcodec_iommu_info *info); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /vcodec_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd 3 | * author: chenhengming chm@rock-chips.com 4 | * Alpha Lin, alpha.lin@rock-chips.com 5 | * 6 | * This software is licensed under the terms of the GNU General Public 7 | * License version 2, as published by the Free Software Foundation, and 8 | * may be copied, distributed, and modified under those terms. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | #ifndef __ROCKCHIP_VCODEC_SERVICE_H__ 18 | #define __ROCKCHIP_VCODEC_SERVICE_H__ 19 | 20 | enum VPU_DEC_FMT { 21 | VPU_DEC_FMT_H264, 22 | VPU_DEC_FMT_MPEG4, 23 | VPU_DEC_FMT_H263, 24 | VPU_DEC_FMT_JPEG, 25 | VPU_DEC_FMT_VC1, 26 | VPU_DEC_FMT_MPEG2, 27 | VPU_DEC_FMT_MPEG1, 28 | VPU_DEC_FMT_VP6, 29 | VPU_DEC_FMT_RESERV0, 30 | VPU_DEC_FMT_VP7, 31 | VPU_DEC_FMT_VP8, 32 | VPU_DEC_FMT_AVS, 33 | VPU_DEC_FMT_RES 34 | }; 35 | 36 | enum vcodec_device_id { 37 | VCODEC_DEVICE_ID_VPU, 38 | VCODEC_DEVICE_ID_HEVC, 39 | VCODEC_DEVICE_ID_COMBO, 40 | VCODEC_DEVICE_ID_RKVDEC, 41 | VCODEC_DEVICE_ID_BUTT 42 | }; 43 | 44 | enum VPU_CLIENT_TYPE { 45 | VPU_ENC = 0x0, 46 | VPU_DEC = 0x1, 47 | VPU_PP = 0x2, 48 | VPU_DEC_PP = 0x3, 49 | VPU_TYPE_BUTT, 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Set this variable with the path to your kernel. 2 | # Don't use /usr/src/linux if you're cross-compiling... 3 | MYY_KERNEL_DIR ?= ../RockMyy/linux 4 | 5 | # If you're compiling for ARM64, this will be arm64 6 | ARCH ?= arm 7 | 8 | # This is the prefix attached to your cross-compiling gcc/ld/... tools 9 | # In my case, gcc is armv7a-hardfloat-linux-gnueabi-gcc 10 | # If you've installed cross-compiling tools and don't know your 11 | # prefix, just type "arm" in a shell, hit twice 12 | # 13 | # If you're compiling from ARM system with the same architecture 14 | # (arm on arm or arm64 on arm64) delete the characters after "?=" 15 | CROSS_COMPILE ?= arm-linux-gnueabihf- 16 | 17 | # The modules will be installed in $(INSTALL_MOD_PATH)/lib/... 18 | # That might not be needed at all, if you're replacing the "install" 19 | # command, see below. 20 | INSTALL_MOD_PATH ?= /tmp/RockMyy-Build 21 | INSTALL_PATH ?= $(INSTALL_MOD_PATH)/boot 22 | INSTALL_HDR_PATH ?= $(INSTALL_MOD_PATH)/usr 23 | 24 | # Determine the CFLAGS specific to this compilation unit. 25 | ccflags-y += -I${src}/include -DCONFIG_DRM=1 26 | 27 | # Determine what's needed to compile rk-vcodec.o 28 | # Every '.o' file corresponds to a '.c' file 29 | rk-vcodec-objs := vcodec_service.o vcodec_iommu_dma.o 30 | 31 | # Replace m by y if you want to integrate it or 32 | # replace it by a configuration option that should be enabled when 33 | # configuring the kernel like obj-$(CONFIG_CRASHY_THE_VPU) 34 | obj-m += rk-vcodec.o 35 | 36 | all: 37 | make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) -C $(MYY_KERNEL_DIR) modules 38 | 39 | clean: 40 | make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) -C $(MYY_KERNEL_DIR) clean 41 | 42 | # This does a normal installation... 43 | # You could replace this by a scp command that sends the module to 44 | # your ARM system. 45 | install: 46 | # make INSTALL_MOD_PATH=$(INSTALL_MOD_PATH) INSTALL_PATH=$(INSTALL_PATH) INSTALL_HDR_PATH=$(INSTALL_HDR_PATH) M=$(PWD) -C $(MYY_KERNEL_DIR) modules_install 47 | scp *.ko 10.100.0.55:/tmp 48 | -------------------------------------------------------------------------------- /include/video/rk_vpu_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd 3 | * 4 | * This software is licensed under the terms of the GNU General Public 5 | * License version 2, as published by the Free Software Foundation, and 6 | * may be copied, distributed, and modified under those terms. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | */ 14 | 15 | #ifndef __UAPI_LINUX_RK_VPU_SERVICE_H__ 16 | #define __UAPI_LINUX_RK_VPU_SERVICE_H__ 17 | 18 | #include 19 | #include 20 | 21 | /* 22 | * Ioctl definitions 23 | */ 24 | 25 | /* Use 'l' as magic number */ 26 | #define VPU_IOC_MAGIC 'l' 27 | 28 | #define VPU_IOC_SET_CLIENT_TYPE _IOW(VPU_IOC_MAGIC, 1, __u32) 29 | #define VPU_IOC_GET_HW_FUSE_STATUS _IOW(VPU_IOC_MAGIC, 2, unsigned long) 30 | 31 | #define VPU_IOC_SET_REG _IOW(VPU_IOC_MAGIC, 3, unsigned long) 32 | #define VPU_IOC_GET_REG _IOW(VPU_IOC_MAGIC, 4, unsigned long) 33 | 34 | #define VPU_IOC_PROBE_IOMMU_STATUS _IOR(VPU_IOC_MAGIC, 5, __u32) 35 | 36 | struct vpu_request { 37 | __u32 *req; 38 | __u32 size; 39 | }; 40 | 41 | /* Hardware decoder configuration description */ 42 | struct vpu_dec_config { 43 | /* Maximum video decoding width supported */ 44 | __u32 max_dec_pic_width; 45 | /* Maximum output width of Post-Processor */ 46 | __u32 max_pp_out_pic_width; 47 | /* HW supports h.264 */ 48 | __u32 h264_support; 49 | /* HW supports JPEG */ 50 | __u32 jpeg_support; 51 | /* HW supports MPEG-4 */ 52 | __u32 mpeg4_support; 53 | /* HW supports custom MPEG-4 features */ 54 | __u32 custom_mpeg4_support; 55 | /* HW supports VC-1 Simple */ 56 | __u32 vc1_support; 57 | /* HW supports MPEG-2 */ 58 | __u32 mpeg2_support; 59 | /* HW supports post-processor */ 60 | __u32 pp_support; 61 | /* HW post-processor functions bitmask */ 62 | __u32 pp_config; 63 | /* HW supports Sorenson Spark */ 64 | __u32 sorenson_support; 65 | /* HW supports reference picture buffering */ 66 | __u32 ref_buf_support; 67 | /* HW supports VP6 */ 68 | __u32 vp6_support; 69 | /* HW supports VP7 */ 70 | __u32 vp7_support; 71 | /* HW supports VP8 */ 72 | __u32 vp8_support; 73 | /* HW supports AVS */ 74 | __u32 avs_support; 75 | /* HW supports JPEG extensions */ 76 | __u32 jpeg_ext_support; 77 | __u32 reserve; 78 | /* HW supports H264 MVC extension */ 79 | __u32 mvc_support; 80 | }; 81 | 82 | /* Hardware encoder configuration description */ 83 | struct vpu_enc_config { 84 | /* Maximum supported width for video encoding (not JPEG) */ 85 | __u32 max_encoded_width; 86 | /* HW supports H.264 */ 87 | __u32 h264_enabled; 88 | /* HW supports JPEG */ 89 | __u32 jpeg_enabled; 90 | /* HW supports MPEG-4 */ 91 | __u32 mpeg4_enabled; 92 | /* HW supports video stabilization */ 93 | __u32 vs_enabled; 94 | /* HW supports RGB input */ 95 | __u32 rgb_enabled; 96 | __u32 reg_size; 97 | __u32 reserv[2]; 98 | }; 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /vcodec_hw_info.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd 3 | * author: Herman Chen herman.chen@rock-chips.com 4 | * Alpha Lin, alpha.lin@rock-chips.com 5 | * 6 | * This software is licensed under the terms of the GNU General Public 7 | * License version 2, as published by the Free Software Foundation, and 8 | * may be copied, distributed, and modified under those terms. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | #ifndef __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_INFO_H 18 | #define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_INFO_H 19 | 20 | /* 21 | * Hardware id is for hardware detection 22 | * Driver will read the hardware ID register first, then try to find a mactch 23 | * hardware from the enum ID below. 24 | */ 25 | enum VPU_HW_ID { 26 | VPU_DEC_ID_9190 = 0x6731, 27 | VPU_ID_8270 = 0x8270, 28 | VPU_ID_4831 = 0x4831, 29 | HEVC_ID = 0x6867, 30 | RKV_DEC_ID = 0x6876, 31 | RKV_DEC_ID2 = 0x3410, 32 | VPU2_ID = 0x0000, 33 | }; 34 | 35 | /* 36 | * Different hardware has different feature. So we catalogue these features 37 | * into three class: 38 | * 39 | * 1. register io feature determined by hardware type 40 | * including register offset, register file size, etc 41 | * 42 | * 2. runtime register config feature determined by task type 43 | * including irq / enable / length register, bit mask, etc 44 | * 45 | * 3. file handle translate feature determined by vcodec format type 46 | * register translation map table 47 | * 48 | * These three type features composite a complete codec information structure 49 | */ 50 | 51 | /* VPU1 and VPU2 */ 52 | #define VCODEC_DEVICE_TYPE_VPUX 0x56505558 53 | /* VPU Combo */ 54 | #define VCODEC_DEVICE_TYPE_VPUC 0x56505543 55 | #define VCODEC_DEVICE_TYPE_HEVC 0x56505532 56 | #define VCODEC_DEVICE_TYPE_RKVD 0x524B5644 57 | 58 | enum TASK_TYPE { 59 | TASK_ENC, 60 | TASK_DEC, 61 | TASK_PP, 62 | TASK_DEC_PP, 63 | TASK_TYPE_BUTT, 64 | }; 65 | 66 | enum FORMAT_TYPE { 67 | FMT_DEC_BASE = 0, 68 | FMT_JPEGD = FMT_DEC_BASE, 69 | 70 | FMT_H263D, 71 | FMT_H264D, 72 | FMT_H265D, 73 | 74 | FMT_MPEG1D, 75 | FMT_MPEG2D, 76 | FMT_MPEG4D, 77 | 78 | FMT_VP6D, 79 | FMT_VP7D, 80 | FMT_VP8D, 81 | FMT_VP9D, 82 | 83 | FMT_VC1D, 84 | FMT_AVSD, 85 | 86 | FMT_DEC_BUTT, 87 | 88 | FMT_PP_BASE = FMT_DEC_BUTT, 89 | FMT_PP = FMT_PP_BASE, 90 | FMT_PP_BUTT, 91 | 92 | FMT_ENC_BASE = FMT_PP_BUTT, 93 | FMT_JPEGE = FMT_ENC_BASE, 94 | 95 | FMT_H264E, 96 | 97 | FMT_VP8E, 98 | 99 | FMT_ENC_BUTT, 100 | FMT_TYPE_BUTT = FMT_ENC_BUTT, 101 | }; 102 | 103 | /** 104 | * struct for hardware task operation 105 | */ 106 | struct vpu_hw_info { 107 | enum VPU_HW_ID hw_id; 108 | u32 enc_offset; 109 | u32 enc_reg_num; 110 | u32 enc_io_size; 111 | 112 | u32 dec_offset; 113 | u32 dec_reg_num; 114 | u32 dec_io_size; 115 | 116 | /* 117 | * register range for enc/dec/pp/dec_pp 118 | * base/end of dec/pp/dec_pp specify the register range to config 119 | */ 120 | u32 base_dec; 121 | u32 base_pp; 122 | u32 base_dec_pp; 123 | u32 end_dec; 124 | u32 end_pp; 125 | u32 end_dec_pp; 126 | }; 127 | 128 | struct vpu_task_info { 129 | char *name; 130 | struct timeval start; 131 | struct timeval end; 132 | 133 | /* 134 | * input stream register 135 | * use for map/unmap drm buffer for avoiding 136 | * cache sync issue 137 | */ 138 | int reg_rlc; 139 | /* 140 | * task enable register 141 | * use for enable hardware task process 142 | * -1 for invalid 143 | */ 144 | int reg_en; 145 | 146 | /* register of task auto gating, alway valid */ 147 | int reg_gating; 148 | 149 | /* register of task irq, alway valid */ 150 | int reg_irq; 151 | 152 | /* 153 | * stream length register 154 | * only valid for decoder task 155 | * -1 for invalid (encoder) 156 | */ 157 | int reg_len; 158 | 159 | /* 160 | * direct mv register 161 | * special offset scale, offset multiply by 16 162 | * 163 | * valid on vpu & vpu2 164 | * -1 for invalid 165 | */ 166 | int reg_dir_mv; 167 | 168 | /* 169 | * pps register 170 | * special register for scaling list address process 171 | * 172 | * valid on rkv 173 | * -1 for invalid 174 | */ 175 | int reg_pps; 176 | 177 | /* 178 | * decoder pipeline mode register 179 | * 180 | * valid on vpu & vpu2 181 | * -1 for invalid 182 | */ 183 | int reg_pipe; 184 | 185 | /* task enable bit mask for enable register */ 186 | u32 enable_mask; 187 | 188 | /* task auto gating mask for enable register */ 189 | u32 gating_mask; 190 | 191 | /* task pipeline mode mask for pipe register */ 192 | u32 pipe_mask; 193 | 194 | /* task inturrpt bit mask for irq register */ 195 | u32 irq_mask; 196 | 197 | /* task ready bit mask for irq register */ 198 | u32 ready_mask; 199 | 200 | /* task error bit mask for irq register */ 201 | u32 error_mask; 202 | 203 | enum FORMAT_TYPE (*get_fmt)(u32 *regs); 204 | }; 205 | 206 | struct vpu_trans_info { 207 | const int count; 208 | const char * const table; 209 | }; 210 | 211 | struct vcodec_info { 212 | enum VPU_HW_ID hw_id; 213 | struct vpu_hw_info *hw_info; 214 | struct vpu_task_info *task_info; 215 | const struct vpu_trans_info *trans_info; 216 | }; 217 | 218 | struct vcodec_device_info { 219 | int32_t device_type; 220 | int8_t *name; 221 | }; 222 | 223 | #define DEF_FMT_TRANS_TBL(fmt, args...) \ 224 | static const char trans_tbl_##fmt[] = { \ 225 | args \ 226 | } 227 | 228 | #define SETUP_FMT_TBL(id, fmt) \ 229 | [id] = { \ 230 | .count = sizeof(trans_tbl_##fmt), \ 231 | .table = trans_tbl_##fmt, \ 232 | } 233 | 234 | #define EMPTY_FMT_TBL(id) \ 235 | [id] = { \ 236 | .count = 0, \ 237 | .table = NULL, \ 238 | } 239 | 240 | #endif 241 | -------------------------------------------------------------------------------- /vcodec_hw_rkv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd 3 | * author: chenhengming chm@rock-chips.com 4 | * Alpha Lin, alpha.lin@rock-chips.com 5 | * 6 | * This software is licensed under the terms of the GNU General Public 7 | * License version 2, as published by the Free Software Foundation, and 8 | * may be copied, distributed, and modified under those terms. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | #ifndef __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_RKV_H 18 | #define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_RKV_H 19 | 20 | #include "vcodec_hw_info.h" 21 | 22 | /* hardware information */ 23 | #define REG_NUM_HEVC_DEC (68) 24 | #define REG_NUM_RKV_DEC (78) 25 | 26 | /* enable and gating register */ 27 | #define RKV_REG_EN_DEC 1 28 | #define RKV_REG_DEC_GATING_BIT BIT(1) 29 | 30 | /* interrupt and error status register */ 31 | #define HEVC_INTERRUPT_REGISTER 1 32 | #define HEVC_INTERRUPT_BIT BIT(8) 33 | #define HEVC_DEC_INT_RAW_BIT BIT(9) 34 | #define HEVC_READY_BIT BIT(12) 35 | #define HEVC_DEC_BUS_ERROR_BIT BIT(13) 36 | #define HEVC_DEC_STR_ERROR_BIT BIT(14) 37 | #define HEVC_DEC_TIMEOUT_BIT BIT(15) 38 | #define HEVC_DEC_BUFFER_EMPTY_BIT BIT(16) 39 | #define HEVC_DEC_COLMV_ERROR_BIT BIT(17) 40 | #define HEVC_DEC_ERR_MASK (HEVC_DEC_BUS_ERROR_BIT \ 41 | |HEVC_DEC_STR_ERROR_BIT \ 42 | |HEVC_DEC_TIMEOUT_BIT \ 43 | |HEVC_DEC_BUFFER_EMPTY_BIT \ 44 | |HEVC_DEC_COLMV_ERROR_BIT) 45 | 46 | #define RKV_DEC_INTERRUPT_REGISTER 1 47 | #define RKV_DEC_INTERRUPT_BIT BIT(8) 48 | #define RKV_DEC_INT_RAW_BIT BIT(9) 49 | #define RKV_DEC_READY_BIT BIT(12) 50 | #define RKV_DEC_BUS_ERROR_BIT BIT(13) 51 | #define RKV_DEC_STR_ERROR_BIT BIT(14) 52 | #define RKV_DEC_TIMEOUT_BIT BIT(15) 53 | #define RKV_DEC_BUFFER_EMPTY_BIT BIT(16) 54 | #define RKV_DEC_COLMV_ERROR_BIT BIT(17) 55 | #define RKV_DEC_ERR_MASK (RKV_DEC_BUS_ERROR_BIT \ 56 | |RKV_DEC_STR_ERROR_BIT \ 57 | |RKV_DEC_TIMEOUT_BIT \ 58 | |RKV_DEC_BUFFER_EMPTY_BIT \ 59 | |RKV_DEC_COLMV_ERROR_BIT) 60 | 61 | static const enum FORMAT_TYPE rkv_dec_fmt_tbl[] = { 62 | [0] = FMT_H265D, 63 | [1] = FMT_H264D, 64 | [2] = FMT_VP9D, 65 | [3] = FMT_TYPE_BUTT, 66 | }; 67 | 68 | static enum FORMAT_TYPE rkv_dec_get_fmt(u32 *regs) 69 | { 70 | u32 fmt_id = (regs[2] >> 20) & 0x3; 71 | enum FORMAT_TYPE type = rkv_dec_fmt_tbl[fmt_id]; 72 | return type; 73 | } 74 | 75 | static struct vpu_task_info task_rkv[TASK_TYPE_BUTT] = { 76 | { 77 | .name = "invalid", 78 | .reg_en = 0, 79 | .reg_irq = 0, 80 | .reg_len = 0, 81 | .reg_dir_mv = 0, 82 | .reg_pps = -1, 83 | .reg_pipe = 0, 84 | .enable_mask = 0, 85 | .gating_mask = 0, 86 | .pipe_mask = 0, 87 | .irq_mask = 0, 88 | .ready_mask = 0, 89 | .error_mask = 0, 90 | .get_fmt = NULL, 91 | }, 92 | { 93 | .name = "rkvdec", 94 | .reg_rlc = 4, 95 | .reg_en = RKV_REG_EN_DEC, 96 | .reg_irq = RKV_DEC_INTERRUPT_REGISTER, 97 | .reg_len = 4, 98 | .reg_dir_mv = 52, 99 | .reg_pps = 42, 100 | .reg_pipe = 0, 101 | .enable_mask = 0, 102 | .gating_mask = RKV_REG_DEC_GATING_BIT, 103 | .irq_mask = HEVC_INTERRUPT_BIT, 104 | .pipe_mask = 0, 105 | .ready_mask = HEVC_READY_BIT, 106 | .error_mask = HEVC_DEC_ERR_MASK, 107 | .get_fmt = rkv_dec_get_fmt, 108 | }, 109 | { 110 | .name = "invalid", 111 | .reg_en = 0, 112 | .reg_irq = 0, 113 | .reg_len = 0, 114 | .reg_dir_mv = 0, 115 | .reg_pps = -1, 116 | .reg_pipe = 0, 117 | .enable_mask = 0, 118 | .gating_mask = 0, 119 | .pipe_mask = 0, 120 | .irq_mask = 0, 121 | .ready_mask = 0, 122 | .error_mask = 0, 123 | .get_fmt = NULL, 124 | }, 125 | { 126 | .name = "invalid", 127 | .reg_en = 0, 128 | .reg_irq = 0, 129 | .reg_len = 0, 130 | .reg_dir_mv = 0, 131 | .reg_pps = -1, 132 | .reg_pipe = 0, 133 | .enable_mask = 0, 134 | .gating_mask = 0, 135 | .pipe_mask = 0, 136 | .irq_mask = 0, 137 | .ready_mask = 0, 138 | .error_mask = 0, 139 | .get_fmt = NULL, 140 | },}; 141 | 142 | static struct vpu_hw_info hw_rkhevc = { 143 | .hw_id = HEVC_ID, 144 | 145 | .enc_offset = 0, 146 | .enc_reg_num = 0, 147 | .enc_io_size = 0, 148 | 149 | .dec_offset = 0, 150 | .dec_reg_num = REG_NUM_HEVC_DEC, 151 | .dec_io_size = REG_NUM_HEVC_DEC * 4, 152 | 153 | /* NOTE: can not write to register 0 */ 154 | .base_dec = 1, 155 | .base_pp = 0, 156 | .base_dec_pp = 0, 157 | .end_dec = REG_NUM_HEVC_DEC, 158 | .end_pp = 0, 159 | .end_dec_pp = 0, 160 | }; 161 | 162 | static struct vpu_hw_info hw_rkvdec = { 163 | .hw_id = RKV_DEC_ID, 164 | 165 | .enc_offset = 0, 166 | .enc_reg_num = 0, 167 | .enc_io_size = 0, 168 | 169 | .dec_offset = 0x0, 170 | .dec_reg_num = REG_NUM_RKV_DEC, 171 | .dec_io_size = REG_NUM_RKV_DEC * 4, 172 | 173 | /* NOTE: can not write to register 0 */ 174 | .base_dec = 1, 175 | .base_pp = 0, 176 | .base_dec_pp = 0, 177 | .end_dec = REG_NUM_RKV_DEC, 178 | .end_pp = 0, 179 | .end_dec_pp = 0, 180 | }; 181 | 182 | /* 183 | * file handle translate information 184 | */ 185 | DEF_FMT_TRANS_TBL(rkv_h264d, 186 | 4, 6, 7, 10, 11, 12, 13, 14, 187 | 15, 16, 17, 18, 19, 20, 21, 22, 188 | 23, 24, 41, 42, 43, 48, 75 189 | ); 190 | 191 | DEF_FMT_TRANS_TBL(rkv_h265d, 192 | 4, 6, 7, 10, 11, 12, 13, 14, 193 | 15, 16, 17, 18, 19, 20, 21, 22, 194 | 23, 24, 42, 43 195 | ); 196 | 197 | DEF_FMT_TRANS_TBL(rkv_vp9d, 198 | 4, 6, 7, 11, 12, 13, 14, 15, 199 | 16, 52 200 | ); 201 | 202 | const struct vpu_trans_info trans_rkv[FMT_TYPE_BUTT] = { 203 | EMPTY_FMT_TBL(FMT_JPEGD), 204 | EMPTY_FMT_TBL(FMT_H263D), 205 | SETUP_FMT_TBL(FMT_H264D , rkv_h264d), 206 | SETUP_FMT_TBL(FMT_H265D , rkv_h265d), 207 | 208 | EMPTY_FMT_TBL(FMT_MPEG1D), 209 | EMPTY_FMT_TBL(FMT_MPEG2D), 210 | EMPTY_FMT_TBL(FMT_MPEG4D), 211 | 212 | EMPTY_FMT_TBL(FMT_VP6D), 213 | EMPTY_FMT_TBL(FMT_VP7D), 214 | EMPTY_FMT_TBL(FMT_VP8D), 215 | SETUP_FMT_TBL(FMT_VP9D , rkv_vp9d), 216 | 217 | EMPTY_FMT_TBL(FMT_PP), 218 | 219 | EMPTY_FMT_TBL(FMT_VC1D), 220 | EMPTY_FMT_TBL(FMT_AVSD), 221 | 222 | EMPTY_FMT_TBL(FMT_JPEGE), 223 | EMPTY_FMT_TBL(FMT_H264E), 224 | EMPTY_FMT_TBL(FMT_VP8E), 225 | }; 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /vcodec_hw_vpu2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd 3 | * author: chenhengming chm@rock-chips.com 4 | * Alpha Lin, alpha.lin@rock-chips.com 5 | * 6 | * This software is licensed under the terms of the GNU General Public 7 | * License version 2, as published by the Free Software Foundation, and 8 | * may be copied, distributed, and modified under those terms. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | #ifndef __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU2_H 18 | #define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU2_H 19 | 20 | #include "vcodec_hw_info.h" 21 | 22 | /* hardware information */ 23 | #define REG_NUM_VPU2_DEC (159) 24 | #define REG_NUM_VPU2_DEC_START (50) 25 | #define REG_NUM_VPU2_DEC_END (159) 26 | #define REG_NUM_VPU2_PP (41) 27 | #define REG_NUM_VPU2_DEC_PP (159) 28 | #define REG_NUM_VPU2_ENC (184) 29 | #define REG_NUM_VPU2_DEC_OFFSET (0x400) 30 | 31 | /* enable and gating register */ 32 | #define VPU2_REG_EN_ENC 103 33 | #define VPU2_REG_ENC_GATE 109 34 | #define VPU2_REG_ENC_GATE_BIT BIT(4) 35 | 36 | #define VPU2_REG_EN_DEC 57 37 | #define VPU2_REG_DEC_GATE 57 38 | #define VPU2_REG_DEC_GATE_BIT BIT(4) 39 | #define VPU2_REG_EN_PP 41 40 | #define VPU2_REG_PP_GATE 1 41 | #define VPU2_REG_PP_GATE_BIT BIT(8) 42 | #define VPU2_REG_EN_DEC_PP 57 43 | #define VPU2_REG_DEC_PP_GATE 57 44 | #define VPU2_REG_DEC_PP_GATE_BIT BIT(4) 45 | 46 | /* interrupt and error status register */ 47 | #define VPU2_DEC_INTERRUPT_REGISTER 55 48 | #define VPU2_DEC_INTERRUPT_BIT BIT(0) 49 | #define VPU2_DEC_READY_BIT BIT(4) 50 | #define VPU2_DEC_BUS_ERROR_BIT BIT(5) 51 | #define VPU2_DEC_BUFFER_EMPTY_BIT BIT(6) 52 | #define VPU2_DEC_ASO_ERROR_BIT BIT(8) 53 | #define VPU2_DEC_SLICE_DONE_BIT BIT(9) 54 | #define VPU2_DEC_STREAM_ERROR_BIT BIT(12) 55 | #define VPU2_DEC_TIMEOUT_BIT BIT(13) 56 | #define VPU2_DEC_ERR_MASK (VPU2_DEC_BUS_ERROR_BIT \ 57 | |VPU2_DEC_BUFFER_EMPTY_BIT \ 58 | |VPU2_DEC_STREAM_ERROR_BIT \ 59 | |VPU2_DEC_TIMEOUT_BIT) 60 | 61 | #define VPU2_PP_INTERRUPT_REGISTER 40 62 | #define VPU2_PP_INTERRUPT_BIT BIT(0) 63 | #define VPU2_PP_READY_BIT BIT(2) 64 | #define VPU2_PP_BUS_ERROR_BIT BIT(3) 65 | #define VPU2_PP_ERR_MASK VPU2_PP_BUS_ERROR_BIT 66 | #define VPU2_PP_PIPELINE_REGISTER 41 67 | #define VPU2_PP_PIPELINE_MODE_BIT BIT(4) 68 | 69 | #define VPU2_ENC_INTERRUPT_REGISTER 109 70 | #define VPU2_ENC_INTERRUPT_BIT BIT(0) 71 | #define VPU2_ENC_READY_BIT BIT(1) 72 | #define VPU2_ENC_BUS_ERROR_BIT BIT(4) 73 | #define VPU2_ENC_BUFFER_FULL_BIT BIT(5) 74 | #define VPU2_ENC_TIMEOUT_BIT BIT(6) 75 | #define VPU2_ENC_ERR_MASK (VPU2_ENC_BUS_ERROR_BIT \ 76 | |VPU2_ENC_BUFFER_FULL_BIT \ 77 | |VPU2_ENC_TIMEOUT_BIT) 78 | 79 | static const enum FORMAT_TYPE vpu2_dec_fmt_tbl[] = { 80 | [0] = FMT_H264D, 81 | [1] = FMT_MPEG4D, 82 | [2] = FMT_H263D, 83 | [3] = FMT_JPEGD, 84 | [4] = FMT_VC1D, 85 | [5] = FMT_MPEG2D, 86 | [6] = FMT_MPEG1D, 87 | [7] = FMT_VP6D, 88 | [8] = FMT_TYPE_BUTT, 89 | [9] = FMT_VP7D, 90 | [10] = FMT_VP8D, 91 | [11] = FMT_AVSD, 92 | [12] = FMT_TYPE_BUTT, 93 | [13] = FMT_TYPE_BUTT, 94 | [14] = FMT_TYPE_BUTT, 95 | [15] = FMT_TYPE_BUTT, 96 | }; 97 | 98 | static enum FORMAT_TYPE vpu2_dec_get_fmt(u32 *regs) 99 | { 100 | u32 fmt_id = regs[53] & 0xf; 101 | enum FORMAT_TYPE type = vpu2_dec_fmt_tbl[fmt_id]; 102 | return type; 103 | } 104 | 105 | static enum FORMAT_TYPE vpu2_pp_get_fmt(u32 *regs) 106 | { 107 | return FMT_PP; 108 | } 109 | 110 | static const enum FORMAT_TYPE vpu2_enc_fmt_tbl[] = { 111 | [0] = FMT_TYPE_BUTT, 112 | [1] = FMT_VP8E, 113 | [2] = FMT_JPEGE, 114 | [3] = FMT_H264E, 115 | }; 116 | 117 | static enum FORMAT_TYPE vpu2_enc_get_fmt(u32 *regs) 118 | { 119 | u32 fmt_id = (regs[VPU2_REG_EN_ENC] >> 4) & 0x3; 120 | enum FORMAT_TYPE type = vpu2_enc_fmt_tbl[fmt_id]; 121 | return type; 122 | } 123 | 124 | static struct vpu_task_info task_vpu2[TASK_TYPE_BUTT] = { 125 | { 126 | .name = "vpu2_enc", 127 | .reg_rlc = 48, 128 | .reg_en = VPU2_REG_EN_ENC, 129 | .reg_gating = VPU2_REG_ENC_GATE, 130 | .reg_irq = VPU2_ENC_INTERRUPT_REGISTER, 131 | .reg_len = -1, 132 | .reg_dir_mv = -1, 133 | .reg_pps = -1, 134 | .reg_pipe = -1, 135 | .enable_mask = 0x30, 136 | .gating_mask = VPU2_REG_ENC_GATE_BIT, 137 | .pipe_mask = 0, 138 | .irq_mask = VPU2_ENC_INTERRUPT_BIT, 139 | .ready_mask = VPU2_ENC_READY_BIT, 140 | .error_mask = VPU2_ENC_ERR_MASK, 141 | .get_fmt = vpu2_enc_get_fmt, 142 | }, 143 | { 144 | .name = "vpu2_dec", 145 | .reg_rlc = 64, 146 | .reg_en = VPU2_REG_EN_DEC, 147 | .reg_irq = VPU2_DEC_INTERRUPT_REGISTER, 148 | .reg_len = 64, 149 | .reg_dir_mv = 62, 150 | .reg_pps = -1, 151 | .reg_pipe = VPU2_PP_PIPELINE_REGISTER, 152 | .enable_mask = 0, 153 | .gating_mask = VPU2_REG_DEC_GATE_BIT, 154 | .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT, 155 | .irq_mask = VPU2_DEC_INTERRUPT_BIT, 156 | .ready_mask = VPU2_DEC_READY_BIT, 157 | .error_mask = VPU2_DEC_ERR_MASK, 158 | .get_fmt = vpu2_dec_get_fmt, 159 | }, 160 | { 161 | .name = "vpu2_pp", 162 | .reg_en = VPU2_REG_EN_PP, 163 | .reg_irq = VPU2_PP_INTERRUPT_REGISTER, 164 | .reg_len = -1, 165 | .reg_dir_mv = -1, 166 | .reg_pps = -1, 167 | .reg_pipe = VPU2_PP_PIPELINE_REGISTER, 168 | .enable_mask = 0, 169 | .gating_mask = VPU2_REG_PP_GATE_BIT, 170 | .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT, 171 | .irq_mask = VPU2_PP_INTERRUPT_BIT, 172 | .ready_mask = VPU2_PP_READY_BIT, 173 | .error_mask = VPU2_PP_ERR_MASK, 174 | .get_fmt = vpu2_pp_get_fmt, 175 | }, 176 | { 177 | .name = "vpu2_dec_pp", 178 | .reg_rlc = 64, 179 | .reg_en = VPU2_REG_EN_DEC_PP, 180 | .reg_irq = VPU2_DEC_INTERRUPT_REGISTER, 181 | .reg_len = 64, 182 | .reg_dir_mv = 62, 183 | .reg_pps = -1, 184 | .reg_pipe = VPU2_PP_PIPELINE_REGISTER, 185 | .enable_mask = 0, 186 | .gating_mask = VPU2_REG_DEC_GATE_BIT, 187 | .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT, 188 | .irq_mask = VPU2_DEC_INTERRUPT_BIT, 189 | .ready_mask = VPU2_DEC_READY_BIT, 190 | .error_mask = VPU2_DEC_ERR_MASK, 191 | .get_fmt = vpu2_dec_get_fmt, 192 | }, 193 | }; 194 | 195 | static struct vpu_hw_info hw_vpu2 = { 196 | .hw_id = VPU2_ID, 197 | 198 | .enc_offset = 0x0, 199 | .enc_reg_num = REG_NUM_VPU2_ENC, 200 | .enc_io_size = REG_NUM_VPU2_ENC * 4, 201 | 202 | .dec_offset = REG_NUM_VPU2_DEC_OFFSET, 203 | .dec_reg_num = REG_NUM_VPU2_DEC_PP, 204 | .dec_io_size = REG_NUM_VPU2_DEC_PP * 4, 205 | 206 | .base_dec = REG_NUM_VPU2_DEC_START, 207 | .base_pp = 0, 208 | .base_dec_pp = 0, 209 | .end_dec = REG_NUM_VPU2_DEC_END, 210 | .end_pp = REG_NUM_VPU2_PP, 211 | .end_dec_pp = REG_NUM_VPU2_DEC_END, 212 | }; 213 | 214 | /* 215 | * file handle translate information 216 | */ 217 | DEF_FMT_TRANS_TBL(vpu2_jpegd, 218 | 131, 64, 63, 61, 21, 22 219 | ); 220 | 221 | DEF_FMT_TRANS_TBL(vpu2_h264d, 222 | 61, 62, 63, 64, 84, 85, 86, 87, 88, 89, 223 | 90, 91, 92, 93, 94, 95, 96, 97, 224 | 98, 99, 225 | ); 226 | 227 | DEF_FMT_TRANS_TBL(vpu2_vp6d, 228 | 64, 63, 131, 136, 145, 61 229 | ); 230 | 231 | DEF_FMT_TRANS_TBL(vpu2_vp8d, 232 | 149, 64, 63, 131, 136, 137, 140, 141, 233 | 142, 143, 144, 145, 146, 147, 61 234 | ); 235 | 236 | DEF_FMT_TRANS_TBL(vpu2_vc1d, 237 | 64, 63, 131, 148, 134, 135, 145, 62 238 | ); 239 | 240 | DEF_FMT_TRANS_TBL(vpu2_default_dec, 241 | 61, 62, 64, 63, 131, 148, 134, 135, 242 | ); 243 | 244 | DEF_FMT_TRANS_TBL(vpu2_default_pp, 245 | 12, 13, 18, 19, 20, 21, 22 246 | ); 247 | 248 | DEF_FMT_TRANS_TBL(vpu2_default_enc, 249 | 77, 78, 56, 57, 63, 64, 48, 49, 250 | 50, 81 251 | ); 252 | 253 | const struct vpu_trans_info trans_vpu2[FMT_TYPE_BUTT] = { 254 | SETUP_FMT_TBL(FMT_JPEGD , vpu2_jpegd), 255 | SETUP_FMT_TBL(FMT_H263D , vpu2_default_dec), 256 | SETUP_FMT_TBL(FMT_H264D , vpu2_h264d), 257 | EMPTY_FMT_TBL(FMT_H265D), 258 | 259 | SETUP_FMT_TBL(FMT_MPEG1D, vpu2_default_dec), 260 | SETUP_FMT_TBL(FMT_MPEG2D, vpu2_default_dec), 261 | SETUP_FMT_TBL(FMT_MPEG4D, vpu2_default_dec), 262 | 263 | SETUP_FMT_TBL(FMT_VP6D , vpu2_vp6d), 264 | SETUP_FMT_TBL(FMT_VP7D , vpu2_default_dec), 265 | SETUP_FMT_TBL(FMT_VP8D , vpu2_vp8d), 266 | EMPTY_FMT_TBL(FMT_VP9D), 267 | 268 | SETUP_FMT_TBL(FMT_PP , vpu2_default_pp), 269 | 270 | SETUP_FMT_TBL(FMT_VC1D , vpu2_vc1d), 271 | SETUP_FMT_TBL(FMT_AVSD , vpu2_default_dec), 272 | 273 | SETUP_FMT_TBL(FMT_JPEGE , vpu2_default_enc), 274 | SETUP_FMT_TBL(FMT_H264E , vpu2_default_enc), 275 | SETUP_FMT_TBL(FMT_VP8E , vpu2_default_enc), 276 | }; 277 | 278 | #endif 279 | -------------------------------------------------------------------------------- /vcodec_iommu_dma.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 - 2017 Fuzhou Rockchip Electronics Co., Ltd 3 | * Randy Li, 4 | * 5 | * This software is licensed under the terms of the GNU General Public 6 | * License version 2, as published by the Free Software Foundation, and 7 | * may be copied, distributed, and modified under those terms. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | /* For kzalloc issues */ 21 | #include 22 | /* For iommu_*_device */ 23 | #include 24 | 25 | #include "vcodec_iommu_dma.h" 26 | 27 | /* pixel buffer, stream buffer and video codec buffer */ 28 | #define BUFFER_LIST_MAX_NUMS 26 29 | 30 | struct vcodec_dma_buffer { 31 | struct list_head list; 32 | /* dma-buf */ 33 | struct dma_buf *dma_buf; 34 | struct dma_buf_attachment *attach; 35 | struct sg_table *sgt; 36 | 37 | dma_addr_t iova; 38 | unsigned long size; 39 | /* Only be used for identifying the buffer */ 40 | int fd; 41 | 42 | int index; 43 | struct kref ref; 44 | }; 45 | 46 | struct vcodec_iommu_info { 47 | struct iommu_domain *domain; 48 | bool attached; 49 | 50 | struct device *dev; 51 | }; 52 | 53 | struct vcodec_dma_session { 54 | int buffer_nums; 55 | struct list_head buffer_list; 56 | /* Mutex for the above buffer list */ 57 | struct mutex list_mutex; 58 | 59 | struct device *dev; 60 | }; 61 | 62 | static struct vcodec_dma_buffer * 63 | vcodec_dma_get_buffer(struct vcodec_dma_session *session, int fd) 64 | { 65 | struct vcodec_dma_buffer *buffer = NULL, *n; 66 | 67 | mutex_lock(&session->list_mutex); 68 | list_for_each_entry_safe(buffer, n, &session->buffer_list, list) { 69 | /* 70 | * As long as the last reference is hold by the buffer pool, 71 | * the same fd won't be assigned to the other application. 72 | */ 73 | if (buffer->fd == fd) { 74 | mutex_unlock(&session->list_mutex); 75 | return buffer; 76 | } 77 | } 78 | mutex_unlock(&session->list_mutex); 79 | 80 | return NULL; 81 | } 82 | 83 | static void vcodec_dma_buffer_release(struct kref *ref) 84 | { 85 | struct vcodec_dma_buffer *buffer = 86 | container_of(ref, struct vcodec_dma_buffer, ref); 87 | 88 | dma_buf_unmap_attachment(buffer->attach, buffer->sgt, 89 | DMA_BIDIRECTIONAL); 90 | dma_buf_detach(buffer->dma_buf, buffer->attach); 91 | dma_buf_put(buffer->dma_buf); 92 | 93 | list_del(&buffer->list); 94 | kfree(buffer); 95 | } 96 | 97 | int vcodec_dma_release_fd(struct vcodec_dma_session *session, int fd) 98 | { 99 | struct device *dev = session->dev; 100 | struct vcodec_dma_buffer *buffer = NULL; 101 | 102 | buffer = vcodec_dma_get_buffer(session, fd); 103 | if (IS_ERR_OR_NULL(buffer)) { 104 | dev_err(dev, "can not find %d buffer in list to release\n", fd); 105 | 106 | return -EINVAL; 107 | } 108 | 109 | kref_put(&buffer->ref, vcodec_dma_buffer_release); 110 | 111 | return 0; 112 | } 113 | 114 | dma_addr_t vcodec_dma_import_fd(struct vcodec_dma_session *session, int fd) 115 | { 116 | struct vcodec_dma_buffer *buffer = NULL; 117 | struct dma_buf_attachment *attach; 118 | struct sg_table *sgt; 119 | struct dma_buf *dma_buf; 120 | int ret = 0; 121 | 122 | if (!session) 123 | return -EINVAL; 124 | 125 | buffer = vcodec_dma_get_buffer(session, fd); 126 | if (!IS_ERR_OR_NULL(buffer)) { 127 | kref_get(&buffer->ref); 128 | return buffer->iova; 129 | } 130 | 131 | dma_buf = dma_buf_get(fd); 132 | if (IS_ERR(dma_buf)) { 133 | ret = PTR_ERR(dma_buf); 134 | return ret; 135 | } 136 | 137 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 138 | if (!buffer) { 139 | ret = -ENOMEM; 140 | goto err; 141 | } 142 | 143 | buffer->dma_buf = dma_buf; 144 | buffer->fd = fd; 145 | 146 | kref_init(&buffer->ref); 147 | 148 | attach = dma_buf_attach(buffer->dma_buf, session->dev); 149 | if (IS_ERR(attach)) { 150 | ret = PTR_ERR(attach); 151 | goto fail_out; 152 | } 153 | 154 | sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); 155 | if (IS_ERR(sgt)) { 156 | ret = PTR_ERR(sgt); 157 | goto fail_detach; 158 | } 159 | 160 | buffer->iova = sg_dma_address(sgt->sgl); 161 | buffer->size = sg_dma_len(sgt->sgl); 162 | 163 | buffer->attach = attach; 164 | buffer->sgt = sgt; 165 | 166 | /* Increase the reference for used outside the buffer pool */ 167 | kref_get(&buffer->ref); 168 | 169 | INIT_LIST_HEAD(&buffer->list); 170 | mutex_lock(&session->list_mutex); 171 | 172 | if (session->buffer_nums >= BUFFER_LIST_MAX_NUMS - 1) { 173 | struct vcodec_dma_buffer *loop_buffer = NULL, *n; 174 | /* 175 | * Clear those buffer not be referenced beyond the buffer pool 176 | * 1. unreference all the buffer in the list 177 | * 2. reference count callback clean and remove it from the list 178 | * 3. Put back the reference from the list 179 | */ 180 | list_for_each_entry_safe(loop_buffer, n, 181 | &session->buffer_list, list) { 182 | kref_put(&loop_buffer->ref, vcodec_dma_buffer_release); 183 | } 184 | 185 | session->buffer_nums = 0; 186 | 187 | list_for_each_entry(loop_buffer, &session->buffer_list, list) { 188 | kref_get(&loop_buffer->ref); 189 | session->buffer_nums++; 190 | } 191 | } 192 | 193 | buffer->index = session->buffer_nums++; 194 | list_add_tail(&buffer->list, &session->buffer_list); 195 | mutex_unlock(&session->list_mutex); 196 | 197 | return buffer->iova; 198 | 199 | fail_detach: 200 | dma_buf_detach(buffer->dma_buf, attach); 201 | dma_buf_put(buffer->dma_buf); 202 | fail_out: 203 | kfree(buffer); 204 | err: 205 | dma_buf_put(dma_buf); 206 | return ret; 207 | } 208 | 209 | void vcodec_dma_destroy_session(struct vcodec_dma_session *session) 210 | { 211 | struct vcodec_dma_buffer *buffer = NULL, *n; 212 | 213 | if (!session) 214 | return; 215 | 216 | list_for_each_entry_safe(buffer, n, &session->buffer_list, list) { 217 | if (buffer->attach) { 218 | dma_buf_unmap_attachment(buffer->attach, buffer->sgt, 219 | DMA_BIDIRECTIONAL); 220 | dma_buf_detach(buffer->dma_buf, buffer->attach); 221 | dma_buf_put(buffer->dma_buf); 222 | buffer->attach = NULL; 223 | } 224 | dma_buf_put(buffer->dma_buf); 225 | list_del(&buffer->list); 226 | kfree(buffer); 227 | } 228 | 229 | kfree(session); 230 | } 231 | 232 | struct vcodec_dma_session *vcodec_dma_session_create(struct device *dev) 233 | { 234 | struct vcodec_dma_session *session = NULL; 235 | 236 | session = kzalloc(sizeof(*session), GFP_KERNEL); 237 | if (!session) 238 | return session; 239 | 240 | INIT_LIST_HEAD(&session->buffer_list); 241 | mutex_init(&session->list_mutex); 242 | session->buffer_nums = 0; 243 | 244 | session->dev = dev; 245 | 246 | return session; 247 | } 248 | 249 | void vcodec_iommu_detach(struct vcodec_iommu_info *info) 250 | { 251 | struct device *dev = info->dev; 252 | struct iommu_domain *domain = info->domain; 253 | 254 | if (!info->attached) 255 | return; 256 | 257 | iommu_detach_device(domain, dev); 258 | info->attached = false; 259 | } 260 | 261 | int vcodec_iommu_attach(struct vcodec_iommu_info *info) 262 | { 263 | struct device *dev = info->dev; 264 | struct iommu_domain *domain = info->domain; 265 | int ret; 266 | 267 | if (info->attached) 268 | return 0; 269 | 270 | ret = iommu_attach_device(domain, dev); 271 | if (ret) 272 | return ret; 273 | 274 | info->attached = true; 275 | 276 | return ret; 277 | } 278 | 279 | struct vcodec_iommu_info *vcodec_iommu_probe(struct device *dev) 280 | { 281 | struct vcodec_iommu_info *info = NULL; 282 | int ret = 0; 283 | 284 | dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); 285 | if (!dev->dma_parms) { 286 | ret = -ENOMEM; 287 | goto err_free_parms; 288 | } 289 | 290 | info = kzalloc(sizeof(*info), GFP_KERNEL); 291 | if (!info) { 292 | ret = -ENOMEM; 293 | goto err_free_parms; 294 | } 295 | info->dev = dev; 296 | 297 | info->domain = iommu_domain_alloc(dev->bus); 298 | if (!info->domain) { 299 | ret = -ENOMEM; 300 | goto err_free_info; 301 | } 302 | 303 | ret = iommu_get_dma_cookie(info->domain); 304 | if (ret) 305 | goto err_free_domain; 306 | 307 | ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 308 | if (ret) 309 | goto err_put_cookie; 310 | 311 | dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); 312 | 313 | ret = iommu_attach_device(info->domain, dev); 314 | if (ret) 315 | goto err_put_cookie; 316 | 317 | /* 318 | * You may use the arch_setup_dma_ops() instead in the future kernel 319 | * version, but the iommu_domain_alloc() will create an unnamed domain. 320 | */ 321 | /* ??? - Myy */ 322 | arch_setup_dma_ops(dev, 0x0, dev->coherent_dma_mask + 1, 323 | info->domain->ops, true); 324 | 325 | return info; 326 | 327 | err_put_cookie: 328 | iommu_put_dma_cookie(info->domain); 329 | err_free_domain: 330 | iommu_domain_free(info->domain); 331 | err_free_info: 332 | kfree(info); 333 | err_free_parms: 334 | return ERR_PTR(ret); 335 | } 336 | 337 | int vcodec_iommu_remove(struct vcodec_iommu_info *info) 338 | { 339 | iommu_detach_device(info->domain, info->dev); 340 | info->attached = false; 341 | 342 | iommu_put_dma_cookie(info->domain); 343 | iommu_domain_free(info->domain); 344 | 345 | kfree(info); 346 | 347 | return 0; 348 | } 349 | -------------------------------------------------------------------------------- /vcodec_hw_vpu.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd 3 | * author: chenhengming chm@rock-chips.com 4 | * Alpha Lin, alpha.lin@rock-chips.com 5 | * 6 | * This software is licensed under the terms of the GNU General Public 7 | * License version 2, as published by the Free Software Foundation, and 8 | * may be copied, distributed, and modified under those terms. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | #ifndef __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU_H 18 | #define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU_H 19 | 20 | #include "vcodec_hw_info.h" 21 | 22 | /* hardware information */ 23 | #define REG_NUM_9190_DEC (60) 24 | #define REG_NUM_9190_PP (41) 25 | #define REG_NUM_9190_DEC_PP (REG_NUM_9190_DEC + REG_NUM_9190_PP) 26 | 27 | #define REG_NUM_DEC_PP (REG_NUM_9190_DEC + REG_NUM_9190_PP) 28 | 29 | #define REG_NUM_ENC_8270 (96) 30 | #define REG_SIZE_ENC_8270 (0x200) 31 | #define REG_NUM_ENC_4831 (164) 32 | #define REG_SIZE_ENC_4831 (0x400) 33 | 34 | 35 | /* enable and gating register */ 36 | #define VPU_REG_EN_ENC 14 37 | #define VPU_REG_ENC_GATE 2 38 | #define VPU_REG_ENC_GATE_BIT BIT(4) 39 | 40 | #define VPU_REG_EN_DEC 1 41 | #define VPU_REG_DEC_GATE 2 42 | #define VPU_REG_DEC_GATE_BIT BIT(10) 43 | #define VPU_REG_EN_PP 0 44 | #define VPU_REG_PP_GATE 1 45 | #define VPU_REG_PP_GATE_BIT BIT(8) 46 | #define VPU_REG_EN_DEC_PP 1 47 | #define VPU_REG_DEC_PP_GATE 61 48 | #define VPU_REG_DEC_PP_GATE_BIT BIT(8) 49 | 50 | /* interrupt and error status register */ 51 | #define VPU_DEC_INTERRUPT_REGISTER 1 52 | #define VPU_DEC_INTERRUPT_BIT BIT(8) 53 | #define VPU_DEC_READY_BIT BIT(12) 54 | #define VPU_DEC_BUS_ERROR_BIT BIT(13) 55 | #define VPU_DEC_BUFFER_EMPTY_BIT BIT(14) 56 | #define VPU_DEC_ASO_ERROR_BIT BIT(15) 57 | #define VPU_DEC_STREAM_ERROR_BIT BIT(16) 58 | #define VPU_DEC_SLICE_DONE_BIT BIT(17) 59 | #define VPU_DEC_TIMEOUT_BIT BIT(18) 60 | #define VPU_DEC_ERR_MASK (VPU_DEC_BUS_ERROR_BIT \ 61 | |VPU_DEC_BUFFER_EMPTY_BIT \ 62 | |VPU_DEC_STREAM_ERROR_BIT \ 63 | |VPU_DEC_TIMEOUT_BIT) 64 | 65 | #define VPU_PP_INTERRUPT_REGISTER 60 66 | #define VPU_PP_PIPELINE_MODE_BIT BIT(1) 67 | #define VPU_PP_INTERRUPT_BIT BIT(8) 68 | #define VPU_PP_READY_BIT BIT(12) 69 | #define VPU_PP_BUS_ERROR_BIT BIT(13) 70 | #define VPU_PP_ERR_MASK VPU_PP_BUS_ERROR_BIT 71 | 72 | #define VPU_ENC_INTERRUPT_REGISTER 1 73 | #define VPU_ENC_INTERRUPT_BIT BIT(0) 74 | #define VPU_ENC_READY_BIT BIT(2) 75 | #define VPU_ENC_BUS_ERROR_BIT BIT(3) 76 | #define VPU_ENC_BUFFER_FULL_BIT BIT(5) 77 | #define VPU_ENC_TIMEOUT_BIT BIT(6) 78 | #define VPU_ENC_ERR_MASK (VPU_ENC_BUS_ERROR_BIT \ 79 | |VPU_ENC_BUFFER_FULL_BIT \ 80 | |VPU_ENC_TIMEOUT_BIT) 81 | 82 | static const enum FORMAT_TYPE vpu_dec_fmt_tbl[] = { 83 | [0] = FMT_H264D, 84 | [1] = FMT_MPEG4D, 85 | [2] = FMT_H263D, 86 | [3] = FMT_JPEGD, 87 | [4] = FMT_VC1D, 88 | [5] = FMT_MPEG2D, 89 | [6] = FMT_MPEG1D, 90 | [7] = FMT_VP6D, 91 | [8] = FMT_TYPE_BUTT, 92 | [9] = FMT_VP7D, 93 | [10] = FMT_VP8D, 94 | [11] = FMT_AVSD, 95 | [12] = FMT_TYPE_BUTT, 96 | [13] = FMT_TYPE_BUTT, 97 | [14] = FMT_TYPE_BUTT, 98 | [15] = FMT_TYPE_BUTT, 99 | }; 100 | 101 | static enum FORMAT_TYPE vpu_dec_get_fmt(u32 *regs) 102 | { 103 | u32 fmt_id = (regs[3] >> 28) & 0xf; 104 | enum FORMAT_TYPE type = vpu_dec_fmt_tbl[fmt_id]; 105 | return type; 106 | } 107 | 108 | static enum FORMAT_TYPE vpu_pp_get_fmt(u32 *regs) 109 | { 110 | return FMT_PP; 111 | } 112 | 113 | static const enum FORMAT_TYPE vpu_enc_fmt_tbl[] = { 114 | [0] = FMT_TYPE_BUTT, 115 | [1] = FMT_VP8E, 116 | [2] = FMT_JPEGE, 117 | [3] = FMT_H264E, 118 | }; 119 | 120 | static enum FORMAT_TYPE vpu_enc_get_fmt(u32 *regs) 121 | { 122 | u32 fmt_id = (regs[VPU_REG_EN_ENC] >> 1) & 0x3; 123 | enum FORMAT_TYPE type = vpu_enc_fmt_tbl[fmt_id]; 124 | return type; 125 | } 126 | 127 | static struct vpu_task_info task_vpu[TASK_TYPE_BUTT] = { 128 | { 129 | .name = "vpu_enc", 130 | .reg_rlc = 11, 131 | .reg_en = VPU_REG_EN_ENC, 132 | .reg_irq = VPU_ENC_INTERRUPT_REGISTER, 133 | .reg_len = -1, 134 | .reg_dir_mv = -1, 135 | .reg_pps = -1, 136 | .reg_pipe = -1, 137 | .enable_mask = 0x6, 138 | .gating_mask = 0, 139 | .pipe_mask = 0, 140 | .irq_mask = VPU_ENC_INTERRUPT_BIT, 141 | .ready_mask = VPU_ENC_READY_BIT, 142 | .error_mask = VPU_ENC_ERR_MASK, 143 | .get_fmt = vpu_enc_get_fmt, 144 | }, 145 | { 146 | .name = "vpu_dec", 147 | .reg_rlc = 12, 148 | .reg_en = VPU_REG_EN_DEC, 149 | .reg_irq = VPU_DEC_INTERRUPT_REGISTER, 150 | .reg_len = 12, 151 | .reg_dir_mv = 41, 152 | .reg_pps = -1, 153 | .reg_pipe = VPU_PP_INTERRUPT_REGISTER, 154 | .enable_mask = 0, 155 | .gating_mask = 0, 156 | .pipe_mask = VPU_PP_PIPELINE_MODE_BIT, 157 | .irq_mask = VPU_DEC_INTERRUPT_BIT, 158 | .ready_mask = VPU_DEC_READY_BIT, 159 | .error_mask = VPU_DEC_ERR_MASK, 160 | .get_fmt = vpu_dec_get_fmt, 161 | }, 162 | { 163 | .name = "vpu_pp", 164 | .reg_en = VPU_REG_EN_PP, 165 | .reg_irq = VPU_PP_INTERRUPT_REGISTER, 166 | .reg_len = -1, 167 | .reg_dir_mv = -1, 168 | .reg_pps = -1, 169 | .reg_pipe = VPU_PP_INTERRUPT_REGISTER, 170 | .enable_mask = 0, 171 | .gating_mask = 0, 172 | .pipe_mask = VPU_PP_PIPELINE_MODE_BIT, 173 | .irq_mask = VPU_PP_INTERRUPT_BIT, 174 | .ready_mask = VPU_PP_READY_BIT, 175 | .error_mask = VPU_PP_ERR_MASK, 176 | .get_fmt = vpu_pp_get_fmt, 177 | }, 178 | { 179 | .name = "vpu_dec_pp", 180 | .reg_rlc = 12, 181 | .reg_en = VPU_REG_EN_DEC, 182 | .reg_irq = VPU_DEC_INTERRUPT_REGISTER, 183 | .reg_len = 12, 184 | .reg_dir_mv = 41, 185 | .reg_pps = -1, 186 | .reg_pipe = VPU_PP_INTERRUPT_REGISTER, 187 | .enable_mask = 0, 188 | .gating_mask = 0, 189 | .pipe_mask = VPU_PP_PIPELINE_MODE_BIT, 190 | .irq_mask = VPU_DEC_INTERRUPT_BIT, 191 | .ready_mask = VPU_DEC_READY_BIT, 192 | .error_mask = VPU_DEC_ERR_MASK, 193 | .get_fmt = vpu_dec_get_fmt, 194 | }, 195 | }; 196 | 197 | static struct vpu_hw_info hw_vpu_8270 = { 198 | .hw_id = VPU_ID_8270, 199 | 200 | .enc_offset = 0x0, 201 | .enc_reg_num = REG_NUM_ENC_8270, 202 | .enc_io_size = REG_NUM_ENC_8270 * 4, 203 | 204 | .dec_offset = REG_SIZE_ENC_8270, 205 | .dec_reg_num = REG_NUM_9190_DEC_PP, 206 | .dec_io_size = REG_NUM_9190_DEC_PP * 4, 207 | 208 | .base_dec = 0, 209 | .base_pp = VPU_PP_INTERRUPT_REGISTER, 210 | .base_dec_pp = 0, 211 | .end_dec = REG_NUM_9190_DEC, 212 | .end_pp = REG_NUM_9190_DEC_PP, 213 | .end_dec_pp = REG_NUM_9190_DEC_PP, 214 | }; 215 | 216 | static struct vpu_hw_info hw_vpu_4831 = { 217 | .hw_id = VPU_ID_4831, 218 | 219 | .enc_offset = 0x0, 220 | .enc_reg_num = REG_NUM_ENC_4831, 221 | .enc_io_size = REG_NUM_ENC_4831 * 4, 222 | 223 | .dec_offset = REG_SIZE_ENC_4831, 224 | .dec_reg_num = REG_NUM_9190_DEC_PP, 225 | .dec_io_size = REG_NUM_9190_DEC_PP * 4, 226 | 227 | .base_dec = 0, 228 | .base_pp = VPU_PP_INTERRUPT_REGISTER, 229 | .base_dec_pp = 0, 230 | .end_dec = REG_NUM_9190_DEC, 231 | .end_pp = REG_NUM_9190_DEC_PP, 232 | .end_dec_pp = REG_NUM_9190_DEC_PP, 233 | }; 234 | 235 | static struct vpu_hw_info hw_vpu_9190 = { 236 | .hw_id = VPU_DEC_ID_9190, 237 | 238 | .enc_offset = 0x0, 239 | .enc_reg_num = 0, 240 | .enc_io_size = 0, 241 | 242 | .dec_offset = 0, 243 | .dec_reg_num = REG_NUM_9190_DEC_PP, 244 | .dec_io_size = REG_NUM_9190_DEC_PP * 4, 245 | 246 | .base_dec = 0, 247 | .base_pp = VPU_PP_INTERRUPT_REGISTER, 248 | .base_dec_pp = 0, 249 | .end_dec = REG_NUM_9190_DEC, 250 | .end_pp = REG_NUM_9190_DEC_PP, 251 | .end_dec_pp = REG_NUM_9190_DEC_PP, 252 | }; 253 | 254 | /* 255 | * file handle translate information 256 | */ 257 | DEF_FMT_TRANS_TBL(vpu_jpegd, 258 | 12, 13, 14, 40, 66, 67 259 | ); 260 | 261 | DEF_FMT_TRANS_TBL(vpu_h264d, 262 | 12, 13, 14, 15, 16, 17, 18, 19, 263 | 20, 21, 22, 23, 24, 25, 26, 27, 264 | 28, 29, 40, 41 265 | ); 266 | 267 | DEF_FMT_TRANS_TBL(vpu_vp6d, 268 | 12, 13, 14, 18, 27, 40 269 | ); 270 | 271 | DEF_FMT_TRANS_TBL(vpu_vp8d, 272 | 10, 12, 13, 14, 18, 19, 22, 23, 273 | 24, 25, 26, 27, 28, 29, 40 274 | ); 275 | 276 | DEF_FMT_TRANS_TBL(vpu_vc1d, 277 | 12, 13, 14, 15, 16, 17, 27, 41 278 | ); 279 | 280 | DEF_FMT_TRANS_TBL(vpu_avsd, 281 | 12, 13, 14, 15, 16, 17, 40, 41, 45 282 | ); 283 | 284 | DEF_FMT_TRANS_TBL(vpu_defaultd, 285 | 12, 13, 14, 15, 16, 17, 40, 41 286 | ); 287 | 288 | DEF_FMT_TRANS_TBL(vpu_default_pp, 289 | 63, 64, 65, 66, 67, 73, 74 290 | ); 291 | 292 | DEF_FMT_TRANS_TBL(vpu_vp8e, 293 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 26, 51, 52, 58, 59 294 | ); 295 | 296 | DEF_FMT_TRANS_TBL(vpu_defaulte, 297 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 51 298 | ); 299 | 300 | static const struct vpu_trans_info trans_vpu[FMT_TYPE_BUTT] = { 301 | SETUP_FMT_TBL(FMT_JPEGD, vpu_jpegd), 302 | SETUP_FMT_TBL(FMT_H263D, vpu_defaultd), 303 | SETUP_FMT_TBL(FMT_H264D, vpu_h264d), 304 | EMPTY_FMT_TBL(FMT_H265D), 305 | 306 | SETUP_FMT_TBL(FMT_MPEG1D, vpu_defaultd), 307 | SETUP_FMT_TBL(FMT_MPEG2D, vpu_defaultd), 308 | SETUP_FMT_TBL(FMT_MPEG4D, vpu_defaultd), 309 | 310 | SETUP_FMT_TBL(FMT_VP6D, vpu_vp6d), 311 | SETUP_FMT_TBL(FMT_VP7D, vpu_defaultd), 312 | SETUP_FMT_TBL(FMT_VP8D, vpu_vp8d), 313 | EMPTY_FMT_TBL(FMT_VP9D), 314 | 315 | SETUP_FMT_TBL(FMT_VC1D, vpu_vc1d), 316 | SETUP_FMT_TBL(FMT_AVSD, vpu_avsd), 317 | 318 | SETUP_FMT_TBL(FMT_PP, vpu_default_pp), 319 | 320 | SETUP_FMT_TBL(FMT_JPEGE, vpu_defaulte), 321 | SETUP_FMT_TBL(FMT_H264E, vpu_defaulte), 322 | SETUP_FMT_TBL(FMT_VP8E, vpu_vp8e), 323 | }; 324 | 325 | #endif 326 | -------------------------------------------------------------------------------- /vcodec_service.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd 3 | * author: chenhengming, chm@rock-chips.com 4 | * Alpha Lin, alpha.lin@rock-chips.com 5 | * Jung Zhao, jung.zhao@rock-chips.com 6 | * 7 | * This software is licensed under the terms of the GNU General Public 8 | * License version 2, as published by the Free Software Foundation, and 9 | * may be copied, distributed, and modified under those terms. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | */ 17 | 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #include