1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * camss-vfe-680.c 4 * 5 * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v680 6 * 7 * Copyright (C) 2025 Linaro Ltd. 8 */ 9 10 #include <linux/delay.h> 11 #include <linux/interrupt.h> 12 #include <linux/io.h> 13 #include <linux/iopoll.h> 14 15 #include "camss.h" 16 #include "camss-vfe.h" 17 18 #define VFE_TOP_IRQn_STATUS(vfe, n) ((vfe_is_lite(vfe) ? 0x1c : 0x44) + (n) * 4) 19 #define VFE_TOP_IRQn_MASK(vfe, n) ((vfe_is_lite(vfe) ? 0x24 : 0x34) + (n) * 4) 20 #define VFE_TOP_IRQn_CLEAR(vfe, n) ((vfe_is_lite(vfe) ? 0x2c : 0x3c) + (n) * 4) 21 #define VFE_IRQ1_SOF(vfe, n) ((vfe_is_lite(vfe) ? BIT(2) : BIT(8)) << ((n) * 2)) 22 #define VFE_IRQ1_EOF(vfe, n) ((vfe_is_lite(vfe) ? BIT(3) : BIT(9)) << ((n) * 2)) 23 #define VFE_TOP_IRQ_CMD(vfe) (vfe_is_lite(vfe) ? 0x38 : 0x30) 24 #define VFE_TOP_IRQ_CMD_GLOBAL_CLEAR BIT(0) 25 #define VFE_TOP_DIAG_CONFIG (vfe_is_lite(vfe) ? 0x40 : 0x50) 26 27 #define VFE_TOP_DEBUG_11(vfe) (vfe_is_lite(vfe) ? 0x40 : 0xcc) 28 #define VFE_TOP_DEBUG_12(vfe) (vfe_is_lite(vfe) ? 0x40 : 0xd0) 29 #define VFE_TOP_DEBUG_13(vfe) (vfe_is_lite(vfe) ? 0x40 : 0xd4) 30 31 #define VFE_BUS_IRQn_MASK(vfe, n) ((vfe_is_lite(vfe) ? 0x218 : 0xc18) + (n) * 4) 32 #define VFE_BUS_IRQn_CLEAR(vfe, n) ((vfe_is_lite(vfe) ? 0x220 : 0xc20) + (n) * 4) 33 #define VFE_BUS_IRQn_STATUS(vfe, n) ((vfe_is_lite(vfe) ? 0x228 : 0xc28) + (n) * 4) 34 #define VFE_BUS_IRQ_GLOBAL_CLEAR(vfe) (vfe_is_lite(vfe) ? 0x230 : 0xc30) 35 #define VFE_BUS_WR_VIOLATION_STATUS(vfe) (vfe_is_lite(vfe) ? 0x264 : 0xc64) 36 #define VFE_BUS_WR_OVERFLOW_STATUS(vfe) (vfe_is_lite(vfe) ? 0x268 : 0xc68) 37 #define VFE_BUS_WR_IMAGE_VIOLATION_STATUS(vfe) (vfe_is_lite(vfe) ? 0x270 : 0xc70) 38 39 #define VFE_BUS_WRITE_CLIENT_CFG(vfe, c) ((vfe_is_lite(vfe) ? 0x400 : 0xe00) + (c) * 0x100) 40 #define VFE_BUS_WRITE_CLIENT_CFG_EN BIT(0) 41 #define VFE_BUS_IMAGE_ADDR(vfe, c) ((vfe_is_lite(vfe) ? 0x404 : 0xe04) + (c) * 0x100) 42 #define VFE_BUS_FRAME_INCR(vfe, c) ((vfe_is_lite(vfe) ? 0x408 : 0xe08) + (c) * 0x100) 43 #define VFE_BUS_IMAGE_CFG0(vfe, c) ((vfe_is_lite(vfe) ? 0x40c : 0xe0c) + (c) * 0x100) 44 #define VFE_BUS_IMAGE_CFG0_DATA(h, s) (((h) << 16) | ((s) >> 4)) 45 #define WM_IMAGE_CFG_0_DEFAULT_WIDTH (0xFFFF) 46 47 #define VFE_BUS_IMAGE_CFG1(vfe, c) ((vfe_is_lite(vfe) ? 0x410 : 0xe10) + (c) * 0x100) 48 #define VFE_BUS_IMAGE_CFG2(vfe, c) ((vfe_is_lite(vfe) ? 0x414 : 0xe14) + (c) * 0x100) 49 #define VFE_BUS_PACKER_CFG(vfe, c) ((vfe_is_lite(vfe) ? 0x418 : 0xe18) + (c) * 0x100) 50 #define VFE_BUS_IRQ_SUBSAMPLE_PERIOD(vfe, c) ((vfe_is_lite(vfe) ? 0x430 : 0xe30) + (c) * 0x100) 51 #define VFE_BUS_IRQ_SUBSAMPLE_PATTERN(vfe, c) ((vfe_is_lite(vfe) ? 0x434 : 0xe34) + (c) * 0x100) 52 #define VFE_BUS_FRAMEDROP_PERIOD(vfe, c) ((vfe_is_lite(vfe) ? 0x438 : 0xe38) + (c) * 0x100) 53 #define VFE_BUS_FRAMEDROP_PATTERN(vfe, c) ((vfe_is_lite(vfe) ? 0x43c : 0xe3c) + (c) * 0x100) 54 #define VFE_BUS_MMU_PREFETCH_CFG(vfe, c) ((vfe_is_lite(vfe) ? 0x460 : 0xe60) + (c) * 0x100) 55 #define VFE_BUS_MMU_PREFETCH_CFG_EN BIT(0) 56 #define VFE_BUS_MMU_PREFETCH_MAX_OFFSET(vfe, c) ((vfe_is_lite(vfe) ? 0x464 : 0xe64) + (c) * 0x100) 57 #define VFE_BUS_ADDR_STATUS0(vfe, c) ((vfe_is_lite(vfe) ? 0x470 : 0xe70) + (c) * 0x100) 58 59 /* 60 * TODO: differentiate the port id based on requested type of RDI, BHIST etc 61 * 62 * IFE write master IDs 63 * 64 * VIDEO_FULL_Y 0 65 * VIDEO_FULL_C 1 66 * VIDEO_DS_4:1 2 67 * VIDEO_DS_16:1 3 68 * DISPLAY_FULL_Y 4 69 * DISPLAY_FULL_C 5 70 * DISPLAY_DS_4:1 6 71 * DISPLAY_DS_16:1 7 72 * FD_Y 8 73 * FD_C 9 74 * PIXEL_RAW 10 75 * STATS_BE0 11 76 * STATS_BHIST0 12 77 * STATS_TINTLESS_BG 13 78 * STATS_AWB_BG 14 79 * STATS_AWB_BFW 15 80 * STATS_BAF 16 81 * STATS_BHIST 17 82 * STATS_RS 18 83 * STATS_IHIST 19 84 * SPARSE_PD 20 85 * PDAF_V2.0_PD_DATA 21 86 * PDAF_V2.0_SAD 22 87 * LCR 23 88 * RDI0 24 89 * RDI1 25 90 * RDI2 26 91 * LTM_STATS 27 92 * 93 * IFE Lite write master IDs 94 * 95 * RDI0 0 96 * RDI1 1 97 * RDI2 2 98 * RDI3 3 99 * GAMMA 4 100 * BE 5 101 */ 102 103 /* TODO: assign an ENUM in resources and use the provided master 104 * id directly for RDI, STATS, AWB_BG, BHIST. 105 * This macro only works because RDI is all we support right now. 106 */ 107 #define RDI_WM(n) ((vfe_is_lite(vfe) ? 0 : 24) + (n)) 108 109 static void vfe_global_reset(struct vfe_device *vfe) 110 { 111 /* VFE680 has no global reset, simply report a completion */ 112 complete(&vfe->reset_complete); 113 } 114 115 /* 116 * vfe_isr - VFE module interrupt handler 117 * @irq: Interrupt line 118 * @dev: VFE device 119 * 120 * Return IRQ_HANDLED on success 121 */ 122 static irqreturn_t vfe_isr(int irq, void *dev) 123 { 124 return IRQ_HANDLED; 125 } 126 127 /* 128 * vfe_halt - Trigger halt on VFE module and wait to complete 129 * @vfe: VFE device 130 * 131 * Return 0 on success or a negative error code otherwise 132 */ 133 static int vfe_halt(struct vfe_device *vfe) 134 { 135 /* rely on vfe_disable_output() to stop the VFE */ 136 return 0; 137 } 138 139 static void vfe_disable_irq(struct vfe_device *vfe) 140 { 141 writel(0u, vfe->base + VFE_TOP_IRQn_MASK(vfe, 0)); 142 writel(0u, vfe->base + VFE_TOP_IRQn_MASK(vfe, 1)); 143 writel(0u, vfe->base + VFE_BUS_IRQn_MASK(vfe, 0)); 144 writel(0u, vfe->base + VFE_BUS_IRQn_MASK(vfe, 1)); 145 } 146 147 static void vfe_wm_update(struct vfe_device *vfe, u8 rdi, u32 addr, 148 struct vfe_line *line) 149 { 150 u8 wm = RDI_WM(rdi); 151 152 writel(addr, vfe->base + VFE_BUS_IMAGE_ADDR(vfe, wm)); 153 } 154 155 static void vfe_wm_start(struct vfe_device *vfe, u8 rdi, struct vfe_line *line) 156 { 157 struct v4l2_pix_format_mplane *pix = 158 &line->video_out.active_fmt.fmt.pix_mp; 159 u32 stride = pix->plane_fmt[0].bytesperline; 160 u32 cfg; 161 u8 wm; 162 163 cfg = VFE_BUS_IMAGE_CFG0_DATA(pix->height, stride); 164 wm = RDI_WM(rdi); 165 166 writel(cfg, vfe->base + VFE_BUS_IMAGE_CFG0(vfe, wm)); 167 writel(0, vfe->base + VFE_BUS_IMAGE_CFG1(vfe, wm)); 168 writel(stride, vfe->base + VFE_BUS_IMAGE_CFG2(vfe, wm)); 169 writel(0, vfe->base + VFE_BUS_PACKER_CFG(vfe, wm)); 170 171 /* Set total frame increment value */ 172 writel(pix->plane_fmt[0].bytesperline * pix->height, 173 vfe->base + VFE_BUS_FRAME_INCR(vfe, wm)); 174 175 /* MMU */ 176 writel(VFE_BUS_MMU_PREFETCH_CFG_EN, vfe->base + VFE_BUS_MMU_PREFETCH_CFG(vfe, wm)); 177 writel(~0u, vfe->base + VFE_BUS_MMU_PREFETCH_MAX_OFFSET(vfe, wm)); 178 179 /* no dropped frames, one irq per frame */ 180 writel(1, vfe->base + VFE_BUS_FRAMEDROP_PATTERN(vfe, wm)); 181 writel(0, vfe->base + VFE_BUS_FRAMEDROP_PERIOD(vfe, wm)); 182 writel(1, vfe->base + VFE_BUS_IRQ_SUBSAMPLE_PATTERN(vfe, wm)); 183 writel(0, vfe->base + VFE_BUS_IRQ_SUBSAMPLE_PERIOD(vfe, wm)); 184 185 /* We don't process IRQs for VFE in RDI mode at the moment */ 186 vfe_disable_irq(vfe); 187 188 /* Enable WM */ 189 writel(VFE_BUS_WRITE_CLIENT_CFG_EN, 190 vfe->base + VFE_BUS_WRITE_CLIENT_CFG(vfe, wm)); 191 192 dev_dbg(vfe->camss->dev, "RDI%d WM:%d width %d height %d stride %d\n", 193 rdi, wm, pix->width, pix->height, stride); 194 } 195 196 static void vfe_wm_stop(struct vfe_device *vfe, u8 rdi) 197 { 198 u8 wm = RDI_WM(rdi); 199 200 writel(0, vfe->base + VFE_BUS_WRITE_CLIENT_CFG(vfe, wm)); 201 } 202 203 static const struct camss_video_ops vfe_video_ops_680 = { 204 .queue_buffer = vfe_queue_buffer_v2, 205 .flush_buffers = vfe_flush_buffers, 206 }; 207 208 static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) 209 { 210 vfe->video_ops = vfe_video_ops_680; 211 } 212 213 static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) 214 { 215 int port_id = line_id; 216 217 camss_reg_update(vfe->camss, vfe->id, port_id, false); 218 } 219 220 static inline void vfe_reg_update_clear(struct vfe_device *vfe, 221 enum vfe_line_id line_id) 222 { 223 int port_id = line_id; 224 225 camss_reg_update(vfe->camss, vfe->id, port_id, true); 226 } 227 228 const struct vfe_hw_ops vfe_ops_680 = { 229 .global_reset = vfe_global_reset, 230 .hw_version = vfe_hw_version, 231 .isr = vfe_isr, 232 .pm_domain_off = vfe_pm_domain_off, 233 .pm_domain_on = vfe_pm_domain_on, 234 .subdev_init = vfe_subdev_init, 235 .vfe_disable = vfe_disable, 236 .vfe_enable = vfe_enable_v2, 237 .vfe_halt = vfe_halt, 238 .vfe_wm_start = vfe_wm_start, 239 .vfe_wm_stop = vfe_wm_stop, 240 .vfe_buf_done = vfe_buf_done, 241 .vfe_wm_update = vfe_wm_update, 242 .reg_update = vfe_reg_update, 243 .reg_update_clear = vfe_reg_update_clear, 244 }; 245