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
vfe_global_reset(struct vfe_device * vfe)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 */
vfe_isr(int irq,void * dev)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 */
vfe_halt(struct vfe_device * vfe)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
vfe_disable_irq(struct vfe_device * vfe)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
vfe_wm_update(struct vfe_device * vfe,u8 rdi,u32 addr,struct vfe_line * line)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
vfe_wm_start(struct vfe_device * vfe,u8 rdi,struct vfe_line * line)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
vfe_wm_stop(struct vfe_device * vfe,u8 rdi)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
vfe_subdev_init(struct device * dev,struct vfe_device * vfe)208 static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
209 {
210 vfe->video_ops = vfe_video_ops_680;
211 }
212
vfe_reg_update(struct vfe_device * vfe,enum vfe_line_id line_id)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
vfe_reg_update_clear(struct vfe_device * vfe,enum vfe_line_id line_id)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