14e1abf66STodor Tomov // SPDX-License-Identifier: GPL-2.0
24e1abf66STodor Tomov /*
34e1abf66STodor Tomov  * camss-vfe-4-7.c
44e1abf66STodor Tomov  *
54e1abf66STodor Tomov  * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7
64e1abf66STodor Tomov  *
74e1abf66STodor Tomov  * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
84e1abf66STodor Tomov  * Copyright (C) 2015-2018 Linaro Ltd.
94e1abf66STodor Tomov  */
104e1abf66STodor Tomov 
112f6f8af6SRobert Foss #include <linux/device.h>
124e1abf66STodor Tomov #include <linux/interrupt.h>
133799eca5SArnd Bergmann #include <linux/io.h>
144e1abf66STodor Tomov #include <linux/iopoll.h>
154e1abf66STodor Tomov 
16c3177cb0SRobert Foss #include "camss.h"
174e1abf66STodor Tomov #include "camss-vfe.h"
18633b388fSRobert Foss #include "camss-vfe-gen1.h"
19633b388fSRobert Foss 
204e1abf66STodor Tomov 
214e1abf66STodor Tomov #define VFE_0_HW_VERSION		0x000
224e1abf66STodor Tomov 
234e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD		0x018
244e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_CORE	BIT(0)
254e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_CAMIF	BIT(1)
264e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_BUS	BIT(2)
274e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
284e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_REGISTER	BIT(4)
294e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_PM	BIT(5)
304e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
314e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_TESTGEN	BIT(7)
324e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_DSP	BIT(8)
334e1abf66STodor Tomov #define VFE_0_GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
344e1abf66STodor Tomov 
354e1abf66STodor Tomov #define VFE_0_MODULE_LENS_EN		0x040
364e1abf66STodor Tomov #define VFE_0_MODULE_LENS_EN_DEMUX		BIT(2)
374e1abf66STodor Tomov #define VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE	BIT(3)
384e1abf66STodor Tomov 
394e1abf66STodor Tomov #define VFE_0_MODULE_ZOOM_EN		0x04c
404e1abf66STodor Tomov #define VFE_0_MODULE_ZOOM_EN_SCALE_ENC		BIT(1)
414e1abf66STodor Tomov #define VFE_0_MODULE_ZOOM_EN_CROP_ENC		BIT(2)
42312e1c85STodor Tomov #define VFE_0_MODULE_ZOOM_EN_REALIGN_BUF	BIT(9)
434e1abf66STodor Tomov 
444e1abf66STodor Tomov #define VFE_0_CORE_CFG			0x050
454e1abf66STodor Tomov #define VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR	0x4
464e1abf66STodor Tomov #define VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB	0x5
474e1abf66STodor Tomov #define VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY	0x6
484e1abf66STodor Tomov #define VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY	0x7
494e1abf66STodor Tomov #define VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
504e1abf66STodor Tomov 
514e1abf66STodor Tomov #define VFE_0_IRQ_CMD			0x058
524e1abf66STodor Tomov #define VFE_0_IRQ_CMD_GLOBAL_CLEAR	BIT(0)
534e1abf66STodor Tomov 
544e1abf66STodor Tomov #define VFE_0_IRQ_MASK_0		0x05c
554e1abf66STodor Tomov #define VFE_0_IRQ_MASK_0_CAMIF_SOF			BIT(0)
564e1abf66STodor Tomov #define VFE_0_IRQ_MASK_0_CAMIF_EOF			BIT(1)
574e1abf66STodor Tomov #define VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
584e1abf66STodor Tomov #define VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(n)		\
594e1abf66STodor Tomov 	((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n))
604e1abf66STodor Tomov #define VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
614e1abf66STodor Tomov #define VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
624e1abf66STodor Tomov #define VFE_0_IRQ_MASK_0_RESET_ACK			BIT(31)
634e1abf66STodor Tomov #define VFE_0_IRQ_MASK_1		0x060
644e1abf66STodor Tomov #define VFE_0_IRQ_MASK_1_CAMIF_ERROR			BIT(0)
654e1abf66STodor Tomov #define VFE_0_IRQ_MASK_1_VIOLATION			BIT(7)
664e1abf66STodor Tomov #define VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK		BIT(8)
674e1abf66STodor Tomov #define VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
684e1abf66STodor Tomov #define VFE_0_IRQ_MASK_1_RDIn_SOF(n)			BIT((n) + 29)
694e1abf66STodor Tomov 
704e1abf66STodor Tomov #define VFE_0_IRQ_CLEAR_0		0x064
714e1abf66STodor Tomov #define VFE_0_IRQ_CLEAR_1		0x068
724e1abf66STodor Tomov 
734e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_0		0x06c
744e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_0_CAMIF_SOF			BIT(0)
754e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
764e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(n)		\
774e1abf66STodor Tomov 	((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n))
784e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
794e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
804e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_0_RESET_ACK			BIT(31)
814e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_1		0x070
824e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_1_VIOLATION			BIT(7)
834e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
844e1abf66STodor Tomov #define VFE_0_IRQ_STATUS_1_RDIn_SOF(n)			BIT((n) + 29)
854e1abf66STodor Tomov 
864e1abf66STodor Tomov #define VFE_0_IRQ_COMPOSITE_MASK_0	0x074
874e1abf66STodor Tomov #define VFE_0_VIOLATION_STATUS		0x07c
884e1abf66STodor Tomov 
894e1abf66STodor Tomov #define VFE_0_BUS_CMD			0x80
904e1abf66STodor Tomov #define VFE_0_BUS_CMD_Mx_RLD_CMD(x)	BIT(x)
914e1abf66STodor Tomov 
924e1abf66STodor Tomov #define VFE_0_BUS_CFG			0x084
934e1abf66STodor Tomov 
944e1abf66STodor Tomov #define VFE_0_BUS_XBAR_CFG_x(x)		(0x90 + 0x4 * ((x) / 2))
954e1abf66STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN			BIT(2)
96312e1c85STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN			BIT(3)
97312e1c85STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTRA		(0x1 << 4)
98312e1c85STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER		(0x2 << 4)
994e1abf66STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA	(0x3 << 4)
1004e1abf66STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT		8
1014e1abf66STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA		0x0
1024e1abf66STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0	0xc
1034e1abf66STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1	0xd
1044e1abf66STodor Tomov #define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2	0xe
1054e1abf66STodor Tomov 
1064e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(n)		(0x0a0 + 0x2c * (n))
1074e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT	0
1084e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(n)	(0x0a4 + 0x2c * (n))
1094e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(n)	(0x0ac + 0x2c * (n))
1104e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(n)		(0x0b4 + 0x2c * (n))
1114e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT	1
1124e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT	2
1134e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK	(0x1f << 2)
1144e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(n)		(0x0b8 + 0x2c * (n))
1154e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT	16
1164e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(n)	(0x0bc + 0x2c * (n))
1174e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(n)	(0x0c0 + 0x2c * (n))
1184e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(n)	\
1194e1abf66STodor Tomov 							(0x0c4 + 0x2c * (n))
1204e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(n)	\
1214e1abf66STodor Tomov 							(0x0c8 + 0x2c * (n))
1224e1abf66STodor Tomov #define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF	0xffffffff
1234e1abf66STodor Tomov 
1244e1abf66STodor Tomov #define VFE_0_BUS_PING_PONG_STATUS	0x338
1254e1abf66STodor Tomov 
1264e1abf66STodor Tomov #define VFE_0_BUS_BDG_CMD		0x400
1274e1abf66STodor Tomov #define VFE_0_BUS_BDG_CMD_HALT_REQ	1
1284e1abf66STodor Tomov 
1294e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_0		0x404
1304e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_0_CFG	0xaaa9aaa9
1314e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_1		0x408
1324e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_2		0x40c
1334e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_3		0x410
1344e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_4		0x414
1354e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_5		0x418
1364e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_6		0x41c
1374e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_7		0x420
1384e1abf66STodor Tomov #define VFE_0_BUS_BDG_QOS_CFG_7_CFG	0x0001aaa9
1394e1abf66STodor Tomov 
14040296e71SAngeloGioacchino Del Regno #define VFE48_0_BUS_BDG_QOS_CFG_0_CFG	0xaaa5aaa5
14140296e71SAngeloGioacchino Del Regno #define VFE48_0_BUS_BDG_QOS_CFG_3_CFG	0xaa55aaa5
14240296e71SAngeloGioacchino Del Regno #define VFE48_0_BUS_BDG_QOS_CFG_4_CFG	0xaa55aa55
14340296e71SAngeloGioacchino Del Regno #define VFE48_0_BUS_BDG_QOS_CFG_7_CFG	0x0005aa55
14440296e71SAngeloGioacchino Del Regno 
1454e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_0		0x424
1464e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_0_CFG	0xcccc0011
1474e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_1		0x428
1484e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_2		0x42c
1494e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_3		0x430
1504e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_4		0x434
1514e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_5		0x438
1524e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_6		0x43c
1534e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_7		0x440
1544e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_8		0x444
1554e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_9		0x448
1564e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_10		0x44c
1574e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_11		0x450
1584e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_12		0x454
1594e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_13		0x458
1604e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_14		0x45c
1614e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_15		0x460
1624e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_16		0x464
1634e1abf66STodor Tomov #define VFE_0_BUS_BDG_DS_CFG_16_CFG	0x40000103
1644e1abf66STodor Tomov 
16540296e71SAngeloGioacchino Del Regno #define VFE48_0_BUS_BDG_DS_CFG_0_CFG	0xcccc1111
16640296e71SAngeloGioacchino Del Regno #define VFE48_0_BUS_BDG_DS_CFG_16_CFG	0x00000110
16740296e71SAngeloGioacchino Del Regno 
1684e1abf66STodor Tomov #define VFE_0_RDI_CFG_x(x)		(0x46c + (0x4 * (x)))
1694e1abf66STodor Tomov #define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT	28
1704e1abf66STodor Tomov #define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK	(0xf << 28)
1714e1abf66STodor Tomov #define VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT	4
1724e1abf66STodor Tomov #define VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK		(0xf << 4)
1734e1abf66STodor Tomov #define VFE_0_RDI_CFG_x_RDI_EN_BIT		BIT(2)
1744e1abf66STodor Tomov #define VFE_0_RDI_CFG_x_MIPI_EN_BITS		0x3
1754e1abf66STodor Tomov 
1764e1abf66STodor Tomov #define VFE_0_CAMIF_CMD				0x478
1774e1abf66STodor Tomov #define VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY	0
1784e1abf66STodor Tomov #define VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY	1
1794e1abf66STodor Tomov #define VFE_0_CAMIF_CMD_NO_CHANGE		3
1804e1abf66STodor Tomov #define VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS	BIT(2)
1814e1abf66STodor Tomov #define VFE_0_CAMIF_CFG				0x47c
1824e1abf66STodor Tomov #define VFE_0_CAMIF_CFG_VFE_OUTPUT_EN		BIT(6)
1834e1abf66STodor Tomov #define VFE_0_CAMIF_FRAME_CFG			0x484
1844e1abf66STodor Tomov #define VFE_0_CAMIF_WINDOW_WIDTH_CFG		0x488
1854e1abf66STodor Tomov #define VFE_0_CAMIF_WINDOW_HEIGHT_CFG		0x48c
1864e1abf66STodor Tomov #define VFE_0_CAMIF_SUBSAMPLE_CFG		0x490
1874e1abf66STodor Tomov #define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN	0x498
1884e1abf66STodor Tomov #define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN	0x49c
1894e1abf66STodor Tomov #define VFE_0_CAMIF_STATUS			0x4a4
1904e1abf66STodor Tomov #define VFE_0_CAMIF_STATUS_HALT			BIT(31)
1914e1abf66STodor Tomov 
1924e1abf66STodor Tomov #define VFE_0_REG_UPDATE		0x4ac
1934e1abf66STodor Tomov #define VFE_0_REG_UPDATE_RDIn(n)		BIT(1 + (n))
1944e1abf66STodor Tomov #define VFE_0_REG_UPDATE_line_n(n)		\
1954e1abf66STodor Tomov 			((n) == VFE_LINE_PIX ? 1 : VFE_0_REG_UPDATE_RDIn(n))
1964e1abf66STodor Tomov 
1974e1abf66STodor Tomov #define VFE_0_DEMUX_CFG				0x560
1984e1abf66STodor Tomov #define VFE_0_DEMUX_CFG_PERIOD			0x3
1994e1abf66STodor Tomov #define VFE_0_DEMUX_GAIN_0			0x564
2004e1abf66STodor Tomov #define VFE_0_DEMUX_GAIN_0_CH0_EVEN		(0x80 << 0)
2014e1abf66STodor Tomov #define VFE_0_DEMUX_GAIN_0_CH0_ODD		(0x80 << 16)
2024e1abf66STodor Tomov #define VFE_0_DEMUX_GAIN_1			0x568
2034e1abf66STodor Tomov #define VFE_0_DEMUX_GAIN_1_CH1			(0x80 << 0)
2044e1abf66STodor Tomov #define VFE_0_DEMUX_GAIN_1_CH2			(0x80 << 16)
2054e1abf66STodor Tomov #define VFE_0_DEMUX_EVEN_CFG			0x574
2064e1abf66STodor Tomov #define VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV	0x9cac
2074e1abf66STodor Tomov #define VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU	0xac9c
2084e1abf66STodor Tomov #define VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY	0xc9ca
2094e1abf66STodor Tomov #define VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY	0xcac9
2104e1abf66STodor Tomov #define VFE_0_DEMUX_ODD_CFG			0x578
2114e1abf66STodor Tomov #define VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV	0x9cac
2124e1abf66STodor Tomov #define VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU	0xac9c
2134e1abf66STodor Tomov #define VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY	0xc9ca
2144e1abf66STodor Tomov #define VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY	0xcac9
2154e1abf66STodor Tomov 
2164e1abf66STodor Tomov #define VFE_0_SCALE_ENC_Y_CFG			0x91c
2174e1abf66STodor Tomov #define VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE		0x920
2184e1abf66STodor Tomov #define VFE_0_SCALE_ENC_Y_H_PHASE		0x924
2194e1abf66STodor Tomov #define VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE		0x934
2204e1abf66STodor Tomov #define VFE_0_SCALE_ENC_Y_V_PHASE		0x938
2214e1abf66STodor Tomov #define VFE_0_SCALE_ENC_CBCR_CFG		0x948
2224e1abf66STodor Tomov #define VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE	0x94c
2234e1abf66STodor Tomov #define VFE_0_SCALE_ENC_CBCR_H_PHASE		0x950
2244e1abf66STodor Tomov #define VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE	0x960
2254e1abf66STodor Tomov #define VFE_0_SCALE_ENC_CBCR_V_PHASE		0x964
2264e1abf66STodor Tomov 
2274e1abf66STodor Tomov #define VFE_0_CROP_ENC_Y_WIDTH			0x974
2284e1abf66STodor Tomov #define VFE_0_CROP_ENC_Y_HEIGHT			0x978
2294e1abf66STodor Tomov #define VFE_0_CROP_ENC_CBCR_WIDTH		0x97c
2304e1abf66STodor Tomov #define VFE_0_CROP_ENC_CBCR_HEIGHT		0x980
2314e1abf66STodor Tomov 
2324e1abf66STodor Tomov #define VFE_0_CLAMP_ENC_MAX_CFG			0x984
2334e1abf66STodor Tomov #define VFE_0_CLAMP_ENC_MAX_CFG_CH0		(0xff << 0)
2344e1abf66STodor Tomov #define VFE_0_CLAMP_ENC_MAX_CFG_CH1		(0xff << 8)
2354e1abf66STodor Tomov #define VFE_0_CLAMP_ENC_MAX_CFG_CH2		(0xff << 16)
2364e1abf66STodor Tomov #define VFE_0_CLAMP_ENC_MIN_CFG			0x988
2374e1abf66STodor Tomov #define VFE_0_CLAMP_ENC_MIN_CFG_CH0		(0x0 << 0)
2384e1abf66STodor Tomov #define VFE_0_CLAMP_ENC_MIN_CFG_CH1		(0x0 << 8)
2394e1abf66STodor Tomov #define VFE_0_CLAMP_ENC_MIN_CFG_CH2		(0x0 << 16)
2404e1abf66STodor Tomov 
241312e1c85STodor Tomov #define VFE_0_REALIGN_BUF_CFG			0xaac
242312e1c85STodor Tomov #define VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL     BIT(2)
243312e1c85STodor Tomov #define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL     BIT(3)
244312e1c85STodor Tomov #define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE      BIT(4)
245312e1c85STodor Tomov 
24640296e71SAngeloGioacchino Del Regno #define VFE48_0_BUS_IMAGE_MASTER_CMD		0xcec
24740296e71SAngeloGioacchino Del Regno #define VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(x)	(2 * (x))
24840296e71SAngeloGioacchino Del Regno 
2494e1abf66STodor Tomov #define CAMIF_TIMEOUT_SLEEP_US 1000
2504e1abf66STodor Tomov #define CAMIF_TIMEOUT_ALL_US 1000000
2514e1abf66STodor Tomov 
2524e1abf66STodor Tomov #define MSM_VFE_VFE0_UB_SIZE 2047
2534e1abf66STodor Tomov #define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3)
2544e1abf66STodor Tomov #define MSM_VFE_VFE1_UB_SIZE 1535
2554e1abf66STodor Tomov #define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3)
2564e1abf66STodor Tomov 
vfe_hw_version(struct vfe_device * vfe)257d2e86540SRobert Foss static u32 vfe_hw_version(struct vfe_device *vfe)
2584e1abf66STodor Tomov {
2594e1abf66STodor Tomov 	u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION);
2604e1abf66STodor Tomov 
2615ad58667SRobert Foss 	dev_dbg(vfe->camss->dev, "VFE HW Version = 0x%08x\n", hw_version);
262d2e86540SRobert Foss 
263d2e86540SRobert Foss 	return hw_version;
2644e1abf66STodor Tomov }
2654e1abf66STodor Tomov 
vfe_get_ub_size(u8 vfe_id)266633b388fSRobert Foss static u16 vfe_get_ub_size(u8 vfe_id)
2674e1abf66STodor Tomov {
2684e1abf66STodor Tomov 	if (vfe_id == 0)
2694e1abf66STodor Tomov 		return MSM_VFE_VFE0_UB_SIZE_RDI;
2704e1abf66STodor Tomov 	else if (vfe_id == 1)
2714e1abf66STodor Tomov 		return MSM_VFE_VFE1_UB_SIZE_RDI;
2724e1abf66STodor Tomov 
2734e1abf66STodor Tomov 	return 0;
2744e1abf66STodor Tomov }
2754e1abf66STodor Tomov 
vfe_reg_clr(struct vfe_device * vfe,u32 reg,u32 clr_bits)2764e1abf66STodor Tomov static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
2774e1abf66STodor Tomov {
2784e1abf66STodor Tomov 	u32 bits = readl_relaxed(vfe->base + reg);
2794e1abf66STodor Tomov 
2804e1abf66STodor Tomov 	writel_relaxed(bits & ~clr_bits, vfe->base + reg);
2814e1abf66STodor Tomov }
2824e1abf66STodor Tomov 
vfe_reg_set(struct vfe_device * vfe,u32 reg,u32 set_bits)2834e1abf66STodor Tomov static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
2844e1abf66STodor Tomov {
2854e1abf66STodor Tomov 	u32 bits = readl_relaxed(vfe->base + reg);
2864e1abf66STodor Tomov 
2874e1abf66STodor Tomov 	writel_relaxed(bits | set_bits, vfe->base + reg);
2884e1abf66STodor Tomov }
2894e1abf66STodor Tomov 
vfe_global_reset(struct vfe_device * vfe)2904e1abf66STodor Tomov static void vfe_global_reset(struct vfe_device *vfe)
2914e1abf66STodor Tomov {
2924e1abf66STodor Tomov 	u32 reset_bits = VFE_0_GLOBAL_RESET_CMD_IDLE_CGC	|
2934e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_DSP		|
2944e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_TESTGEN		|
2954e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_BUS_MISR	|
2964e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_PM		|
2974e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_REGISTER	|
2984e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_BUS_BDG		|
2994e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_BUS		|
3004e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_CAMIF		|
3014e1abf66STodor Tomov 			 VFE_0_GLOBAL_RESET_CMD_CORE;
3024e1abf66STodor Tomov 
3034e1abf66STodor Tomov 	writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
304633b388fSRobert Foss 
305633b388fSRobert Foss 	/* Enforce barrier between IRQ mask setup and global reset */
3064e1abf66STodor Tomov 	wmb();
3074e1abf66STodor Tomov 	writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
3084e1abf66STodor Tomov }
3094e1abf66STodor Tomov 
vfe_halt_request(struct vfe_device * vfe)3104e1abf66STodor Tomov static void vfe_halt_request(struct vfe_device *vfe)
3114e1abf66STodor Tomov {
3124e1abf66STodor Tomov 	writel_relaxed(VFE_0_BUS_BDG_CMD_HALT_REQ,
3134e1abf66STodor Tomov 		       vfe->base + VFE_0_BUS_BDG_CMD);
3144e1abf66STodor Tomov }
3154e1abf66STodor Tomov 
vfe_halt_clear(struct vfe_device * vfe)3164e1abf66STodor Tomov static void vfe_halt_clear(struct vfe_device *vfe)
3174e1abf66STodor Tomov {
3184e1abf66STodor Tomov 	writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
3194e1abf66STodor Tomov }
3204e1abf66STodor Tomov 
vfe_wm_enable(struct vfe_device * vfe,u8 wm,u8 enable)321633b388fSRobert Foss static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
3224e1abf66STodor Tomov {
3234e1abf66STodor Tomov 	if (enable)
3244e1abf66STodor Tomov 		vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm),
3254e1abf66STodor Tomov 			    1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT);
3264e1abf66STodor Tomov 	else
3274e1abf66STodor Tomov 		vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm),
3284e1abf66STodor Tomov 			    1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT);
3294e1abf66STodor Tomov }
3304e1abf66STodor Tomov 
vfe_wm_frame_based(struct vfe_device * vfe,u8 wm,u8 enable)3314e1abf66STodor Tomov static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
3324e1abf66STodor Tomov {
3334e1abf66STodor Tomov 	if (enable)
3344e1abf66STodor Tomov 		vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
3354e1abf66STodor Tomov 			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
3364e1abf66STodor Tomov 	else
3374e1abf66STodor Tomov 		vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
3384e1abf66STodor Tomov 			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
3394e1abf66STodor Tomov }
3404e1abf66STodor Tomov 
3414e1abf66STodor Tomov #define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
3424e1abf66STodor Tomov 
vfe_word_per_line_by_pixel(u32 format,u32 pixel_per_line)343312e1c85STodor Tomov static int vfe_word_per_line_by_pixel(u32 format, u32 pixel_per_line)
3444e1abf66STodor Tomov {
3454e1abf66STodor Tomov 	int val = 0;
3464e1abf66STodor Tomov 
3474e1abf66STodor Tomov 	switch (format) {
3484e1abf66STodor Tomov 	case V4L2_PIX_FMT_NV12:
3494e1abf66STodor Tomov 	case V4L2_PIX_FMT_NV21:
3504e1abf66STodor Tomov 	case V4L2_PIX_FMT_NV16:
3514e1abf66STodor Tomov 	case V4L2_PIX_FMT_NV61:
3524e1abf66STodor Tomov 		val = CALC_WORD(pixel_per_line, 1, 8);
3534e1abf66STodor Tomov 		break;
3544e1abf66STodor Tomov 	case V4L2_PIX_FMT_YUYV:
3554e1abf66STodor Tomov 	case V4L2_PIX_FMT_YVYU:
3564e1abf66STodor Tomov 	case V4L2_PIX_FMT_UYVY:
3574e1abf66STodor Tomov 	case V4L2_PIX_FMT_VYUY:
3584e1abf66STodor Tomov 		val = CALC_WORD(pixel_per_line, 2, 8);
3594e1abf66STodor Tomov 		break;
3604e1abf66STodor Tomov 	}
3614e1abf66STodor Tomov 
3624e1abf66STodor Tomov 	return val;
3634e1abf66STodor Tomov }
3644e1abf66STodor Tomov 
vfe_word_per_line_by_bytes(u32 bytes_per_line)365312e1c85STodor Tomov static int vfe_word_per_line_by_bytes(u32 bytes_per_line)
366312e1c85STodor Tomov {
367312e1c85STodor Tomov 	return CALC_WORD(bytes_per_line, 1, 8);
368312e1c85STodor Tomov }
369312e1c85STodor Tomov 
vfe_get_wm_sizes(struct v4l2_pix_format_mplane * pix,u8 plane,u16 * width,u16 * height,u16 * bytesperline)3704e1abf66STodor Tomov static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
3714e1abf66STodor Tomov 			     u16 *width, u16 *height, u16 *bytesperline)
3724e1abf66STodor Tomov {
373*749d8965STom Rix 	*width = pix->width;
374*749d8965STom Rix 	*height = pix->height;
375*749d8965STom Rix 
3764e1abf66STodor Tomov 	switch (pix->pixelformat) {
3774e1abf66STodor Tomov 	case V4L2_PIX_FMT_NV12:
3784e1abf66STodor Tomov 	case V4L2_PIX_FMT_NV21:
3794e1abf66STodor Tomov 		*bytesperline = pix->plane_fmt[0].bytesperline;
3804e1abf66STodor Tomov 		if (plane == 1)
3814e1abf66STodor Tomov 			*height /= 2;
3824e1abf66STodor Tomov 		break;
3834e1abf66STodor Tomov 	case V4L2_PIX_FMT_NV16:
3844e1abf66STodor Tomov 	case V4L2_PIX_FMT_NV61:
3854e1abf66STodor Tomov 		*bytesperline = pix->plane_fmt[0].bytesperline;
3864e1abf66STodor Tomov 		break;
387312e1c85STodor Tomov 	case V4L2_PIX_FMT_YUYV:
388312e1c85STodor Tomov 	case V4L2_PIX_FMT_YVYU:
389312e1c85STodor Tomov 	case V4L2_PIX_FMT_VYUY:
390312e1c85STodor Tomov 	case V4L2_PIX_FMT_UYVY:
391312e1c85STodor Tomov 		*bytesperline = pix->plane_fmt[plane].bytesperline;
392312e1c85STodor Tomov 		break;
3934e1abf66STodor Tomov 	}
3944e1abf66STodor Tomov }
3954e1abf66STodor Tomov 
vfe_wm_line_based(struct vfe_device * vfe,u32 wm,struct v4l2_pix_format_mplane * pix,u8 plane,u32 enable)3964e1abf66STodor Tomov static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm,
3974e1abf66STodor Tomov 			      struct v4l2_pix_format_mplane *pix,
3984e1abf66STodor Tomov 			      u8 plane, u32 enable)
3994e1abf66STodor Tomov {
4004e1abf66STodor Tomov 	u32 reg;
4014e1abf66STodor Tomov 
4024e1abf66STodor Tomov 	if (enable) {
4034e1abf66STodor Tomov 		u16 width = 0, height = 0, bytesperline = 0, wpl;
4044e1abf66STodor Tomov 
4054e1abf66STodor Tomov 		vfe_get_wm_sizes(pix, plane, &width, &height, &bytesperline);
4064e1abf66STodor Tomov 
407312e1c85STodor Tomov 		wpl = vfe_word_per_line_by_pixel(pix->pixelformat, width);
4084e1abf66STodor Tomov 
4094e1abf66STodor Tomov 		reg = height - 1;
4104e1abf66STodor Tomov 		reg |= ((wpl + 3) / 4 - 1) << 16;
4114e1abf66STodor Tomov 
4124e1abf66STodor Tomov 		writel_relaxed(reg, vfe->base +
4134e1abf66STodor Tomov 			       VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
4144e1abf66STodor Tomov 
415312e1c85STodor Tomov 		wpl = vfe_word_per_line_by_bytes(bytesperline);
4164e1abf66STodor Tomov 
4174e1abf66STodor Tomov 		reg = 0x3;
4184e1abf66STodor Tomov 		reg |= (height - 1) << 2;
4194e1abf66STodor Tomov 		reg |= ((wpl + 1) / 2) << 16;
4204e1abf66STodor Tomov 
4214e1abf66STodor Tomov 		writel_relaxed(reg, vfe->base +
4224e1abf66STodor Tomov 			       VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
4234e1abf66STodor Tomov 	} else {
4244e1abf66STodor Tomov 		writel_relaxed(0, vfe->base +
4254e1abf66STodor Tomov 			       VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
4264e1abf66STodor Tomov 		writel_relaxed(0, vfe->base +
4274e1abf66STodor Tomov 			       VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
4284e1abf66STodor Tomov 	}
4294e1abf66STodor Tomov }
4304e1abf66STodor Tomov 
vfe_wm_set_framedrop_period(struct vfe_device * vfe,u8 wm,u8 per)4314e1abf66STodor Tomov static void vfe_wm_set_framedrop_period(struct vfe_device *vfe, u8 wm, u8 per)
4324e1abf66STodor Tomov {
4334e1abf66STodor Tomov 	u32 reg;
4344e1abf66STodor Tomov 
4354e1abf66STodor Tomov 	reg = readl_relaxed(vfe->base +
4364e1abf66STodor Tomov 			    VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
4374e1abf66STodor Tomov 
4384e1abf66STodor Tomov 	reg &= ~(VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK);
4394e1abf66STodor Tomov 
4404e1abf66STodor Tomov 	reg |= (per << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT)
4414e1abf66STodor Tomov 		& VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK;
4424e1abf66STodor Tomov 
4434e1abf66STodor Tomov 	writel_relaxed(reg,
4444e1abf66STodor Tomov 		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
4454e1abf66STodor Tomov }
4464e1abf66STodor Tomov 
vfe_wm_set_framedrop_pattern(struct vfe_device * vfe,u8 wm,u32 pattern)4474e1abf66STodor Tomov static void vfe_wm_set_framedrop_pattern(struct vfe_device *vfe, u8 wm,
4484e1abf66STodor Tomov 					 u32 pattern)
4494e1abf66STodor Tomov {
4504e1abf66STodor Tomov 	writel_relaxed(pattern,
4514e1abf66STodor Tomov 	       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(wm));
4524e1abf66STodor Tomov }
4534e1abf66STodor Tomov 
vfe_wm_set_ub_cfg(struct vfe_device * vfe,u8 wm,u16 offset,u16 depth)4544e1abf66STodor Tomov static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
4554e1abf66STodor Tomov 			      u16 offset, u16 depth)
4564e1abf66STodor Tomov {
4574e1abf66STodor Tomov 	u32 reg;
4584e1abf66STodor Tomov 
4594e1abf66STodor Tomov 	reg = (offset << VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT) |
4604e1abf66STodor Tomov 		depth;
4614e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(wm));
4624e1abf66STodor Tomov }
4634e1abf66STodor Tomov 
vfe_bus_reload_wm(struct vfe_device * vfe,u8 wm)4644e1abf66STodor Tomov static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
4654e1abf66STodor Tomov {
466633b388fSRobert Foss 	/* Enforce barrier between any outstanding register write */
4674e1abf66STodor Tomov 	wmb();
468633b388fSRobert Foss 
4694e1abf66STodor Tomov 	writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
470633b388fSRobert Foss 
471633b388fSRobert Foss 	/* Use barrier to make sure bus reload is issued before anything else */
4724e1abf66STodor Tomov 	wmb();
4734e1abf66STodor Tomov }
4744e1abf66STodor Tomov 
vfe_wm_set_ping_addr(struct vfe_device * vfe,u8 wm,u32 addr)4754e1abf66STodor Tomov static void vfe_wm_set_ping_addr(struct vfe_device *vfe, u8 wm, u32 addr)
4764e1abf66STodor Tomov {
4774e1abf66STodor Tomov 	writel_relaxed(addr,
4784e1abf66STodor Tomov 		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(wm));
4794e1abf66STodor Tomov }
4804e1abf66STodor Tomov 
vfe_wm_set_pong_addr(struct vfe_device * vfe,u8 wm,u32 addr)4814e1abf66STodor Tomov static void vfe_wm_set_pong_addr(struct vfe_device *vfe, u8 wm, u32 addr)
4824e1abf66STodor Tomov {
4834e1abf66STodor Tomov 	writel_relaxed(addr,
4844e1abf66STodor Tomov 		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(wm));
4854e1abf66STodor Tomov }
4864e1abf66STodor Tomov 
vfe_wm_get_ping_pong_status(struct vfe_device * vfe,u8 wm)4874e1abf66STodor Tomov static int vfe_wm_get_ping_pong_status(struct vfe_device *vfe, u8 wm)
4884e1abf66STodor Tomov {
4894e1abf66STodor Tomov 	u32 reg;
4904e1abf66STodor Tomov 
4914e1abf66STodor Tomov 	reg = readl_relaxed(vfe->base + VFE_0_BUS_PING_PONG_STATUS);
4924e1abf66STodor Tomov 
4934e1abf66STodor Tomov 	return (reg >> wm) & 0x1;
4944e1abf66STodor Tomov }
4954e1abf66STodor Tomov 
vfe_bus_enable_wr_if(struct vfe_device * vfe,u8 enable)4964e1abf66STodor Tomov static void vfe_bus_enable_wr_if(struct vfe_device *vfe, u8 enable)
4974e1abf66STodor Tomov {
4984e1abf66STodor Tomov 	if (enable)
4994e1abf66STodor Tomov 		writel_relaxed(0x101, vfe->base + VFE_0_BUS_CFG);
5004e1abf66STodor Tomov 	else
5014e1abf66STodor Tomov 		writel_relaxed(0, vfe->base + VFE_0_BUS_CFG);
5024e1abf66STodor Tomov }
5034e1abf66STodor Tomov 
vfe_bus_connect_wm_to_rdi(struct vfe_device * vfe,u8 wm,enum vfe_line_id id)5044e1abf66STodor Tomov static void vfe_bus_connect_wm_to_rdi(struct vfe_device *vfe, u8 wm,
5054e1abf66STodor Tomov 				      enum vfe_line_id id)
5064e1abf66STodor Tomov {
5074e1abf66STodor Tomov 	u32 reg;
5084e1abf66STodor Tomov 
5094e1abf66STodor Tomov 	reg = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
5104e1abf66STodor Tomov 	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), reg);
5114e1abf66STodor Tomov 
5124e1abf66STodor Tomov 	reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
5134e1abf66STodor Tomov 	reg |= ((3 * id) << VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT) &
5144e1abf66STodor Tomov 		VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK;
5154e1abf66STodor Tomov 	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), reg);
5164e1abf66STodor Tomov 
5174e1abf66STodor Tomov 	switch (id) {
5184e1abf66STodor Tomov 	case VFE_LINE_RDI0:
5194e1abf66STodor Tomov 	default:
5204e1abf66STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
5214e1abf66STodor Tomov 		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
5224e1abf66STodor Tomov 		break;
5234e1abf66STodor Tomov 	case VFE_LINE_RDI1:
5244e1abf66STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
5254e1abf66STodor Tomov 		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
5264e1abf66STodor Tomov 		break;
5274e1abf66STodor Tomov 	case VFE_LINE_RDI2:
5284e1abf66STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
5294e1abf66STodor Tomov 		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
5304e1abf66STodor Tomov 		break;
5314e1abf66STodor Tomov 	}
5324e1abf66STodor Tomov 
5334e1abf66STodor Tomov 	if (wm % 2 == 1)
5344e1abf66STodor Tomov 		reg <<= 16;
5354e1abf66STodor Tomov 
5364e1abf66STodor Tomov 	vfe_reg_set(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
5374e1abf66STodor Tomov }
5384e1abf66STodor Tomov 
vfe_wm_set_subsample(struct vfe_device * vfe,u8 wm)5394e1abf66STodor Tomov static void vfe_wm_set_subsample(struct vfe_device *vfe, u8 wm)
5404e1abf66STodor Tomov {
5414e1abf66STodor Tomov 	writel_relaxed(VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF,
5424e1abf66STodor Tomov 	       vfe->base +
5434e1abf66STodor Tomov 	       VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(wm));
5444e1abf66STodor Tomov }
5454e1abf66STodor Tomov 
vfe_bus_disconnect_wm_from_rdi(struct vfe_device * vfe,u8 wm,enum vfe_line_id id)5464e1abf66STodor Tomov static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm,
5474e1abf66STodor Tomov 					   enum vfe_line_id id)
5484e1abf66STodor Tomov {
5494e1abf66STodor Tomov 	u32 reg;
5504e1abf66STodor Tomov 
5514e1abf66STodor Tomov 	reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
5524e1abf66STodor Tomov 	vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), reg);
5534e1abf66STodor Tomov 
5544e1abf66STodor Tomov 	switch (id) {
5554e1abf66STodor Tomov 	case VFE_LINE_RDI0:
5564e1abf66STodor Tomov 	default:
5574e1abf66STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
5584e1abf66STodor Tomov 		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
5594e1abf66STodor Tomov 		break;
5604e1abf66STodor Tomov 	case VFE_LINE_RDI1:
5614e1abf66STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
5624e1abf66STodor Tomov 		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
5634e1abf66STodor Tomov 		break;
5644e1abf66STodor Tomov 	case VFE_LINE_RDI2:
5654e1abf66STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
5664e1abf66STodor Tomov 		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
5674e1abf66STodor Tomov 		break;
5684e1abf66STodor Tomov 	}
5694e1abf66STodor Tomov 
5704e1abf66STodor Tomov 	if (wm % 2 == 1)
5714e1abf66STodor Tomov 		reg <<= 16;
5724e1abf66STodor Tomov 
5734e1abf66STodor Tomov 	vfe_reg_clr(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
5744e1abf66STodor Tomov }
5754e1abf66STodor Tomov 
vfe_set_xbar_cfg(struct vfe_device * vfe,struct vfe_output * output,u8 enable)5764e1abf66STodor Tomov static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
5774e1abf66STodor Tomov 			     u8 enable)
5784e1abf66STodor Tomov {
5794e1abf66STodor Tomov 	struct vfe_line *line = container_of(output, struct vfe_line, output);
5804e1abf66STodor Tomov 	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
5814e1abf66STodor Tomov 	u32 reg;
5824e1abf66STodor Tomov 
583312e1c85STodor Tomov 	switch (p) {
584312e1c85STodor Tomov 	case V4L2_PIX_FMT_NV12:
585312e1c85STodor Tomov 	case V4L2_PIX_FMT_NV21:
586312e1c85STodor Tomov 	case V4L2_PIX_FMT_NV16:
587312e1c85STodor Tomov 	case V4L2_PIX_FMT_NV61:
5884e1abf66STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA <<
5894e1abf66STodor Tomov 			VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
5904e1abf66STodor Tomov 
591312e1c85STodor Tomov 		if (output->wm_idx[0] % 2 == 1)
5924e1abf66STodor Tomov 			reg <<= 16;
5934e1abf66STodor Tomov 
5944e1abf66STodor Tomov 		if (enable)
5954e1abf66STodor Tomov 			vfe_reg_set(vfe,
596312e1c85STodor Tomov 				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
5974e1abf66STodor Tomov 				    reg);
5984e1abf66STodor Tomov 		else
5994e1abf66STodor Tomov 			vfe_reg_clr(vfe,
600312e1c85STodor Tomov 				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
6014e1abf66STodor Tomov 				    reg);
602312e1c85STodor Tomov 
603312e1c85STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
604312e1c85STodor Tomov 		if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16)
605312e1c85STodor Tomov 			reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA;
606312e1c85STodor Tomov 
607312e1c85STodor Tomov 		if (output->wm_idx[1] % 2 == 1)
608312e1c85STodor Tomov 			reg <<= 16;
609312e1c85STodor Tomov 
610312e1c85STodor Tomov 		if (enable)
611312e1c85STodor Tomov 			vfe_reg_set(vfe,
612312e1c85STodor Tomov 				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
613312e1c85STodor Tomov 				    reg);
614312e1c85STodor Tomov 		else
615312e1c85STodor Tomov 			vfe_reg_clr(vfe,
616312e1c85STodor Tomov 				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
617312e1c85STodor Tomov 				    reg);
618312e1c85STodor Tomov 		break;
619312e1c85STodor Tomov 	case V4L2_PIX_FMT_YUYV:
620312e1c85STodor Tomov 	case V4L2_PIX_FMT_YVYU:
621312e1c85STodor Tomov 	case V4L2_PIX_FMT_VYUY:
622312e1c85STodor Tomov 	case V4L2_PIX_FMT_UYVY:
623312e1c85STodor Tomov 		reg = VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN;
624312e1c85STodor Tomov 		reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
625312e1c85STodor Tomov 
626312e1c85STodor Tomov 		if (p == V4L2_PIX_FMT_YUYV || p == V4L2_PIX_FMT_YVYU)
627312e1c85STodor Tomov 			reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA;
628312e1c85STodor Tomov 
629312e1c85STodor Tomov 		if (output->wm_idx[0] % 2 == 1)
630312e1c85STodor Tomov 			reg <<= 16;
631312e1c85STodor Tomov 
632312e1c85STodor Tomov 		if (enable)
633312e1c85STodor Tomov 			vfe_reg_set(vfe,
634312e1c85STodor Tomov 				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
635312e1c85STodor Tomov 				    reg);
636312e1c85STodor Tomov 		else
637312e1c85STodor Tomov 			vfe_reg_clr(vfe,
638312e1c85STodor Tomov 				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
639312e1c85STodor Tomov 				    reg);
640312e1c85STodor Tomov 		break;
641312e1c85STodor Tomov 	default:
642312e1c85STodor Tomov 		break;
6434e1abf66STodor Tomov 	}
6444e1abf66STodor Tomov }
6454e1abf66STodor Tomov 
vfe_set_realign_cfg(struct vfe_device * vfe,struct vfe_line * line,u8 enable)646312e1c85STodor Tomov static void vfe_set_realign_cfg(struct vfe_device *vfe, struct vfe_line *line,
647312e1c85STodor Tomov 				u8 enable)
648312e1c85STodor Tomov {
649312e1c85STodor Tomov 	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
650312e1c85STodor Tomov 	u32 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF;
651312e1c85STodor Tomov 
652312e1c85STodor Tomov 	if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU &&
653312e1c85STodor Tomov 			p != V4L2_PIX_FMT_VYUY && p != V4L2_PIX_FMT_UYVY)
654312e1c85STodor Tomov 		return;
655312e1c85STodor Tomov 
656312e1c85STodor Tomov 	if (enable) {
657312e1c85STodor Tomov 		vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val);
658312e1c85STodor Tomov 	} else {
659312e1c85STodor Tomov 		vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val);
660312e1c85STodor Tomov 		return;
661312e1c85STodor Tomov 	}
662312e1c85STodor Tomov 
663312e1c85STodor Tomov 	val = VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE;
664312e1c85STodor Tomov 
665312e1c85STodor Tomov 	if (p == V4L2_PIX_FMT_UYVY || p == V4L2_PIX_FMT_YUYV)
666312e1c85STodor Tomov 		val |= VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL;
667312e1c85STodor Tomov 	else
668312e1c85STodor Tomov 		val |= VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL;
669312e1c85STodor Tomov 
670312e1c85STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_REALIGN_BUF_CFG);
671312e1c85STodor Tomov }
672312e1c85STodor Tomov 
vfe_set_rdi_cid(struct vfe_device * vfe,enum vfe_line_id id,u8 cid)6734e1abf66STodor Tomov static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
6744e1abf66STodor Tomov {
6754e1abf66STodor Tomov 	vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id),
6764e1abf66STodor Tomov 		    VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK);
6774e1abf66STodor Tomov 
6784e1abf66STodor Tomov 	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id),
6794e1abf66STodor Tomov 		    cid << VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT);
6804e1abf66STodor Tomov }
6814e1abf66STodor Tomov 
vfe_reg_update(struct vfe_device * vfe,enum vfe_line_id line_id)6824e1abf66STodor Tomov static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
6834e1abf66STodor Tomov {
6844e1abf66STodor Tomov 	vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
685633b388fSRobert Foss 
686633b388fSRobert Foss 	/* Enforce barrier between line update and commit */
6874e1abf66STodor Tomov 	wmb();
6884e1abf66STodor Tomov 	writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
689633b388fSRobert Foss 
690633b388fSRobert Foss 	/* Make sure register update is issued before further reg writes */
6914e1abf66STodor Tomov 	wmb();
6924e1abf66STodor Tomov }
6934e1abf66STodor Tomov 
vfe_reg_update_clear(struct vfe_device * vfe,enum vfe_line_id line_id)6944e1abf66STodor Tomov static inline void vfe_reg_update_clear(struct vfe_device *vfe,
6954e1abf66STodor Tomov 					enum vfe_line_id line_id)
6964e1abf66STodor Tomov {
6974e1abf66STodor Tomov 	vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line_id);
6984e1abf66STodor Tomov }
6994e1abf66STodor Tomov 
vfe_enable_irq_wm_line(struct vfe_device * vfe,u8 wm,enum vfe_line_id line_id,u8 enable)7004e1abf66STodor Tomov static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm,
7014e1abf66STodor Tomov 				   enum vfe_line_id line_id, u8 enable)
7024e1abf66STodor Tomov {
7034e1abf66STodor Tomov 	u32 irq_en0 = VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(wm) |
7044e1abf66STodor Tomov 		      VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id);
7054e1abf66STodor Tomov 	u32 irq_en1 = VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(wm) |
7064e1abf66STodor Tomov 		      VFE_0_IRQ_MASK_1_RDIn_SOF(line_id);
7074e1abf66STodor Tomov 
7084e1abf66STodor Tomov 	if (enable) {
7094e1abf66STodor Tomov 		vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
7104e1abf66STodor Tomov 		vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
7114e1abf66STodor Tomov 	} else {
7124e1abf66STodor Tomov 		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
7134e1abf66STodor Tomov 		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
7144e1abf66STodor Tomov 	}
7154e1abf66STodor Tomov }
7164e1abf66STodor Tomov 
vfe_enable_irq_pix_line(struct vfe_device * vfe,u8 comp,enum vfe_line_id line_id,u8 enable)7174e1abf66STodor Tomov static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp,
7184e1abf66STodor Tomov 				    enum vfe_line_id line_id, u8 enable)
7194e1abf66STodor Tomov {
7204e1abf66STodor Tomov 	struct vfe_output *output = &vfe->line[line_id].output;
7214e1abf66STodor Tomov 	unsigned int i;
7224e1abf66STodor Tomov 	u32 irq_en0;
7234e1abf66STodor Tomov 	u32 irq_en1;
7244e1abf66STodor Tomov 	u32 comp_mask = 0;
7254e1abf66STodor Tomov 
7264e1abf66STodor Tomov 	irq_en0 = VFE_0_IRQ_MASK_0_CAMIF_SOF;
7274e1abf66STodor Tomov 	irq_en0 |= VFE_0_IRQ_MASK_0_CAMIF_EOF;
7284e1abf66STodor Tomov 	irq_en0 |= VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(comp);
7294e1abf66STodor Tomov 	irq_en0 |= VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id);
7304e1abf66STodor Tomov 	irq_en1 = VFE_0_IRQ_MASK_1_CAMIF_ERROR;
7314e1abf66STodor Tomov 	for (i = 0; i < output->wm_num; i++) {
7324e1abf66STodor Tomov 		irq_en1 |= VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(
7334e1abf66STodor Tomov 							output->wm_idx[i]);
7344e1abf66STodor Tomov 		comp_mask |= (1 << output->wm_idx[i]) << comp * 8;
7354e1abf66STodor Tomov 	}
7364e1abf66STodor Tomov 
7374e1abf66STodor Tomov 	if (enable) {
7384e1abf66STodor Tomov 		vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
7394e1abf66STodor Tomov 		vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
7404e1abf66STodor Tomov 		vfe_reg_set(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
7414e1abf66STodor Tomov 	} else {
7424e1abf66STodor Tomov 		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
7434e1abf66STodor Tomov 		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
7444e1abf66STodor Tomov 		vfe_reg_clr(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
7454e1abf66STodor Tomov 	}
7464e1abf66STodor Tomov }
7474e1abf66STodor Tomov 
vfe_enable_irq_common(struct vfe_device * vfe)7484e1abf66STodor Tomov static void vfe_enable_irq_common(struct vfe_device *vfe)
7494e1abf66STodor Tomov {
7504e1abf66STodor Tomov 	u32 irq_en0 = VFE_0_IRQ_MASK_0_RESET_ACK;
7514e1abf66STodor Tomov 	u32 irq_en1 = VFE_0_IRQ_MASK_1_VIOLATION |
7524e1abf66STodor Tomov 		      VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK;
7534e1abf66STodor Tomov 
7544e1abf66STodor Tomov 	vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
7554e1abf66STodor Tomov 	vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
7564e1abf66STodor Tomov }
7574e1abf66STodor Tomov 
vfe_set_demux_cfg(struct vfe_device * vfe,struct vfe_line * line)7584e1abf66STodor Tomov static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
7594e1abf66STodor Tomov {
7604e1abf66STodor Tomov 	u32 val, even_cfg, odd_cfg;
7614e1abf66STodor Tomov 
7624e1abf66STodor Tomov 	writel_relaxed(VFE_0_DEMUX_CFG_PERIOD, vfe->base + VFE_0_DEMUX_CFG);
7634e1abf66STodor Tomov 
7644e1abf66STodor Tomov 	val = VFE_0_DEMUX_GAIN_0_CH0_EVEN | VFE_0_DEMUX_GAIN_0_CH0_ODD;
7654e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_0);
7664e1abf66STodor Tomov 
7674e1abf66STodor Tomov 	val = VFE_0_DEMUX_GAIN_1_CH1 | VFE_0_DEMUX_GAIN_1_CH2;
7684e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1);
7694e1abf66STodor Tomov 
7704e1abf66STodor Tomov 	switch (line->fmt[MSM_VFE_PAD_SINK].code) {
7714e1abf66STodor Tomov 	case MEDIA_BUS_FMT_YUYV8_2X8:
7724e1abf66STodor Tomov 		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV;
7734e1abf66STodor Tomov 		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV;
7744e1abf66STodor Tomov 		break;
7754e1abf66STodor Tomov 	case MEDIA_BUS_FMT_YVYU8_2X8:
7764e1abf66STodor Tomov 		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU;
7774e1abf66STodor Tomov 		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU;
7784e1abf66STodor Tomov 		break;
7794e1abf66STodor Tomov 	case MEDIA_BUS_FMT_UYVY8_2X8:
7804e1abf66STodor Tomov 	default:
7814e1abf66STodor Tomov 		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY;
7824e1abf66STodor Tomov 		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY;
7834e1abf66STodor Tomov 		break;
7844e1abf66STodor Tomov 	case MEDIA_BUS_FMT_VYUY8_2X8:
7854e1abf66STodor Tomov 		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY;
7864e1abf66STodor Tomov 		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY;
7874e1abf66STodor Tomov 		break;
7884e1abf66STodor Tomov 	}
7894e1abf66STodor Tomov 
7904e1abf66STodor Tomov 	writel_relaxed(even_cfg, vfe->base + VFE_0_DEMUX_EVEN_CFG);
7914e1abf66STodor Tomov 	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
7924e1abf66STodor Tomov }
7934e1abf66STodor Tomov 
vfe_set_scale_cfg(struct vfe_device * vfe,struct vfe_line * line)7944e1abf66STodor Tomov static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
7954e1abf66STodor Tomov {
7964e1abf66STodor Tomov 	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
7974e1abf66STodor Tomov 	u32 reg;
7984e1abf66STodor Tomov 	u16 input, output;
7994e1abf66STodor Tomov 	u8 interp_reso;
8004e1abf66STodor Tomov 	u32 phase_mult;
8014e1abf66STodor Tomov 
8024e1abf66STodor Tomov 	writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_Y_CFG);
8034e1abf66STodor Tomov 
8044e1abf66STodor Tomov 	input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
8054e1abf66STodor Tomov 	output = line->compose.width - 1;
8064e1abf66STodor Tomov 	reg = (output << 16) | input;
8074e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE);
8084e1abf66STodor Tomov 
8094e1abf66STodor Tomov 	interp_reso = vfe_calc_interp_reso(input, output);
8104e1abf66STodor Tomov 	phase_mult = input * (1 << (14 + interp_reso)) / output;
8114e1abf66STodor Tomov 	reg = (interp_reso << 28) | phase_mult;
8124e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_PHASE);
8134e1abf66STodor Tomov 
8144e1abf66STodor Tomov 	input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
8154e1abf66STodor Tomov 	output = line->compose.height - 1;
8164e1abf66STodor Tomov 	reg = (output << 16) | input;
8174e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE);
8184e1abf66STodor Tomov 
8194e1abf66STodor Tomov 	interp_reso = vfe_calc_interp_reso(input, output);
8204e1abf66STodor Tomov 	phase_mult = input * (1 << (14 + interp_reso)) / output;
8214e1abf66STodor Tomov 	reg = (interp_reso << 28) | phase_mult;
8224e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_PHASE);
8234e1abf66STodor Tomov 
8244e1abf66STodor Tomov 	writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_CBCR_CFG);
8254e1abf66STodor Tomov 
8264e1abf66STodor Tomov 	input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
8274e1abf66STodor Tomov 	output = line->compose.width / 2 - 1;
8284e1abf66STodor Tomov 	reg = (output << 16) | input;
8294e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE);
8304e1abf66STodor Tomov 
8314e1abf66STodor Tomov 	interp_reso = vfe_calc_interp_reso(input, output);
8324e1abf66STodor Tomov 	phase_mult = input * (1 << (14 + interp_reso)) / output;
8334e1abf66STodor Tomov 	reg = (interp_reso << 28) | phase_mult;
8344e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_PHASE);
8354e1abf66STodor Tomov 
8364e1abf66STodor Tomov 	input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
8374e1abf66STodor Tomov 	output = line->compose.height - 1;
8384e1abf66STodor Tomov 	if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21)
8394e1abf66STodor Tomov 		output = line->compose.height / 2 - 1;
8404e1abf66STodor Tomov 	reg = (output << 16) | input;
8414e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE);
8424e1abf66STodor Tomov 
8434e1abf66STodor Tomov 	interp_reso = vfe_calc_interp_reso(input, output);
8444e1abf66STodor Tomov 	phase_mult = input * (1 << (14 + interp_reso)) / output;
8454e1abf66STodor Tomov 	reg = (interp_reso << 28) | phase_mult;
8464e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_PHASE);
8474e1abf66STodor Tomov }
8484e1abf66STodor Tomov 
vfe_set_crop_cfg(struct vfe_device * vfe,struct vfe_line * line)8494e1abf66STodor Tomov static void vfe_set_crop_cfg(struct vfe_device *vfe, struct vfe_line *line)
8504e1abf66STodor Tomov {
8514e1abf66STodor Tomov 	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
8524e1abf66STodor Tomov 	u32 reg;
8534e1abf66STodor Tomov 	u16 first, last;
8544e1abf66STodor Tomov 
8554e1abf66STodor Tomov 	first = line->crop.left;
8564e1abf66STodor Tomov 	last = line->crop.left + line->crop.width - 1;
8574e1abf66STodor Tomov 	reg = (first << 16) | last;
8584e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_WIDTH);
8594e1abf66STodor Tomov 
8604e1abf66STodor Tomov 	first = line->crop.top;
8614e1abf66STodor Tomov 	last = line->crop.top + line->crop.height - 1;
8624e1abf66STodor Tomov 	reg = (first << 16) | last;
8634e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_HEIGHT);
8644e1abf66STodor Tomov 
8654e1abf66STodor Tomov 	first = line->crop.left / 2;
8664e1abf66STodor Tomov 	last = line->crop.left / 2 + line->crop.width / 2 - 1;
8674e1abf66STodor Tomov 	reg = (first << 16) | last;
8684e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_WIDTH);
8694e1abf66STodor Tomov 
8704e1abf66STodor Tomov 	first = line->crop.top;
8714e1abf66STodor Tomov 	last = line->crop.top + line->crop.height - 1;
8724e1abf66STodor Tomov 	if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) {
8734e1abf66STodor Tomov 		first = line->crop.top / 2;
8744e1abf66STodor Tomov 		last = line->crop.top / 2 + line->crop.height / 2 - 1;
8754e1abf66STodor Tomov 	}
8764e1abf66STodor Tomov 	reg = (first << 16) | last;
8774e1abf66STodor Tomov 	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_HEIGHT);
8784e1abf66STodor Tomov }
8794e1abf66STodor Tomov 
vfe_set_clamp_cfg(struct vfe_device * vfe)8804e1abf66STodor Tomov static void vfe_set_clamp_cfg(struct vfe_device *vfe)
8814e1abf66STodor Tomov {
8824e1abf66STodor Tomov 	u32 val = VFE_0_CLAMP_ENC_MAX_CFG_CH0 |
8834e1abf66STodor Tomov 		VFE_0_CLAMP_ENC_MAX_CFG_CH1 |
8844e1abf66STodor Tomov 		VFE_0_CLAMP_ENC_MAX_CFG_CH2;
8854e1abf66STodor Tomov 
8864e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MAX_CFG);
8874e1abf66STodor Tomov 
8884e1abf66STodor Tomov 	val = VFE_0_CLAMP_ENC_MIN_CFG_CH0 |
8894e1abf66STodor Tomov 		VFE_0_CLAMP_ENC_MIN_CFG_CH1 |
8904e1abf66STodor Tomov 		VFE_0_CLAMP_ENC_MIN_CFG_CH2;
8914e1abf66STodor Tomov 
8924e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
8934e1abf66STodor Tomov }
8944e1abf66STodor Tomov 
vfe_set_qos(struct vfe_device * vfe)895633b388fSRobert Foss static void vfe_set_qos(struct vfe_device *vfe)
8964e1abf66STodor Tomov {
8974e1abf66STodor Tomov 	u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
8984e1abf66STodor Tomov 	u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
8994e1abf66STodor Tomov 
9004e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
9014e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
9024e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
9034e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
9044e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
9054e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
9064e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
9074e1abf66STodor Tomov 	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
9084e1abf66STodor Tomov }
9094e1abf66STodor Tomov 
vfe_set_ds(struct vfe_device * vfe)910633b388fSRobert Foss static void vfe_set_ds(struct vfe_device *vfe)
9114e1abf66STodor Tomov {
9124e1abf66STodor Tomov 	u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
9134e1abf66STodor Tomov 	u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
9144e1abf66STodor Tomov 
9154e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
9164e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
9174e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
9184e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
9194e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
9204e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
9214e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
9224e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
9234e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
9244e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
9254e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
9264e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
9274e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
9284e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
9294e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
9304e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
9314e1abf66STodor Tomov 	writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
9324e1abf66STodor Tomov }
9334e1abf66STodor Tomov 
vfe_set_cgc_override(struct vfe_device * vfe,u8 wm,u8 enable)9344e1abf66STodor Tomov static void vfe_set_cgc_override(struct vfe_device *vfe, u8 wm, u8 enable)
9354e1abf66STodor Tomov {
9364e1abf66STodor Tomov 	/* empty */
9374e1abf66STodor Tomov }
9384e1abf66STodor Tomov 
vfe_set_camif_cfg(struct vfe_device * vfe,struct vfe_line * line)9394e1abf66STodor Tomov static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line)
9404e1abf66STodor Tomov {
9414e1abf66STodor Tomov 	u32 val;
9424e1abf66STodor Tomov 
9434e1abf66STodor Tomov 	switch (line->fmt[MSM_VFE_PAD_SINK].code) {
9444e1abf66STodor Tomov 	case MEDIA_BUS_FMT_YUYV8_2X8:
9454e1abf66STodor Tomov 		val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR;
9464e1abf66STodor Tomov 		break;
9474e1abf66STodor Tomov 	case MEDIA_BUS_FMT_YVYU8_2X8:
9484e1abf66STodor Tomov 		val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB;
9494e1abf66STodor Tomov 		break;
9504e1abf66STodor Tomov 	case MEDIA_BUS_FMT_UYVY8_2X8:
9514e1abf66STodor Tomov 	default:
9524e1abf66STodor Tomov 		val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY;
9534e1abf66STodor Tomov 		break;
9544e1abf66STodor Tomov 	case MEDIA_BUS_FMT_VYUY8_2X8:
9554e1abf66STodor Tomov 		val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY;
9564e1abf66STodor Tomov 		break;
9574e1abf66STodor Tomov 	}
9584e1abf66STodor Tomov 
9594e1abf66STodor Tomov 	val |= VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN;
9604e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CORE_CFG);
9614e1abf66STodor Tomov 
9624e1abf66STodor Tomov 	val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
9634e1abf66STodor Tomov 	val |= (line->fmt[MSM_VFE_PAD_SINK].height - 1) << 16;
9644e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CAMIF_FRAME_CFG);
9654e1abf66STodor Tomov 
9664e1abf66STodor Tomov 	val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
9674e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_WIDTH_CFG);
9684e1abf66STodor Tomov 
9694e1abf66STodor Tomov 	val = line->fmt[MSM_VFE_PAD_SINK].height - 1;
9704e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_HEIGHT_CFG);
9714e1abf66STodor Tomov 
9724e1abf66STodor Tomov 	val = 0xffffffff;
9734e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CAMIF_SUBSAMPLE_CFG);
9744e1abf66STodor Tomov 
9754e1abf66STodor Tomov 	val = 0xffffffff;
9764e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN);
9774e1abf66STodor Tomov 
9784e1abf66STodor Tomov 	val = 0xffffffff;
9794e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN);
9804e1abf66STodor Tomov 
9814e1abf66STodor Tomov 	val = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
9824e1abf66STodor Tomov 	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), val);
9834e1abf66STodor Tomov 
9844e1abf66STodor Tomov 	val = VFE_0_CAMIF_CFG_VFE_OUTPUT_EN;
9854e1abf66STodor Tomov 	writel_relaxed(val, vfe->base + VFE_0_CAMIF_CFG);
9864e1abf66STodor Tomov }
9874e1abf66STodor Tomov 
vfe_set_camif_cmd(struct vfe_device * vfe,u8 enable)9884e1abf66STodor Tomov static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
9894e1abf66STodor Tomov {
9904e1abf66STodor Tomov 	u32 cmd;
9914e1abf66STodor Tomov 
9924e1abf66STodor Tomov 	cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
9934e1abf66STodor Tomov 	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
994633b388fSRobert Foss 
995633b388fSRobert Foss 	/* Make sure camif command is issued written before it is changed again */
9964e1abf66STodor Tomov 	wmb();
9974e1abf66STodor Tomov 
9984e1abf66STodor Tomov 	if (enable)
9994e1abf66STodor Tomov 		cmd = VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY;
10004e1abf66STodor Tomov 	else
10014e1abf66STodor Tomov 		cmd = VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY;
10024e1abf66STodor Tomov 
10034e1abf66STodor Tomov 	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
10044e1abf66STodor Tomov }
10054e1abf66STodor Tomov 
vfe_set_module_cfg(struct vfe_device * vfe,u8 enable)10064e1abf66STodor Tomov static void vfe_set_module_cfg(struct vfe_device *vfe, u8 enable)
10074e1abf66STodor Tomov {
10084e1abf66STodor Tomov 	u32 val_lens = VFE_0_MODULE_LENS_EN_DEMUX |
10094e1abf66STodor Tomov 		       VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE;
10104e1abf66STodor Tomov 	u32 val_zoom = VFE_0_MODULE_ZOOM_EN_SCALE_ENC |
10114e1abf66STodor Tomov 		       VFE_0_MODULE_ZOOM_EN_CROP_ENC;
10124e1abf66STodor Tomov 
10134e1abf66STodor Tomov 	if (enable) {
1014312e1c85STodor Tomov 		vfe_reg_set(vfe, VFE_0_MODULE_LENS_EN, val_lens);
1015312e1c85STodor Tomov 		vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
10164e1abf66STodor Tomov 	} else {
1017312e1c85STodor Tomov 		vfe_reg_clr(vfe, VFE_0_MODULE_LENS_EN, val_lens);
1018312e1c85STodor Tomov 		vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
10194e1abf66STodor Tomov 	}
10204e1abf66STodor Tomov }
10214e1abf66STodor Tomov 
vfe_camif_wait_for_stop(struct vfe_device * vfe,struct device * dev)10224e1abf66STodor Tomov static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
10234e1abf66STodor Tomov {
10244e1abf66STodor Tomov 	u32 val;
10254e1abf66STodor Tomov 	int ret;
10264e1abf66STodor Tomov 
10274e1abf66STodor Tomov 	ret = readl_poll_timeout(vfe->base + VFE_0_CAMIF_STATUS,
10284e1abf66STodor Tomov 				 val,
10294e1abf66STodor Tomov 				 (val & VFE_0_CAMIF_STATUS_HALT),
10304e1abf66STodor Tomov 				 CAMIF_TIMEOUT_SLEEP_US,
10314e1abf66STodor Tomov 				 CAMIF_TIMEOUT_ALL_US);
10324e1abf66STodor Tomov 	if (ret < 0)
10334e1abf66STodor Tomov 		dev_err(dev, "%s: camif stop timeout\n", __func__);
10344e1abf66STodor Tomov 
10354e1abf66STodor Tomov 	return ret;
10364e1abf66STodor Tomov }
10374e1abf66STodor Tomov 
10384e1abf66STodor Tomov 
10394e1abf66STodor Tomov 
10404e1abf66STodor Tomov /*
1041ad46e1a8SRobert Foss  * vfe_isr - VFE module interrupt handler
10424e1abf66STodor Tomov  * @irq: Interrupt line
10434e1abf66STodor Tomov  * @dev: VFE device
10444e1abf66STodor Tomov  *
10454e1abf66STodor Tomov  * Return IRQ_HANDLED on success
10464e1abf66STodor Tomov  */
vfe_isr(int irq,void * dev)10474e1abf66STodor Tomov static irqreturn_t vfe_isr(int irq, void *dev)
10484e1abf66STodor Tomov {
10494e1abf66STodor Tomov 	struct vfe_device *vfe = dev;
10504e1abf66STodor Tomov 	u32 value0, value1;
10514e1abf66STodor Tomov 	int i, j;
10524e1abf66STodor Tomov 
10534e1abf66STodor Tomov 	vfe->ops->isr_read(vfe, &value0, &value1);
10544e1abf66STodor Tomov 
1055c3177cb0SRobert Foss 	dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n",
10564e1abf66STodor Tomov 		value0, value1);
10574e1abf66STodor Tomov 
10584e1abf66STodor Tomov 	if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK)
10594e1abf66STodor Tomov 		vfe->isr_ops.reset_ack(vfe);
10604e1abf66STodor Tomov 
10614e1abf66STodor Tomov 	if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION)
10624e1abf66STodor Tomov 		vfe->ops->violation_read(vfe);
10634e1abf66STodor Tomov 
10644e1abf66STodor Tomov 	if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK)
10654e1abf66STodor Tomov 		vfe->isr_ops.halt_ack(vfe);
10664e1abf66STodor Tomov 
1067633b388fSRobert Foss 	for (i = VFE_LINE_RDI0; i < vfe->line_num; i++)
10684e1abf66STodor Tomov 		if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
10694e1abf66STodor Tomov 			vfe->isr_ops.reg_update(vfe, i);
10704e1abf66STodor Tomov 
10714e1abf66STodor Tomov 	if (value0 & VFE_0_IRQ_STATUS_0_CAMIF_SOF)
10724e1abf66STodor Tomov 		vfe->isr_ops.sof(vfe, VFE_LINE_PIX);
10734e1abf66STodor Tomov 
10744e1abf66STodor Tomov 	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
10754e1abf66STodor Tomov 		if (value1 & VFE_0_IRQ_STATUS_1_RDIn_SOF(i))
10764e1abf66STodor Tomov 			vfe->isr_ops.sof(vfe, i);
10774e1abf66STodor Tomov 
10784e1abf66STodor Tomov 	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
10794e1abf66STodor Tomov 		if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(i)) {
10804e1abf66STodor Tomov 			vfe->isr_ops.comp_done(vfe, i);
10814e1abf66STodor Tomov 			for (j = 0; j < ARRAY_SIZE(vfe->wm_output_map); j++)
10824e1abf66STodor Tomov 				if (vfe->wm_output_map[j] == VFE_LINE_PIX)
10834e1abf66STodor Tomov 					value0 &= ~VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(j);
10844e1abf66STodor Tomov 		}
10854e1abf66STodor Tomov 
10864e1abf66STodor Tomov 	for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++)
10874e1abf66STodor Tomov 		if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(i))
10884e1abf66STodor Tomov 			vfe->isr_ops.wm_done(vfe, i);
10894e1abf66STodor Tomov 
10904e1abf66STodor Tomov 	return IRQ_HANDLED;
10914e1abf66STodor Tomov }
10924e1abf66STodor Tomov 
vfe_isr_read(struct vfe_device * vfe,u32 * value0,u32 * value1)1093633b388fSRobert Foss static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
1094633b388fSRobert Foss {
1095633b388fSRobert Foss 	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
1096633b388fSRobert Foss 	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
1097633b388fSRobert Foss 
1098633b388fSRobert Foss 	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
1099633b388fSRobert Foss 	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
1100633b388fSRobert Foss 
1101633b388fSRobert Foss 	/* Enforce barrier between local & global IRQ clear */
1102633b388fSRobert Foss 	wmb();
1103633b388fSRobert Foss 	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
1104633b388fSRobert Foss }
1105633b388fSRobert Foss 
11062f6f8af6SRobert Foss /*
11072f6f8af6SRobert Foss  * vfe_pm_domain_off - Disable power domains specific to this VFE.
11082f6f8af6SRobert Foss  * @vfe: VFE Device
11092f6f8af6SRobert Foss  */
vfe_pm_domain_off(struct vfe_device * vfe)11102f6f8af6SRobert Foss static void vfe_pm_domain_off(struct vfe_device *vfe)
11112f6f8af6SRobert Foss {
11122f6f8af6SRobert Foss 	struct camss *camss;
11132f6f8af6SRobert Foss 
11142f6f8af6SRobert Foss 	if (!vfe)
11152f6f8af6SRobert Foss 		return;
11162f6f8af6SRobert Foss 
11172f6f8af6SRobert Foss 	camss = vfe->camss;
11182f6f8af6SRobert Foss 
11192f6f8af6SRobert Foss 	device_link_del(camss->genpd_link[vfe->id]);
11202f6f8af6SRobert Foss }
11212f6f8af6SRobert Foss 
11222f6f8af6SRobert Foss /*
11232f6f8af6SRobert Foss  * vfe_pm_domain_on - Enable power domains specific to this VFE.
11242f6f8af6SRobert Foss  * @vfe: VFE Device
11252f6f8af6SRobert Foss  */
vfe_pm_domain_on(struct vfe_device * vfe)11262f6f8af6SRobert Foss static int vfe_pm_domain_on(struct vfe_device *vfe)
11272f6f8af6SRobert Foss {
11282f6f8af6SRobert Foss 	struct camss *camss = vfe->camss;
11292f6f8af6SRobert Foss 	enum vfe_line_id id = vfe->id;
11302f6f8af6SRobert Foss 
11312f6f8af6SRobert Foss 	camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS |
11322f6f8af6SRobert Foss 						DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
11332f6f8af6SRobert Foss 
11342f6f8af6SRobert Foss 	if (!camss->genpd_link[id]) {
11352f6f8af6SRobert Foss 		dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id);
11362f6f8af6SRobert Foss 		return -EINVAL;
11372f6f8af6SRobert Foss 	}
11382f6f8af6SRobert Foss 
11392f6f8af6SRobert Foss 	return 0;
11402f6f8af6SRobert Foss }
11412f6f8af6SRobert Foss 
vfe_violation_read(struct vfe_device * vfe)1142633b388fSRobert Foss static void vfe_violation_read(struct vfe_device *vfe)
1143633b388fSRobert Foss {
1144633b388fSRobert Foss 	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
1145633b388fSRobert Foss 
1146633b388fSRobert Foss 	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
1147633b388fSRobert Foss }
1148633b388fSRobert Foss 
1149633b388fSRobert Foss static const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_7 = {
11504e1abf66STodor Tomov 	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
11514e1abf66STodor Tomov 	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
1152633b388fSRobert Foss 	.bus_enable_wr_if = vfe_bus_enable_wr_if,
1153633b388fSRobert Foss 	.bus_reload_wm = vfe_bus_reload_wm,
1154633b388fSRobert Foss 	.camif_wait_for_stop = vfe_camif_wait_for_stop,
11554e1abf66STodor Tomov 	.enable_irq_common = vfe_enable_irq_common,
1156633b388fSRobert Foss 	.enable_irq_pix_line = vfe_enable_irq_pix_line,
1157633b388fSRobert Foss 	.enable_irq_wm_line = vfe_enable_irq_wm_line,
1158633b388fSRobert Foss 	.get_ub_size = vfe_get_ub_size,
1159633b388fSRobert Foss 	.halt_clear = vfe_halt_clear,
1160633b388fSRobert Foss 	.halt_request = vfe_halt_request,
11614e1abf66STodor Tomov 	.set_camif_cfg = vfe_set_camif_cfg,
11624e1abf66STodor Tomov 	.set_camif_cmd = vfe_set_camif_cmd,
1163633b388fSRobert Foss 	.set_cgc_override = vfe_set_cgc_override,
1164633b388fSRobert Foss 	.set_clamp_cfg = vfe_set_clamp_cfg,
1165633b388fSRobert Foss 	.set_crop_cfg = vfe_set_crop_cfg,
1166633b388fSRobert Foss 	.set_demux_cfg = vfe_set_demux_cfg,
1167633b388fSRobert Foss 	.set_ds = vfe_set_ds,
11684e1abf66STodor Tomov 	.set_module_cfg = vfe_set_module_cfg,
1169633b388fSRobert Foss 	.set_qos = vfe_set_qos,
1170633b388fSRobert Foss 	.set_rdi_cid = vfe_set_rdi_cid,
1171633b388fSRobert Foss 	.set_realign_cfg = vfe_set_realign_cfg,
1172633b388fSRobert Foss 	.set_scale_cfg = vfe_set_scale_cfg,
1173633b388fSRobert Foss 	.set_xbar_cfg = vfe_set_xbar_cfg,
1174633b388fSRobert Foss 	.wm_enable = vfe_wm_enable,
1175633b388fSRobert Foss 	.wm_frame_based = vfe_wm_frame_based,
1176633b388fSRobert Foss 	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
1177633b388fSRobert Foss 	.wm_line_based = vfe_wm_line_based,
1178633b388fSRobert Foss 	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
1179633b388fSRobert Foss 	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
1180633b388fSRobert Foss 	.wm_set_ping_addr = vfe_wm_set_ping_addr,
1181633b388fSRobert Foss 	.wm_set_pong_addr = vfe_wm_set_pong_addr,
1182633b388fSRobert Foss 	.wm_set_subsample = vfe_wm_set_subsample,
1183633b388fSRobert Foss 	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
11844e1abf66STodor Tomov };
118540296e71SAngeloGioacchino Del Regno 
vfe_subdev_init(struct device * dev,struct vfe_device * vfe)1186633b388fSRobert Foss static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
118740296e71SAngeloGioacchino Del Regno {
1188633b388fSRobert Foss 	vfe->isr_ops = vfe_isr_ops_gen1;
1189633b388fSRobert Foss 	vfe->ops_gen1 = &vfe_ops_gen1_4_7;
1190633b388fSRobert Foss 	vfe->video_ops = vfe_video_ops_gen1;
1191633b388fSRobert Foss 
1192633b388fSRobert Foss 	vfe->line_num = VFE_LINE_NUM_GEN1;
119340296e71SAngeloGioacchino Del Regno }
119440296e71SAngeloGioacchino Del Regno 
1195633b388fSRobert Foss const struct vfe_hw_ops vfe_ops_4_7 = {
119640296e71SAngeloGioacchino Del Regno 	.global_reset = vfe_global_reset,
1197d2e86540SRobert Foss 	.hw_version = vfe_hw_version,
119840296e71SAngeloGioacchino Del Regno 	.isr_read = vfe_isr_read,
119940296e71SAngeloGioacchino Del Regno 	.isr = vfe_isr,
12002f6f8af6SRobert Foss 	.pm_domain_off = vfe_pm_domain_off,
12012f6f8af6SRobert Foss 	.pm_domain_on = vfe_pm_domain_on,
1202633b388fSRobert Foss 	.reg_update_clear = vfe_reg_update_clear,
1203633b388fSRobert Foss 	.reg_update = vfe_reg_update,
1204633b388fSRobert Foss 	.subdev_init = vfe_subdev_init,
1205633b388fSRobert Foss 	.vfe_disable = vfe_gen1_disable,
1206633b388fSRobert Foss 	.vfe_enable = vfe_gen1_enable,
1207633b388fSRobert Foss 	.vfe_halt = vfe_gen1_halt,
1208633b388fSRobert Foss 	.violation_read = vfe_violation_read,
120940296e71SAngeloGioacchino Del Regno };
1210