brintos

brintos / linux-shallow public Read only

0
0
Text · 46.6 KiB · 83c5a36 Raw
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