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_GLOBAL_RESET_CMD (0x018)
187319cdf1SRobert Foss #define GLOBAL_RESET_CMD_CORE BIT(0)
197319cdf1SRobert Foss #define GLOBAL_RESET_CMD_CAMIF BIT(1)
207319cdf1SRobert Foss #define GLOBAL_RESET_CMD_BUS BIT(2)
217319cdf1SRobert Foss #define GLOBAL_RESET_CMD_BUS_BDG BIT(3)
227319cdf1SRobert Foss #define GLOBAL_RESET_CMD_REGISTER BIT(4)
237319cdf1SRobert Foss #define GLOBAL_RESET_CMD_PM BIT(5)
247319cdf1SRobert Foss #define GLOBAL_RESET_CMD_BUS_MISR BIT(6)
257319cdf1SRobert Foss #define GLOBAL_RESET_CMD_TESTGEN BIT(7)
267319cdf1SRobert Foss #define GLOBAL_RESET_CMD_DSP BIT(8)
277319cdf1SRobert Foss #define GLOBAL_RESET_CMD_IDLE_CGC BIT(9)
287319cdf1SRobert Foss #define GLOBAL_RESET_CMD_RDI0 BIT(10)
297319cdf1SRobert Foss #define GLOBAL_RESET_CMD_RDI1 BIT(11)
307319cdf1SRobert Foss #define GLOBAL_RESET_CMD_RDI2 BIT(12)
317319cdf1SRobert Foss #define GLOBAL_RESET_CMD_RDI3 BIT(13)
327319cdf1SRobert Foss #define GLOBAL_RESET_CMD_VFE_DOMAIN BIT(30)
337319cdf1SRobert Foss #define GLOBAL_RESET_CMD_RESET_BYPASS BIT(31)
347319cdf1SRobert Foss
357319cdf1SRobert Foss #define VFE_CORE_CFG (0x050)
367319cdf1SRobert Foss #define CFG_PIXEL_PATTERN_YCBYCR (0x4)
377319cdf1SRobert Foss #define CFG_PIXEL_PATTERN_YCRYCB (0x5)
387319cdf1SRobert Foss #define CFG_PIXEL_PATTERN_CBYCRY (0x6)
397319cdf1SRobert Foss #define CFG_PIXEL_PATTERN_CRYCBY (0x7)
407319cdf1SRobert Foss #define CFG_COMPOSITE_REG_UPDATE_EN BIT(4)
417319cdf1SRobert Foss
427319cdf1SRobert Foss #define VFE_IRQ_CMD (0x058)
437319cdf1SRobert Foss #define CMD_GLOBAL_CLEAR BIT(0)
447319cdf1SRobert Foss
457319cdf1SRobert Foss #define VFE_IRQ_MASK_0 (0x05c)
467319cdf1SRobert Foss #define MASK_0_CAMIF_SOF BIT(0)
477319cdf1SRobert Foss #define MASK_0_CAMIF_EOF BIT(1)
487319cdf1SRobert Foss #define MASK_0_RDI_REG_UPDATE(n) BIT((n) + 5)
497319cdf1SRobert Foss #define MASK_0_IMAGE_MASTER_n_PING_PONG(n) BIT((n) + 8)
507319cdf1SRobert Foss #define MASK_0_IMAGE_COMPOSITE_DONE_n(n) BIT((n) + 25)
517319cdf1SRobert Foss #define MASK_0_RESET_ACK BIT(31)
527319cdf1SRobert Foss
537319cdf1SRobert Foss #define VFE_IRQ_MASK_1 (0x060)
547319cdf1SRobert Foss #define MASK_1_CAMIF_ERROR BIT(0)
557319cdf1SRobert Foss #define MASK_1_VIOLATION BIT(7)
567319cdf1SRobert Foss #define MASK_1_BUS_BDG_HALT_ACK BIT(8)
577319cdf1SRobert Foss #define MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n) BIT((n) + 9)
587319cdf1SRobert Foss #define MASK_1_RDI_SOF(n) BIT((n) + 29)
597319cdf1SRobert Foss
607319cdf1SRobert Foss #define VFE_IRQ_CLEAR_0 (0x064)
617319cdf1SRobert Foss #define VFE_IRQ_CLEAR_1 (0x068)
627319cdf1SRobert Foss
637319cdf1SRobert Foss #define VFE_IRQ_STATUS_0 (0x06c)
647319cdf1SRobert Foss #define STATUS_0_CAMIF_SOF BIT(0)
657319cdf1SRobert Foss #define STATUS_0_RDI_REG_UPDATE(n) BIT((n) + 5)
667319cdf1SRobert Foss #define STATUS_0_IMAGE_MASTER_PING_PONG(n) BIT((n) + 8)
677319cdf1SRobert Foss #define STATUS_0_IMAGE_COMPOSITE_DONE(n) BIT((n) + 25)
687319cdf1SRobert Foss #define STATUS_0_RESET_ACK BIT(31)
697319cdf1SRobert Foss
707319cdf1SRobert Foss #define VFE_IRQ_STATUS_1 (0x070)
717319cdf1SRobert Foss #define STATUS_1_VIOLATION BIT(7)
727319cdf1SRobert Foss #define STATUS_1_BUS_BDG_HALT_ACK BIT(8)
737319cdf1SRobert Foss #define STATUS_1_RDI_SOF(n) BIT((n) + 27)
747319cdf1SRobert Foss
757319cdf1SRobert Foss #define VFE_VIOLATION_STATUS (0x07c)
767319cdf1SRobert Foss
777319cdf1SRobert Foss #define VFE_CAMIF_CMD (0x478)
787319cdf1SRobert Foss #define CMD_CLEAR_CAMIF_STATUS BIT(2)
797319cdf1SRobert Foss
807319cdf1SRobert Foss #define VFE_CAMIF_CFG (0x47c)
817319cdf1SRobert Foss #define CFG_VSYNC_SYNC_EDGE (0)
827319cdf1SRobert Foss #define VSYNC_ACTIVE_HIGH (0)
837319cdf1SRobert Foss #define VSYNC_ACTIVE_LOW (1)
847319cdf1SRobert Foss #define CFG_HSYNC_SYNC_EDGE (1)
857319cdf1SRobert Foss #define HSYNC_ACTIVE_HIGH (0)
867319cdf1SRobert Foss #define HSYNC_ACTIVE_LOW (1)
877319cdf1SRobert Foss #define CFG_VFE_SUBSAMPLE_ENABLE BIT(4)
887319cdf1SRobert Foss #define CFG_BUS_SUBSAMPLE_ENABLE BIT(5)
897319cdf1SRobert Foss #define CFG_VFE_OUTPUT_EN BIT(6)
907319cdf1SRobert Foss #define CFG_BUS_OUTPUT_EN BIT(7)
917319cdf1SRobert Foss #define CFG_BINNING_EN BIT(9)
927319cdf1SRobert Foss #define CFG_FRAME_BASED_EN BIT(10)
937319cdf1SRobert Foss #define CFG_RAW_CROP_EN BIT(22)
947319cdf1SRobert Foss
957319cdf1SRobert Foss #define VFE_REG_UPDATE_CMD (0x4ac)
967319cdf1SRobert Foss #define REG_UPDATE_RDI(n) BIT(1 + (n))
977319cdf1SRobert Foss
987319cdf1SRobert Foss #define VFE_BUS_IRQ_MASK(n) (0x2044 + (n) * 4)
997319cdf1SRobert Foss #define VFE_BUS_IRQ_CLEAR(n) (0x2050 + (n) * 4)
1007319cdf1SRobert Foss #define VFE_BUS_IRQ_STATUS(n) (0x205c + (n) * 4)
1017319cdf1SRobert Foss #define STATUS0_COMP_RESET_DONE BIT(0)
1027319cdf1SRobert Foss #define STATUS0_COMP_REG_UPDATE0_DONE BIT(1)
1037319cdf1SRobert Foss #define STATUS0_COMP_REG_UPDATE1_DONE BIT(2)
1047319cdf1SRobert Foss #define STATUS0_COMP_REG_UPDATE2_DONE BIT(3)
1057319cdf1SRobert Foss #define STATUS0_COMP_REG_UPDATE3_DONE BIT(4)
1067319cdf1SRobert Foss #define STATUS0_COMP_REG_UPDATE_DONE(n) BIT((n) + 1)
1077319cdf1SRobert Foss #define STATUS0_COMP0_BUF_DONE BIT(5)
1087319cdf1SRobert Foss #define STATUS0_COMP1_BUF_DONE BIT(6)
1097319cdf1SRobert Foss #define STATUS0_COMP2_BUF_DONE BIT(7)
1107319cdf1SRobert Foss #define STATUS0_COMP3_BUF_DONE BIT(8)
1117319cdf1SRobert Foss #define STATUS0_COMP4_BUF_DONE BIT(9)
1127319cdf1SRobert Foss #define STATUS0_COMP5_BUF_DONE BIT(10)
1137319cdf1SRobert Foss #define STATUS0_COMP_BUF_DONE(n) BIT((n) + 5)
1147319cdf1SRobert Foss #define STATUS0_COMP_ERROR BIT(11)
1157319cdf1SRobert Foss #define STATUS0_COMP_OVERWRITE BIT(12)
1167319cdf1SRobert Foss #define STATUS0_OVERFLOW BIT(13)
1177319cdf1SRobert Foss #define STATUS0_VIOLATION BIT(14)
1187319cdf1SRobert Foss /* WM_CLIENT_BUF_DONE defined for buffers 0:19 */
1197319cdf1SRobert Foss #define STATUS1_WM_CLIENT_BUF_DONE(n) BIT(n)
1207319cdf1SRobert Foss #define STATUS1_EARLY_DONE BIT(24)
1217319cdf1SRobert Foss #define STATUS2_DUAL_COMP0_BUF_DONE BIT(0)
1227319cdf1SRobert Foss #define STATUS2_DUAL_COMP1_BUF_DONE BIT(1)
1237319cdf1SRobert Foss #define STATUS2_DUAL_COMP2_BUF_DONE BIT(2)
1247319cdf1SRobert Foss #define STATUS2_DUAL_COMP3_BUF_DONE BIT(3)
1257319cdf1SRobert Foss #define STATUS2_DUAL_COMP4_BUF_DONE BIT(4)
1267319cdf1SRobert Foss #define STATUS2_DUAL_COMP5_BUF_DONE BIT(5)
1277319cdf1SRobert Foss #define STATUS2_DUAL_COMP_BUF_DONE(n) BIT(n)
1287319cdf1SRobert Foss #define STATUS2_DUAL_COMP_ERROR BIT(6)
1297319cdf1SRobert Foss #define STATUS2_DUAL_COMP_OVERWRITE BIT(7)
1307319cdf1SRobert Foss
1317319cdf1SRobert Foss #define VFE_BUS_IRQ_CLEAR_GLOBAL (0x2068)
1327319cdf1SRobert Foss
1337319cdf1SRobert Foss #define VFE_BUS_WM_DEBUG_STATUS_CFG (0x226c)
1347319cdf1SRobert Foss #define DEBUG_STATUS_CFG_STATUS0(n) BIT(n)
1357319cdf1SRobert Foss #define DEBUG_STATUS_CFG_STATUS1(n) BIT(8 + (n))
1367319cdf1SRobert Foss
1377319cdf1SRobert Foss #define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER (0x2080)
1387319cdf1SRobert Foss
1397319cdf1SRobert Foss #define VFE_BUS_WM_ADDR_SYNC_NO_SYNC (0x2084)
1407319cdf1SRobert Foss #define BUS_VER2_MAX_CLIENTS (24)
1417319cdf1SRobert Foss #define WM_ADDR_NO_SYNC_DEFAULT_VAL \
1427319cdf1SRobert Foss ((1 << BUS_VER2_MAX_CLIENTS) - 1)
1437319cdf1SRobert Foss
1447319cdf1SRobert Foss #define VFE_BUS_WM_CGC_OVERRIDE (0x200c)
1457319cdf1SRobert Foss #define WM_CGC_OVERRIDE_ALL (0xFFFFF)
1467319cdf1SRobert Foss
1477319cdf1SRobert Foss #define VFE_BUS_WM_TEST_BUS_CTRL (0x211c)
1487319cdf1SRobert Foss
1497319cdf1SRobert Foss #define VFE_BUS_WM_STATUS0(n) (0x2200 + (n) * 0x100)
1507319cdf1SRobert Foss #define VFE_BUS_WM_STATUS1(n) (0x2204 + (n) * 0x100)
1517319cdf1SRobert Foss #define VFE_BUS_WM_CFG(n) (0x2208 + (n) * 0x100)
1527319cdf1SRobert Foss #define WM_CFG_EN (0)
1537319cdf1SRobert Foss #define WM_CFG_MODE (1)
1547319cdf1SRobert Foss #define MODE_QCOM_PLAIN (0)
1557319cdf1SRobert Foss #define MODE_MIPI_RAW (1)
1567319cdf1SRobert Foss #define WM_CFG_VIRTUALFRAME (2)
1577319cdf1SRobert Foss #define VFE_BUS_WM_HEADER_ADDR(n) (0x220c + (n) * 0x100)
1587319cdf1SRobert Foss #define VFE_BUS_WM_HEADER_CFG(n) (0x2210 + (n) * 0x100)
1597319cdf1SRobert Foss #define VFE_BUS_WM_IMAGE_ADDR(n) (0x2214 + (n) * 0x100)
1607319cdf1SRobert Foss #define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n) (0x2218 + (n) * 0x100)
1617319cdf1SRobert Foss #define VFE_BUS_WM_BUFFER_WIDTH_CFG(n) (0x221c + (n) * 0x100)
1627319cdf1SRobert Foss #define WM_BUFFER_DEFAULT_WIDTH (0xFF01)
1637319cdf1SRobert Foss
1647319cdf1SRobert Foss #define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n) (0x2220 + (n) * 0x100)
1657319cdf1SRobert Foss #define VFE_BUS_WM_PACKER_CFG(n) (0x2224 + (n) * 0x100)
1667319cdf1SRobert Foss
1677319cdf1SRobert Foss #define VFE_BUS_WM_STRIDE(n) (0x2228 + (n) * 0x100)
1687319cdf1SRobert Foss #define WM_STRIDE_DEFAULT_STRIDE (0xFF01)
1697319cdf1SRobert Foss
1707319cdf1SRobert Foss #define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n) (0x2248 + (n) * 0x100)
1717319cdf1SRobert Foss #define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n) (0x224c + (n) * 0x100)
1727319cdf1SRobert Foss #define VFE_BUS_WM_FRAMEDROP_PERIOD(n) (0x2250 + (n) * 0x100)
1737319cdf1SRobert Foss #define VFE_BUS_WM_FRAMEDROP_PATTERN(n) (0x2254 + (n) * 0x100)
1747319cdf1SRobert Foss #define VFE_BUS_WM_FRAME_INC(n) (0x2258 + (n) * 0x100)
1757319cdf1SRobert Foss #define VFE_BUS_WM_BURST_LIMIT(n) (0x225c + (n) * 0x100)
1767319cdf1SRobert Foss
vfe_reg_set(struct vfe_device * vfe,u32 reg,u32 set_bits)1777319cdf1SRobert Foss static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
1787319cdf1SRobert Foss {
1797319cdf1SRobert Foss u32 bits = readl_relaxed(vfe->base + reg);
1807319cdf1SRobert Foss
1817319cdf1SRobert Foss writel_relaxed(bits | set_bits, vfe->base + reg);
1827319cdf1SRobert Foss }
1837319cdf1SRobert Foss
vfe_global_reset(struct vfe_device * vfe)1847319cdf1SRobert Foss static void vfe_global_reset(struct vfe_device *vfe)
1857319cdf1SRobert Foss {
1867319cdf1SRobert Foss u32 reset_bits = GLOBAL_RESET_CMD_CORE |
1877319cdf1SRobert Foss GLOBAL_RESET_CMD_CAMIF |
1887319cdf1SRobert Foss GLOBAL_RESET_CMD_BUS |
1897319cdf1SRobert Foss GLOBAL_RESET_CMD_BUS_BDG |
1907319cdf1SRobert Foss GLOBAL_RESET_CMD_REGISTER |
1917319cdf1SRobert Foss GLOBAL_RESET_CMD_TESTGEN |
1927319cdf1SRobert Foss GLOBAL_RESET_CMD_DSP |
1937319cdf1SRobert Foss GLOBAL_RESET_CMD_IDLE_CGC |
1947319cdf1SRobert Foss GLOBAL_RESET_CMD_RDI0 |
1957319cdf1SRobert Foss GLOBAL_RESET_CMD_RDI1 |
1962ce0bd41SBryan O'Donoghue GLOBAL_RESET_CMD_RDI2 |
1972ce0bd41SBryan O'Donoghue GLOBAL_RESET_CMD_RDI3;
1987319cdf1SRobert Foss
1997319cdf1SRobert Foss writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0);
2007319cdf1SRobert Foss
2017319cdf1SRobert Foss /* Make sure IRQ mask has been written before resetting */
2027319cdf1SRobert Foss wmb();
2037319cdf1SRobert Foss
2047319cdf1SRobert Foss writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD);
2057319cdf1SRobert Foss }
2067319cdf1SRobert Foss
vfe_wm_start(struct vfe_device * vfe,u8 wm,struct vfe_line * line)2077319cdf1SRobert Foss static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
2087319cdf1SRobert Foss {
2097319cdf1SRobert Foss u32 val;
2107319cdf1SRobert Foss
2117319cdf1SRobert Foss /*Set Debug Registers*/
2127319cdf1SRobert Foss val = DEBUG_STATUS_CFG_STATUS0(1) |
2137319cdf1SRobert Foss DEBUG_STATUS_CFG_STATUS0(7);
2147319cdf1SRobert Foss writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG);
2157319cdf1SRobert Foss
2167319cdf1SRobert Foss /* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
2177319cdf1SRobert Foss writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER);
2187319cdf1SRobert Foss
2197319cdf1SRobert Foss /* no clock gating at bus input */
2207319cdf1SRobert Foss val = WM_CGC_OVERRIDE_ALL;
2217319cdf1SRobert Foss writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
2227319cdf1SRobert Foss
2237319cdf1SRobert Foss writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
2247319cdf1SRobert Foss
2257319cdf1SRobert Foss /* if addr_no_sync has default value then config the addr no sync reg */
2267319cdf1SRobert Foss val = WM_ADDR_NO_SYNC_DEFAULT_VAL;
2277319cdf1SRobert Foss writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC);
2287319cdf1SRobert Foss
2297319cdf1SRobert Foss writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm));
2307319cdf1SRobert Foss
2317319cdf1SRobert Foss val = WM_BUFFER_DEFAULT_WIDTH;
2327319cdf1SRobert Foss writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm));
2337319cdf1SRobert Foss
2347319cdf1SRobert Foss val = 0;
2357319cdf1SRobert Foss writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm));
2367319cdf1SRobert Foss
2377319cdf1SRobert Foss val = 0;
2387319cdf1SRobert Foss writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8?
2397319cdf1SRobert Foss
2407319cdf1SRobert Foss /* Configure stride for RDIs */
2417319cdf1SRobert Foss val = WM_STRIDE_DEFAULT_STRIDE;
2427319cdf1SRobert Foss writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm));
2437319cdf1SRobert Foss
2447319cdf1SRobert Foss /* Enable WM */
2457319cdf1SRobert Foss val = 1 << WM_CFG_EN |
2467319cdf1SRobert Foss MODE_MIPI_RAW << WM_CFG_MODE;
2477319cdf1SRobert Foss writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
2487319cdf1SRobert Foss }
2497319cdf1SRobert Foss
vfe_wm_stop(struct vfe_device * vfe,u8 wm)2507319cdf1SRobert Foss static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
2517319cdf1SRobert Foss {
2527319cdf1SRobert Foss /* Disable WM */
2537319cdf1SRobert Foss writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm));
2547319cdf1SRobert Foss }
2557319cdf1SRobert Foss
vfe_wm_update(struct vfe_device * vfe,u8 wm,u32 addr,struct vfe_line * line)2567319cdf1SRobert Foss static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
2577319cdf1SRobert Foss struct vfe_line *line)
2587319cdf1SRobert Foss {
2597319cdf1SRobert Foss struct v4l2_pix_format_mplane *pix =
2607319cdf1SRobert Foss &line->video_out.active_fmt.fmt.pix_mp;
2617319cdf1SRobert Foss u32 stride = pix->plane_fmt[0].bytesperline;
2627319cdf1SRobert Foss
2637319cdf1SRobert Foss writel_relaxed(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
2647319cdf1SRobert Foss writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
2657319cdf1SRobert Foss }
2667319cdf1SRobert Foss
vfe_reg_update(struct vfe_device * vfe,enum vfe_line_id line_id)2677319cdf1SRobert Foss static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
2687319cdf1SRobert Foss {
2697319cdf1SRobert Foss vfe->reg_update |= REG_UPDATE_RDI(line_id);
2707319cdf1SRobert Foss
2717319cdf1SRobert Foss /* Enforce ordering between previous reg writes and reg update */
2727319cdf1SRobert Foss wmb();
2737319cdf1SRobert Foss
2747319cdf1SRobert Foss writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD);
2757319cdf1SRobert Foss
2767319cdf1SRobert Foss /* Enforce ordering between reg update and subsequent reg writes */
2777319cdf1SRobert Foss wmb();
2787319cdf1SRobert Foss }
2797319cdf1SRobert Foss
vfe_reg_update_clear(struct vfe_device * vfe,enum vfe_line_id line_id)2807319cdf1SRobert Foss static inline void vfe_reg_update_clear(struct vfe_device *vfe,
2817319cdf1SRobert Foss enum vfe_line_id line_id)
2827319cdf1SRobert Foss {
2837319cdf1SRobert Foss vfe->reg_update &= ~REG_UPDATE_RDI(line_id);
2847319cdf1SRobert Foss }
2857319cdf1SRobert Foss
vfe_enable_irq_common(struct vfe_device * vfe)2867319cdf1SRobert Foss static void vfe_enable_irq_common(struct vfe_device *vfe)
2877319cdf1SRobert Foss {
2887319cdf1SRobert Foss vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u);
2897319cdf1SRobert Foss vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u);
2907319cdf1SRobert Foss
2917319cdf1SRobert Foss writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0));
2927319cdf1SRobert Foss writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1));
2937319cdf1SRobert Foss writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2));
2947319cdf1SRobert Foss }
2957319cdf1SRobert Foss
vfe_isr_halt_ack(struct vfe_device * vfe)2967319cdf1SRobert Foss static void vfe_isr_halt_ack(struct vfe_device *vfe)
2977319cdf1SRobert Foss {
2987319cdf1SRobert Foss complete(&vfe->halt_complete);
2997319cdf1SRobert Foss }
3007319cdf1SRobert Foss
vfe_isr_read(struct vfe_device * vfe,u32 * status0,u32 * status1)3017319cdf1SRobert Foss static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1)
3027319cdf1SRobert Foss {
3037319cdf1SRobert Foss *status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
3047319cdf1SRobert Foss *status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
3057319cdf1SRobert Foss
3067319cdf1SRobert Foss writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0);
3077319cdf1SRobert Foss writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1);
3087319cdf1SRobert Foss
3097319cdf1SRobert Foss /* Enforce ordering between IRQ Clear and Global IRQ Clear */
3107319cdf1SRobert Foss wmb();
3117319cdf1SRobert Foss writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
3127319cdf1SRobert Foss }
3137319cdf1SRobert Foss
vfe_violation_read(struct vfe_device * vfe)3147319cdf1SRobert Foss static void vfe_violation_read(struct vfe_device *vfe)
3157319cdf1SRobert Foss {
3167319cdf1SRobert Foss u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS);
3177319cdf1SRobert Foss
3187319cdf1SRobert Foss pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
3197319cdf1SRobert Foss }
3207319cdf1SRobert Foss
3217319cdf1SRobert Foss /*
3227319cdf1SRobert Foss * vfe_isr - VFE module interrupt handler
3237319cdf1SRobert Foss * @irq: Interrupt line
3247319cdf1SRobert Foss * @dev: VFE device
3257319cdf1SRobert Foss *
3267319cdf1SRobert Foss * Return IRQ_HANDLED on success
3277319cdf1SRobert Foss */
vfe_isr(int irq,void * dev)3287319cdf1SRobert Foss static irqreturn_t vfe_isr(int irq, void *dev)
3297319cdf1SRobert Foss {
3307319cdf1SRobert Foss struct vfe_device *vfe = dev;
3312ce0bd41SBryan O'Donoghue u32 status0, status1, vfe_bus_status[VFE_LINE_NUM_MAX];
3327319cdf1SRobert Foss int i, wm;
3337319cdf1SRobert Foss
3347319cdf1SRobert Foss status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
3357319cdf1SRobert Foss status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
3367319cdf1SRobert Foss
3377319cdf1SRobert Foss writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
3387319cdf1SRobert Foss writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
3397319cdf1SRobert Foss
340ae44829aSRadoslav Tsvetkov for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
3417319cdf1SRobert Foss vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
3427319cdf1SRobert Foss writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
3437319cdf1SRobert Foss }
3447319cdf1SRobert Foss
3457319cdf1SRobert Foss /* Enforce ordering between IRQ reading and interpretation */
3467319cdf1SRobert Foss wmb();
3477319cdf1SRobert Foss
3487319cdf1SRobert Foss writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
3497319cdf1SRobert Foss writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
3507319cdf1SRobert Foss
3517319cdf1SRobert Foss if (status0 & STATUS_0_RESET_ACK)
3527319cdf1SRobert Foss vfe->isr_ops.reset_ack(vfe);
3537319cdf1SRobert Foss
354ae44829aSRadoslav Tsvetkov for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++)
3557319cdf1SRobert Foss if (status0 & STATUS_0_RDI_REG_UPDATE(i))
3567319cdf1SRobert Foss vfe->isr_ops.reg_update(vfe, i);
3577319cdf1SRobert Foss
358ae44829aSRadoslav Tsvetkov for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++)
3597319cdf1SRobert Foss if (status0 & STATUS_1_RDI_SOF(i))
3607319cdf1SRobert Foss vfe->isr_ops.sof(vfe, i);
3617319cdf1SRobert Foss
3627319cdf1SRobert Foss for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
3637319cdf1SRobert Foss if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i))
3647319cdf1SRobert Foss vfe->isr_ops.comp_done(vfe, i);
3657319cdf1SRobert Foss
3667319cdf1SRobert Foss for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++)
3677319cdf1SRobert Foss if (status0 & BIT(9))
3687319cdf1SRobert Foss if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm))
3697319cdf1SRobert Foss vfe->isr_ops.wm_done(vfe, wm);
3707319cdf1SRobert Foss
3717319cdf1SRobert Foss return IRQ_HANDLED;
3727319cdf1SRobert Foss }
3737319cdf1SRobert Foss
3747319cdf1SRobert Foss /*
3757319cdf1SRobert Foss * vfe_halt - Trigger halt on VFE module and wait to complete
3767319cdf1SRobert Foss * @vfe: VFE device
3777319cdf1SRobert Foss *
3787319cdf1SRobert Foss * Return 0 on success or a negative error code otherwise
3797319cdf1SRobert Foss */
vfe_halt(struct vfe_device * vfe)3807319cdf1SRobert Foss static int vfe_halt(struct vfe_device *vfe)
3817319cdf1SRobert Foss {
3821ce8c48bSJonathan Marek /* rely on vfe_disable_output() to stop the VFE */
3837319cdf1SRobert Foss return 0;
3847319cdf1SRobert Foss }
3857319cdf1SRobert Foss
vfe_get_output(struct vfe_line * line)3867319cdf1SRobert Foss static int vfe_get_output(struct vfe_line *line)
3877319cdf1SRobert Foss {
3887319cdf1SRobert Foss struct vfe_device *vfe = to_vfe(line);
3897319cdf1SRobert Foss struct vfe_output *output;
3907319cdf1SRobert Foss unsigned long flags;
3917319cdf1SRobert Foss int wm_idx;
3927319cdf1SRobert Foss
3937319cdf1SRobert Foss spin_lock_irqsave(&vfe->output_lock, flags);
3947319cdf1SRobert Foss
3957319cdf1SRobert Foss output = &line->output;
3968ce158c1SMilen Mitkov if (output->state > VFE_OUTPUT_RESERVED) {
3977319cdf1SRobert Foss dev_err(vfe->camss->dev, "Output is running\n");
3987319cdf1SRobert Foss goto error;
3997319cdf1SRobert Foss }
4007319cdf1SRobert Foss
4017319cdf1SRobert Foss output->wm_num = 1;
4027319cdf1SRobert Foss
4037319cdf1SRobert Foss wm_idx = vfe_reserve_wm(vfe, line->id);
4047319cdf1SRobert Foss if (wm_idx < 0) {
4057319cdf1SRobert Foss dev_err(vfe->camss->dev, "Can not reserve wm\n");
4067319cdf1SRobert Foss goto error_get_wm;
4077319cdf1SRobert Foss }
4087319cdf1SRobert Foss output->wm_idx[0] = wm_idx;
4097319cdf1SRobert Foss
4107319cdf1SRobert Foss output->drop_update_idx = 0;
4117319cdf1SRobert Foss
4127319cdf1SRobert Foss spin_unlock_irqrestore(&vfe->output_lock, flags);
4137319cdf1SRobert Foss
4147319cdf1SRobert Foss return 0;
4157319cdf1SRobert Foss
4167319cdf1SRobert Foss error_get_wm:
4177319cdf1SRobert Foss vfe_release_wm(vfe, output->wm_idx[0]);
4187319cdf1SRobert Foss output->state = VFE_OUTPUT_OFF;
4197319cdf1SRobert Foss error:
4207319cdf1SRobert Foss spin_unlock_irqrestore(&vfe->output_lock, flags);
4217319cdf1SRobert Foss
4227319cdf1SRobert Foss return -EINVAL;
4237319cdf1SRobert Foss }
4247319cdf1SRobert Foss
4257319cdf1SRobert Foss /*
4267319cdf1SRobert Foss * vfe_enable - Enable streaming on VFE line
4277319cdf1SRobert Foss * @line: VFE line
4287319cdf1SRobert Foss *
4297319cdf1SRobert Foss * Return 0 on success or a negative error code otherwise
4307319cdf1SRobert Foss */
vfe_enable(struct vfe_line * line)4317319cdf1SRobert Foss static int vfe_enable(struct vfe_line *line)
4327319cdf1SRobert Foss {
4337319cdf1SRobert Foss struct vfe_device *vfe = to_vfe(line);
4347319cdf1SRobert Foss int ret;
4357319cdf1SRobert Foss
4367319cdf1SRobert Foss mutex_lock(&vfe->stream_lock);
4377319cdf1SRobert Foss
4387319cdf1SRobert Foss if (!vfe->stream_count)
4397319cdf1SRobert Foss vfe_enable_irq_common(vfe);
4407319cdf1SRobert Foss
4417319cdf1SRobert Foss vfe->stream_count++;
4427319cdf1SRobert Foss
4437319cdf1SRobert Foss mutex_unlock(&vfe->stream_lock);
4447319cdf1SRobert Foss
4457319cdf1SRobert Foss ret = vfe_get_output(line);
4467319cdf1SRobert Foss if (ret < 0)
4477319cdf1SRobert Foss goto error_get_output;
4487319cdf1SRobert Foss
449*10693fedSDepeng Shao ret = vfe_enable_output_v2(line);
4507319cdf1SRobert Foss if (ret < 0)
4517319cdf1SRobert Foss goto error_enable_output;
4527319cdf1SRobert Foss
4537319cdf1SRobert Foss vfe->was_streaming = 1;
4547319cdf1SRobert Foss
4557319cdf1SRobert Foss return 0;
4567319cdf1SRobert Foss
4577319cdf1SRobert Foss error_enable_output:
4587319cdf1SRobert Foss vfe_put_output(line);
4597319cdf1SRobert Foss
4607319cdf1SRobert Foss error_get_output:
4617319cdf1SRobert Foss mutex_lock(&vfe->stream_lock);
4627319cdf1SRobert Foss
4637319cdf1SRobert Foss vfe->stream_count--;
4647319cdf1SRobert Foss
4657319cdf1SRobert Foss mutex_unlock(&vfe->stream_lock);
4667319cdf1SRobert Foss
4677319cdf1SRobert Foss return ret;
4687319cdf1SRobert Foss }
4697319cdf1SRobert Foss
4707319cdf1SRobert Foss /*
4717319cdf1SRobert Foss * vfe_isr_sof - Process start of frame interrupt
4727319cdf1SRobert Foss * @vfe: VFE Device
4737319cdf1SRobert Foss * @line_id: VFE line
4747319cdf1SRobert Foss */
vfe_isr_sof(struct vfe_device * vfe,enum vfe_line_id line_id)4757319cdf1SRobert Foss static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
4767319cdf1SRobert Foss {
4777319cdf1SRobert Foss /* nop */
4787319cdf1SRobert Foss }
4797319cdf1SRobert Foss
4807319cdf1SRobert Foss /*
4817319cdf1SRobert Foss * vfe_isr_reg_update - Process reg update interrupt
4827319cdf1SRobert Foss * @vfe: VFE Device
4837319cdf1SRobert Foss * @line_id: VFE line
4847319cdf1SRobert Foss */
vfe_isr_reg_update(struct vfe_device * vfe,enum vfe_line_id line_id)4857319cdf1SRobert Foss static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
4867319cdf1SRobert Foss {
4877319cdf1SRobert Foss struct vfe_output *output;
4887319cdf1SRobert Foss unsigned long flags;
4897319cdf1SRobert Foss
4907319cdf1SRobert Foss spin_lock_irqsave(&vfe->output_lock, flags);
491ae44829aSRadoslav Tsvetkov vfe->res->hw_ops->reg_update_clear(vfe, line_id);
4927319cdf1SRobert Foss
4937319cdf1SRobert Foss output = &vfe->line[line_id].output;
4947319cdf1SRobert Foss
4957319cdf1SRobert Foss if (output->wait_reg_update) {
4967319cdf1SRobert Foss output->wait_reg_update = 0;
4977319cdf1SRobert Foss complete(&output->reg_update);
4987319cdf1SRobert Foss }
4997319cdf1SRobert Foss
5007319cdf1SRobert Foss spin_unlock_irqrestore(&vfe->output_lock, flags);
5017319cdf1SRobert Foss }
5027319cdf1SRobert Foss
5037319cdf1SRobert Foss /*
5047319cdf1SRobert Foss * vfe_isr_wm_done - Process write master done interrupt
5057319cdf1SRobert Foss * @vfe: VFE Device
5067319cdf1SRobert Foss * @wm: Write master id
5077319cdf1SRobert Foss */
vfe_isr_wm_done(struct vfe_device * vfe,u8 wm)5087319cdf1SRobert Foss static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
5097319cdf1SRobert Foss {
5107319cdf1SRobert Foss struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
5117319cdf1SRobert Foss struct camss_buffer *ready_buf;
5127319cdf1SRobert Foss struct vfe_output *output;
5137319cdf1SRobert Foss unsigned long flags;
5147319cdf1SRobert Foss u32 index;
5157319cdf1SRobert Foss u64 ts = ktime_get_ns();
5167319cdf1SRobert Foss
5177319cdf1SRobert Foss spin_lock_irqsave(&vfe->output_lock, flags);
5187319cdf1SRobert Foss
5197319cdf1SRobert Foss if (vfe->wm_output_map[wm] == VFE_LINE_NONE) {
5207319cdf1SRobert Foss dev_err_ratelimited(vfe->camss->dev,
5217319cdf1SRobert Foss "Received wm done for unmapped index\n");
5227319cdf1SRobert Foss goto out_unlock;
5237319cdf1SRobert Foss }
5247319cdf1SRobert Foss output = &vfe->line[vfe->wm_output_map[wm]].output;
5257319cdf1SRobert Foss
5267319cdf1SRobert Foss ready_buf = output->buf[0];
5277319cdf1SRobert Foss if (!ready_buf) {
5287319cdf1SRobert Foss dev_err_ratelimited(vfe->camss->dev,
5297319cdf1SRobert Foss "Missing ready buf %d!\n", output->state);
5307319cdf1SRobert Foss goto out_unlock;
5317319cdf1SRobert Foss }
5327319cdf1SRobert Foss
5337319cdf1SRobert Foss ready_buf->vb.vb2_buf.timestamp = ts;
5347319cdf1SRobert Foss ready_buf->vb.sequence = output->sequence++;
5357319cdf1SRobert Foss
5367319cdf1SRobert Foss index = 0;
5377319cdf1SRobert Foss output->buf[0] = output->buf[1];
5387319cdf1SRobert Foss if (output->buf[0])
5397319cdf1SRobert Foss index = 1;
5407319cdf1SRobert Foss
5417319cdf1SRobert Foss output->buf[index] = vfe_buf_get_pending(output);
5427319cdf1SRobert Foss
5437319cdf1SRobert Foss if (output->buf[index])
5447319cdf1SRobert Foss vfe_wm_update(vfe, output->wm_idx[0], output->buf[index]->addr[0], line);
5457319cdf1SRobert Foss else
5467319cdf1SRobert Foss output->gen2.active_num--;
5477319cdf1SRobert Foss
5487319cdf1SRobert Foss spin_unlock_irqrestore(&vfe->output_lock, flags);
5497319cdf1SRobert Foss
5507319cdf1SRobert Foss vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
5517319cdf1SRobert Foss
5527319cdf1SRobert Foss return;
5537319cdf1SRobert Foss
5547319cdf1SRobert Foss out_unlock:
5557319cdf1SRobert Foss spin_unlock_irqrestore(&vfe->output_lock, flags);
5567319cdf1SRobert Foss }
5577319cdf1SRobert Foss
5587319cdf1SRobert Foss static const struct vfe_isr_ops vfe_isr_ops_170 = {
5597319cdf1SRobert Foss .reset_ack = vfe_isr_reset_ack,
5607319cdf1SRobert Foss .halt_ack = vfe_isr_halt_ack,
5617319cdf1SRobert Foss .reg_update = vfe_isr_reg_update,
5627319cdf1SRobert Foss .sof = vfe_isr_sof,
5637319cdf1SRobert Foss .comp_done = vfe_isr_comp_done,
5647319cdf1SRobert Foss .wm_done = vfe_isr_wm_done,
5657319cdf1SRobert Foss };
5667319cdf1SRobert Foss
5677319cdf1SRobert Foss static const struct camss_video_ops vfe_video_ops_170 = {
568*10693fedSDepeng Shao .queue_buffer = vfe_queue_buffer_v2,
5697319cdf1SRobert Foss .flush_buffers = vfe_flush_buffers,
5707319cdf1SRobert Foss };
5717319cdf1SRobert Foss
vfe_subdev_init(struct device * dev,struct vfe_device * vfe)5727319cdf1SRobert Foss static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
5737319cdf1SRobert Foss {
5747319cdf1SRobert Foss vfe->isr_ops = vfe_isr_ops_170;
5757319cdf1SRobert Foss vfe->video_ops = vfe_video_ops_170;
5767319cdf1SRobert Foss }
5777319cdf1SRobert Foss
5787319cdf1SRobert Foss const struct vfe_hw_ops vfe_ops_170 = {
5797319cdf1SRobert Foss .global_reset = vfe_global_reset,
580d2e86540SRobert Foss .hw_version = vfe_hw_version,
5817319cdf1SRobert Foss .isr_read = vfe_isr_read,
5827319cdf1SRobert Foss .isr = vfe_isr,
5832f6f8af6SRobert Foss .pm_domain_off = vfe_pm_domain_off,
5842f6f8af6SRobert Foss .pm_domain_on = vfe_pm_domain_on,
5857319cdf1SRobert Foss .reg_update_clear = vfe_reg_update_clear,
5867319cdf1SRobert Foss .reg_update = vfe_reg_update,
5877319cdf1SRobert Foss .subdev_init = vfe_subdev_init,
5887319cdf1SRobert Foss .vfe_disable = vfe_disable,
5897319cdf1SRobert Foss .vfe_enable = vfe_enable,
5907319cdf1SRobert Foss .vfe_halt = vfe_halt,
5917319cdf1SRobert Foss .violation_read = vfe_violation_read,
592*10693fedSDepeng Shao .vfe_wm_start = vfe_wm_start,
59390cc4555SBryan O'Donoghue .vfe_wm_stop = vfe_wm_stop,
594*10693fedSDepeng Shao .vfe_wm_update = vfe_wm_update,
5957319cdf1SRobert Foss };
596