1853 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * camss-vfe.c4 *5 * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module6 *7 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.8 * Copyright (C) 2015-2018 Linaro Ltd.9 */10#include <linux/clk.h>11#include <linux/completion.h>12#include <linux/interrupt.h>13#include <linux/iommu.h>14#include <linux/mutex.h>15#include <linux/of.h>16#include <linux/platform_device.h>17#include <linux/pm_domain.h>18#include <linux/pm_runtime.h>19#include <linux/spinlock_types.h>20#include <linux/spinlock.h>21#include <media/media-entity.h>22#include <media/v4l2-device.h>23#include <media/v4l2-subdev.h>24 25#include "camss-vfe.h"26#include "camss.h"27 28#define MSM_VFE_NAME "msm_vfe"29 30/* VFE reset timeout */31#define VFE_RESET_TIMEOUT_MS 5032 33#define SCALER_RATIO_MAX 1634 35static const struct camss_format_info formats_rdi_8x16[] = {36 { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,37 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },38 { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,39 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },40 { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,41 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },42 { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,43 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },44 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, V4L2_PIX_FMT_SBGGR8, 1,45 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },46 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, V4L2_PIX_FMT_SGBRG8, 1,47 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },48 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, V4L2_PIX_FMT_SGRBG8, 1,49 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },50 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, V4L2_PIX_FMT_SRGGB8, 1,51 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },52 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, V4L2_PIX_FMT_SBGGR10P, 1,53 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },54 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, V4L2_PIX_FMT_SGBRG10P, 1,55 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },56 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, V4L2_PIX_FMT_SGRBG10P, 1,57 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },58 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, V4L2_PIX_FMT_SRGGB10P, 1,59 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },60 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, V4L2_PIX_FMT_SBGGR12P, 1,61 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },62 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, V4L2_PIX_FMT_SGBRG12P, 1,63 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },64 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, V4L2_PIX_FMT_SGRBG12P, 1,65 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },66 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, V4L2_PIX_FMT_SRGGB12P, 1,67 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },68 { MEDIA_BUS_FMT_Y10_1X10, 10, V4L2_PIX_FMT_Y10P, 1,69 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },70};71 72static const struct camss_format_info formats_rdi_8x96[] = {73 { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,74 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },75 { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,76 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },77 { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,78 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },79 { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,80 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },81 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, V4L2_PIX_FMT_SBGGR8, 1,82 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },83 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, V4L2_PIX_FMT_SGBRG8, 1,84 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },85 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, V4L2_PIX_FMT_SGRBG8, 1,86 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },87 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, V4L2_PIX_FMT_SRGGB8, 1,88 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },89 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, V4L2_PIX_FMT_SBGGR10P, 1,90 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },91 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, V4L2_PIX_FMT_SGBRG10P, 1,92 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },93 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, V4L2_PIX_FMT_SGRBG10P, 1,94 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },95 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, V4L2_PIX_FMT_SRGGB10P, 1,96 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },97 { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_SBGGR10, 1,98 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },99 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, V4L2_PIX_FMT_SBGGR12P, 1,100 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },101 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, V4L2_PIX_FMT_SGBRG12P, 1,102 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },103 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, V4L2_PIX_FMT_SGRBG12P, 1,104 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },105 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, V4L2_PIX_FMT_SRGGB12P, 1,106 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },107 { MEDIA_BUS_FMT_SBGGR14_1X14, 14, V4L2_PIX_FMT_SBGGR14P, 1,108 PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },109 { MEDIA_BUS_FMT_SGBRG14_1X14, 14, V4L2_PIX_FMT_SGBRG14P, 1,110 PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },111 { MEDIA_BUS_FMT_SGRBG14_1X14, 14, V4L2_PIX_FMT_SGRBG14P, 1,112 PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },113 { MEDIA_BUS_FMT_SRGGB14_1X14, 14, V4L2_PIX_FMT_SRGGB14P, 1,114 PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },115 { MEDIA_BUS_FMT_Y10_1X10, 10, V4L2_PIX_FMT_Y10P, 1,116 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },117 { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_Y10, 1,118 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },119};120 121static const struct camss_format_info formats_rdi_845[] = {122 { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,123 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },124 { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,125 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },126 { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,127 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },128 { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,129 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },130 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, V4L2_PIX_FMT_SBGGR8, 1,131 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },132 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, V4L2_PIX_FMT_SGBRG8, 1,133 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },134 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, V4L2_PIX_FMT_SGRBG8, 1,135 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },136 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, V4L2_PIX_FMT_SRGGB8, 1,137 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },138 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, V4L2_PIX_FMT_SBGGR10P, 1,139 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },140 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, V4L2_PIX_FMT_SGBRG10P, 1,141 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },142 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, V4L2_PIX_FMT_SGRBG10P, 1,143 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },144 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, V4L2_PIX_FMT_SRGGB10P, 1,145 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },146 { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_SBGGR10, 1,147 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },148 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, V4L2_PIX_FMT_SBGGR12P, 1,149 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },150 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, V4L2_PIX_FMT_SGBRG12P, 1,151 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },152 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, V4L2_PIX_FMT_SGRBG12P, 1,153 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },154 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, V4L2_PIX_FMT_SRGGB12P, 1,155 PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },156 { MEDIA_BUS_FMT_SBGGR14_1X14, 14, V4L2_PIX_FMT_SBGGR14P, 1,157 PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },158 { MEDIA_BUS_FMT_SGBRG14_1X14, 14, V4L2_PIX_FMT_SGBRG14P, 1,159 PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },160 { MEDIA_BUS_FMT_SGRBG14_1X14, 14, V4L2_PIX_FMT_SGRBG14P, 1,161 PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },162 { MEDIA_BUS_FMT_SRGGB14_1X14, 14, V4L2_PIX_FMT_SRGGB14P, 1,163 PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },164 { MEDIA_BUS_FMT_Y8_1X8, 8, V4L2_PIX_FMT_GREY, 1,165 PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },166 { MEDIA_BUS_FMT_Y10_1X10, 10, V4L2_PIX_FMT_Y10P, 1,167 PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },168 { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_Y10, 1,169 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },170};171 172static const struct camss_format_info formats_pix_8x16[] = {173 { MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,174 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },175 { MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,176 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },177 { MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,178 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },179 { MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,180 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },181 { MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,182 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },183 { MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,184 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },185 { MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,186 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },187 { MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,188 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },189 { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV16, 1,190 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },191 { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV16, 1,192 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },193 { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,194 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },195 { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,196 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },197 { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV61, 1,198 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },199 { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV61, 1,200 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },201 { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,202 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },203 { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,204 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },205};206 207static const struct camss_format_info formats_pix_8x96[] = {208 { MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,209 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },210 { MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,211 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },212 { MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,213 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },214 { MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,215 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },216 { MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,217 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },218 { MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,219 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },220 { MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,221 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },222 { MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,223 PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },224 { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV16, 1,225 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },226 { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV16, 1,227 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },228 { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,229 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },230 { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,231 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },232 { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV61, 1,233 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },234 { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV61, 1,235 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },236 { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,237 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },238 { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,239 PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },240 { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,241 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },242 { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,243 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },244 { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,245 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },246 { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,247 PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },248};249 250const struct camss_formats vfe_formats_rdi_8x16 = {251 .nformats = ARRAY_SIZE(formats_rdi_8x16),252 .formats = formats_rdi_8x16253};254 255const struct camss_formats vfe_formats_pix_8x16 = {256 .nformats = ARRAY_SIZE(formats_pix_8x16),257 .formats = formats_pix_8x16258};259 260const struct camss_formats vfe_formats_rdi_8x96 = {261 .nformats = ARRAY_SIZE(formats_rdi_8x96),262 .formats = formats_rdi_8x96263};264 265const struct camss_formats vfe_formats_pix_8x96 = {266 .nformats = ARRAY_SIZE(formats_pix_8x96),267 .formats = formats_pix_8x96268};269 270const struct camss_formats vfe_formats_rdi_845 = {271 .nformats = ARRAY_SIZE(formats_rdi_845),272 .formats = formats_rdi_845273};274 275/* TODO: Replace with pix formats */276const struct camss_formats vfe_formats_pix_845 = {277 .nformats = ARRAY_SIZE(formats_rdi_845),278 .formats = formats_rdi_845279};280 281static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,282 unsigned int index, u32 src_req_code)283{284 struct vfe_device *vfe = to_vfe(line);285 286 switch (vfe->camss->res->version) {287 case CAMSS_8x16:288 switch (sink_code) {289 case MEDIA_BUS_FMT_YUYV8_1X16:290 {291 u32 src_code[] = {292 MEDIA_BUS_FMT_YUYV8_1X16,293 MEDIA_BUS_FMT_YUYV8_1_5X8,294 };295 296 return camss_format_find_code(src_code, ARRAY_SIZE(src_code),297 index, src_req_code);298 }299 case MEDIA_BUS_FMT_YVYU8_1X16:300 {301 u32 src_code[] = {302 MEDIA_BUS_FMT_YVYU8_1X16,303 MEDIA_BUS_FMT_YVYU8_1_5X8,304 };305 306 return camss_format_find_code(src_code, ARRAY_SIZE(src_code),307 index, src_req_code);308 }309 case MEDIA_BUS_FMT_UYVY8_1X16:310 {311 u32 src_code[] = {312 MEDIA_BUS_FMT_UYVY8_1X16,313 MEDIA_BUS_FMT_UYVY8_1_5X8,314 };315 316 return camss_format_find_code(src_code, ARRAY_SIZE(src_code),317 index, src_req_code);318 }319 case MEDIA_BUS_FMT_VYUY8_1X16:320 {321 u32 src_code[] = {322 MEDIA_BUS_FMT_VYUY8_1X16,323 MEDIA_BUS_FMT_VYUY8_1_5X8,324 };325 326 return camss_format_find_code(src_code, ARRAY_SIZE(src_code),327 index, src_req_code);328 }329 default:330 if (index > 0)331 return 0;332 333 return sink_code;334 }335 break;336 case CAMSS_8x96:337 case CAMSS_660:338 case CAMSS_845:339 case CAMSS_8250:340 case CAMSS_8280XP:341 switch (sink_code) {342 case MEDIA_BUS_FMT_YUYV8_1X16:343 {344 u32 src_code[] = {345 MEDIA_BUS_FMT_YUYV8_1X16,346 MEDIA_BUS_FMT_YVYU8_1X16,347 MEDIA_BUS_FMT_UYVY8_1X16,348 MEDIA_BUS_FMT_VYUY8_1X16,349 MEDIA_BUS_FMT_YUYV8_1_5X8,350 };351 352 return camss_format_find_code(src_code, ARRAY_SIZE(src_code),353 index, src_req_code);354 }355 case MEDIA_BUS_FMT_YVYU8_1X16:356 {357 u32 src_code[] = {358 MEDIA_BUS_FMT_YVYU8_1X16,359 MEDIA_BUS_FMT_YUYV8_1X16,360 MEDIA_BUS_FMT_UYVY8_1X16,361 MEDIA_BUS_FMT_VYUY8_1X16,362 MEDIA_BUS_FMT_YVYU8_1_5X8,363 };364 365 return camss_format_find_code(src_code, ARRAY_SIZE(src_code),366 index, src_req_code);367 }368 case MEDIA_BUS_FMT_UYVY8_1X16:369 {370 u32 src_code[] = {371 MEDIA_BUS_FMT_UYVY8_1X16,372 MEDIA_BUS_FMT_YUYV8_1X16,373 MEDIA_BUS_FMT_YVYU8_1X16,374 MEDIA_BUS_FMT_VYUY8_1X16,375 MEDIA_BUS_FMT_UYVY8_1_5X8,376 };377 378 return camss_format_find_code(src_code, ARRAY_SIZE(src_code),379 index, src_req_code);380 }381 case MEDIA_BUS_FMT_VYUY8_1X16:382 {383 u32 src_code[] = {384 MEDIA_BUS_FMT_VYUY8_1X16,385 MEDIA_BUS_FMT_YUYV8_1X16,386 MEDIA_BUS_FMT_YVYU8_1X16,387 MEDIA_BUS_FMT_UYVY8_1X16,388 MEDIA_BUS_FMT_VYUY8_1_5X8,389 };390 391 return camss_format_find_code(src_code, ARRAY_SIZE(src_code),392 index, src_req_code);393 }394 default:395 if (index > 0)396 return 0;397 398 return sink_code;399 }400 break;401 }402 return 0;403}404 405int vfe_reset(struct vfe_device *vfe)406{407 unsigned long time;408 409 reinit_completion(&vfe->reset_complete);410 411 vfe->res->hw_ops->global_reset(vfe);412 413 time = wait_for_completion_timeout(&vfe->reset_complete,414 msecs_to_jiffies(VFE_RESET_TIMEOUT_MS));415 if (!time) {416 dev_err(vfe->camss->dev, "VFE reset timeout\n");417 return -EIO;418 }419 420 return 0;421}422 423static void vfe_init_outputs(struct vfe_device *vfe)424{425 int i;426 427 for (i = 0; i < vfe->res->line_num; i++) {428 struct vfe_output *output = &vfe->line[i].output;429 430 output->state = VFE_OUTPUT_OFF;431 output->buf[0] = NULL;432 output->buf[1] = NULL;433 INIT_LIST_HEAD(&output->pending_bufs);434 }435}436 437static void vfe_reset_output_maps(struct vfe_device *vfe)438{439 int i;440 441 for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++)442 vfe->wm_output_map[i] = VFE_LINE_NONE;443}444 445int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)446{447 int ret = -EBUSY;448 int i;449 450 for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++) {451 if (vfe->wm_output_map[i] == VFE_LINE_NONE) {452 vfe->wm_output_map[i] = line_id;453 ret = i;454 break;455 }456 }457 458 return ret;459}460 461int vfe_release_wm(struct vfe_device *vfe, u8 wm)462{463 if (wm >= ARRAY_SIZE(vfe->wm_output_map))464 return -EINVAL;465 466 vfe->wm_output_map[wm] = VFE_LINE_NONE;467 468 return 0;469}470 471struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)472{473 struct camss_buffer *buffer = NULL;474 475 if (!list_empty(&output->pending_bufs)) {476 buffer = list_first_entry(&output->pending_bufs,477 struct camss_buffer,478 queue);479 list_del(&buffer->queue);480 }481 482 return buffer;483}484 485void vfe_buf_add_pending(struct vfe_output *output,486 struct camss_buffer *buffer)487{488 INIT_LIST_HEAD(&buffer->queue);489 list_add_tail(&buffer->queue, &output->pending_bufs);490}491 492/*493 * vfe_buf_flush_pending - Flush all pending buffers.494 * @output: VFE output495 * @state: vb2 buffer state496 */497static void vfe_buf_flush_pending(struct vfe_output *output,498 enum vb2_buffer_state state)499{500 struct camss_buffer *buf;501 struct camss_buffer *t;502 503 list_for_each_entry_safe(buf, t, &output->pending_bufs, queue) {504 vb2_buffer_done(&buf->vb.vb2_buf, state);505 list_del(&buf->queue);506 }507}508 509int vfe_put_output(struct vfe_line *line)510{511 struct vfe_device *vfe = to_vfe(line);512 struct vfe_output *output = &line->output;513 unsigned long flags;514 unsigned int i;515 516 spin_lock_irqsave(&vfe->output_lock, flags);517 518 for (i = 0; i < output->wm_num; i++)519 vfe_release_wm(vfe, output->wm_idx[i]);520 521 output->state = VFE_OUTPUT_OFF;522 523 spin_unlock_irqrestore(&vfe->output_lock, flags);524 return 0;525}526 527static int vfe_disable_output(struct vfe_line *line)528{529 struct vfe_device *vfe = to_vfe(line);530 struct vfe_output *output = &line->output;531 unsigned long flags;532 unsigned int i;533 534 spin_lock_irqsave(&vfe->output_lock, flags);535 for (i = 0; i < output->wm_num; i++)536 vfe->res->hw_ops->vfe_wm_stop(vfe, output->wm_idx[i]);537 output->gen2.active_num = 0;538 spin_unlock_irqrestore(&vfe->output_lock, flags);539 540 return vfe_reset(vfe);541}542 543/*544 * vfe_disable - Disable streaming on VFE line545 * @line: VFE line546 *547 * Return 0 on success or a negative error code otherwise548 */549int vfe_disable(struct vfe_line *line)550{551 struct vfe_device *vfe = to_vfe(line);552 int ret;553 554 ret = vfe_disable_output(line);555 if (ret)556 goto error;557 558 vfe_put_output(line);559 560 mutex_lock(&vfe->stream_lock);561 562 vfe->stream_count--;563 564 mutex_unlock(&vfe->stream_lock);565 566error:567 return ret;568}569 570/**571 * vfe_isr_comp_done() - Process composite image done interrupt572 * @vfe: VFE Device573 * @comp: Composite image id574 */575void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp)576{577 unsigned int i;578 579 for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++)580 if (vfe->wm_output_map[i] == VFE_LINE_PIX) {581 vfe->isr_ops.wm_done(vfe, i);582 break;583 }584}585 586void vfe_isr_reset_ack(struct vfe_device *vfe)587{588 complete(&vfe->reset_complete);589}590 591/*592 * vfe_pm_domain_off - Disable power domains specific to this VFE.593 * @vfe: VFE Device594 */595void vfe_pm_domain_off(struct vfe_device *vfe)596{597 if (!vfe->genpd)598 return;599 600 device_link_del(vfe->genpd_link);601 vfe->genpd_link = NULL;602}603 604/*605 * vfe_pm_domain_on - Enable power domains specific to this VFE.606 * @vfe: VFE Device607 */608int vfe_pm_domain_on(struct vfe_device *vfe)609{610 struct camss *camss = vfe->camss;611 612 if (!vfe->genpd)613 return 0;614 615 vfe->genpd_link = device_link_add(camss->dev, vfe->genpd,616 DL_FLAG_STATELESS |617 DL_FLAG_PM_RUNTIME |618 DL_FLAG_RPM_ACTIVE);619 if (!vfe->genpd_link)620 return -EINVAL;621 622 return 0;623}624 625static int vfe_match_clock_names(struct vfe_device *vfe,626 struct camss_clock *clock)627{628 char vfe_name[7]; /* vfeXXX\0 */629 char vfe_lite_name[12]; /* vfe_liteXXX\0 */630 631 snprintf(vfe_name, sizeof(vfe_name), "vfe%d", vfe->id);632 snprintf(vfe_lite_name, sizeof(vfe_lite_name), "vfe_lite%d", vfe->id);633 634 return (!strcmp(clock->name, vfe_name) ||635 !strcmp(clock->name, vfe_lite_name) ||636 !strcmp(clock->name, "vfe_lite"));637}638 639/*640 * vfe_set_clock_rates - Calculate and set clock rates on VFE module641 * @vfe: VFE device642 *643 * Return 0 on success or a negative error code otherwise644 */645static int vfe_set_clock_rates(struct vfe_device *vfe)646{647 struct device *dev = vfe->camss->dev;648 u64 pixel_clock[VFE_LINE_NUM_MAX];649 int i, j;650 int ret;651 652 for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {653 ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,654 &pixel_clock[i]);655 if (ret)656 pixel_clock[i] = 0;657 }658 659 for (i = 0; i < vfe->nclocks; i++) {660 struct camss_clock *clock = &vfe->clock[i];661 662 if (vfe_match_clock_names(vfe, clock)) {663 u64 min_rate = 0;664 long rate;665 666 for (j = VFE_LINE_RDI0; j < vfe->res->line_num; j++) {667 u32 tmp;668 u8 bpp;669 670 if (j == VFE_LINE_PIX) {671 tmp = pixel_clock[j];672 } else {673 struct vfe_line *l = &vfe->line[j];674 675 bpp = camss_format_get_bpp(l->formats,676 l->nformats,677 l->fmt[MSM_VFE_PAD_SINK].code);678 tmp = pixel_clock[j] * bpp / 64;679 }680 681 if (min_rate < tmp)682 min_rate = tmp;683 }684 685 camss_add_clock_margin(&min_rate);686 687 for (j = 0; j < clock->nfreqs; j++)688 if (min_rate < clock->freq[j])689 break;690 691 if (j == clock->nfreqs) {692 dev_err(dev,693 "Pixel clock is too high for VFE");694 return -EINVAL;695 }696 697 /* if sensor pixel clock is not available */698 /* set highest possible VFE clock rate */699 if (min_rate == 0)700 j = clock->nfreqs - 1;701 702 rate = clk_round_rate(clock->clk, clock->freq[j]);703 if (rate < 0) {704 dev_err(dev, "clk round rate failed: %ld\n",705 rate);706 return -EINVAL;707 }708 709 ret = clk_set_rate(clock->clk, rate);710 if (ret < 0) {711 dev_err(dev, "clk set rate failed: %d\n", ret);712 return ret;713 }714 }715 }716 717 return 0;718}719 720/*721 * vfe_check_clock_rates - Check current clock rates on VFE module722 * @vfe: VFE device723 *724 * Return 0 if current clock rates are suitable for a new pipeline725 * or a negative error code otherwise726 */727static int vfe_check_clock_rates(struct vfe_device *vfe)728{729 u64 pixel_clock[VFE_LINE_NUM_MAX];730 int i, j;731 int ret;732 733 for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {734 ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,735 &pixel_clock[i]);736 if (ret)737 pixel_clock[i] = 0;738 }739 740 for (i = 0; i < vfe->nclocks; i++) {741 struct camss_clock *clock = &vfe->clock[i];742 743 if (vfe_match_clock_names(vfe, clock)) {744 u64 min_rate = 0;745 unsigned long rate;746 747 for (j = VFE_LINE_RDI0; j < vfe->res->line_num; j++) {748 u32 tmp;749 u8 bpp;750 751 if (j == VFE_LINE_PIX) {752 tmp = pixel_clock[j];753 } else {754 struct vfe_line *l = &vfe->line[j];755 756 bpp = camss_format_get_bpp(l->formats,757 l->nformats,758 l->fmt[MSM_VFE_PAD_SINK].code);759 tmp = pixel_clock[j] * bpp / 64;760 }761 762 if (min_rate < tmp)763 min_rate = tmp;764 }765 766 camss_add_clock_margin(&min_rate);767 768 rate = clk_get_rate(clock->clk);769 if (rate < min_rate)770 return -EBUSY;771 }772 }773 774 return 0;775}776 777/*778 * vfe_get - Power up and reset VFE module779 * @vfe: VFE Device780 *781 * Return 0 on success or a negative error code otherwise782 */783int vfe_get(struct vfe_device *vfe)784{785 int ret;786 787 mutex_lock(&vfe->power_lock);788 789 if (vfe->power_count == 0) {790 ret = vfe->res->hw_ops->pm_domain_on(vfe);791 if (ret < 0)792 goto error_pm_domain;793 794 ret = pm_runtime_resume_and_get(vfe->camss->dev);795 if (ret < 0)796 goto error_domain_off;797 798 ret = vfe_set_clock_rates(vfe);799 if (ret < 0)800 goto error_pm_runtime_get;801 802 ret = camss_enable_clocks(vfe->nclocks, vfe->clock,803 vfe->camss->dev);804 if (ret < 0)805 goto error_pm_runtime_get;806 807 ret = vfe_reset(vfe);808 if (ret < 0)809 goto error_reset;810 811 vfe_reset_output_maps(vfe);812 813 vfe_init_outputs(vfe);814 815 vfe->res->hw_ops->hw_version(vfe);816 } else {817 ret = vfe_check_clock_rates(vfe);818 if (ret < 0)819 goto error_pm_domain;820 }821 vfe->power_count++;822 823 mutex_unlock(&vfe->power_lock);824 825 return 0;826 827error_reset:828 camss_disable_clocks(vfe->nclocks, vfe->clock);829 830error_pm_runtime_get:831 pm_runtime_put_sync(vfe->camss->dev);832error_domain_off:833 vfe->res->hw_ops->pm_domain_off(vfe);834 835error_pm_domain:836 mutex_unlock(&vfe->power_lock);837 838 return ret;839}840 841/*842 * vfe_put - Power down VFE module843 * @vfe: VFE Device844 */845void vfe_put(struct vfe_device *vfe)846{847 mutex_lock(&vfe->power_lock);848 849 if (vfe->power_count == 0) {850 dev_err(vfe->camss->dev, "vfe power off on power_count == 0\n");851 goto exit;852 } else if (vfe->power_count == 1) {853 if (vfe->was_streaming) {854 vfe->was_streaming = 0;855 vfe->res->hw_ops->vfe_halt(vfe);856 }857 camss_disable_clocks(vfe->nclocks, vfe->clock);858 pm_runtime_put_sync(vfe->camss->dev);859 vfe->res->hw_ops->pm_domain_off(vfe);860 }861 862 vfe->power_count--;863 864exit:865 mutex_unlock(&vfe->power_lock);866}867 868/*869 * vfe_flush_buffers - Return all vb2 buffers870 * @vid: Video device structure871 * @state: vb2 buffer state of the returned buffers872 *873 * Return all buffers to vb2. This includes queued pending buffers (still874 * unused) and any buffers given to the hardware but again still not used.875 *876 * Return 0 on success or a negative error code otherwise877 */878int vfe_flush_buffers(struct camss_video *vid,879 enum vb2_buffer_state state)880{881 struct vfe_line *line = container_of(vid, struct vfe_line, video_out);882 struct vfe_device *vfe = to_vfe(line);883 struct vfe_output *output;884 unsigned long flags;885 886 output = &line->output;887 888 spin_lock_irqsave(&vfe->output_lock, flags);889 890 vfe_buf_flush_pending(output, state);891 892 if (output->buf[0])893 vb2_buffer_done(&output->buf[0]->vb.vb2_buf, state);894 895 if (output->buf[1])896 vb2_buffer_done(&output->buf[1]->vb.vb2_buf, state);897 898 if (output->last_buffer) {899 vb2_buffer_done(&output->last_buffer->vb.vb2_buf, state);900 output->last_buffer = NULL;901 }902 903 spin_unlock_irqrestore(&vfe->output_lock, flags);904 905 return 0;906}907 908/*909 * vfe_set_power - Power on/off VFE module910 * @sd: VFE V4L2 subdevice911 * @on: Requested power state912 *913 * Return 0 on success or a negative error code otherwise914 */915static int vfe_set_power(struct v4l2_subdev *sd, int on)916{917 struct vfe_line *line = v4l2_get_subdevdata(sd);918 struct vfe_device *vfe = to_vfe(line);919 int ret;920 921 if (on) {922 ret = vfe_get(vfe);923 if (ret < 0)924 return ret;925 } else {926 vfe_put(vfe);927 }928 929 return 0;930}931 932/*933 * vfe_set_stream - Enable/disable streaming on VFE module934 * @sd: VFE V4L2 subdevice935 * @enable: Requested streaming state936 *937 * Main configuration of VFE module is triggered here.938 *939 * Return 0 on success or a negative error code otherwise940 */941static int vfe_set_stream(struct v4l2_subdev *sd, int enable)942{943 struct vfe_line *line = v4l2_get_subdevdata(sd);944 struct vfe_device *vfe = to_vfe(line);945 int ret;946 947 if (enable) {948 line->output.state = VFE_OUTPUT_RESERVED;949 ret = vfe->res->hw_ops->vfe_enable(line);950 if (ret < 0)951 dev_err(vfe->camss->dev,952 "Failed to enable vfe outputs\n");953 } else {954 ret = vfe->res->hw_ops->vfe_disable(line);955 if (ret < 0)956 dev_err(vfe->camss->dev,957 "Failed to disable vfe outputs\n");958 }959 960 return ret;961}962 963/*964 * __vfe_get_format - Get pointer to format structure965 * @line: VFE line966 * @sd_state: V4L2 subdev state967 * @pad: pad from which format is requested968 * @which: TRY or ACTIVE format969 *970 * Return pointer to TRY or ACTIVE format structure971 */972static struct v4l2_mbus_framefmt *973__vfe_get_format(struct vfe_line *line,974 struct v4l2_subdev_state *sd_state,975 unsigned int pad,976 enum v4l2_subdev_format_whence which)977{978 if (which == V4L2_SUBDEV_FORMAT_TRY)979 return v4l2_subdev_state_get_format(sd_state, pad);980 981 return &line->fmt[pad];982}983 984/*985 * __vfe_get_compose - Get pointer to compose selection structure986 * @line: VFE line987 * @sd_state: V4L2 subdev state988 * @which: TRY or ACTIVE format989 *990 * Return pointer to TRY or ACTIVE compose rectangle structure991 */992static struct v4l2_rect *993__vfe_get_compose(struct vfe_line *line,994 struct v4l2_subdev_state *sd_state,995 enum v4l2_subdev_format_whence which)996{997 if (which == V4L2_SUBDEV_FORMAT_TRY)998 return v4l2_subdev_state_get_compose(sd_state,999 MSM_VFE_PAD_SINK);1000 1001 return &line->compose;1002}1003 1004/*1005 * __vfe_get_crop - Get pointer to crop selection structure1006 * @line: VFE line1007 * @sd_state: V4L2 subdev state1008 * @which: TRY or ACTIVE format1009 *1010 * Return pointer to TRY or ACTIVE crop rectangle structure1011 */1012static struct v4l2_rect *1013__vfe_get_crop(struct vfe_line *line,1014 struct v4l2_subdev_state *sd_state,1015 enum v4l2_subdev_format_whence which)1016{1017 if (which == V4L2_SUBDEV_FORMAT_TRY)1018 return v4l2_subdev_state_get_crop(sd_state, MSM_VFE_PAD_SRC);1019 1020 return &line->crop;1021}1022 1023/*1024 * vfe_try_format - Handle try format by pad subdev method1025 * @line: VFE line1026 * @sd_state: V4L2 subdev state1027 * @pad: pad on which format is requested1028 * @fmt: pointer to v4l2 format structure1029 * @which: wanted subdev format1030 */1031static void vfe_try_format(struct vfe_line *line,1032 struct v4l2_subdev_state *sd_state,1033 unsigned int pad,1034 struct v4l2_mbus_framefmt *fmt,1035 enum v4l2_subdev_format_whence which)1036{1037 unsigned int i;1038 u32 code;1039 1040 switch (pad) {1041 case MSM_VFE_PAD_SINK:1042 /* Set format on sink pad */1043 1044 for (i = 0; i < line->nformats; i++)1045 if (fmt->code == line->formats[i].code)1046 break;1047 1048 /* If not found, use UYVY as default */1049 if (i >= line->nformats)1050 fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;1051 1052 fmt->width = clamp_t(u32, fmt->width, 1, 8191);1053 fmt->height = clamp_t(u32, fmt->height, 1, 8191);1054 1055 fmt->field = V4L2_FIELD_NONE;1056 fmt->colorspace = V4L2_COLORSPACE_SRGB;1057 1058 break;1059 1060 case MSM_VFE_PAD_SRC:1061 /* Set and return a format same as sink pad */1062 code = fmt->code;1063 1064 *fmt = *__vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK,1065 which);1066 1067 fmt->code = vfe_src_pad_code(line, fmt->code, 0, code);1068 1069 if (line->id == VFE_LINE_PIX) {1070 struct v4l2_rect *rect;1071 1072 rect = __vfe_get_crop(line, sd_state, which);1073 1074 fmt->width = rect->width;1075 fmt->height = rect->height;1076 }1077 1078 break;1079 }1080 1081 fmt->colorspace = V4L2_COLORSPACE_SRGB;1082}1083 1084/*1085 * vfe_try_compose - Handle try compose selection by pad subdev method1086 * @line: VFE line1087 * @sd_state: V4L2 subdev state1088 * @rect: pointer to v4l2 rect structure1089 * @which: wanted subdev format1090 */1091static void vfe_try_compose(struct vfe_line *line,1092 struct v4l2_subdev_state *sd_state,1093 struct v4l2_rect *rect,1094 enum v4l2_subdev_format_whence which)1095{1096 struct v4l2_mbus_framefmt *fmt;1097 1098 fmt = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK, which);1099 1100 if (rect->width > fmt->width)1101 rect->width = fmt->width;1102 1103 if (rect->height > fmt->height)1104 rect->height = fmt->height;1105 1106 if (fmt->width > rect->width * SCALER_RATIO_MAX)1107 rect->width = (fmt->width + SCALER_RATIO_MAX - 1) /1108 SCALER_RATIO_MAX;1109 1110 rect->width &= ~0x1;1111 1112 if (fmt->height > rect->height * SCALER_RATIO_MAX)1113 rect->height = (fmt->height + SCALER_RATIO_MAX - 1) /1114 SCALER_RATIO_MAX;1115 1116 if (rect->width < 16)1117 rect->width = 16;1118 1119 if (rect->height < 4)1120 rect->height = 4;1121}1122 1123/*1124 * vfe_try_crop - Handle try crop selection by pad subdev method1125 * @line: VFE line1126 * @sd_state: V4L2 subdev state1127 * @rect: pointer to v4l2 rect structure1128 * @which: wanted subdev format1129 */1130static void vfe_try_crop(struct vfe_line *line,1131 struct v4l2_subdev_state *sd_state,1132 struct v4l2_rect *rect,1133 enum v4l2_subdev_format_whence which)1134{1135 struct v4l2_rect *compose;1136 1137 compose = __vfe_get_compose(line, sd_state, which);1138 1139 if (rect->width > compose->width)1140 rect->width = compose->width;1141 1142 if (rect->width + rect->left > compose->width)1143 rect->left = compose->width - rect->width;1144 1145 if (rect->height > compose->height)1146 rect->height = compose->height;1147 1148 if (rect->height + rect->top > compose->height)1149 rect->top = compose->height - rect->height;1150 1151 /* wm in line based mode writes multiple of 16 horizontally */1152 rect->left += (rect->width & 0xf) >> 1;1153 rect->width &= ~0xf;1154 1155 if (rect->width < 16) {1156 rect->left = 0;1157 rect->width = 16;1158 }1159 1160 if (rect->height < 4) {1161 rect->top = 0;1162 rect->height = 4;1163 }1164}1165 1166/*1167 * vfe_enum_mbus_code - Handle pixel format enumeration1168 * @sd: VFE V4L2 subdevice1169 * @sd_state: V4L2 subdev state1170 * @code: pointer to v4l2_subdev_mbus_code_enum structure1171 *1172 * return -EINVAL or zero on success1173 */1174static int vfe_enum_mbus_code(struct v4l2_subdev *sd,1175 struct v4l2_subdev_state *sd_state,1176 struct v4l2_subdev_mbus_code_enum *code)1177{1178 struct vfe_line *line = v4l2_get_subdevdata(sd);1179 1180 if (code->pad == MSM_VFE_PAD_SINK) {1181 if (code->index >= line->nformats)1182 return -EINVAL;1183 1184 code->code = line->formats[code->index].code;1185 } else {1186 struct v4l2_mbus_framefmt *sink_fmt;1187 1188 sink_fmt = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK,1189 code->which);1190 1191 code->code = vfe_src_pad_code(line, sink_fmt->code,1192 code->index, 0);1193 if (!code->code)1194 return -EINVAL;1195 }1196 1197 return 0;1198}1199 1200/*1201 * vfe_enum_frame_size - Handle frame size enumeration1202 * @sd: VFE V4L2 subdevice1203 * @sd_state: V4L2 subdev state1204 * @fse: pointer to v4l2_subdev_frame_size_enum structure1205 *1206 * Return -EINVAL or zero on success1207 */1208static int vfe_enum_frame_size(struct v4l2_subdev *sd,1209 struct v4l2_subdev_state *sd_state,1210 struct v4l2_subdev_frame_size_enum *fse)1211{1212 struct vfe_line *line = v4l2_get_subdevdata(sd);1213 struct v4l2_mbus_framefmt format;1214 1215 if (fse->index != 0)1216 return -EINVAL;1217 1218 format.code = fse->code;1219 format.width = 1;1220 format.height = 1;1221 vfe_try_format(line, sd_state, fse->pad, &format, fse->which);1222 fse->min_width = format.width;1223 fse->min_height = format.height;1224 1225 if (format.code != fse->code)1226 return -EINVAL;1227 1228 format.code = fse->code;1229 format.width = -1;1230 format.height = -1;1231 vfe_try_format(line, sd_state, fse->pad, &format, fse->which);1232 fse->max_width = format.width;1233 fse->max_height = format.height;1234 1235 return 0;1236}1237 1238/*1239 * vfe_get_format - Handle get format by pads subdev method1240 * @sd: VFE V4L2 subdevice1241 * @sd_state: V4L2 subdev state1242 * @fmt: pointer to v4l2 subdev format structure1243 *1244 * Return -EINVAL or zero on success1245 */1246static int vfe_get_format(struct v4l2_subdev *sd,1247 struct v4l2_subdev_state *sd_state,1248 struct v4l2_subdev_format *fmt)1249{1250 struct vfe_line *line = v4l2_get_subdevdata(sd);1251 struct v4l2_mbus_framefmt *format;1252 1253 format = __vfe_get_format(line, sd_state, fmt->pad, fmt->which);1254 if (format == NULL)1255 return -EINVAL;1256 1257 fmt->format = *format;1258 1259 return 0;1260}1261 1262static int vfe_set_selection(struct v4l2_subdev *sd,1263 struct v4l2_subdev_state *sd_state,1264 struct v4l2_subdev_selection *sel);1265 1266/*1267 * vfe_set_format - Handle set format by pads subdev method1268 * @sd: VFE V4L2 subdevice1269 * @sd_state: V4L2 subdev state1270 * @fmt: pointer to v4l2 subdev format structure1271 *1272 * Return -EINVAL or zero on success1273 */1274static int vfe_set_format(struct v4l2_subdev *sd,1275 struct v4l2_subdev_state *sd_state,1276 struct v4l2_subdev_format *fmt)1277{1278 struct vfe_line *line = v4l2_get_subdevdata(sd);1279 struct v4l2_mbus_framefmt *format;1280 1281 format = __vfe_get_format(line, sd_state, fmt->pad, fmt->which);1282 if (format == NULL)1283 return -EINVAL;1284 1285 vfe_try_format(line, sd_state, fmt->pad, &fmt->format, fmt->which);1286 *format = fmt->format;1287 1288 if (fmt->pad == MSM_VFE_PAD_SINK) {1289 struct v4l2_subdev_selection sel = { 0 };1290 int ret;1291 1292 /* Propagate the format from sink to source */1293 format = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SRC,1294 fmt->which);1295 1296 *format = fmt->format;1297 vfe_try_format(line, sd_state, MSM_VFE_PAD_SRC, format,1298 fmt->which);1299 1300 if (line->id != VFE_LINE_PIX)1301 return 0;1302 1303 /* Reset sink pad compose selection */1304 sel.which = fmt->which;1305 sel.pad = MSM_VFE_PAD_SINK;1306 sel.target = V4L2_SEL_TGT_COMPOSE;1307 sel.r.width = fmt->format.width;1308 sel.r.height = fmt->format.height;1309 ret = vfe_set_selection(sd, sd_state, &sel);1310 if (ret < 0)1311 return ret;1312 }1313 1314 return 0;1315}1316 1317/*1318 * vfe_get_selection - Handle get selection by pads subdev method1319 * @sd: VFE V4L2 subdevice1320 * @sd_state: V4L2 subdev state1321 * @sel: pointer to v4l2 subdev selection structure1322 *1323 * Return -EINVAL or zero on success1324 */1325static int vfe_get_selection(struct v4l2_subdev *sd,1326 struct v4l2_subdev_state *sd_state,1327 struct v4l2_subdev_selection *sel)1328{1329 struct vfe_line *line = v4l2_get_subdevdata(sd);1330 struct v4l2_subdev_format fmt = { 0 };1331 struct v4l2_rect *rect;1332 int ret;1333 1334 if (line->id != VFE_LINE_PIX)1335 return -EINVAL;1336 1337 if (sel->pad == MSM_VFE_PAD_SINK)1338 switch (sel->target) {1339 case V4L2_SEL_TGT_COMPOSE_BOUNDS:1340 fmt.pad = sel->pad;1341 fmt.which = sel->which;1342 ret = vfe_get_format(sd, sd_state, &fmt);1343 if (ret < 0)1344 return ret;1345 1346 sel->r.left = 0;1347 sel->r.top = 0;1348 sel->r.width = fmt.format.width;1349 sel->r.height = fmt.format.height;1350 break;1351 case V4L2_SEL_TGT_COMPOSE:1352 rect = __vfe_get_compose(line, sd_state, sel->which);1353 if (rect == NULL)1354 return -EINVAL;1355 1356 sel->r = *rect;1357 break;1358 default:1359 return -EINVAL;1360 }1361 else if (sel->pad == MSM_VFE_PAD_SRC)1362 switch (sel->target) {1363 case V4L2_SEL_TGT_CROP_BOUNDS:1364 rect = __vfe_get_compose(line, sd_state, sel->which);1365 if (rect == NULL)1366 return -EINVAL;1367 1368 sel->r.left = rect->left;1369 sel->r.top = rect->top;1370 sel->r.width = rect->width;1371 sel->r.height = rect->height;1372 break;1373 case V4L2_SEL_TGT_CROP:1374 rect = __vfe_get_crop(line, sd_state, sel->which);1375 if (rect == NULL)1376 return -EINVAL;1377 1378 sel->r = *rect;1379 break;1380 default:1381 return -EINVAL;1382 }1383 1384 return 0;1385}1386 1387/*1388 * vfe_set_selection - Handle set selection by pads subdev method1389 * @sd: VFE V4L2 subdevice1390 * @sd_state: V4L2 subdev state1391 * @sel: pointer to v4l2 subdev selection structure1392 *1393 * Return -EINVAL or zero on success1394 */1395static int vfe_set_selection(struct v4l2_subdev *sd,1396 struct v4l2_subdev_state *sd_state,1397 struct v4l2_subdev_selection *sel)1398{1399 struct vfe_line *line = v4l2_get_subdevdata(sd);1400 struct v4l2_rect *rect;1401 int ret;1402 1403 if (line->id != VFE_LINE_PIX)1404 return -EINVAL;1405 1406 if (sel->target == V4L2_SEL_TGT_COMPOSE &&1407 sel->pad == MSM_VFE_PAD_SINK) {1408 struct v4l2_subdev_selection crop = { 0 };1409 1410 rect = __vfe_get_compose(line, sd_state, sel->which);1411 if (rect == NULL)1412 return -EINVAL;1413 1414 vfe_try_compose(line, sd_state, &sel->r, sel->which);1415 *rect = sel->r;1416 1417 /* Reset source crop selection */1418 crop.which = sel->which;1419 crop.pad = MSM_VFE_PAD_SRC;1420 crop.target = V4L2_SEL_TGT_CROP;1421 crop.r = *rect;1422 ret = vfe_set_selection(sd, sd_state, &crop);1423 } else if (sel->target == V4L2_SEL_TGT_CROP &&1424 sel->pad == MSM_VFE_PAD_SRC) {1425 struct v4l2_subdev_format fmt = { 0 };1426 1427 rect = __vfe_get_crop(line, sd_state, sel->which);1428 if (rect == NULL)1429 return -EINVAL;1430 1431 vfe_try_crop(line, sd_state, &sel->r, sel->which);1432 *rect = sel->r;1433 1434 /* Reset source pad format width and height */1435 fmt.which = sel->which;1436 fmt.pad = MSM_VFE_PAD_SRC;1437 ret = vfe_get_format(sd, sd_state, &fmt);1438 if (ret < 0)1439 return ret;1440 1441 fmt.format.width = rect->width;1442 fmt.format.height = rect->height;1443 ret = vfe_set_format(sd, sd_state, &fmt);1444 } else {1445 ret = -EINVAL;1446 }1447 1448 return ret;1449}1450 1451/*1452 * vfe_init_formats - Initialize formats on all pads1453 * @sd: VFE V4L2 subdevice1454 * @fh: V4L2 subdev file handle1455 *1456 * Initialize all pad formats with default values.1457 *1458 * Return 0 on success or a negative error code otherwise1459 */1460static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)1461{1462 struct v4l2_subdev_format format = {1463 .pad = MSM_VFE_PAD_SINK,1464 .which = fh ? V4L2_SUBDEV_FORMAT_TRY :1465 V4L2_SUBDEV_FORMAT_ACTIVE,1466 .format = {1467 .code = MEDIA_BUS_FMT_UYVY8_1X16,1468 .width = 1920,1469 .height = 10801470 }1471 };1472 1473 return vfe_set_format(sd, fh ? fh->state : NULL, &format);1474}1475 1476/*1477 * msm_vfe_subdev_init - Initialize VFE device structure and resources1478 * @vfe: VFE device1479 * @res: VFE module resources table1480 *1481 * Return 0 on success or a negative error code otherwise1482 */1483int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,1484 const struct camss_subdev_resources *res, u8 id)1485{1486 struct device *dev = camss->dev;1487 struct platform_device *pdev = to_platform_device(dev);1488 int i, j;1489 int ret;1490 1491 if (!res->vfe.line_num)1492 return -EINVAL;1493 1494 vfe->res = &res->vfe;1495 vfe->res->hw_ops->subdev_init(dev, vfe);1496 1497 /* Power domain */1498 1499 if (res->vfe.pd_name) {1500 vfe->genpd = dev_pm_domain_attach_by_name(camss->dev,1501 res->vfe.pd_name);1502 if (IS_ERR(vfe->genpd)) {1503 ret = PTR_ERR(vfe->genpd);1504 return ret;1505 }1506 }1507 1508 if (!vfe->genpd && res->vfe.has_pd) {1509 /*1510 * Legacy magic index.1511 * Requires1512 * power-domain = <VFE_X>,1513 * <VFE_Y>,1514 * <TITAN_TOP>1515 * id must correspondng to the index of the VFE which must1516 * come before the TOP GDSC. VFE Lite has no individually1517 * collapasible domain which is why id < vfe_num is a valid1518 * check.1519 */1520 vfe->genpd = dev_pm_domain_attach_by_id(camss->dev, id);1521 if (IS_ERR(vfe->genpd))1522 return PTR_ERR(vfe->genpd);1523 }1524 1525 /* Memory */1526 1527 vfe->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);1528 if (IS_ERR(vfe->base)) {1529 dev_err(dev, "could not map memory\n");1530 return PTR_ERR(vfe->base);1531 }1532 1533 /* Interrupt */1534 1535 ret = platform_get_irq_byname(pdev, res->interrupt[0]);1536 if (ret < 0)1537 return ret;1538 1539 vfe->irq = ret;1540 snprintf(vfe->irq_name, sizeof(vfe->irq_name), "%s_%s%d",1541 dev_name(dev), MSM_VFE_NAME, id);1542 ret = devm_request_irq(dev, vfe->irq, vfe->res->hw_ops->isr,1543 IRQF_TRIGGER_RISING, vfe->irq_name, vfe);1544 if (ret < 0) {1545 dev_err(dev, "request_irq failed: %d\n", ret);1546 return ret;1547 }1548 1549 /* Clocks */1550 1551 vfe->nclocks = 0;1552 while (res->clock[vfe->nclocks])1553 vfe->nclocks++;1554 1555 vfe->clock = devm_kcalloc(dev, vfe->nclocks, sizeof(*vfe->clock),1556 GFP_KERNEL);1557 if (!vfe->clock)1558 return -ENOMEM;1559 1560 for (i = 0; i < vfe->nclocks; i++) {1561 struct camss_clock *clock = &vfe->clock[i];1562 1563 clock->clk = devm_clk_get(dev, res->clock[i]);1564 if (IS_ERR(clock->clk))1565 return PTR_ERR(clock->clk);1566 1567 clock->name = res->clock[i];1568 1569 clock->nfreqs = 0;1570 while (res->clock_rate[i][clock->nfreqs])1571 clock->nfreqs++;1572 1573 if (!clock->nfreqs) {1574 clock->freq = NULL;1575 continue;1576 }1577 1578 clock->freq = devm_kcalloc(dev,1579 clock->nfreqs,1580 sizeof(*clock->freq),1581 GFP_KERNEL);1582 if (!clock->freq)1583 return -ENOMEM;1584 1585 for (j = 0; j < clock->nfreqs; j++)1586 clock->freq[j] = res->clock_rate[i][j];1587 }1588 1589 mutex_init(&vfe->power_lock);1590 vfe->power_count = 0;1591 1592 mutex_init(&vfe->stream_lock);1593 vfe->stream_count = 0;1594 1595 spin_lock_init(&vfe->output_lock);1596 1597 vfe->camss = camss;1598 vfe->id = id;1599 vfe->reg_update = 0;1600 1601 for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {1602 struct vfe_line *l = &vfe->line[i];1603 1604 l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;1605 l->video_out.camss = camss;1606 l->id = i;1607 init_completion(&l->output.sof);1608 init_completion(&l->output.reg_update);1609 1610 if (i == VFE_LINE_PIX) {1611 l->nformats = res->vfe.formats_pix->nformats;1612 l->formats = res->vfe.formats_pix->formats;1613 } else {1614 l->nformats = res->vfe.formats_rdi->nformats;1615 l->formats = res->vfe.formats_rdi->formats;1616 }1617 }1618 1619 init_completion(&vfe->reset_complete);1620 init_completion(&vfe->halt_complete);1621 1622 return 0;1623}1624 1625/*1626 * msm_vfe_genpd_cleanup - Cleanup VFE genpd linkages1627 * @vfe: VFE device1628 */1629void msm_vfe_genpd_cleanup(struct vfe_device *vfe)1630{1631 if (vfe->genpd_link)1632 device_link_del(vfe->genpd_link);1633 1634 if (vfe->genpd)1635 dev_pm_domain_detach(vfe->genpd, true);1636}1637 1638/*1639 * vfe_link_setup - Setup VFE connections1640 * @entity: Pointer to media entity structure1641 * @local: Pointer to local pad1642 * @remote: Pointer to remote pad1643 * @flags: Link flags1644 *1645 * Return 0 on success1646 */1647static int vfe_link_setup(struct media_entity *entity,1648 const struct media_pad *local,1649 const struct media_pad *remote, u32 flags)1650{1651 if (flags & MEDIA_LNK_FL_ENABLED)1652 if (media_pad_remote_pad_first(local))1653 return -EBUSY;1654 1655 return 0;1656}1657 1658static const struct v4l2_subdev_core_ops vfe_core_ops = {1659 .s_power = vfe_set_power,1660};1661 1662static const struct v4l2_subdev_video_ops vfe_video_ops = {1663 .s_stream = vfe_set_stream,1664};1665 1666static const struct v4l2_subdev_pad_ops vfe_pad_ops = {1667 .enum_mbus_code = vfe_enum_mbus_code,1668 .enum_frame_size = vfe_enum_frame_size,1669 .get_fmt = vfe_get_format,1670 .set_fmt = vfe_set_format,1671 .get_selection = vfe_get_selection,1672 .set_selection = vfe_set_selection,1673};1674 1675static const struct v4l2_subdev_ops vfe_v4l2_ops = {1676 .core = &vfe_core_ops,1677 .video = &vfe_video_ops,1678 .pad = &vfe_pad_ops,1679};1680 1681static const struct v4l2_subdev_internal_ops vfe_v4l2_internal_ops = {1682 .open = vfe_init_formats,1683};1684 1685static const struct media_entity_operations vfe_media_ops = {1686 .link_setup = vfe_link_setup,1687 .link_validate = v4l2_subdev_link_validate,1688};1689 1690static int vfe_bpl_align(struct vfe_device *vfe)1691{1692 int ret = 8;1693 1694 switch (vfe->camss->res->version) {1695 case CAMSS_845:1696 case CAMSS_8250:1697 case CAMSS_8280XP:1698 ret = 16;1699 break;1700 default:1701 break;1702 }1703 1704 return ret;1705}1706 1707/*1708 * msm_vfe_register_entities - Register subdev node for VFE module1709 * @vfe: VFE device1710 * @v4l2_dev: V4L2 device1711 *1712 * Initialize and register a subdev node for the VFE module. Then1713 * call msm_video_register() to register the video device node which1714 * will be connected to this subdev node. Then actually create the1715 * media link between them.1716 *1717 * Return 0 on success or a negative error code otherwise1718 */1719int msm_vfe_register_entities(struct vfe_device *vfe,1720 struct v4l2_device *v4l2_dev)1721{1722 struct device *dev = vfe->camss->dev;1723 struct v4l2_subdev *sd;1724 struct media_pad *pads;1725 struct camss_video *video_out;1726 int ret;1727 int i;1728 1729 for (i = 0; i < vfe->res->line_num; i++) {1730 char name[32];1731 1732 sd = &vfe->line[i].subdev;1733 pads = vfe->line[i].pads;1734 video_out = &vfe->line[i].video_out;1735 1736 v4l2_subdev_init(sd, &vfe_v4l2_ops);1737 sd->internal_ops = &vfe_v4l2_internal_ops;1738 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;1739 if (i == VFE_LINE_PIX)1740 snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s",1741 MSM_VFE_NAME, vfe->id, "pix");1742 else1743 snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s%d",1744 MSM_VFE_NAME, vfe->id, "rdi", i);1745 1746 v4l2_set_subdevdata(sd, &vfe->line[i]);1747 1748 ret = vfe_init_formats(sd, NULL);1749 if (ret < 0) {1750 dev_err(dev, "Failed to init format: %d\n", ret);1751 goto error_init;1752 }1753 1754 pads[MSM_VFE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;1755 pads[MSM_VFE_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;1756 1757 sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;1758 sd->entity.ops = &vfe_media_ops;1759 ret = media_entity_pads_init(&sd->entity, MSM_VFE_PADS_NUM,1760 pads);1761 if (ret < 0) {1762 dev_err(dev, "Failed to init media entity: %d\n", ret);1763 goto error_init;1764 }1765 1766 ret = v4l2_device_register_subdev(v4l2_dev, sd);1767 if (ret < 0) {1768 dev_err(dev, "Failed to register subdev: %d\n", ret);1769 goto error_reg_subdev;1770 }1771 1772 video_out->ops = &vfe->video_ops;1773 video_out->bpl_alignment = vfe_bpl_align(vfe);1774 video_out->line_based = 0;1775 if (i == VFE_LINE_PIX) {1776 video_out->bpl_alignment = 16;1777 video_out->line_based = 1;1778 }1779 1780 video_out->nformats = vfe->line[i].nformats;1781 video_out->formats = vfe->line[i].formats;1782 1783 snprintf(name, ARRAY_SIZE(name), "%s%d_%s%d",1784 MSM_VFE_NAME, vfe->id, "video", i);1785 ret = msm_video_register(video_out, v4l2_dev, name);1786 if (ret < 0) {1787 dev_err(dev, "Failed to register video node: %d\n",1788 ret);1789 goto error_reg_video;1790 }1791 1792 ret = media_create_pad_link(1793 &sd->entity, MSM_VFE_PAD_SRC,1794 &video_out->vdev.entity, 0,1795 MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);1796 if (ret < 0) {1797 dev_err(dev, "Failed to link %s->%s entities: %d\n",1798 sd->entity.name, video_out->vdev.entity.name,1799 ret);1800 goto error_link;1801 }1802 }1803 1804 return 0;1805 1806error_link:1807 msm_video_unregister(video_out);1808 1809error_reg_video:1810 v4l2_device_unregister_subdev(sd);1811 1812error_reg_subdev:1813 media_entity_cleanup(&sd->entity);1814 1815error_init:1816 for (i--; i >= 0; i--) {1817 sd = &vfe->line[i].subdev;1818 video_out = &vfe->line[i].video_out;1819 1820 msm_video_unregister(video_out);1821 v4l2_device_unregister_subdev(sd);1822 media_entity_cleanup(&sd->entity);1823 }1824 1825 return ret;1826}1827 1828/*1829 * msm_vfe_unregister_entities - Unregister VFE module subdev node1830 * @vfe: VFE device1831 */1832void msm_vfe_unregister_entities(struct vfe_device *vfe)1833{1834 int i;1835 1836 mutex_destroy(&vfe->power_lock);1837 mutex_destroy(&vfe->stream_lock);1838 1839 for (i = 0; i < vfe->res->line_num; i++) {1840 struct v4l2_subdev *sd = &vfe->line[i].subdev;1841 struct camss_video *video_out = &vfe->line[i].video_out;1842 1843 msm_video_unregister(video_out);1844 v4l2_device_unregister_subdev(sd);1845 media_entity_cleanup(&sd->entity);1846 }1847}1848 1849bool vfe_is_lite(struct vfe_device *vfe)1850{1851 return vfe->camss->res->vfe_res[vfe->id].vfe.is_lite;1852}1853