17319cdf1SRobert Foss // SPDX-License-Identifier: GPL-2.0
27319cdf1SRobert Foss /*
37319cdf1SRobert Foss  * camss-vfe-170.c
47319cdf1SRobert Foss  *
57319cdf1SRobert Foss  * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v170
67319cdf1SRobert Foss  *
77319cdf1SRobert Foss  * Copyright (C) 2020-2021 Linaro Ltd.
87319cdf1SRobert Foss  */
97319cdf1SRobert Foss 
107319cdf1SRobert Foss #include <linux/interrupt.h>
117319cdf1SRobert Foss #include <linux/io.h>
127319cdf1SRobert Foss #include <linux/iopoll.h>
137319cdf1SRobert Foss 
147319cdf1SRobert Foss #include "camss.h"
157319cdf1SRobert Foss #include "camss-vfe.h"
167319cdf1SRobert Foss 
177319cdf1SRobert Foss #define VFE_HW_VERSION				(0x000)
187319cdf1SRobert Foss 
197319cdf1SRobert Foss #define VFE_GLOBAL_RESET_CMD			(0x018)
207319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_CORE		BIT(0)
217319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_CAMIF		BIT(1)
227319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_BUS		BIT(2)
237319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
247319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_REGISTER	BIT(4)
257319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_PM		BIT(5)
267319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
277319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_TESTGEN	BIT(7)
287319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_DSP		BIT(8)
297319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
307319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_RDI0		BIT(10)
317319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_RDI1		BIT(11)
327319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_RDI2		BIT(12)
337319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_RDI3		BIT(13)
347319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_VFE_DOMAIN	BIT(30)
357319cdf1SRobert Foss #define		GLOBAL_RESET_CMD_RESET_BYPASS	BIT(31)
367319cdf1SRobert Foss 
377319cdf1SRobert Foss #define VFE_CORE_CFG				(0x050)
387319cdf1SRobert Foss #define		CFG_PIXEL_PATTERN_YCBYCR	(0x4)
397319cdf1SRobert Foss #define		CFG_PIXEL_PATTERN_YCRYCB	(0x5)
407319cdf1SRobert Foss #define		CFG_PIXEL_PATTERN_CBYCRY	(0x6)
417319cdf1SRobert Foss #define		CFG_PIXEL_PATTERN_CRYCBY	(0x7)
427319cdf1SRobert Foss #define		CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
437319cdf1SRobert Foss 
447319cdf1SRobert Foss #define VFE_IRQ_CMD				(0x058)
457319cdf1SRobert Foss #define		CMD_GLOBAL_CLEAR		BIT(0)
467319cdf1SRobert Foss 
477319cdf1SRobert Foss #define VFE_IRQ_MASK_0					(0x05c)
487319cdf1SRobert Foss #define		MASK_0_CAMIF_SOF			BIT(0)
497319cdf1SRobert Foss #define		MASK_0_CAMIF_EOF			BIT(1)
507319cdf1SRobert Foss #define		MASK_0_RDI_REG_UPDATE(n)		BIT((n) + 5)
517319cdf1SRobert Foss #define		MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
527319cdf1SRobert Foss #define		MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
537319cdf1SRobert Foss #define		MASK_0_RESET_ACK			BIT(31)
547319cdf1SRobert Foss 
557319cdf1SRobert Foss #define VFE_IRQ_MASK_1					(0x060)
567319cdf1SRobert Foss #define		MASK_1_CAMIF_ERROR			BIT(0)
577319cdf1SRobert Foss #define		MASK_1_VIOLATION			BIT(7)
587319cdf1SRobert Foss #define		MASK_1_BUS_BDG_HALT_ACK			BIT(8)
597319cdf1SRobert Foss #define		MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
607319cdf1SRobert Foss #define		MASK_1_RDI_SOF(n)			BIT((n) + 29)
617319cdf1SRobert Foss 
627319cdf1SRobert Foss #define VFE_IRQ_CLEAR_0					(0x064)
637319cdf1SRobert Foss #define VFE_IRQ_CLEAR_1					(0x068)
647319cdf1SRobert Foss 
657319cdf1SRobert Foss #define VFE_IRQ_STATUS_0				(0x06c)
667319cdf1SRobert Foss #define		STATUS_0_CAMIF_SOF			BIT(0)
677319cdf1SRobert Foss #define		STATUS_0_RDI_REG_UPDATE(n)		BIT((n) + 5)
687319cdf1SRobert Foss #define		STATUS_0_IMAGE_MASTER_PING_PONG(n)	BIT((n) + 8)
697319cdf1SRobert Foss #define		STATUS_0_IMAGE_COMPOSITE_DONE(n)	BIT((n) + 25)
707319cdf1SRobert Foss #define		STATUS_0_RESET_ACK			BIT(31)
717319cdf1SRobert Foss 
727319cdf1SRobert Foss #define VFE_IRQ_STATUS_1				(0x070)
737319cdf1SRobert Foss #define		STATUS_1_VIOLATION			BIT(7)
747319cdf1SRobert Foss #define		STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
757319cdf1SRobert Foss #define		STATUS_1_RDI_SOF(n)			BIT((n) + 27)
767319cdf1SRobert Foss 
777319cdf1SRobert Foss #define VFE_VIOLATION_STATUS			(0x07c)
787319cdf1SRobert Foss 
797319cdf1SRobert Foss #define VFE_CAMIF_CMD				(0x478)
807319cdf1SRobert Foss #define		CMD_CLEAR_CAMIF_STATUS		BIT(2)
817319cdf1SRobert Foss 
827319cdf1SRobert Foss #define VFE_CAMIF_CFG				(0x47c)
837319cdf1SRobert Foss #define		CFG_VSYNC_SYNC_EDGE		(0)
847319cdf1SRobert Foss #define			VSYNC_ACTIVE_HIGH	(0)
857319cdf1SRobert Foss #define			VSYNC_ACTIVE_LOW	(1)
867319cdf1SRobert Foss #define		CFG_HSYNC_SYNC_EDGE		(1)
877319cdf1SRobert Foss #define			HSYNC_ACTIVE_HIGH	(0)
887319cdf1SRobert Foss #define			HSYNC_ACTIVE_LOW	(1)
897319cdf1SRobert Foss #define		CFG_VFE_SUBSAMPLE_ENABLE	BIT(4)
907319cdf1SRobert Foss #define		CFG_BUS_SUBSAMPLE_ENABLE	BIT(5)
917319cdf1SRobert Foss #define		CFG_VFE_OUTPUT_EN		BIT(6)
927319cdf1SRobert Foss #define		CFG_BUS_OUTPUT_EN		BIT(7)
937319cdf1SRobert Foss #define		CFG_BINNING_EN			BIT(9)
947319cdf1SRobert Foss #define		CFG_FRAME_BASED_EN		BIT(10)
957319cdf1SRobert Foss #define		CFG_RAW_CROP_EN			BIT(22)
967319cdf1SRobert Foss 
977319cdf1SRobert Foss #define VFE_REG_UPDATE_CMD			(0x4ac)
987319cdf1SRobert Foss #define		REG_UPDATE_RDI(n)		BIT(1 + (n))
997319cdf1SRobert Foss 
1007319cdf1SRobert Foss #define VFE_BUS_IRQ_MASK(n)		(0x2044 + (n) * 4)
1017319cdf1SRobert Foss #define VFE_BUS_IRQ_CLEAR(n)		(0x2050 + (n) * 4)
1027319cdf1SRobert Foss #define VFE_BUS_IRQ_STATUS(n)		(0x205c + (n) * 4)
1037319cdf1SRobert Foss #define		STATUS0_COMP_RESET_DONE		BIT(0)
1047319cdf1SRobert Foss #define		STATUS0_COMP_REG_UPDATE0_DONE	BIT(1)
1057319cdf1SRobert Foss #define		STATUS0_COMP_REG_UPDATE1_DONE	BIT(2)
1067319cdf1SRobert Foss #define		STATUS0_COMP_REG_UPDATE2_DONE	BIT(3)
1077319cdf1SRobert Foss #define		STATUS0_COMP_REG_UPDATE3_DONE	BIT(4)
1087319cdf1SRobert Foss #define		STATUS0_COMP_REG_UPDATE_DONE(n)	BIT((n) + 1)
1097319cdf1SRobert Foss #define		STATUS0_COMP0_BUF_DONE		BIT(5)
1107319cdf1SRobert Foss #define		STATUS0_COMP1_BUF_DONE		BIT(6)
1117319cdf1SRobert Foss #define		STATUS0_COMP2_BUF_DONE		BIT(7)
1127319cdf1SRobert Foss #define		STATUS0_COMP3_BUF_DONE		BIT(8)
1137319cdf1SRobert Foss #define		STATUS0_COMP4_BUF_DONE		BIT(9)
1147319cdf1SRobert Foss #define		STATUS0_COMP5_BUF_DONE		BIT(10)
1157319cdf1SRobert Foss #define		STATUS0_COMP_BUF_DONE(n)	BIT((n) + 5)
1167319cdf1SRobert Foss #define		STATUS0_COMP_ERROR		BIT(11)
1177319cdf1SRobert Foss #define		STATUS0_COMP_OVERWRITE		BIT(12)
1187319cdf1SRobert Foss #define		STATUS0_OVERFLOW		BIT(13)
1197319cdf1SRobert Foss #define		STATUS0_VIOLATION		BIT(14)
1207319cdf1SRobert Foss /* WM_CLIENT_BUF_DONE defined for buffers 0:19 */
1217319cdf1SRobert Foss #define		STATUS1_WM_CLIENT_BUF_DONE(n)		BIT(n)
1227319cdf1SRobert Foss #define		STATUS1_EARLY_DONE			BIT(24)
1237319cdf1SRobert Foss #define		STATUS2_DUAL_COMP0_BUF_DONE		BIT(0)
1247319cdf1SRobert Foss #define		STATUS2_DUAL_COMP1_BUF_DONE		BIT(1)
1257319cdf1SRobert Foss #define		STATUS2_DUAL_COMP2_BUF_DONE		BIT(2)
1267319cdf1SRobert Foss #define		STATUS2_DUAL_COMP3_BUF_DONE		BIT(3)
1277319cdf1SRobert Foss #define		STATUS2_DUAL_COMP4_BUF_DONE		BIT(4)
1287319cdf1SRobert Foss #define		STATUS2_DUAL_COMP5_BUF_DONE		BIT(5)
1297319cdf1SRobert Foss #define		STATUS2_DUAL_COMP_BUF_DONE(n)		BIT(n)
1307319cdf1SRobert Foss #define		STATUS2_DUAL_COMP_ERROR			BIT(6)
1317319cdf1SRobert Foss #define		STATUS2_DUAL_COMP_OVERWRITE		BIT(7)
1327319cdf1SRobert Foss 
1337319cdf1SRobert Foss #define VFE_BUS_IRQ_CLEAR_GLOBAL		(0x2068)
1347319cdf1SRobert Foss 
1357319cdf1SRobert Foss #define VFE_BUS_WM_DEBUG_STATUS_CFG		(0x226c)
1367319cdf1SRobert Foss #define		DEBUG_STATUS_CFG_STATUS0(n)	BIT(n)
1377319cdf1SRobert Foss #define		DEBUG_STATUS_CFG_STATUS1(n)	BIT(8 + (n))
1387319cdf1SRobert Foss 
1397319cdf1SRobert Foss #define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER	(0x2080)
1407319cdf1SRobert Foss 
1417319cdf1SRobert Foss #define VFE_BUS_WM_ADDR_SYNC_NO_SYNC		(0x2084)
1427319cdf1SRobert Foss #define		BUS_VER2_MAX_CLIENTS (24)
1437319cdf1SRobert Foss #define		WM_ADDR_NO_SYNC_DEFAULT_VAL \
1447319cdf1SRobert Foss 				((1 << BUS_VER2_MAX_CLIENTS) - 1)
1457319cdf1SRobert Foss 
1467319cdf1SRobert Foss #define VFE_BUS_WM_CGC_OVERRIDE			(0x200c)
1477319cdf1SRobert Foss #define		WM_CGC_OVERRIDE_ALL		(0xFFFFF)
1487319cdf1SRobert Foss 
1497319cdf1SRobert Foss #define VFE_BUS_WM_TEST_BUS_CTRL		(0x211c)
1507319cdf1SRobert Foss 
1517319cdf1SRobert Foss #define VFE_BUS_WM_STATUS0(n)			(0x2200 + (n) * 0x100)
1527319cdf1SRobert Foss #define VFE_BUS_WM_STATUS1(n)			(0x2204 + (n) * 0x100)
1537319cdf1SRobert Foss #define VFE_BUS_WM_CFG(n)			(0x2208 + (n) * 0x100)
1547319cdf1SRobert Foss #define		WM_CFG_EN			(0)
1557319cdf1SRobert Foss #define		WM_CFG_MODE			(1)
1567319cdf1SRobert Foss #define			MODE_QCOM_PLAIN	(0)
1577319cdf1SRobert Foss #define			MODE_MIPI_RAW	(1)
1587319cdf1SRobert Foss #define		WM_CFG_VIRTUALFRAME		(2)
1597319cdf1SRobert Foss #define VFE_BUS_WM_HEADER_ADDR(n)		(0x220c + (n) * 0x100)
1607319cdf1SRobert Foss #define VFE_BUS_WM_HEADER_CFG(n)		(0x2210 + (n) * 0x100)
1617319cdf1SRobert Foss #define VFE_BUS_WM_IMAGE_ADDR(n)		(0x2214 + (n) * 0x100)
1627319cdf1SRobert Foss #define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n)		(0x2218 + (n) * 0x100)
1637319cdf1SRobert Foss #define VFE_BUS_WM_BUFFER_WIDTH_CFG(n)		(0x221c + (n) * 0x100)
1647319cdf1SRobert Foss #define		WM_BUFFER_DEFAULT_WIDTH		(0xFF01)
1657319cdf1SRobert Foss 
1667319cdf1SRobert Foss #define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n)		(0x2220 + (n) * 0x100)
1677319cdf1SRobert Foss #define VFE_BUS_WM_PACKER_CFG(n)		(0x2224 + (n) * 0x100)
1687319cdf1SRobert Foss 
1697319cdf1SRobert Foss #define VFE_BUS_WM_STRIDE(n)			(0x2228 + (n) * 0x100)
1707319cdf1SRobert Foss #define		WM_STRIDE_DEFAULT_STRIDE	(0xFF01)
1717319cdf1SRobert Foss 
1727319cdf1SRobert Foss #define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n)	(0x2248 + (n) * 0x100)
1737319cdf1SRobert Foss #define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n)	(0x224c + (n) * 0x100)
1747319cdf1SRobert Foss #define VFE_BUS_WM_FRAMEDROP_PERIOD(n)		(0x2250 + (n) * 0x100)
1757319cdf1SRobert Foss #define VFE_BUS_WM_FRAMEDROP_PATTERN(n)		(0x2254 + (n) * 0x100)
1767319cdf1SRobert Foss #define VFE_BUS_WM_FRAME_INC(n)			(0x2258 + (n) * 0x100)
1777319cdf1SRobert Foss #define VFE_BUS_WM_BURST_LIMIT(n)		(0x225c + (n) * 0x100)
1787319cdf1SRobert Foss 
vfe_hw_version(struct vfe_device * vfe)179d2e86540SRobert Foss static u32 vfe_hw_version(struct vfe_device *vfe)
1807319cdf1SRobert Foss {
1817319cdf1SRobert Foss 	u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION);
1827319cdf1SRobert Foss 
1837319cdf1SRobert Foss 	u32 gen = (hw_version >> 28) & 0xF;
1847319cdf1SRobert Foss 	u32 rev = (hw_version >> 16) & 0xFFF;
1857319cdf1SRobert Foss 	u32 step = hw_version & 0xFFFF;
1867319cdf1SRobert Foss 
1875ad58667SRobert Foss 	dev_dbg(vfe->camss->dev, "VFE HW Version = %u.%u.%u\n",
1885ad58667SRobert Foss 		gen, rev, step);
189d2e86540SRobert Foss 
190d2e86540SRobert Foss 	return hw_version;
1917319cdf1SRobert Foss }
1927319cdf1SRobert Foss 
vfe_reg_set(struct vfe_device * vfe,u32 reg,u32 set_bits)1937319cdf1SRobert Foss static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
1947319cdf1SRobert Foss {
1957319cdf1SRobert Foss 	u32 bits = readl_relaxed(vfe->base + reg);
1967319cdf1SRobert Foss 
1977319cdf1SRobert Foss 	writel_relaxed(bits | set_bits, vfe->base + reg);
1987319cdf1SRobert Foss }
1997319cdf1SRobert Foss 
vfe_global_reset(struct vfe_device * vfe)2007319cdf1SRobert Foss static void vfe_global_reset(struct vfe_device *vfe)
2017319cdf1SRobert Foss {
2027319cdf1SRobert Foss 	u32 reset_bits = GLOBAL_RESET_CMD_CORE		|
2037319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_CAMIF		|
2047319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_BUS		|
2057319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_BUS_BDG	|
2067319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_REGISTER	|
2077319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_TESTGEN	|
2087319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_DSP		|
2097319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_IDLE_CGC	|
2107319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_RDI0		|
2117319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_RDI1		|
2127319cdf1SRobert Foss 			 GLOBAL_RESET_CMD_RDI2;
2137319cdf1SRobert Foss 
2147319cdf1SRobert Foss 	writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0);
2157319cdf1SRobert Foss 
2167319cdf1SRobert Foss 	/* Make sure IRQ mask has been written before resetting */
2177319cdf1SRobert Foss 	wmb();
2187319cdf1SRobert Foss 
2197319cdf1SRobert Foss 	writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD);
2207319cdf1SRobert Foss }
2217319cdf1SRobert Foss 
vfe_wm_start(struct vfe_device * vfe,u8 wm,struct vfe_line * line)2227319cdf1SRobert Foss static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
2237319cdf1SRobert Foss {
2247319cdf1SRobert Foss 	u32 val;
2257319cdf1SRobert Foss 
2267319cdf1SRobert Foss 	/*Set Debug Registers*/
2277319cdf1SRobert Foss 	val = DEBUG_STATUS_CFG_STATUS0(1) |
2287319cdf1SRobert Foss 	      DEBUG_STATUS_CFG_STATUS0(7);
2297319cdf1SRobert Foss 	writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG);
2307319cdf1SRobert Foss 
2317319cdf1SRobert Foss 	/* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
2327319cdf1SRobert Foss 	writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER);
2337319cdf1SRobert Foss 
2347319cdf1SRobert Foss 	/* no clock gating at bus input */
2357319cdf1SRobert Foss 	val = WM_CGC_OVERRIDE_ALL;
2367319cdf1SRobert Foss 	writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
2377319cdf1SRobert Foss 
2387319cdf1SRobert Foss 	writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
2397319cdf1SRobert Foss 
2407319cdf1SRobert Foss 	/* if addr_no_sync has default value then config the addr no sync reg */
2417319cdf1SRobert Foss 	val = WM_ADDR_NO_SYNC_DEFAULT_VAL;
2427319cdf1SRobert Foss 	writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC);
2437319cdf1SRobert Foss 
2447319cdf1SRobert Foss 	writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm));
2457319cdf1SRobert Foss 
2467319cdf1SRobert Foss 	val = WM_BUFFER_DEFAULT_WIDTH;
2477319cdf1SRobert Foss 	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm));
2487319cdf1SRobert Foss 
2497319cdf1SRobert Foss 	val = 0;
2507319cdf1SRobert Foss 	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm));
2517319cdf1SRobert Foss 
2527319cdf1SRobert Foss 	val = 0;
2537319cdf1SRobert Foss 	writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8?
2547319cdf1SRobert Foss 
2557319cdf1SRobert Foss 	/* Configure stride for RDIs */
2567319cdf1SRobert Foss 	val = WM_STRIDE_DEFAULT_STRIDE;
2577319cdf1SRobert Foss 	writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm));
2587319cdf1SRobert Foss 
2597319cdf1SRobert Foss 	/* Enable WM */
2607319cdf1SRobert Foss 	val = 1 << WM_CFG_EN |
2617319cdf1SRobert Foss 	      MODE_MIPI_RAW << WM_CFG_MODE;
2627319cdf1SRobert Foss 	writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
2637319cdf1SRobert Foss }
2647319cdf1SRobert Foss 
vfe_wm_stop(struct vfe_device * vfe,u8 wm)2657319cdf1SRobert Foss static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
2667319cdf1SRobert Foss {
2677319cdf1SRobert Foss 	/* Disable WM */
2687319cdf1SRobert Foss 	writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm));
2697319cdf1SRobert Foss }
2707319cdf1SRobert Foss 
vfe_wm_update(struct vfe_device * vfe,u8 wm,u32 addr,struct vfe_line * line)2717319cdf1SRobert Foss static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
2727319cdf1SRobert Foss 			  struct vfe_line *line)
2737319cdf1SRobert Foss {
2747319cdf1SRobert Foss 	struct v4l2_pix_format_mplane *pix =
2757319cdf1SRobert Foss 		&line->video_out.active_fmt.fmt.pix_mp;
2767319cdf1SRobert Foss 	u32 stride = pix->plane_fmt[0].bytesperline;
2777319cdf1SRobert Foss 
2787319cdf1SRobert Foss 	writel_relaxed(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
2797319cdf1SRobert Foss 	writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
2807319cdf1SRobert Foss }
2817319cdf1SRobert Foss 
vfe_reg_update(struct vfe_device * vfe,enum vfe_line_id line_id)2827319cdf1SRobert Foss static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
2837319cdf1SRobert Foss {
2847319cdf1SRobert Foss 	vfe->reg_update |= REG_UPDATE_RDI(line_id);
2857319cdf1SRobert Foss 
2867319cdf1SRobert Foss 	/* Enforce ordering between previous reg writes and reg update */
2877319cdf1SRobert Foss 	wmb();
2887319cdf1SRobert Foss 
2897319cdf1SRobert Foss 	writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD);
2907319cdf1SRobert Foss 
2917319cdf1SRobert Foss 	/* Enforce ordering between reg update and subsequent reg writes */
2927319cdf1SRobert Foss 	wmb();
2937319cdf1SRobert Foss }
2947319cdf1SRobert Foss 
vfe_reg_update_clear(struct vfe_device * vfe,enum vfe_line_id line_id)2957319cdf1SRobert Foss static inline void vfe_reg_update_clear(struct vfe_device *vfe,
2967319cdf1SRobert Foss 					enum vfe_line_id line_id)
2977319cdf1SRobert Foss {
2987319cdf1SRobert Foss 	vfe->reg_update &= ~REG_UPDATE_RDI(line_id);
2997319cdf1SRobert Foss }
3007319cdf1SRobert Foss 
vfe_enable_irq_common(struct vfe_device * vfe)3017319cdf1SRobert Foss static void vfe_enable_irq_common(struct vfe_device *vfe)
3027319cdf1SRobert Foss {
3037319cdf1SRobert Foss 	vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u);
3047319cdf1SRobert Foss 	vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u);
3057319cdf1SRobert Foss 
3067319cdf1SRobert Foss 	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0));
3077319cdf1SRobert Foss 	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1));
3087319cdf1SRobert Foss 	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2));
3097319cdf1SRobert Foss }
3107319cdf1SRobert Foss 
vfe_isr_halt_ack(struct vfe_device * vfe)3117319cdf1SRobert Foss static void vfe_isr_halt_ack(struct vfe_device *vfe)
3127319cdf1SRobert Foss {
3137319cdf1SRobert Foss 	complete(&vfe->halt_complete);
3147319cdf1SRobert Foss }
3157319cdf1SRobert Foss 
vfe_isr_read(struct vfe_device * vfe,u32 * status0,u32 * status1)3167319cdf1SRobert Foss static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1)
3177319cdf1SRobert Foss {
3187319cdf1SRobert Foss 	*status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
3197319cdf1SRobert Foss 	*status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
3207319cdf1SRobert Foss 
3217319cdf1SRobert Foss 	writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0);
3227319cdf1SRobert Foss 	writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1);
3237319cdf1SRobert Foss 
3247319cdf1SRobert Foss 	/* Enforce ordering between IRQ Clear and Global IRQ Clear */
3257319cdf1SRobert Foss 	wmb();
3267319cdf1SRobert Foss 	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
3277319cdf1SRobert Foss }
3287319cdf1SRobert Foss 
vfe_violation_read(struct vfe_device * vfe)3297319cdf1SRobert Foss static void vfe_violation_read(struct vfe_device *vfe)
3307319cdf1SRobert Foss {
3317319cdf1SRobert Foss 	u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS);
3327319cdf1SRobert Foss 
3337319cdf1SRobert Foss 	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
3347319cdf1SRobert Foss }
3357319cdf1SRobert Foss 
3367319cdf1SRobert Foss /*
3377319cdf1SRobert Foss  * vfe_isr - VFE module interrupt handler
3387319cdf1SRobert Foss  * @irq: Interrupt line
3397319cdf1SRobert Foss  * @dev: VFE device
3407319cdf1SRobert Foss  *
3417319cdf1SRobert Foss  * Return IRQ_HANDLED on success
3427319cdf1SRobert Foss  */
vfe_isr(int irq,void * dev)3437319cdf1SRobert Foss static irqreturn_t vfe_isr(int irq, void *dev)
3447319cdf1SRobert Foss {
3457319cdf1SRobert Foss 	struct vfe_device *vfe = dev;
3467319cdf1SRobert Foss 	u32 status0, status1, vfe_bus_status[3];
3477319cdf1SRobert Foss 	int i, wm;
3487319cdf1SRobert Foss 
3497319cdf1SRobert Foss 	status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
3507319cdf1SRobert Foss 	status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
3517319cdf1SRobert Foss 
3527319cdf1SRobert Foss 	writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
3537319cdf1SRobert Foss 	writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
3547319cdf1SRobert Foss 
3557319cdf1SRobert Foss 	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) {
3567319cdf1SRobert Foss 		vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
3577319cdf1SRobert Foss 		writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
3587319cdf1SRobert Foss 	}
3597319cdf1SRobert Foss 
3607319cdf1SRobert Foss 	/* Enforce ordering between IRQ reading and interpretation */
3617319cdf1SRobert Foss 	wmb();
3627319cdf1SRobert Foss 
3637319cdf1SRobert Foss 	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
3647319cdf1SRobert Foss 	writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
3657319cdf1SRobert Foss 
3667319cdf1SRobert Foss 	if (status0 & STATUS_0_RESET_ACK)
3677319cdf1SRobert Foss 		vfe->isr_ops.reset_ack(vfe);
3687319cdf1SRobert Foss 
3697319cdf1SRobert Foss 	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
3707319cdf1SRobert Foss 		if (status0 & STATUS_0_RDI_REG_UPDATE(i))
3717319cdf1SRobert Foss 			vfe->isr_ops.reg_update(vfe, i);
3727319cdf1SRobert Foss 
3737319cdf1SRobert Foss 	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
3747319cdf1SRobert Foss 		if (status0 & STATUS_1_RDI_SOF(i))
3757319cdf1SRobert Foss 			vfe->isr_ops.sof(vfe, i);
3767319cdf1SRobert Foss 
3777319cdf1SRobert Foss 	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
3787319cdf1SRobert Foss 		if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i))
3797319cdf1SRobert Foss 			vfe->isr_ops.comp_done(vfe, i);
3807319cdf1SRobert Foss 
3817319cdf1SRobert Foss 	for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++)
3827319cdf1SRobert Foss 		if (status0 & BIT(9))
3837319cdf1SRobert Foss 			if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm))
3847319cdf1SRobert Foss 				vfe->isr_ops.wm_done(vfe, wm);
3857319cdf1SRobert Foss 
3867319cdf1SRobert Foss 	return IRQ_HANDLED;
3877319cdf1SRobert Foss }
3887319cdf1SRobert Foss 
3897319cdf1SRobert Foss /*
3907319cdf1SRobert Foss  * vfe_halt - Trigger halt on VFE module and wait to complete
3917319cdf1SRobert Foss  * @vfe: VFE device
3927319cdf1SRobert Foss  *
3937319cdf1SRobert Foss  * Return 0 on success or a negative error code otherwise
3947319cdf1SRobert Foss  */
vfe_halt(struct vfe_device * vfe)3957319cdf1SRobert Foss static int vfe_halt(struct vfe_device *vfe)
3967319cdf1SRobert Foss {
3971ce8c48bSJonathan Marek 	/* rely on vfe_disable_output() to stop the VFE */
3987319cdf1SRobert Foss 	return 0;
3997319cdf1SRobert Foss }
4007319cdf1SRobert Foss 
vfe_get_output(struct vfe_line * line)4017319cdf1SRobert Foss static int vfe_get_output(struct vfe_line *line)
4027319cdf1SRobert Foss {
4037319cdf1SRobert Foss 	struct vfe_device *vfe = to_vfe(line);
4047319cdf1SRobert Foss 	struct vfe_output *output;
4057319cdf1SRobert Foss 	unsigned long flags;
4067319cdf1SRobert Foss 	int wm_idx;
4077319cdf1SRobert Foss 
4087319cdf1SRobert Foss 	spin_lock_irqsave(&vfe->output_lock, flags);
4097319cdf1SRobert Foss 
4107319cdf1SRobert Foss 	output = &line->output;
4118ce158c1SMilen Mitkov 	if (output->state > VFE_OUTPUT_RESERVED) {
4127319cdf1SRobert Foss 		dev_err(vfe->camss->dev, "Output is running\n");
4137319cdf1SRobert Foss 		goto error;
4147319cdf1SRobert Foss 	}
4157319cdf1SRobert Foss 
4167319cdf1SRobert Foss 	output->wm_num = 1;
4177319cdf1SRobert Foss 
4187319cdf1SRobert Foss 	wm_idx = vfe_reserve_wm(vfe, line->id);
4197319cdf1SRobert Foss 	if (wm_idx < 0) {
4207319cdf1SRobert Foss 		dev_err(vfe->camss->dev, "Can not reserve wm\n");
4217319cdf1SRobert Foss 		goto error_get_wm;
4227319cdf1SRobert Foss 	}
4237319cdf1SRobert Foss 	output->wm_idx[0] = wm_idx;
4247319cdf1SRobert Foss 
4257319cdf1SRobert Foss 	output->drop_update_idx = 0;
4267319cdf1SRobert Foss 
4277319cdf1SRobert Foss 	spin_unlock_irqrestore(&vfe->output_lock, flags);
4287319cdf1SRobert Foss 
4297319cdf1SRobert Foss 	return 0;
4307319cdf1SRobert Foss 
4317319cdf1SRobert Foss error_get_wm:
4327319cdf1SRobert Foss 	vfe_release_wm(vfe, output->wm_idx[0]);
4337319cdf1SRobert Foss 	output->state = VFE_OUTPUT_OFF;
4347319cdf1SRobert Foss error:
4357319cdf1SRobert Foss 	spin_unlock_irqrestore(&vfe->output_lock, flags);
4367319cdf1SRobert Foss 
4377319cdf1SRobert Foss 	return -EINVAL;
4387319cdf1SRobert Foss }
4397319cdf1SRobert Foss 
vfe_enable_output(struct vfe_line * line)4407319cdf1SRobert Foss static int vfe_enable_output(struct vfe_line *line)
4417319cdf1SRobert Foss {
4427319cdf1SRobert Foss 	struct vfe_device *vfe = to_vfe(line);
4437319cdf1SRobert Foss 	struct vfe_output *output = &line->output;
4447319cdf1SRobert Foss 	const struct vfe_hw_ops *ops = vfe->ops;
4457319cdf1SRobert Foss 	struct media_entity *sensor;
4467319cdf1SRobert Foss 	unsigned long flags;
4477319cdf1SRobert Foss 	unsigned int frame_skip = 0;
4487319cdf1SRobert Foss 	unsigned int i;
4497319cdf1SRobert Foss 
4507319cdf1SRobert Foss 	sensor = camss_find_sensor(&line->subdev.entity);
4517319cdf1SRobert Foss 	if (sensor) {
4527319cdf1SRobert Foss 		struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(sensor);
4537319cdf1SRobert Foss 
4547319cdf1SRobert Foss 		v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
4557319cdf1SRobert Foss 		/* Max frame skip is 29 frames */
4567319cdf1SRobert Foss 		if (frame_skip > VFE_FRAME_DROP_VAL - 1)
4577319cdf1SRobert Foss 			frame_skip = VFE_FRAME_DROP_VAL - 1;
4587319cdf1SRobert Foss 	}
4597319cdf1SRobert Foss 
4607319cdf1SRobert Foss 	spin_lock_irqsave(&vfe->output_lock, flags);
4617319cdf1SRobert Foss 
4627319cdf1SRobert Foss 	ops->reg_update_clear(vfe, line->id);
4637319cdf1SRobert Foss 
4648ce158c1SMilen Mitkov 	if (output->state > VFE_OUTPUT_RESERVED) {
4657319cdf1SRobert Foss 		dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
4667319cdf1SRobert Foss 			output->state);
4677319cdf1SRobert Foss 		spin_unlock_irqrestore(&vfe->output_lock, flags);
4687319cdf1SRobert Foss 		return -EINVAL;
4697319cdf1SRobert Foss 	}
4707319cdf1SRobert Foss 
4717319cdf1SRobert Foss 	WARN_ON(output->gen2.active_num);
4727319cdf1SRobert Foss 
4737319cdf1SRobert Foss 	output->state = VFE_OUTPUT_ON;
4747319cdf1SRobert Foss 
4757319cdf1SRobert Foss 	output->sequence = 0;
4767319cdf1SRobert Foss 	output->wait_reg_update = 0;
4777319cdf1SRobert Foss 	reinit_completion(&output->reg_update);
4787319cdf1SRobert Foss 
4797319cdf1SRobert Foss 	vfe_wm_start(vfe, output->wm_idx[0], line);
4807319cdf1SRobert Foss 
4817319cdf1SRobert Foss 	for (i = 0; i < 2; i++) {
4827319cdf1SRobert Foss 		output->buf[i] = vfe_buf_get_pending(output);
4837319cdf1SRobert Foss 		if (!output->buf[i])
4847319cdf1SRobert Foss 			break;
4857319cdf1SRobert Foss 		output->gen2.active_num++;
4867319cdf1SRobert Foss 		vfe_wm_update(vfe, output->wm_idx[0], output->buf[i]->addr[0], line);
4877319cdf1SRobert Foss 	}
4887319cdf1SRobert Foss 
4897319cdf1SRobert Foss 	ops->reg_update(vfe, line->id);
4907319cdf1SRobert Foss 
4917319cdf1SRobert Foss 	spin_unlock_irqrestore(&vfe->output_lock, flags);
4927319cdf1SRobert Foss 
4937319cdf1SRobert Foss 	return 0;
4947319cdf1SRobert Foss }
4957319cdf1SRobert Foss 
vfe_disable_output(struct vfe_line * line)496*b1eaec00SBryan O'Donoghue static void vfe_disable_output(struct vfe_line *line)
4977319cdf1SRobert Foss {
4987319cdf1SRobert Foss 	struct vfe_device *vfe = to_vfe(line);
4997319cdf1SRobert Foss 	struct vfe_output *output = &line->output;
5007319cdf1SRobert Foss 	unsigned long flags;
5017319cdf1SRobert Foss 	unsigned int i;
5027319cdf1SRobert Foss 
5037319cdf1SRobert Foss 	spin_lock_irqsave(&vfe->output_lock, flags);
5047319cdf1SRobert Foss 	for (i = 0; i < output->wm_num; i++)
5057319cdf1SRobert Foss 		vfe_wm_stop(vfe, output->wm_idx[i]);
506*b1eaec00SBryan O'Donoghue 	output->gen2.active_num = 0;
5077319cdf1SRobert Foss 	spin_unlock_irqrestore(&vfe->output_lock, flags);
5087319cdf1SRobert Foss 
509*b1eaec00SBryan O'Donoghue 	vfe_reset(vfe);
5107319cdf1SRobert Foss }
5117319cdf1SRobert Foss 
5127319cdf1SRobert Foss /*
5137319cdf1SRobert Foss  * vfe_enable - Enable streaming on VFE line
5147319cdf1SRobert Foss  * @line: VFE line
5157319cdf1SRobert Foss  *
5167319cdf1SRobert Foss  * Return 0 on success or a negative error code otherwise
5177319cdf1SRobert Foss  */
vfe_enable(struct vfe_line * line)5187319cdf1SRobert Foss static int vfe_enable(struct vfe_line *line)
5197319cdf1SRobert Foss {
5207319cdf1SRobert Foss 	struct vfe_device *vfe = to_vfe(line);
5217319cdf1SRobert Foss 	int ret;
5227319cdf1SRobert Foss 
5237319cdf1SRobert Foss 	mutex_lock(&vfe->stream_lock);
5247319cdf1SRobert Foss 
5257319cdf1SRobert Foss 	if (!vfe->stream_count)
5267319cdf1SRobert Foss 		vfe_enable_irq_common(vfe);
5277319cdf1SRobert Foss 
5287319cdf1SRobert Foss 	vfe->stream_count++;
5297319cdf1SRobert Foss 
5307319cdf1SRobert Foss 	mutex_unlock(&vfe->stream_lock);
5317319cdf1SRobert Foss 
5327319cdf1SRobert Foss 	ret = vfe_get_output(line);
5337319cdf1SRobert Foss 	if (ret < 0)
5347319cdf1SRobert Foss 		goto error_get_output;
5357319cdf1SRobert Foss 
5367319cdf1SRobert Foss 	ret = vfe_enable_output(line);
5377319cdf1SRobert Foss 	if (ret < 0)
5387319cdf1SRobert Foss 		goto error_enable_output;
5397319cdf1SRobert Foss 
5407319cdf1SRobert Foss 	vfe->was_streaming = 1;
5417319cdf1SRobert Foss 
5427319cdf1SRobert Foss 	return 0;
5437319cdf1SRobert Foss 
5447319cdf1SRobert Foss error_enable_output:
5457319cdf1SRobert Foss 	vfe_put_output(line);
5467319cdf1SRobert Foss 
5477319cdf1SRobert Foss error_get_output:
5487319cdf1SRobert Foss 	mutex_lock(&vfe->stream_lock);
5497319cdf1SRobert Foss 
5507319cdf1SRobert Foss 	vfe->stream_count--;
5517319cdf1SRobert Foss 
5527319cdf1SRobert Foss 	mutex_unlock(&vfe->stream_lock);
5537319cdf1SRobert Foss 
5547319cdf1SRobert Foss 	return ret;
5557319cdf1SRobert Foss }
5567319cdf1SRobert Foss 
5577319cdf1SRobert Foss /*
5587319cdf1SRobert Foss  * vfe_disable - Disable streaming on VFE line
5597319cdf1SRobert Foss  * @line: VFE line
5607319cdf1SRobert Foss  *
5617319cdf1SRobert Foss  * Return 0 on success or a negative error code otherwise
5627319cdf1SRobert Foss  */
vfe_disable(struct vfe_line * line)5637319cdf1SRobert Foss static int vfe_disable(struct vfe_line *line)
5647319cdf1SRobert Foss {
5657319cdf1SRobert Foss 	struct vfe_device *vfe = to_vfe(line);
5667319cdf1SRobert Foss 
5677319cdf1SRobert Foss 	vfe_disable_output(line);
5687319cdf1SRobert Foss 
5697319cdf1SRobert Foss 	vfe_put_output(line);
5707319cdf1SRobert Foss 
5717319cdf1SRobert Foss 	mutex_lock(&vfe->stream_lock);
5727319cdf1SRobert Foss 
5737319cdf1SRobert Foss 	vfe->stream_count--;
5747319cdf1SRobert Foss 
5757319cdf1SRobert Foss 	mutex_unlock(&vfe->stream_lock);
5767319cdf1SRobert Foss 
5777319cdf1SRobert Foss 	return 0;
5787319cdf1SRobert Foss }
5797319cdf1SRobert Foss 
5807319cdf1SRobert Foss /*
5817319cdf1SRobert Foss  * vfe_isr_sof - Process start of frame interrupt
5827319cdf1SRobert Foss  * @vfe: VFE Device
5837319cdf1SRobert Foss  * @line_id: VFE line
5847319cdf1SRobert Foss  */
vfe_isr_sof(struct vfe_device * vfe,enum vfe_line_id line_id)5857319cdf1SRobert Foss static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
5867319cdf1SRobert Foss {
5877319cdf1SRobert Foss 	/* nop */
5887319cdf1SRobert Foss }
5897319cdf1SRobert Foss 
5907319cdf1SRobert Foss /*
5917319cdf1SRobert Foss  * vfe_isr_reg_update - Process reg update interrupt
5927319cdf1SRobert Foss  * @vfe: VFE Device
5937319cdf1SRobert Foss  * @line_id: VFE line
5947319cdf1SRobert Foss  */
vfe_isr_reg_update(struct vfe_device * vfe,enum vfe_line_id line_id)5957319cdf1SRobert Foss static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
5967319cdf1SRobert Foss {
5977319cdf1SRobert Foss 	struct vfe_output *output;
5987319cdf1SRobert Foss 	unsigned long flags;
5997319cdf1SRobert Foss 
6007319cdf1SRobert Foss 	spin_lock_irqsave(&vfe->output_lock, flags);
6017319cdf1SRobert Foss 	vfe->ops->reg_update_clear(vfe, line_id);
6027319cdf1SRobert Foss 
6037319cdf1SRobert Foss 	output = &vfe->line[line_id].output;
6047319cdf1SRobert Foss 
6057319cdf1SRobert Foss 	if (output->wait_reg_update) {
6067319cdf1SRobert Foss 		output->wait_reg_update = 0;
6077319cdf1SRobert Foss 		complete(&output->reg_update);
6087319cdf1SRobert Foss 	}
6097319cdf1SRobert Foss 
6107319cdf1SRobert Foss 	spin_unlock_irqrestore(&vfe->output_lock, flags);
6117319cdf1SRobert Foss }
6127319cdf1SRobert Foss 
6137319cdf1SRobert Foss /*
6147319cdf1SRobert Foss  * vfe_isr_wm_done - Process write master done interrupt
6157319cdf1SRobert Foss  * @vfe: VFE Device
6167319cdf1SRobert Foss  * @wm: Write master id
6177319cdf1SRobert Foss  */
vfe_isr_wm_done(struct vfe_device * vfe,u8 wm)6187319cdf1SRobert Foss static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
6197319cdf1SRobert Foss {
6207319cdf1SRobert Foss 	struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
6217319cdf1SRobert Foss 	struct camss_buffer *ready_buf;
6227319cdf1SRobert Foss 	struct vfe_output *output;
6237319cdf1SRobert Foss 	unsigned long flags;
6247319cdf1SRobert Foss 	u32 index;
6257319cdf1SRobert Foss 	u64 ts = ktime_get_ns();
6267319cdf1SRobert Foss 
6277319cdf1SRobert Foss 	spin_lock_irqsave(&vfe->output_lock, flags);
6287319cdf1SRobert Foss 
6297319cdf1SRobert Foss 	if (vfe->wm_output_map[wm] == VFE_LINE_NONE) {
6307319cdf1SRobert Foss 		dev_err_ratelimited(vfe->camss->dev,
6317319cdf1SRobert Foss 				    "Received wm done for unmapped index\n");
6327319cdf1SRobert Foss 		goto out_unlock;
6337319cdf1SRobert Foss 	}
6347319cdf1SRobert Foss 	output = &vfe->line[vfe->wm_output_map[wm]].output;
6357319cdf1SRobert Foss 
6367319cdf1SRobert Foss 	ready_buf = output->buf[0];
6377319cdf1SRobert Foss 	if (!ready_buf) {
6387319cdf1SRobert Foss 		dev_err_ratelimited(vfe->camss->dev,
6397319cdf1SRobert Foss 				    "Missing ready buf %d!\n", output->state);
6407319cdf1SRobert Foss 		goto out_unlock;
6417319cdf1SRobert Foss 	}
6427319cdf1SRobert Foss 
6437319cdf1SRobert Foss 	ready_buf->vb.vb2_buf.timestamp = ts;
6447319cdf1SRobert Foss 	ready_buf->vb.sequence = output->sequence++;
6457319cdf1SRobert Foss 
6467319cdf1SRobert Foss 	index = 0;
6477319cdf1SRobert Foss 	output->buf[0] = output->buf[1];
6487319cdf1SRobert Foss 	if (output->buf[0])
6497319cdf1SRobert Foss 		index = 1;
6507319cdf1SRobert Foss 
6517319cdf1SRobert Foss 	output->buf[index] = vfe_buf_get_pending(output);
6527319cdf1SRobert Foss 
6537319cdf1SRobert Foss 	if (output->buf[index])
6547319cdf1SRobert Foss 		vfe_wm_update(vfe, output->wm_idx[0], output->buf[index]->addr[0], line);
6557319cdf1SRobert Foss 	else
6567319cdf1SRobert Foss 		output->gen2.active_num--;
6577319cdf1SRobert Foss 
6587319cdf1SRobert Foss 	spin_unlock_irqrestore(&vfe->output_lock, flags);
6597319cdf1SRobert Foss 
6607319cdf1SRobert Foss 	vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
6617319cdf1SRobert Foss 
6627319cdf1SRobert Foss 	return;
6637319cdf1SRobert Foss 
6647319cdf1SRobert Foss out_unlock:
6657319cdf1SRobert Foss 	spin_unlock_irqrestore(&vfe->output_lock, flags);
6667319cdf1SRobert Foss }
6677319cdf1SRobert Foss 
6687319cdf1SRobert Foss /*
6692f6f8af6SRobert Foss  * vfe_pm_domain_off - Disable power domains specific to this VFE.
6702f6f8af6SRobert Foss  * @vfe: VFE Device
6712f6f8af6SRobert Foss  */
vfe_pm_domain_off(struct vfe_device * vfe)6722f6f8af6SRobert Foss static void vfe_pm_domain_off(struct vfe_device *vfe)
6732f6f8af6SRobert Foss {
67446cc0317SVladimir Zapolskiy 	struct camss *camss = vfe->camss;
67546cc0317SVladimir Zapolskiy 
67646cc0317SVladimir Zapolskiy 	if (vfe->id >= camss->vfe_num)
67746cc0317SVladimir Zapolskiy 		return;
67846cc0317SVladimir Zapolskiy 
67946cc0317SVladimir Zapolskiy 	device_link_del(camss->genpd_link[vfe->id]);
6802f6f8af6SRobert Foss }
6812f6f8af6SRobert Foss 
6822f6f8af6SRobert Foss /*
6832f6f8af6SRobert Foss  * vfe_pm_domain_on - Enable power domains specific to this VFE.
6842f6f8af6SRobert Foss  * @vfe: VFE Device
6852f6f8af6SRobert Foss  */
vfe_pm_domain_on(struct vfe_device * vfe)6862f6f8af6SRobert Foss static int vfe_pm_domain_on(struct vfe_device *vfe)
6872f6f8af6SRobert Foss {
68846cc0317SVladimir Zapolskiy 	struct camss *camss = vfe->camss;
68946cc0317SVladimir Zapolskiy 	enum vfe_line_id id = vfe->id;
69046cc0317SVladimir Zapolskiy 
69146cc0317SVladimir Zapolskiy 	if (id >= camss->vfe_num)
69246cc0317SVladimir Zapolskiy 		return 0;
69346cc0317SVladimir Zapolskiy 
69446cc0317SVladimir Zapolskiy 	camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id],
69546cc0317SVladimir Zapolskiy 						DL_FLAG_STATELESS |
69646cc0317SVladimir Zapolskiy 						DL_FLAG_PM_RUNTIME |
69746cc0317SVladimir Zapolskiy 						DL_FLAG_RPM_ACTIVE);
69846cc0317SVladimir Zapolskiy 	if (!camss->genpd_link[id])
69946cc0317SVladimir Zapolskiy 		return -EINVAL;
70046cc0317SVladimir Zapolskiy 
7012f6f8af6SRobert Foss 	return 0;
7022f6f8af6SRobert Foss }
7032f6f8af6SRobert Foss 
7042f6f8af6SRobert Foss /*
7057319cdf1SRobert Foss  * vfe_queue_buffer - Add empty buffer
7067319cdf1SRobert Foss  * @vid: Video device structure
7077319cdf1SRobert Foss  * @buf: Buffer to be enqueued
7087319cdf1SRobert Foss  *
7097319cdf1SRobert Foss  * Add an empty buffer - depending on the current number of buffers it will be
7107319cdf1SRobert Foss  * put in pending buffer queue or directly given to the hardware to be filled.
7117319cdf1SRobert Foss  *
7127319cdf1SRobert Foss  * Return 0 on success or a negative error code otherwise
7137319cdf1SRobert Foss  */
vfe_queue_buffer(struct camss_video * vid,struct camss_buffer * buf)7147319cdf1SRobert Foss static int vfe_queue_buffer(struct camss_video *vid,
7157319cdf1SRobert Foss 			    struct camss_buffer *buf)
7167319cdf1SRobert Foss {
7177319cdf1SRobert Foss 	struct vfe_line *line = container_of(vid, struct vfe_line, video_out);
7187319cdf1SRobert Foss 	struct vfe_device *vfe = to_vfe(line);
7197319cdf1SRobert Foss 	struct vfe_output *output;
7207319cdf1SRobert Foss 	unsigned long flags;
7217319cdf1SRobert Foss 
7227319cdf1SRobert Foss 	output = &line->output;
7237319cdf1SRobert Foss 
7247319cdf1SRobert Foss 	spin_lock_irqsave(&vfe->output_lock, flags);
7257319cdf1SRobert Foss 
7267319cdf1SRobert Foss 	if (output->state == VFE_OUTPUT_ON && output->gen2.active_num < 2) {
7277319cdf1SRobert Foss 		output->buf[output->gen2.active_num++] = buf;
7287319cdf1SRobert Foss 		vfe_wm_update(vfe, output->wm_idx[0], buf->addr[0], line);
7297319cdf1SRobert Foss 	} else {
7307319cdf1SRobert Foss 		vfe_buf_add_pending(output, buf);
7317319cdf1SRobert Foss 	}
7327319cdf1SRobert Foss 
7337319cdf1SRobert Foss 	spin_unlock_irqrestore(&vfe->output_lock, flags);
7347319cdf1SRobert Foss 
7357319cdf1SRobert Foss 	return 0;
7367319cdf1SRobert Foss }
7377319cdf1SRobert Foss 
7387319cdf1SRobert Foss static const struct vfe_isr_ops vfe_isr_ops_170 = {
7397319cdf1SRobert Foss 	.reset_ack = vfe_isr_reset_ack,
7407319cdf1SRobert Foss 	.halt_ack = vfe_isr_halt_ack,
7417319cdf1SRobert Foss 	.reg_update = vfe_isr_reg_update,
7427319cdf1SRobert Foss 	.sof = vfe_isr_sof,
7437319cdf1SRobert Foss 	.comp_done = vfe_isr_comp_done,
7447319cdf1SRobert Foss 	.wm_done = vfe_isr_wm_done,
7457319cdf1SRobert Foss };
7467319cdf1SRobert Foss 
7477319cdf1SRobert Foss static const struct camss_video_ops vfe_video_ops_170 = {
7487319cdf1SRobert Foss 	.queue_buffer = vfe_queue_buffer,
7497319cdf1SRobert Foss 	.flush_buffers = vfe_flush_buffers,
7507319cdf1SRobert Foss };
7517319cdf1SRobert Foss 
vfe_subdev_init(struct device * dev,struct vfe_device * vfe)7527319cdf1SRobert Foss static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
7537319cdf1SRobert Foss {
7547319cdf1SRobert Foss 	vfe->isr_ops = vfe_isr_ops_170;
7557319cdf1SRobert Foss 	vfe->video_ops = vfe_video_ops_170;
7567319cdf1SRobert Foss 
7577319cdf1SRobert Foss 	vfe->line_num = VFE_LINE_NUM_GEN2;
7587319cdf1SRobert Foss }
7597319cdf1SRobert Foss 
7607319cdf1SRobert Foss const struct vfe_hw_ops vfe_ops_170 = {
7617319cdf1SRobert Foss 	.global_reset = vfe_global_reset,
762d2e86540SRobert Foss 	.hw_version = vfe_hw_version,
7637319cdf1SRobert Foss 	.isr_read = vfe_isr_read,
7647319cdf1SRobert Foss 	.isr = vfe_isr,
7652f6f8af6SRobert Foss 	.pm_domain_off = vfe_pm_domain_off,
7662f6f8af6SRobert Foss 	.pm_domain_on = vfe_pm_domain_on,
7677319cdf1SRobert Foss 	.reg_update_clear = vfe_reg_update_clear,
7687319cdf1SRobert Foss 	.reg_update = vfe_reg_update,
7697319cdf1SRobert Foss 	.subdev_init = vfe_subdev_init,
7707319cdf1SRobert Foss 	.vfe_disable = vfe_disable,
7717319cdf1SRobert Foss 	.vfe_enable = vfe_enable,
7727319cdf1SRobert Foss 	.vfe_halt = vfe_halt,
7737319cdf1SRobert Foss 	.violation_read = vfe_violation_read,
7747319cdf1SRobert Foss };
775