Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: platform: Add C3 ISP driver

The C3 ISP supports multi-camera and multi-exposure HDR, integrates
advanced imaging technologies for optimal quality, and drives the
core pipeline to transform raw sensor data into high-fidelity images
through demosaicing, color correction, and tone mapping operations.

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Keke Li <keke.li@amlogic.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
[hverkuil: drop unnecessary vb2_ops_wait_prepare/finish callbacks]

authored by

Keke Li and committed by
Hans Verkuil
fb2e1352 6d406187

+5081
+1
MAINTAINERS
··· 1259 1259 L: linux-media@vger.kernel.org 1260 1260 S: Maintained 1261 1261 F: Documentation/devicetree/bindings/media/amlogic,c3-isp.yaml 1262 + F: drivers/media/platform/amlogic/c3/isp/ 1262 1263 F: include/uapi/linux/media/amlogic/ 1263 1264 1264 1265 AMLOGIC MIPI ADAPTER DRIVER
+1
drivers/media/platform/amlogic/c3/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 3 + source "drivers/media/platform/amlogic/c3/isp/Kconfig" 3 4 source "drivers/media/platform/amlogic/c3/mipi-adapter/Kconfig" 4 5 source "drivers/media/platform/amlogic/c3/mipi-csi2/Kconfig"
+1
drivers/media/platform/amlogic/c3/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 3 + obj-y += isp/ 3 4 obj-y += mipi-adapter/ 4 5 obj-y += mipi-csi2/
+18
drivers/media/platform/amlogic/c3/isp/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + config VIDEO_C3_ISP 4 + tristate "Amlogic C3 Image Signal Processor (ISP) driver" 5 + depends on ARCH_MESON || COMPILE_TEST 6 + depends on VIDEO_DEV 7 + depends on OF 8 + select MEDIA_CONTROLLER 9 + select V4L2_FWNODE 10 + select VIDEO_V4L2_SUBDEV_API 11 + select VIDEOBUF2_DMA_CONTIG 12 + select VIDEOBUF2_VMALLOC 13 + help 14 + Video4Linux2 driver for Amlogic C3 ISP pipeline. 15 + The C3 ISP is used for processing raw images and 16 + outputing results to memory. 17 + 18 + To compile this driver as a module choose m here.
+10
drivers/media/platform/amlogic/c3/isp/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + c3-isp-objs := c3-isp-dev.o \ 4 + c3-isp-params.o \ 5 + c3-isp-stats.o \ 6 + c3-isp-capture.o \ 7 + c3-isp-core.o \ 8 + c3-isp-resizer.o 9 + 10 + obj-$(CONFIG_VIDEO_C3_ISP) += c3-isp.o
+804
drivers/media/platform/amlogic/c3/isp/c3-isp-capture.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + */ 5 + 6 + #include <linux/cleanup.h> 7 + #include <linux/pm_runtime.h> 8 + 9 + #include <media/v4l2-ctrls.h> 10 + #include <media/v4l2-event.h> 11 + #include <media/v4l2-ioctl.h> 12 + #include <media/v4l2-mc.h> 13 + #include <media/videobuf2-dma-contig.h> 14 + 15 + #include "c3-isp-common.h" 16 + #include "c3-isp-regs.h" 17 + 18 + #define C3_ISP_WRMIFX3_REG(addr, id) ((addr) + (id) * 0x100) 19 + 20 + static const struct c3_isp_cap_format_info cap_formats[] = { 21 + /* YUV formats */ 22 + { 23 + .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 24 + .fourcc = V4L2_PIX_FMT_GREY, 25 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_Y_ONLY, 26 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X1, 27 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_8BITS, 28 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_VU, 29 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_8BIT, 30 + .hdiv = 1, 31 + .vdiv = 1, 32 + }, { 33 + .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 34 + .fourcc = V4L2_PIX_FMT_NV12M, 35 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_YUV420, 36 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X2, 37 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_8BITS, 38 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_UV, 39 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_8BIT, 40 + .hdiv = 2, 41 + .vdiv = 2, 42 + }, { 43 + .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 44 + .fourcc = V4L2_PIX_FMT_NV21M, 45 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_YUV420, 46 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X2, 47 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_8BITS, 48 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_VU, 49 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_8BIT, 50 + .hdiv = 2, 51 + .vdiv = 2, 52 + }, { 53 + .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 54 + .fourcc = V4L2_PIX_FMT_NV16M, 55 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_YUV422, 56 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X2, 57 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_8BITS, 58 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_UV, 59 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_8BIT, 60 + .hdiv = 1, 61 + .vdiv = 2 62 + }, { 63 + .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 64 + .fourcc = V4L2_PIX_FMT_NV61M, 65 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_YUV422, 66 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X2, 67 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_8BITS, 68 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_VU, 69 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_8BIT, 70 + .hdiv = 1, 71 + .vdiv = 2, 72 + }, 73 + /* RAW formats */ 74 + { 75 + .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, 76 + .fourcc = V4L2_PIX_FMT_SRGGB12, 77 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_RAW, 78 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X1, 79 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_16BITS, 80 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_VU, 81 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_16BIT, 82 + .hdiv = 1, 83 + .vdiv = 1, 84 + }, { 85 + .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, 86 + .fourcc = V4L2_PIX_FMT_SBGGR12, 87 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_RAW, 88 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X1, 89 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_16BITS, 90 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_VU, 91 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_16BIT, 92 + .hdiv = 1, 93 + .vdiv = 1, 94 + }, { 95 + .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, 96 + .fourcc = V4L2_PIX_FMT_SGRBG12, 97 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_RAW, 98 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X1, 99 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_16BITS, 100 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_VU, 101 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_16BIT, 102 + .hdiv = 1, 103 + .vdiv = 1, 104 + }, { 105 + .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, 106 + .fourcc = V4L2_PIX_FMT_SGBRG12, 107 + .format = ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_RAW, 108 + .planes = ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X1, 109 + .ch0_pix_bits = ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_16BITS, 110 + .uv_swap = ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_VU, 111 + .in_bits = ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_16BIT, 112 + .hdiv = 1, 113 + .vdiv = 1, 114 + }, 115 + }; 116 + 117 + /* Hardware configuration */ 118 + 119 + /* Set the address of wrmifx3(write memory interface) */ 120 + static void c3_isp_cap_wrmifx3_buff(struct c3_isp_capture *cap) 121 + { 122 + dma_addr_t y_dma_addr; 123 + dma_addr_t uv_dma_addr; 124 + 125 + if (cap->buff) { 126 + y_dma_addr = cap->buff->dma_addr[C3_ISP_PLANE_Y]; 127 + uv_dma_addr = cap->buff->dma_addr[C3_ISP_PLANE_UV]; 128 + } else { 129 + y_dma_addr = cap->dummy_buff.dma_addr; 130 + uv_dma_addr = cap->dummy_buff.dma_addr; 131 + } 132 + 133 + c3_isp_write(cap->isp, 134 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_CH0_BADDR, cap->id), 135 + ISP_WRMIFX3_0_CH0_BASE_ADDR(y_dma_addr)); 136 + 137 + c3_isp_write(cap->isp, 138 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_CH1_BADDR, cap->id), 139 + ISP_WRMIFX3_0_CH1_BASE_ADDR(uv_dma_addr)); 140 + } 141 + 142 + static void c3_isp_cap_wrmifx3_format(struct c3_isp_capture *cap) 143 + { 144 + struct v4l2_pix_format_mplane *pix_mp = &cap->format.pix_mp; 145 + const struct c3_isp_cap_format_info *info = cap->format.info; 146 + u32 stride; 147 + u32 chrom_h; 148 + u32 chrom_v; 149 + 150 + c3_isp_write(cap->isp, 151 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_FMT_SIZE, cap->id), 152 + ISP_WRMIFX3_0_FMT_SIZE_HSIZE(pix_mp->width) | 153 + ISP_WRMIFX3_0_FMT_SIZE_VSIZE(pix_mp->height)); 154 + 155 + c3_isp_update_bits(cap->isp, 156 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_FMT_CTRL, cap->id), 157 + ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_MASK, info->format); 158 + 159 + c3_isp_update_bits(cap->isp, 160 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_FMT_CTRL, cap->id), 161 + ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_MASK, 162 + info->in_bits); 163 + 164 + c3_isp_update_bits(cap->isp, 165 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_FMT_CTRL, cap->id), 166 + ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_MASK, info->planes); 167 + 168 + c3_isp_update_bits(cap->isp, 169 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_FMT_CTRL, cap->id), 170 + ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_MASK, 171 + info->uv_swap); 172 + 173 + stride = DIV_ROUND_UP(pix_mp->plane_fmt[C3_ISP_PLANE_Y].bytesperline, 174 + C3_ISP_DMA_SIZE_ALIGN_BYTES); 175 + c3_isp_update_bits(cap->isp, 176 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_CH0_CTRL0, cap->id), 177 + ISP_WRMIFX3_0_CH0_CTRL0_STRIDE_MASK, 178 + ISP_WRMIFX3_0_CH0_CTRL0_STRIDE(stride)); 179 + 180 + c3_isp_update_bits(cap->isp, 181 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_CH0_CTRL1, cap->id), 182 + ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_MODE_MASK, 183 + info->ch0_pix_bits); 184 + 185 + c3_isp_write(cap->isp, 186 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_WIN_LUMA_H, cap->id), 187 + ISP_WRMIFX3_0_WIN_LUMA_H_LUMA_HEND(pix_mp->width)); 188 + 189 + c3_isp_write(cap->isp, 190 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_WIN_LUMA_V, cap->id), 191 + ISP_WRMIFX3_0_WIN_LUMA_V_LUMA_VEND(pix_mp->height)); 192 + 193 + stride = DIV_ROUND_UP(pix_mp->plane_fmt[C3_ISP_PLANE_UV].bytesperline, 194 + C3_ISP_DMA_SIZE_ALIGN_BYTES); 195 + c3_isp_update_bits(cap->isp, 196 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_CH1_CTRL0, cap->id), 197 + ISP_WRMIFX3_0_CH1_CTRL0_STRIDE_MASK, 198 + ISP_WRMIFX3_0_CH1_CTRL0_STRIDE(stride)); 199 + 200 + c3_isp_update_bits(cap->isp, 201 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_CH1_CTRL1, cap->id), 202 + ISP_WRMIFX3_0_CH1_CTRL1_PIX_BITS_MODE_MASK, 203 + ISP_WRMIFX3_0_CH1_CTRL1_PIX_BITS_16BITS); 204 + 205 + chrom_h = DIV_ROUND_UP(pix_mp->width, info->hdiv); 206 + c3_isp_write(cap->isp, 207 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_WIN_CHROM_H, cap->id), 208 + ISP_WRMIFX3_0_WIN_CHROM_H_CHROM_HEND(chrom_h)); 209 + 210 + chrom_v = DIV_ROUND_UP(pix_mp->height, info->vdiv); 211 + c3_isp_write(cap->isp, 212 + C3_ISP_WRMIFX3_REG(ISP_WRMIFX3_0_WIN_CHROM_V, cap->id), 213 + ISP_WRMIFX3_0_WIN_CHROM_V_CHROM_VEND(chrom_v)); 214 + } 215 + 216 + static int c3_isp_cap_dummy_buff_create(struct c3_isp_capture *cap) 217 + { 218 + struct c3_isp_dummy_buffer *dummy_buff = &cap->dummy_buff; 219 + struct v4l2_pix_format_mplane *pix_mp = &cap->format.pix_mp; 220 + 221 + if (pix_mp->num_planes == 1) 222 + dummy_buff->size = pix_mp->plane_fmt[C3_ISP_PLANE_Y].sizeimage; 223 + else 224 + dummy_buff->size = 225 + max(pix_mp->plane_fmt[C3_ISP_PLANE_Y].sizeimage, 226 + pix_mp->plane_fmt[C3_ISP_PLANE_UV].sizeimage); 227 + 228 + /* The driver never access vaddr, no mapping is required */ 229 + dummy_buff->vaddr = dma_alloc_attrs(cap->isp->dev, dummy_buff->size, 230 + &dummy_buff->dma_addr, GFP_KERNEL, 231 + DMA_ATTR_NO_KERNEL_MAPPING); 232 + if (!dummy_buff->vaddr) 233 + return -ENOMEM; 234 + 235 + return 0; 236 + } 237 + 238 + static void c3_isp_cap_dummy_buff_destroy(struct c3_isp_capture *cap) 239 + { 240 + dma_free_attrs(cap->isp->dev, cap->dummy_buff.size, 241 + cap->dummy_buff.vaddr, cap->dummy_buff.dma_addr, 242 + DMA_ATTR_NO_KERNEL_MAPPING); 243 + } 244 + 245 + static void c3_isp_cap_cfg_buff(struct c3_isp_capture *cap) 246 + { 247 + cap->buff = list_first_entry_or_null(&cap->pending, 248 + struct c3_isp_cap_buffer, list); 249 + 250 + c3_isp_cap_wrmifx3_buff(cap); 251 + 252 + if (cap->buff) 253 + list_del(&cap->buff->list); 254 + } 255 + 256 + static void c3_isp_cap_start(struct c3_isp_capture *cap) 257 + { 258 + u32 mask; 259 + u32 val; 260 + 261 + scoped_guard(spinlock_irqsave, &cap->buff_lock) 262 + c3_isp_cap_cfg_buff(cap); 263 + 264 + c3_isp_cap_wrmifx3_format(cap); 265 + 266 + if (cap->id == C3_ISP_CAP_DEV_0) { 267 + mask = ISP_TOP_PATH_EN_WRMIF0_EN_MASK; 268 + val = ISP_TOP_PATH_EN_WRMIF0_EN; 269 + } else if (cap->id == C3_ISP_CAP_DEV_1) { 270 + mask = ISP_TOP_PATH_EN_WRMIF1_EN_MASK; 271 + val = ISP_TOP_PATH_EN_WRMIF1_EN; 272 + } else { 273 + mask = ISP_TOP_PATH_EN_WRMIF2_EN_MASK; 274 + val = ISP_TOP_PATH_EN_WRMIF2_EN; 275 + } 276 + 277 + c3_isp_update_bits(cap->isp, ISP_TOP_PATH_EN, mask, val); 278 + } 279 + 280 + static void c3_isp_cap_stop(struct c3_isp_capture *cap) 281 + { 282 + u32 mask; 283 + u32 val; 284 + 285 + if (cap->id == C3_ISP_CAP_DEV_0) { 286 + mask = ISP_TOP_PATH_EN_WRMIF0_EN_MASK; 287 + val = ISP_TOP_PATH_EN_WRMIF0_DIS; 288 + } else if (cap->id == C3_ISP_CAP_DEV_1) { 289 + mask = ISP_TOP_PATH_EN_WRMIF1_EN_MASK; 290 + val = ISP_TOP_PATH_EN_WRMIF1_DIS; 291 + } else { 292 + mask = ISP_TOP_PATH_EN_WRMIF2_EN_MASK; 293 + val = ISP_TOP_PATH_EN_WRMIF2_DIS; 294 + } 295 + 296 + c3_isp_update_bits(cap->isp, ISP_TOP_PATH_EN, mask, val); 297 + } 298 + 299 + static void c3_isp_cap_done(struct c3_isp_capture *cap) 300 + { 301 + struct c3_isp_cap_buffer *buff = cap->buff; 302 + 303 + guard(spinlock_irqsave)(&cap->buff_lock); 304 + 305 + if (buff) { 306 + buff->vb.sequence = cap->isp->frm_sequence; 307 + buff->vb.vb2_buf.timestamp = ktime_get(); 308 + buff->vb.field = V4L2_FIELD_NONE; 309 + vb2_buffer_done(&buff->vb.vb2_buf, VB2_BUF_STATE_DONE); 310 + } 311 + 312 + c3_isp_cap_cfg_buff(cap); 313 + } 314 + 315 + /* V4L2 video operations */ 316 + 317 + static const struct c3_isp_cap_format_info *c3_cap_find_fmt(u32 fourcc) 318 + { 319 + for (unsigned int i = 0; i < ARRAY_SIZE(cap_formats); i++) { 320 + if (cap_formats[i].fourcc == fourcc) 321 + return &cap_formats[i]; 322 + } 323 + 324 + return NULL; 325 + } 326 + 327 + static void c3_cap_try_fmt(struct v4l2_pix_format_mplane *pix_mp) 328 + { 329 + const struct c3_isp_cap_format_info *fmt; 330 + const struct v4l2_format_info *info; 331 + struct v4l2_plane_pix_format *plane; 332 + 333 + fmt = c3_cap_find_fmt(pix_mp->pixelformat); 334 + if (!fmt) 335 + fmt = &cap_formats[0]; 336 + 337 + pix_mp->width = clamp(pix_mp->width, C3_ISP_MIN_WIDTH, 338 + C3_ISP_MAX_WIDTH); 339 + pix_mp->height = clamp(pix_mp->height, C3_ISP_MIN_HEIGHT, 340 + C3_ISP_MAX_HEIGHT); 341 + pix_mp->pixelformat = fmt->fourcc; 342 + pix_mp->field = V4L2_FIELD_NONE; 343 + pix_mp->colorspace = V4L2_COLORSPACE_SRGB; 344 + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_601; 345 + pix_mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; 346 + 347 + info = v4l2_format_info(fmt->fourcc); 348 + pix_mp->num_planes = info->mem_planes; 349 + memset(pix_mp->plane_fmt, 0, sizeof(pix_mp->plane_fmt)); 350 + 351 + for (unsigned int i = 0; i < info->comp_planes; i++) { 352 + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; 353 + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; 354 + 355 + plane = &pix_mp->plane_fmt[i]; 356 + 357 + plane->bytesperline = DIV_ROUND_UP(pix_mp->width, hdiv) * 358 + info->bpp[i] / info->bpp_div[i]; 359 + plane->bytesperline = ALIGN(plane->bytesperline, 360 + C3_ISP_DMA_SIZE_ALIGN_BYTES); 361 + plane->sizeimage = plane->bytesperline * 362 + DIV_ROUND_UP(pix_mp->height, vdiv); 363 + } 364 + } 365 + 366 + static void c3_isp_cap_return_buffers(struct c3_isp_capture *cap, 367 + enum vb2_buffer_state state) 368 + { 369 + struct c3_isp_cap_buffer *buff; 370 + 371 + guard(spinlock_irqsave)(&cap->buff_lock); 372 + 373 + if (cap->buff) { 374 + vb2_buffer_done(&cap->buff->vb.vb2_buf, state); 375 + cap->buff = NULL; 376 + } 377 + 378 + while (!list_empty(&cap->pending)) { 379 + buff = list_first_entry(&cap->pending, 380 + struct c3_isp_cap_buffer, list); 381 + list_del(&buff->list); 382 + vb2_buffer_done(&buff->vb.vb2_buf, state); 383 + } 384 + } 385 + 386 + static int c3_isp_cap_querycap(struct file *file, void *fh, 387 + struct v4l2_capability *cap) 388 + { 389 + strscpy(cap->driver, C3_ISP_DRIVER_NAME, sizeof(cap->driver)); 390 + strscpy(cap->card, "AML C3 ISP", sizeof(cap->card)); 391 + 392 + return 0; 393 + } 394 + 395 + static int c3_isp_cap_enum_fmt(struct file *file, void *fh, 396 + struct v4l2_fmtdesc *f) 397 + { 398 + const struct c3_isp_cap_format_info *fmt; 399 + unsigned int index = 0; 400 + unsigned int i; 401 + 402 + if (!f->mbus_code) { 403 + if (f->index >= ARRAY_SIZE(cap_formats)) 404 + return -EINVAL; 405 + 406 + fmt = &cap_formats[f->index]; 407 + f->pixelformat = fmt->fourcc; 408 + return 0; 409 + } 410 + 411 + for (i = 0; i < ARRAY_SIZE(cap_formats); i++) { 412 + fmt = &cap_formats[i]; 413 + if (f->mbus_code != fmt->mbus_code) 414 + continue; 415 + 416 + if (index++ == f->index) { 417 + f->pixelformat = cap_formats[i].fourcc; 418 + return 0; 419 + } 420 + } 421 + 422 + return -EINVAL; 423 + } 424 + 425 + static int c3_isp_cap_g_fmt_mplane(struct file *file, void *fh, 426 + struct v4l2_format *f) 427 + { 428 + struct c3_isp_capture *cap = video_drvdata(file); 429 + 430 + f->fmt.pix_mp = cap->format.pix_mp; 431 + 432 + return 0; 433 + } 434 + 435 + static int c3_isp_cap_s_fmt_mplane(struct file *file, void *fh, 436 + struct v4l2_format *f) 437 + { 438 + struct c3_isp_capture *cap = video_drvdata(file); 439 + 440 + c3_cap_try_fmt(&f->fmt.pix_mp); 441 + 442 + cap->format.pix_mp = f->fmt.pix_mp; 443 + cap->format.info = c3_cap_find_fmt(f->fmt.pix_mp.pixelformat); 444 + 445 + return 0; 446 + } 447 + 448 + static int c3_isp_cap_try_fmt_mplane(struct file *file, void *fh, 449 + struct v4l2_format *f) 450 + { 451 + c3_cap_try_fmt(&f->fmt.pix_mp); 452 + 453 + return 0; 454 + } 455 + 456 + static int c3_isp_cap_enum_frmsize(struct file *file, void *fh, 457 + struct v4l2_frmsizeenum *fsize) 458 + { 459 + const struct c3_isp_cap_format_info *fmt; 460 + 461 + if (fsize->index) 462 + return -EINVAL; 463 + 464 + fmt = c3_cap_find_fmt(fsize->pixel_format); 465 + if (!fmt) 466 + return -EINVAL; 467 + 468 + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 469 + fsize->stepwise.min_width = C3_ISP_MIN_WIDTH; 470 + fsize->stepwise.min_height = C3_ISP_MIN_HEIGHT; 471 + fsize->stepwise.max_width = C3_ISP_MAX_WIDTH; 472 + fsize->stepwise.max_height = C3_ISP_MAX_HEIGHT; 473 + fsize->stepwise.step_width = 2; 474 + fsize->stepwise.step_height = 2; 475 + 476 + return 0; 477 + } 478 + 479 + static const struct v4l2_ioctl_ops isp_cap_v4l2_ioctl_ops = { 480 + .vidioc_querycap = c3_isp_cap_querycap, 481 + .vidioc_enum_fmt_vid_cap = c3_isp_cap_enum_fmt, 482 + .vidioc_g_fmt_vid_cap_mplane = c3_isp_cap_g_fmt_mplane, 483 + .vidioc_s_fmt_vid_cap_mplane = c3_isp_cap_s_fmt_mplane, 484 + .vidioc_try_fmt_vid_cap_mplane = c3_isp_cap_try_fmt_mplane, 485 + .vidioc_reqbufs = vb2_ioctl_reqbufs, 486 + .vidioc_querybuf = vb2_ioctl_querybuf, 487 + .vidioc_qbuf = vb2_ioctl_qbuf, 488 + .vidioc_expbuf = vb2_ioctl_expbuf, 489 + .vidioc_dqbuf = vb2_ioctl_dqbuf, 490 + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 491 + .vidioc_create_bufs = vb2_ioctl_create_bufs, 492 + .vidioc_streamon = vb2_ioctl_streamon, 493 + .vidioc_streamoff = vb2_ioctl_streamoff, 494 + .vidioc_enum_framesizes = c3_isp_cap_enum_frmsize, 495 + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 496 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 497 + }; 498 + 499 + static const struct v4l2_file_operations isp_cap_v4l2_fops = { 500 + .open = v4l2_fh_open, 501 + .release = vb2_fop_release, 502 + .poll = vb2_fop_poll, 503 + .unlocked_ioctl = video_ioctl2, 504 + .mmap = vb2_fop_mmap, 505 + }; 506 + 507 + static int c3_isp_cap_link_validate(struct media_link *link) 508 + { 509 + struct video_device *vdev = 510 + media_entity_to_video_device(link->sink->entity); 511 + struct v4l2_subdev *sd = 512 + media_entity_to_v4l2_subdev(link->source->entity); 513 + struct c3_isp_capture *cap = video_get_drvdata(vdev); 514 + struct v4l2_subdev_format src_fmt = { 515 + .which = V4L2_SUBDEV_FORMAT_ACTIVE, 516 + .pad = link->source->index, 517 + }; 518 + int ret; 519 + 520 + ret = v4l2_subdev_call_state_active(sd, pad, get_fmt, &src_fmt); 521 + if (ret) 522 + return ret; 523 + 524 + if (src_fmt.format.width != cap->format.pix_mp.width || 525 + src_fmt.format.height != cap->format.pix_mp.height || 526 + src_fmt.format.code != cap->format.info->mbus_code) { 527 + dev_err(cap->isp->dev, 528 + "link %s: %u -> %s: %u not valid: 0x%04x/%ux%u not match 0x%04x/%ux%u\n", 529 + link->source->entity->name, link->source->index, 530 + link->sink->entity->name, link->sink->index, 531 + src_fmt.format.code, src_fmt.format.width, 532 + src_fmt.format.height, cap->format.info->mbus_code, 533 + cap->format.pix_mp.width, cap->format.pix_mp.height); 534 + 535 + return -EPIPE; 536 + } 537 + 538 + return 0; 539 + } 540 + 541 + static const struct media_entity_operations isp_cap_entity_ops = { 542 + .link_validate = c3_isp_cap_link_validate, 543 + }; 544 + 545 + static int c3_isp_vb2_queue_setup(struct vb2_queue *q, 546 + unsigned int *num_buffers, 547 + unsigned int *num_planes, 548 + unsigned int sizes[], 549 + struct device *alloc_devs[]) 550 + { 551 + struct c3_isp_capture *cap = vb2_get_drv_priv(q); 552 + const struct v4l2_pix_format_mplane *pix_mp = &cap->format.pix_mp; 553 + unsigned int i; 554 + 555 + if (*num_planes) { 556 + if (*num_planes != pix_mp->num_planes) 557 + return -EINVAL; 558 + 559 + for (i = 0; i < pix_mp->num_planes; i++) 560 + if (sizes[i] < pix_mp->plane_fmt[i].sizeimage) 561 + return -EINVAL; 562 + 563 + return 0; 564 + } 565 + 566 + *num_planes = pix_mp->num_planes; 567 + for (i = 0; i < pix_mp->num_planes; i++) 568 + sizes[i] = pix_mp->plane_fmt[i].sizeimage; 569 + 570 + return 0; 571 + } 572 + 573 + static void c3_isp_vb2_buf_queue(struct vb2_buffer *vb) 574 + { 575 + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 576 + struct c3_isp_cap_buffer *buf = 577 + container_of(v4l2_buf, struct c3_isp_cap_buffer, vb); 578 + struct c3_isp_capture *cap = vb2_get_drv_priv(vb->vb2_queue); 579 + 580 + guard(spinlock_irqsave)(&cap->buff_lock); 581 + 582 + list_add_tail(&buf->list, &cap->pending); 583 + } 584 + 585 + static int c3_isp_vb2_buf_prepare(struct vb2_buffer *vb) 586 + { 587 + struct c3_isp_capture *cap = vb2_get_drv_priv(vb->vb2_queue); 588 + unsigned long size; 589 + 590 + for (unsigned int i = 0; i < cap->format.pix_mp.num_planes; i++) { 591 + size = cap->format.pix_mp.plane_fmt[i].sizeimage; 592 + if (vb2_plane_size(vb, i) < size) { 593 + dev_err(cap->isp->dev, 594 + "User buffer too small (%ld < %lu)\n", 595 + vb2_plane_size(vb, i), size); 596 + return -EINVAL; 597 + } 598 + 599 + vb2_set_plane_payload(vb, i, size); 600 + } 601 + 602 + return 0; 603 + } 604 + 605 + static int c3_isp_vb2_buf_init(struct vb2_buffer *vb) 606 + { 607 + struct c3_isp_capture *cap = vb2_get_drv_priv(vb->vb2_queue); 608 + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 609 + struct c3_isp_cap_buffer *buf = 610 + container_of(v4l2_buf, struct c3_isp_cap_buffer, vb); 611 + 612 + for (unsigned int i = 0; i < cap->format.pix_mp.num_planes; i++) 613 + buf->dma_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); 614 + 615 + return 0; 616 + } 617 + 618 + static int c3_isp_vb2_start_streaming(struct vb2_queue *q, 619 + unsigned int count) 620 + { 621 + struct c3_isp_capture *cap = vb2_get_drv_priv(q); 622 + int ret; 623 + 624 + ret = video_device_pipeline_start(&cap->vdev, &cap->isp->pipe); 625 + if (ret) { 626 + dev_err(cap->isp->dev, 627 + "Failed to start cap%u pipeline: %d\n", cap->id, ret); 628 + goto err_return_buffers; 629 + } 630 + 631 + ret = c3_isp_cap_dummy_buff_create(cap); 632 + if (ret) 633 + goto err_pipeline_stop; 634 + 635 + ret = pm_runtime_resume_and_get(cap->isp->dev); 636 + if (ret) 637 + goto err_dummy_destroy; 638 + 639 + c3_isp_cap_start(cap); 640 + 641 + ret = v4l2_subdev_enable_streams(&cap->rsz->sd, C3_ISP_RSZ_PAD_SOURCE, 642 + BIT(0)); 643 + if (ret) 644 + goto err_pm_put; 645 + 646 + return 0; 647 + 648 + err_pm_put: 649 + pm_runtime_put(cap->isp->dev); 650 + err_dummy_destroy: 651 + c3_isp_cap_dummy_buff_destroy(cap); 652 + err_pipeline_stop: 653 + video_device_pipeline_stop(&cap->vdev); 654 + err_return_buffers: 655 + c3_isp_cap_return_buffers(cap, VB2_BUF_STATE_QUEUED); 656 + return ret; 657 + } 658 + 659 + static void c3_isp_vb2_stop_streaming(struct vb2_queue *q) 660 + { 661 + struct c3_isp_capture *cap = vb2_get_drv_priv(q); 662 + 663 + c3_isp_cap_stop(cap); 664 + 665 + c3_isp_cap_return_buffers(cap, VB2_BUF_STATE_ERROR); 666 + 667 + v4l2_subdev_disable_streams(&cap->rsz->sd, C3_ISP_RSZ_PAD_SOURCE, 668 + BIT(0)); 669 + 670 + pm_runtime_put(cap->isp->dev); 671 + 672 + c3_isp_cap_dummy_buff_destroy(cap); 673 + 674 + video_device_pipeline_stop(&cap->vdev); 675 + } 676 + 677 + static const struct vb2_ops isp_video_vb2_ops = { 678 + .queue_setup = c3_isp_vb2_queue_setup, 679 + .buf_queue = c3_isp_vb2_buf_queue, 680 + .buf_prepare = c3_isp_vb2_buf_prepare, 681 + .buf_init = c3_isp_vb2_buf_init, 682 + .start_streaming = c3_isp_vb2_start_streaming, 683 + .stop_streaming = c3_isp_vb2_stop_streaming, 684 + }; 685 + 686 + static int c3_isp_register_capture(struct c3_isp_capture *cap) 687 + { 688 + struct video_device *vdev = &cap->vdev; 689 + struct vb2_queue *vb2_q = &cap->vb2_q; 690 + int ret; 691 + 692 + snprintf(vdev->name, sizeof(vdev->name), "c3-isp-cap%u", cap->id); 693 + vdev->fops = &isp_cap_v4l2_fops; 694 + vdev->ioctl_ops = &isp_cap_v4l2_ioctl_ops; 695 + vdev->v4l2_dev = &cap->isp->v4l2_dev; 696 + vdev->entity.ops = &isp_cap_entity_ops; 697 + vdev->lock = &cap->lock; 698 + vdev->minor = -1; 699 + vdev->queue = vb2_q; 700 + vdev->release = video_device_release_empty; 701 + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | 702 + V4L2_CAP_STREAMING; 703 + vdev->vfl_dir = VFL_DIR_RX; 704 + video_set_drvdata(vdev, cap); 705 + 706 + vb2_q->drv_priv = cap; 707 + vb2_q->mem_ops = &vb2_dma_contig_memops; 708 + vb2_q->ops = &isp_video_vb2_ops; 709 + vb2_q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 710 + vb2_q->io_modes = VB2_DMABUF | VB2_MMAP; 711 + vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 712 + vb2_q->buf_struct_size = sizeof(struct c3_isp_cap_buffer); 713 + vb2_q->dev = cap->isp->dev; 714 + vb2_q->lock = &cap->lock; 715 + 716 + ret = vb2_queue_init(vb2_q); 717 + if (ret) 718 + goto err_destroy; 719 + 720 + cap->pad.flags = MEDIA_PAD_FL_SINK; 721 + ret = media_entity_pads_init(&vdev->entity, 1, &cap->pad); 722 + if (ret) 723 + goto err_queue_release; 724 + 725 + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 726 + if (ret) { 727 + dev_err(cap->isp->dev, 728 + "Failed to register %s: %d\n", vdev->name, ret); 729 + goto err_entity_cleanup; 730 + } 731 + 732 + return 0; 733 + 734 + err_entity_cleanup: 735 + media_entity_cleanup(&vdev->entity); 736 + err_queue_release: 737 + vb2_queue_release(vb2_q); 738 + err_destroy: 739 + mutex_destroy(&cap->lock); 740 + return ret; 741 + } 742 + 743 + int c3_isp_captures_register(struct c3_isp_device *isp) 744 + { 745 + int ret; 746 + unsigned int i; 747 + struct c3_isp_capture *cap; 748 + 749 + for (i = C3_ISP_CAP_DEV_0; i < C3_ISP_NUM_CAP_DEVS; i++) { 750 + cap = &isp->caps[i]; 751 + memset(cap, 0, sizeof(*cap)); 752 + 753 + cap->format.pix_mp.width = C3_ISP_DEFAULT_WIDTH; 754 + cap->format.pix_mp.height = C3_ISP_DEFAULT_HEIGHT; 755 + cap->format.pix_mp.field = V4L2_FIELD_NONE; 756 + cap->format.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; 757 + cap->format.pix_mp.colorspace = V4L2_COLORSPACE_SRGB; 758 + cap->format.info = 759 + c3_cap_find_fmt(cap->format.pix_mp.pixelformat); 760 + 761 + c3_cap_try_fmt(&cap->format.pix_mp); 762 + 763 + cap->id = i; 764 + cap->rsz = &isp->resizers[i]; 765 + cap->isp = isp; 766 + INIT_LIST_HEAD(&cap->pending); 767 + spin_lock_init(&cap->buff_lock); 768 + mutex_init(&cap->lock); 769 + 770 + ret = c3_isp_register_capture(cap); 771 + if (ret) { 772 + cap->isp = NULL; 773 + mutex_destroy(&cap->lock); 774 + c3_isp_captures_unregister(isp); 775 + return ret; 776 + } 777 + } 778 + 779 + return 0; 780 + } 781 + 782 + void c3_isp_captures_unregister(struct c3_isp_device *isp) 783 + { 784 + unsigned int i; 785 + struct c3_isp_capture *cap; 786 + 787 + for (i = C3_ISP_CAP_DEV_0; i < C3_ISP_NUM_CAP_DEVS; i++) { 788 + cap = &isp->caps[i]; 789 + 790 + if (!cap->isp) 791 + continue; 792 + vb2_queue_release(&cap->vb2_q); 793 + media_entity_cleanup(&cap->vdev.entity); 794 + video_unregister_device(&cap->vdev); 795 + mutex_destroy(&cap->lock); 796 + } 797 + } 798 + 799 + void c3_isp_captures_isr(struct c3_isp_device *isp) 800 + { 801 + c3_isp_cap_done(&isp->caps[C3_ISP_CAP_DEV_0]); 802 + c3_isp_cap_done(&isp->caps[C3_ISP_CAP_DEV_1]); 803 + c3_isp_cap_done(&isp->caps[C3_ISP_CAP_DEV_2]); 804 + }
+340
drivers/media/platform/amlogic/c3/isp/c3-isp-common.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + */ 5 + 6 + #ifndef __C3_ISP_COMMON_H__ 7 + #define __C3_ISP_COMMON_H__ 8 + 9 + #include <linux/clk.h> 10 + 11 + #include <media/media-device.h> 12 + #include <media/videobuf2-core.h> 13 + #include <media/v4l2-device.h> 14 + #include <media/v4l2-subdev.h> 15 + #include <media/videobuf2-v4l2.h> 16 + 17 + #define C3_ISP_DRIVER_NAME "c3-isp" 18 + #define C3_ISP_CLOCK_NUM_MAX 3 19 + 20 + #define C3_ISP_DEFAULT_WIDTH 1920 21 + #define C3_ISP_DEFAULT_HEIGHT 1080 22 + #define C3_ISP_MAX_WIDTH 2888 23 + #define C3_ISP_MAX_HEIGHT 2240 24 + #define C3_ISP_MIN_WIDTH 160 25 + #define C3_ISP_MIN_HEIGHT 120 26 + 27 + #define C3_ISP_DMA_SIZE_ALIGN_BYTES 16 28 + 29 + enum c3_isp_core_pads { 30 + C3_ISP_CORE_PAD_SINK_VIDEO, 31 + C3_ISP_CORE_PAD_SINK_PARAMS, 32 + C3_ISP_CORE_PAD_SOURCE_STATS, 33 + C3_ISP_CORE_PAD_SOURCE_VIDEO_0, 34 + C3_ISP_CORE_PAD_SOURCE_VIDEO_1, 35 + C3_ISP_CORE_PAD_SOURCE_VIDEO_2, 36 + C3_ISP_CORE_PAD_MAX 37 + }; 38 + 39 + enum c3_isp_resizer_ids { 40 + C3_ISP_RSZ_0, 41 + C3_ISP_RSZ_1, 42 + C3_ISP_RSZ_2, 43 + C3_ISP_NUM_RSZ 44 + }; 45 + 46 + enum c3_isp_resizer_pads { 47 + C3_ISP_RSZ_PAD_SINK, 48 + C3_ISP_RSZ_PAD_SOURCE, 49 + C3_ISP_RSZ_PAD_MAX 50 + }; 51 + 52 + enum c3_isp_cap_devs { 53 + C3_ISP_CAP_DEV_0, 54 + C3_ISP_CAP_DEV_1, 55 + C3_ISP_CAP_DEV_2, 56 + C3_ISP_NUM_CAP_DEVS 57 + }; 58 + 59 + enum c3_isp_planes { 60 + C3_ISP_PLANE_Y, 61 + C3_ISP_PLANE_UV, 62 + C3_ISP_NUM_PLANES 63 + }; 64 + 65 + /* 66 + * struct c3_isp_cap_format_info - The image format of capture device 67 + * 68 + * @mbus_code: the mbus code 69 + * @fourcc: the pixel format 70 + * @format: defines the output format of hardware 71 + * @planes: defines the mutil plane of hardware 72 + * @ch0_pix_bits: defines the channel 0 pixel bits mode of hardware 73 + * @uv_swap: defines the uv swap flag of hardware 74 + * @in_bits: defines the input bits of hardware 75 + * @hdiv: horizontal chroma subsampling factor of hardware 76 + * @vdiv: vertical chroma subsampling factor of hardware 77 + */ 78 + struct c3_isp_cap_format_info { 79 + u32 mbus_code; 80 + u32 fourcc; 81 + u32 format; 82 + u32 planes; 83 + u32 ch0_pix_bits; 84 + u8 uv_swap; 85 + u8 in_bits; 86 + u8 hdiv; 87 + u8 vdiv; 88 + }; 89 + 90 + /* 91 + * struct c3_isp_cap_buffer - A container of vb2 buffer used by the video 92 + * devices: capture video devices 93 + * 94 + * @vb: vb2 buffer 95 + * @dma_addr: buffer physical address 96 + * @list: entry of the buffer in the queue 97 + */ 98 + struct c3_isp_cap_buffer { 99 + struct vb2_v4l2_buffer vb; 100 + dma_addr_t dma_addr[C3_ISP_NUM_PLANES]; 101 + struct list_head list; 102 + }; 103 + 104 + /* 105 + * struct c3_isp_stats_dma_buffer - A container of vb2 buffer used by the video 106 + * devices: stats video devices 107 + * 108 + * @vb: vb2 buffer 109 + * @dma_addr: buffer physical address 110 + * @list: entry of the buffer in the queue 111 + */ 112 + struct c3_isp_stats_buffer { 113 + struct vb2_v4l2_buffer vb; 114 + dma_addr_t dma_addr; 115 + struct list_head list; 116 + }; 117 + 118 + /* 119 + * struct c3_isp_params_buffer - A container of vb2 buffer used by the 120 + * params video device 121 + * 122 + * @vb: vb2 buffer 123 + * @cfg: scratch buffer used for caching the ISP configuration parameters 124 + * @list: entry of the buffer in the queue 125 + */ 126 + struct c3_isp_params_buffer { 127 + struct vb2_v4l2_buffer vb; 128 + void *cfg; 129 + struct list_head list; 130 + }; 131 + 132 + /* 133 + * struct c3_isp_dummy_buffer - A buffer to write the next frame to in case 134 + * there are no vb2 buffers available. 135 + * 136 + * @vaddr: return value of call to dma_alloc_attrs 137 + * @dma_addr: dma address of the buffer 138 + * @size: size of the buffer 139 + */ 140 + struct c3_isp_dummy_buffer { 141 + void *vaddr; 142 + dma_addr_t dma_addr; 143 + u32 size; 144 + }; 145 + 146 + /* 147 + * struct c3_isp_core - ISP core subdev 148 + * 149 + * @sd: ISP sub-device 150 + * @pads: ISP sub-device pads 151 + * @src_pad: source sub-device pad 152 + * @isp: pointer to c3_isp_device 153 + */ 154 + struct c3_isp_core { 155 + struct v4l2_subdev sd; 156 + struct media_pad pads[C3_ISP_CORE_PAD_MAX]; 157 + struct media_pad *src_pad; 158 + struct c3_isp_device *isp; 159 + }; 160 + 161 + /* 162 + * struct c3_isp_resizer - ISP resizer subdev 163 + * 164 + * @id: resizer id 165 + * @sd: resizer sub-device 166 + * @pads: resizer sub-device pads 167 + * @src_sd: source sub-device 168 + * @isp: pointer to c3_isp_device 169 + * @src_pad: the pad of source sub-device 170 + */ 171 + struct c3_isp_resizer { 172 + enum c3_isp_resizer_ids id; 173 + struct v4l2_subdev sd; 174 + struct media_pad pads[C3_ISP_RSZ_PAD_MAX]; 175 + struct v4l2_subdev *src_sd; 176 + struct c3_isp_device *isp; 177 + u32 src_pad; 178 + }; 179 + 180 + /* 181 + * struct c3_isp_stats - ISP statistics device 182 + * 183 + * @vb2_q: vb2 buffer queue 184 + * @vdev: video node 185 + * @vfmt: v4l2_format of the metadata format 186 + * @pad: media pad 187 + * @lock: protects vb2_q, vdev 188 + * @isp: pointer to c3_isp_device 189 + * @buff: in use buffer 190 + * @buff_lock: protects stats buffer 191 + * @pending: stats buffer list head 192 + */ 193 + struct c3_isp_stats { 194 + struct vb2_queue vb2_q; 195 + struct video_device vdev; 196 + struct v4l2_format vfmt; 197 + struct media_pad pad; 198 + 199 + struct mutex lock; /* Protects vb2_q, vdev */ 200 + struct c3_isp_device *isp; 201 + 202 + struct c3_isp_stats_buffer *buff; 203 + spinlock_t buff_lock; /* Protects stats buffer */ 204 + struct list_head pending; 205 + }; 206 + 207 + /* 208 + * struct c3_isp_params - ISP parameters device 209 + * 210 + * @vb2_q: vb2 buffer queue 211 + * @vdev: video node 212 + * @vfmt: v4l2_format of the metadata format 213 + * @pad: media pad 214 + * @lock: protects vb2_q, vdev 215 + * @isp: pointer to c3_isp_device 216 + * @buff: in use buffer 217 + * @buff_lock: protects stats buffer 218 + * @pending: stats buffer list head 219 + */ 220 + struct c3_isp_params { 221 + struct vb2_queue vb2_q; 222 + struct video_device vdev; 223 + struct v4l2_format vfmt; 224 + struct media_pad pad; 225 + 226 + struct mutex lock; /* Protects vb2_q, vdev */ 227 + struct c3_isp_device *isp; 228 + 229 + struct c3_isp_params_buffer *buff; 230 + spinlock_t buff_lock; /* Protects params buffer */ 231 + struct list_head pending; 232 + }; 233 + 234 + /* 235 + * struct c3_isp_capture - ISP capture device 236 + * 237 + * @id: capture device ID 238 + * @vb2_q: vb2 buffer queue 239 + * @vdev: video node 240 + * @pad: media pad 241 + * @lock: protects vb2_q, vdev 242 + * @isp: pointer to c3_isp_device 243 + * @rsz: pointer to c3_isp_resizer 244 + * @buff: in use buffer 245 + * @buff_lock: protects capture buffer 246 + * @pending: capture buffer list head 247 + * @format.info: a pointer to the c3_isp_capture_format of the pixel format 248 + * @format.fmt: buffer format 249 + */ 250 + struct c3_isp_capture { 251 + enum c3_isp_cap_devs id; 252 + struct vb2_queue vb2_q; 253 + struct video_device vdev; 254 + struct media_pad pad; 255 + 256 + struct mutex lock; /* Protects vb2_q, vdev */ 257 + struct c3_isp_device *isp; 258 + struct c3_isp_resizer *rsz; 259 + 260 + struct c3_isp_dummy_buffer dummy_buff; 261 + struct c3_isp_cap_buffer *buff; 262 + spinlock_t buff_lock; /* Protects stream buffer */ 263 + struct list_head pending; 264 + struct { 265 + const struct c3_isp_cap_format_info *info; 266 + struct v4l2_pix_format_mplane pix_mp; 267 + } format; 268 + }; 269 + 270 + /** 271 + * struct c3_isp_info - ISP information 272 + * 273 + * @clocks: array of ISP clock names 274 + * @clock_num: actual clock number 275 + */ 276 + struct c3_isp_info { 277 + char *clocks[C3_ISP_CLOCK_NUM_MAX]; 278 + u32 clock_num; 279 + }; 280 + 281 + /** 282 + * struct c3_isp_device - ISP platform device 283 + * 284 + * @dev: pointer to the struct device 285 + * @base: base register address 286 + * @clks: array of clocks 287 + * @notifier: notifier to register on the v4l2-async API 288 + * @v4l2_dev: v4l2_device variable 289 + * @media_dev: media device variable 290 + * @pipe: media pipeline 291 + * @core: ISP core subdev 292 + * @resizers: ISP resizer subdev 293 + * @stats: ISP stats device 294 + * @params: ISP params device 295 + * @caps: array of ISP capture device 296 + * @frm_sequence: used to record frame id 297 + * @info: version-specific ISP information 298 + */ 299 + struct c3_isp_device { 300 + struct device *dev; 301 + void __iomem *base; 302 + struct clk_bulk_data clks[C3_ISP_CLOCK_NUM_MAX]; 303 + 304 + struct v4l2_async_notifier notifier; 305 + struct v4l2_device v4l2_dev; 306 + struct media_device media_dev; 307 + struct media_pipeline pipe; 308 + 309 + struct c3_isp_core core; 310 + struct c3_isp_resizer resizers[C3_ISP_NUM_RSZ]; 311 + struct c3_isp_stats stats; 312 + struct c3_isp_params params; 313 + struct c3_isp_capture caps[C3_ISP_NUM_CAP_DEVS]; 314 + 315 + u32 frm_sequence; 316 + const struct c3_isp_info *info; 317 + }; 318 + 319 + u32 c3_isp_read(struct c3_isp_device *isp, u32 reg); 320 + void c3_isp_write(struct c3_isp_device *isp, u32 reg, u32 val); 321 + void c3_isp_update_bits(struct c3_isp_device *isp, u32 reg, u32 mask, u32 val); 322 + 323 + void c3_isp_core_queue_sof(struct c3_isp_device *isp); 324 + int c3_isp_core_register(struct c3_isp_device *isp); 325 + void c3_isp_core_unregister(struct c3_isp_device *isp); 326 + int c3_isp_resizers_register(struct c3_isp_device *isp); 327 + void c3_isp_resizers_unregister(struct c3_isp_device *isp); 328 + int c3_isp_captures_register(struct c3_isp_device *isp); 329 + void c3_isp_captures_unregister(struct c3_isp_device *isp); 330 + void c3_isp_captures_isr(struct c3_isp_device *isp); 331 + void c3_isp_stats_pre_cfg(struct c3_isp_device *isp); 332 + int c3_isp_stats_register(struct c3_isp_device *isp); 333 + void c3_isp_stats_unregister(struct c3_isp_device *isp); 334 + void c3_isp_stats_isr(struct c3_isp_device *isp); 335 + void c3_isp_params_pre_cfg(struct c3_isp_device *isp); 336 + int c3_isp_params_register(struct c3_isp_device *isp); 337 + void c3_isp_params_unregister(struct c3_isp_device *isp); 338 + void c3_isp_params_isr(struct c3_isp_device *isp); 339 + 340 + #endif
+641
drivers/media/platform/amlogic/c3/isp/c3-isp-core.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + */ 5 + 6 + #include <linux/media/amlogic/c3-isp-config.h> 7 + #include <linux/pm_runtime.h> 8 + 9 + #include <media/v4l2-event.h> 10 + 11 + #include "c3-isp-common.h" 12 + #include "c3-isp-regs.h" 13 + 14 + #define C3_ISP_CORE_SUBDEV_NAME "c3-isp-core" 15 + 16 + #define C3_ISP_PHASE_OFFSET_0 0 17 + #define C3_ISP_PHASE_OFFSET_1 1 18 + #define C3_ISP_PHASE_OFFSET_NONE 0xff 19 + 20 + #define C3_ISP_CORE_DEF_SINK_PAD_FMT MEDIA_BUS_FMT_SRGGB10_1X10 21 + #define C3_ISP_CORE_DEF_SRC_PAD_FMT MEDIA_BUS_FMT_YUV10_1X30 22 + 23 + /* 24 + * struct c3_isp_core_format_info - ISP core format information 25 + * 26 + * @mbus_code: the mbus code 27 + * @pads: bitmask detailing valid pads for this mbus_code 28 + * @xofst: horizontal phase offset of hardware 29 + * @yofst: vertical phase offset of hardware 30 + * @is_raw: the raw format flag of mbus code 31 + */ 32 + struct c3_isp_core_format_info { 33 + u32 mbus_code; 34 + u32 pads; 35 + u8 xofst; 36 + u8 yofst; 37 + bool is_raw; 38 + }; 39 + 40 + static const struct c3_isp_core_format_info c3_isp_core_fmts[] = { 41 + /* RAW formats */ 42 + { 43 + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, 44 + .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 45 + .xofst = C3_ISP_PHASE_OFFSET_0, 46 + .yofst = C3_ISP_PHASE_OFFSET_1, 47 + .is_raw = true, 48 + }, { 49 + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, 50 + .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 51 + .xofst = C3_ISP_PHASE_OFFSET_1, 52 + .yofst = C3_ISP_PHASE_OFFSET_1, 53 + .is_raw = true, 54 + }, { 55 + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, 56 + .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 57 + .xofst = C3_ISP_PHASE_OFFSET_0, 58 + .yofst = C3_ISP_PHASE_OFFSET_0, 59 + .is_raw = true, 60 + }, { 61 + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, 62 + .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 63 + .xofst = C3_ISP_PHASE_OFFSET_1, 64 + .yofst = C3_ISP_PHASE_OFFSET_0, 65 + .is_raw = true, 66 + }, { 67 + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, 68 + .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 69 + .xofst = C3_ISP_PHASE_OFFSET_0, 70 + .yofst = C3_ISP_PHASE_OFFSET_1, 71 + .is_raw = true, 72 + }, { 73 + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, 74 + .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 75 + .xofst = C3_ISP_PHASE_OFFSET_1, 76 + .yofst = C3_ISP_PHASE_OFFSET_1, 77 + .is_raw = true, 78 + }, { 79 + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, 80 + .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 81 + .xofst = C3_ISP_PHASE_OFFSET_0, 82 + .yofst = C3_ISP_PHASE_OFFSET_0, 83 + .is_raw = true, 84 + }, { 85 + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, 86 + .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 87 + .xofst = C3_ISP_PHASE_OFFSET_1, 88 + .yofst = C3_ISP_PHASE_OFFSET_0, 89 + .is_raw = true, 90 + }, { 91 + .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, 92 + .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) 93 + | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) 94 + | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 95 + .xofst = C3_ISP_PHASE_OFFSET_NONE, 96 + .yofst = C3_ISP_PHASE_OFFSET_NONE, 97 + .is_raw = true, 98 + }, { 99 + .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, 100 + .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) 101 + | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) 102 + | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 103 + .xofst = C3_ISP_PHASE_OFFSET_NONE, 104 + .yofst = C3_ISP_PHASE_OFFSET_NONE, 105 + .is_raw = true, 106 + }, { 107 + .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, 108 + .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) 109 + | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) 110 + | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 111 + .xofst = C3_ISP_PHASE_OFFSET_NONE, 112 + .yofst = C3_ISP_PHASE_OFFSET_NONE, 113 + .is_raw = true, 114 + }, { 115 + .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, 116 + .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) 117 + | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) 118 + | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 119 + .xofst = C3_ISP_PHASE_OFFSET_NONE, 120 + .yofst = C3_ISP_PHASE_OFFSET_NONE, 121 + .is_raw = true, 122 + }, 123 + /* YUV formats */ 124 + { 125 + .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 126 + .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) | 127 + BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) | 128 + BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 129 + .xofst = C3_ISP_PHASE_OFFSET_NONE, 130 + .yofst = C3_ISP_PHASE_OFFSET_NONE, 131 + .is_raw = false, 132 + }, 133 + }; 134 + 135 + static const struct c3_isp_core_format_info 136 + *core_find_format_by_code(u32 code, u32 pad) 137 + { 138 + for (unsigned int i = 0; i < ARRAY_SIZE(c3_isp_core_fmts); i++) { 139 + const struct c3_isp_core_format_info *info = 140 + &c3_isp_core_fmts[i]; 141 + 142 + if (info->mbus_code == code && info->pads & BIT(pad)) 143 + return info; 144 + } 145 + 146 + return NULL; 147 + } 148 + 149 + static const struct c3_isp_core_format_info 150 + *core_find_format_by_index(u32 index, u32 pad) 151 + { 152 + for (unsigned int i = 0; i < ARRAY_SIZE(c3_isp_core_fmts); i++) { 153 + const struct c3_isp_core_format_info *info = 154 + &c3_isp_core_fmts[i]; 155 + 156 + if (!(info->pads & BIT(pad))) 157 + continue; 158 + 159 + if (!index) 160 + return info; 161 + 162 + index--; 163 + } 164 + 165 + return NULL; 166 + } 167 + 168 + static void c3_isp_core_enable(struct c3_isp_device *isp) 169 + { 170 + c3_isp_update_bits(isp, ISP_TOP_IRQ_EN, ISP_TOP_IRQ_EN_FRM_END_MASK, 171 + ISP_TOP_IRQ_EN_FRM_END_EN); 172 + c3_isp_update_bits(isp, ISP_TOP_IRQ_EN, ISP_TOP_IRQ_EN_FRM_RST_MASK, 173 + ISP_TOP_IRQ_EN_FRM_RST_EN); 174 + 175 + /* Enable image data to ISP core */ 176 + c3_isp_update_bits(isp, ISP_TOP_PATH_SEL, ISP_TOP_PATH_SEL_CORE_MASK, 177 + ISP_TOP_PATH_SEL_CORE_MIPI_CORE); 178 + } 179 + 180 + static void c3_isp_core_disable(struct c3_isp_device *isp) 181 + { 182 + /* Disable image data to ISP core */ 183 + c3_isp_update_bits(isp, ISP_TOP_PATH_SEL, ISP_TOP_PATH_SEL_CORE_MASK, 184 + ISP_TOP_PATH_SEL_CORE_CORE_DIS); 185 + 186 + c3_isp_update_bits(isp, ISP_TOP_IRQ_EN, ISP_TOP_IRQ_EN_FRM_END_MASK, 187 + ISP_TOP_IRQ_EN_FRM_END_DIS); 188 + c3_isp_update_bits(isp, ISP_TOP_IRQ_EN, ISP_TOP_IRQ_EN_FRM_RST_MASK, 189 + ISP_TOP_IRQ_EN_FRM_RST_DIS); 190 + } 191 + 192 + /* Set the phase offset of blc, wb and lns */ 193 + static void c3_isp_core_lswb_ofst(struct c3_isp_device *isp, 194 + u8 xofst, u8 yofst) 195 + { 196 + c3_isp_update_bits(isp, ISP_LSWB_BLC_PHSOFST, 197 + ISP_LSWB_BLC_PHSOFST_HORIZ_OFST_MASK, 198 + ISP_LSWB_BLC_PHSOFST_HORIZ_OFST(xofst)); 199 + c3_isp_update_bits(isp, ISP_LSWB_BLC_PHSOFST, 200 + ISP_LSWB_BLC_PHSOFST_VERT_OFST_MASK, 201 + ISP_LSWB_BLC_PHSOFST_VERT_OFST(yofst)); 202 + 203 + c3_isp_update_bits(isp, ISP_LSWB_WB_PHSOFST, 204 + ISP_LSWB_WB_PHSOFST_HORIZ_OFST_MASK, 205 + ISP_LSWB_WB_PHSOFST_HORIZ_OFST(xofst)); 206 + c3_isp_update_bits(isp, ISP_LSWB_WB_PHSOFST, 207 + ISP_LSWB_WB_PHSOFST_VERT_OFST_MASK, 208 + ISP_LSWB_WB_PHSOFST_VERT_OFST(yofst)); 209 + 210 + c3_isp_update_bits(isp, ISP_LSWB_LNS_PHSOFST, 211 + ISP_LSWB_LNS_PHSOFST_HORIZ_OFST_MASK, 212 + ISP_LSWB_LNS_PHSOFST_HORIZ_OFST(xofst)); 213 + c3_isp_update_bits(isp, ISP_LSWB_LNS_PHSOFST, 214 + ISP_LSWB_LNS_PHSOFST_VERT_OFST_MASK, 215 + ISP_LSWB_LNS_PHSOFST_VERT_OFST(yofst)); 216 + } 217 + 218 + /* Set the phase offset of af, ae and awb */ 219 + static void c3_isp_core_3a_ofst(struct c3_isp_device *isp, 220 + u8 xofst, u8 yofst) 221 + { 222 + c3_isp_update_bits(isp, ISP_AF_CTRL, ISP_AF_CTRL_HORIZ_OFST_MASK, 223 + ISP_AF_CTRL_HORIZ_OFST(xofst)); 224 + c3_isp_update_bits(isp, ISP_AF_CTRL, ISP_AF_CTRL_VERT_OFST_MASK, 225 + ISP_AF_CTRL_VERT_OFST(yofst)); 226 + 227 + c3_isp_update_bits(isp, ISP_AE_CTRL, ISP_AE_CTRL_HORIZ_OFST_MASK, 228 + ISP_AE_CTRL_HORIZ_OFST(xofst)); 229 + c3_isp_update_bits(isp, ISP_AE_CTRL, ISP_AE_CTRL_VERT_OFST_MASK, 230 + ISP_AE_CTRL_VERT_OFST(yofst)); 231 + 232 + c3_isp_update_bits(isp, ISP_AWB_CTRL, ISP_AWB_CTRL_HORIZ_OFST_MASK, 233 + ISP_AWB_CTRL_HORIZ_OFST(xofst)); 234 + c3_isp_update_bits(isp, ISP_AWB_CTRL, ISP_AWB_CTRL_VERT_OFST_MASK, 235 + ISP_AWB_CTRL_VERT_OFST(yofst)); 236 + } 237 + 238 + /* Set the phase offset of demosaic */ 239 + static void c3_isp_core_dms_ofst(struct c3_isp_device *isp, 240 + u8 xofst, u8 yofst) 241 + { 242 + c3_isp_update_bits(isp, ISP_DMS_COMMON_PARAM0, 243 + ISP_DMS_COMMON_PARAM0_HORIZ_PHS_OFST_MASK, 244 + ISP_DMS_COMMON_PARAM0_HORIZ_PHS_OFST(xofst)); 245 + c3_isp_update_bits(isp, ISP_DMS_COMMON_PARAM0, 246 + ISP_DMS_COMMON_PARAM0_VERT_PHS_OFST_MASK, 247 + ISP_DMS_COMMON_PARAM0_VERT_PHS_OFST(yofst)); 248 + } 249 + 250 + static void c3_isp_core_cfg_format(struct c3_isp_device *isp, 251 + struct v4l2_subdev_state *state) 252 + { 253 + struct v4l2_mbus_framefmt *fmt; 254 + const struct c3_isp_core_format_info *isp_fmt; 255 + 256 + fmt = v4l2_subdev_state_get_format(state, C3_ISP_CORE_PAD_SINK_VIDEO); 257 + isp_fmt = core_find_format_by_code(fmt->code, 258 + C3_ISP_CORE_PAD_SINK_VIDEO); 259 + 260 + c3_isp_write(isp, ISP_TOP_INPUT_SIZE, 261 + ISP_TOP_INPUT_SIZE_HORIZ_SIZE(fmt->width) | 262 + ISP_TOP_INPUT_SIZE_VERT_SIZE(fmt->height)); 263 + c3_isp_write(isp, ISP_TOP_FRM_SIZE, 264 + ISP_TOP_FRM_SIZE_CORE_HORIZ_SIZE(fmt->width) | 265 + ISP_TOP_FRM_SIZE_CORE_VERT_SIZE(fmt->height)); 266 + 267 + c3_isp_update_bits(isp, ISP_TOP_HOLD_SIZE, 268 + ISP_TOP_HOLD_SIZE_CORE_HORIZ_SIZE_MASK, 269 + ISP_TOP_HOLD_SIZE_CORE_HORIZ_SIZE(fmt->width)); 270 + 271 + c3_isp_write(isp, ISP_AF_HV_SIZE, 272 + ISP_AF_HV_SIZE_GLB_WIN_XSIZE(fmt->width) | 273 + ISP_AF_HV_SIZE_GLB_WIN_YSIZE(fmt->height)); 274 + c3_isp_write(isp, ISP_AE_HV_SIZE, 275 + ISP_AE_HV_SIZE_HORIZ_SIZE(fmt->width) | 276 + ISP_AE_HV_SIZE_VERT_SIZE(fmt->height)); 277 + c3_isp_write(isp, ISP_AWB_HV_SIZE, 278 + ISP_AWB_HV_SIZE_HORIZ_SIZE(fmt->width) | 279 + ISP_AWB_HV_SIZE_VERT_SIZE(fmt->height)); 280 + 281 + c3_isp_core_lswb_ofst(isp, isp_fmt->xofst, isp_fmt->yofst); 282 + c3_isp_core_3a_ofst(isp, isp_fmt->xofst, isp_fmt->yofst); 283 + c3_isp_core_dms_ofst(isp, isp_fmt->xofst, isp_fmt->yofst); 284 + } 285 + 286 + static bool c3_isp_core_streams_ready(struct c3_isp_core *core) 287 + { 288 + unsigned int n_links = 0; 289 + struct media_link *link; 290 + 291 + for_each_media_entity_data_link(&core->sd.entity, link) { 292 + if ((link->source->index == C3_ISP_CORE_PAD_SOURCE_VIDEO_0 || 293 + link->source->index == C3_ISP_CORE_PAD_SOURCE_VIDEO_1 || 294 + link->source->index == C3_ISP_CORE_PAD_SOURCE_VIDEO_2) && 295 + link->flags == MEDIA_LNK_FL_ENABLED) 296 + n_links++; 297 + } 298 + 299 + return n_links == core->isp->pipe.start_count; 300 + } 301 + 302 + static int c3_isp_core_enable_streams(struct v4l2_subdev *sd, 303 + struct v4l2_subdev_state *state, 304 + u32 pad, u64 streams_mask) 305 + { 306 + struct c3_isp_core *core = v4l2_get_subdevdata(sd); 307 + struct media_pad *sink_pad; 308 + struct v4l2_subdev *src_sd; 309 + int ret; 310 + 311 + if (!c3_isp_core_streams_ready(core)) 312 + return 0; 313 + 314 + core->isp->frm_sequence = 0; 315 + c3_isp_core_cfg_format(core->isp, state); 316 + c3_isp_core_enable(core->isp); 317 + 318 + sink_pad = &core->pads[C3_ISP_CORE_PAD_SINK_VIDEO]; 319 + core->src_pad = media_pad_remote_pad_unique(sink_pad); 320 + if (IS_ERR(core->src_pad)) { 321 + dev_dbg(core->isp->dev, 322 + "Failed to get source pad for ISP core\n"); 323 + return -EPIPE; 324 + } 325 + 326 + src_sd = media_entity_to_v4l2_subdev(core->src_pad->entity); 327 + 328 + ret = v4l2_subdev_enable_streams(src_sd, core->src_pad->index, BIT(0)); 329 + if (ret) { 330 + c3_isp_core_disable(core->isp); 331 + return ret; 332 + } 333 + 334 + return 0; 335 + } 336 + 337 + static int c3_isp_core_disable_streams(struct v4l2_subdev *sd, 338 + struct v4l2_subdev_state *state, 339 + u32 pad, u64 streams_mask) 340 + { 341 + struct c3_isp_core *core = v4l2_get_subdevdata(sd); 342 + struct v4l2_subdev *src_sd; 343 + 344 + if (core->isp->pipe.start_count != 1) 345 + return 0; 346 + 347 + if (core->src_pad) { 348 + src_sd = media_entity_to_v4l2_subdev(core->src_pad->entity); 349 + v4l2_subdev_disable_streams(src_sd, core->src_pad->index, 350 + BIT(0)); 351 + } 352 + core->src_pad = NULL; 353 + 354 + c3_isp_core_disable(core->isp); 355 + 356 + return 0; 357 + } 358 + 359 + static int c3_isp_core_enum_mbus_code(struct v4l2_subdev *sd, 360 + struct v4l2_subdev_state *state, 361 + struct v4l2_subdev_mbus_code_enum *code) 362 + { 363 + const struct c3_isp_core_format_info *info; 364 + 365 + switch (code->pad) { 366 + case C3_ISP_CORE_PAD_SINK_VIDEO: 367 + case C3_ISP_CORE_PAD_SOURCE_VIDEO_0: 368 + case C3_ISP_CORE_PAD_SOURCE_VIDEO_1: 369 + case C3_ISP_CORE_PAD_SOURCE_VIDEO_2: 370 + info = core_find_format_by_index(code->index, code->pad); 371 + if (!info) 372 + return -EINVAL; 373 + 374 + code->code = info->mbus_code; 375 + 376 + break; 377 + case C3_ISP_CORE_PAD_SINK_PARAMS: 378 + case C3_ISP_CORE_PAD_SOURCE_STATS: 379 + if (code->index) 380 + return -EINVAL; 381 + 382 + code->code = MEDIA_BUS_FMT_METADATA_FIXED; 383 + 384 + break; 385 + default: 386 + return -EINVAL; 387 + } 388 + 389 + return 0; 390 + } 391 + 392 + static void c3_isp_core_set_sink_fmt(struct v4l2_subdev_state *state, 393 + struct v4l2_subdev_format *format) 394 + { 395 + struct v4l2_mbus_framefmt *sink_fmt; 396 + struct v4l2_mbus_framefmt *src_fmt; 397 + const struct c3_isp_core_format_info *isp_fmt; 398 + 399 + sink_fmt = v4l2_subdev_state_get_format(state, format->pad); 400 + 401 + isp_fmt = core_find_format_by_code(format->format.code, format->pad); 402 + if (!isp_fmt) 403 + sink_fmt->code = C3_ISP_CORE_DEF_SINK_PAD_FMT; 404 + else 405 + sink_fmt->code = format->format.code; 406 + 407 + sink_fmt->width = clamp_t(u32, format->format.width, 408 + C3_ISP_MIN_WIDTH, C3_ISP_MAX_WIDTH); 409 + sink_fmt->height = clamp_t(u32, format->format.height, 410 + C3_ISP_MIN_HEIGHT, C3_ISP_MAX_HEIGHT); 411 + sink_fmt->field = V4L2_FIELD_NONE; 412 + sink_fmt->colorspace = V4L2_COLORSPACE_RAW; 413 + sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 414 + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 415 + sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 416 + 417 + for (unsigned int i = C3_ISP_CORE_PAD_SOURCE_VIDEO_0; 418 + i < C3_ISP_CORE_PAD_MAX; i++) { 419 + src_fmt = v4l2_subdev_state_get_format(state, i); 420 + 421 + src_fmt->width = sink_fmt->width; 422 + src_fmt->height = sink_fmt->height; 423 + } 424 + 425 + format->format = *sink_fmt; 426 + } 427 + 428 + static void c3_isp_core_set_source_fmt(struct v4l2_subdev_state *state, 429 + struct v4l2_subdev_format *format) 430 + { 431 + const struct c3_isp_core_format_info *isp_fmt; 432 + struct v4l2_mbus_framefmt *src_fmt; 433 + struct v4l2_mbus_framefmt *sink_fmt; 434 + 435 + sink_fmt = v4l2_subdev_state_get_format(state, 436 + C3_ISP_CORE_PAD_SINK_VIDEO); 437 + src_fmt = v4l2_subdev_state_get_format(state, format->pad); 438 + 439 + isp_fmt = core_find_format_by_code(format->format.code, format->pad); 440 + if (!isp_fmt) 441 + src_fmt->code = C3_ISP_CORE_DEF_SRC_PAD_FMT; 442 + else 443 + src_fmt->code = format->format.code; 444 + 445 + src_fmt->width = sink_fmt->width; 446 + src_fmt->height = sink_fmt->height; 447 + src_fmt->field = V4L2_FIELD_NONE; 448 + src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 449 + 450 + if (isp_fmt && isp_fmt->is_raw) { 451 + src_fmt->colorspace = V4L2_COLORSPACE_RAW; 452 + src_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 453 + src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 454 + } else { 455 + src_fmt->colorspace = V4L2_COLORSPACE_SRGB; 456 + src_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 457 + src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 458 + } 459 + 460 + format->format = *src_fmt; 461 + } 462 + 463 + static int c3_isp_core_set_fmt(struct v4l2_subdev *sd, 464 + struct v4l2_subdev_state *state, 465 + struct v4l2_subdev_format *format) 466 + { 467 + if (format->pad == C3_ISP_CORE_PAD_SINK_VIDEO) 468 + c3_isp_core_set_sink_fmt(state, format); 469 + else if (format->pad == C3_ISP_CORE_PAD_SOURCE_VIDEO_0 || 470 + format->pad == C3_ISP_CORE_PAD_SOURCE_VIDEO_1 || 471 + format->pad == C3_ISP_CORE_PAD_SOURCE_VIDEO_2) 472 + c3_isp_core_set_source_fmt(state, format); 473 + else 474 + format->format = 475 + *v4l2_subdev_state_get_format(state, format->pad); 476 + 477 + return 0; 478 + } 479 + 480 + static int c3_isp_core_init_state(struct v4l2_subdev *sd, 481 + struct v4l2_subdev_state *state) 482 + { 483 + struct v4l2_mbus_framefmt *fmt; 484 + 485 + /* Video sink pad */ 486 + fmt = v4l2_subdev_state_get_format(state, C3_ISP_CORE_PAD_SINK_VIDEO); 487 + fmt->width = C3_ISP_DEFAULT_WIDTH; 488 + fmt->height = C3_ISP_DEFAULT_HEIGHT; 489 + fmt->field = V4L2_FIELD_NONE; 490 + fmt->code = C3_ISP_CORE_DEF_SINK_PAD_FMT; 491 + fmt->colorspace = V4L2_COLORSPACE_RAW; 492 + fmt->xfer_func = V4L2_XFER_FUNC_NONE; 493 + fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 494 + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 495 + 496 + /* Video source pad */ 497 + for (unsigned int i = C3_ISP_CORE_PAD_SOURCE_VIDEO_0; 498 + i < C3_ISP_CORE_PAD_MAX; i++) { 499 + fmt = v4l2_subdev_state_get_format(state, i); 500 + fmt->width = C3_ISP_DEFAULT_WIDTH; 501 + fmt->height = C3_ISP_DEFAULT_HEIGHT; 502 + fmt->field = V4L2_FIELD_NONE; 503 + fmt->code = C3_ISP_CORE_DEF_SRC_PAD_FMT; 504 + fmt->colorspace = V4L2_COLORSPACE_SRGB; 505 + fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 506 + fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 507 + fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 508 + } 509 + 510 + /* Parameters pad */ 511 + fmt = v4l2_subdev_state_get_format(state, C3_ISP_CORE_PAD_SINK_PARAMS); 512 + fmt->width = 0; 513 + fmt->height = 0; 514 + fmt->field = V4L2_FIELD_NONE; 515 + fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; 516 + 517 + /* Statistics pad */ 518 + fmt = v4l2_subdev_state_get_format(state, C3_ISP_CORE_PAD_SOURCE_STATS); 519 + fmt->width = 0; 520 + fmt->height = 0; 521 + fmt->field = V4L2_FIELD_NONE; 522 + fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; 523 + 524 + return 0; 525 + } 526 + 527 + static int c3_isp_core_subscribe_event(struct v4l2_subdev *sd, 528 + struct v4l2_fh *fh, 529 + struct v4l2_event_subscription *sub) 530 + { 531 + if (sub->type != V4L2_EVENT_FRAME_SYNC) 532 + return -EINVAL; 533 + 534 + /* V4L2_EVENT_FRAME_SYNC doesn't need id, so should set 0 */ 535 + if (sub->id != 0) 536 + return -EINVAL; 537 + 538 + return v4l2_event_subscribe(fh, sub, 0, NULL); 539 + } 540 + 541 + static const struct v4l2_subdev_pad_ops c3_isp_core_pad_ops = { 542 + .enum_mbus_code = c3_isp_core_enum_mbus_code, 543 + .get_fmt = v4l2_subdev_get_fmt, 544 + .set_fmt = c3_isp_core_set_fmt, 545 + .enable_streams = c3_isp_core_enable_streams, 546 + .disable_streams = c3_isp_core_disable_streams, 547 + }; 548 + 549 + static const struct v4l2_subdev_core_ops c3_isp_core_core_ops = { 550 + .subscribe_event = c3_isp_core_subscribe_event, 551 + .unsubscribe_event = v4l2_event_subdev_unsubscribe, 552 + }; 553 + 554 + static const struct v4l2_subdev_ops c3_isp_core_subdev_ops = { 555 + .core = &c3_isp_core_core_ops, 556 + .pad = &c3_isp_core_pad_ops, 557 + }; 558 + 559 + static const struct v4l2_subdev_internal_ops c3_isp_core_internal_ops = { 560 + .init_state = c3_isp_core_init_state, 561 + }; 562 + 563 + static int c3_isp_core_link_validate(struct media_link *link) 564 + { 565 + if (link->sink->index == C3_ISP_CORE_PAD_SINK_PARAMS) 566 + return 0; 567 + 568 + return v4l2_subdev_link_validate(link); 569 + } 570 + 571 + /* Media entity operations */ 572 + static const struct media_entity_operations c3_isp_core_entity_ops = { 573 + .link_validate = c3_isp_core_link_validate, 574 + }; 575 + 576 + void c3_isp_core_queue_sof(struct c3_isp_device *isp) 577 + { 578 + struct v4l2_event event = { 579 + .type = V4L2_EVENT_FRAME_SYNC, 580 + }; 581 + 582 + event.u.frame_sync.frame_sequence = isp->frm_sequence; 583 + v4l2_event_queue(isp->core.sd.devnode, &event); 584 + } 585 + 586 + int c3_isp_core_register(struct c3_isp_device *isp) 587 + { 588 + struct c3_isp_core *core = &isp->core; 589 + struct v4l2_subdev *sd = &core->sd; 590 + int ret; 591 + 592 + v4l2_subdev_init(sd, &c3_isp_core_subdev_ops); 593 + sd->owner = THIS_MODULE; 594 + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 595 + sd->internal_ops = &c3_isp_core_internal_ops; 596 + snprintf(sd->name, sizeof(sd->name), "%s", C3_ISP_CORE_SUBDEV_NAME); 597 + 598 + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; 599 + sd->entity.ops = &c3_isp_core_entity_ops; 600 + 601 + core->isp = isp; 602 + sd->dev = isp->dev; 603 + v4l2_set_subdevdata(sd, core); 604 + 605 + core->pads[C3_ISP_CORE_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK; 606 + core->pads[C3_ISP_CORE_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK; 607 + core->pads[C3_ISP_CORE_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; 608 + core->pads[C3_ISP_CORE_PAD_SOURCE_VIDEO_0].flags = MEDIA_PAD_FL_SOURCE; 609 + core->pads[C3_ISP_CORE_PAD_SOURCE_VIDEO_1].flags = MEDIA_PAD_FL_SOURCE; 610 + core->pads[C3_ISP_CORE_PAD_SOURCE_VIDEO_2].flags = MEDIA_PAD_FL_SOURCE; 611 + ret = media_entity_pads_init(&sd->entity, C3_ISP_CORE_PAD_MAX, 612 + core->pads); 613 + if (ret) 614 + return ret; 615 + 616 + ret = v4l2_subdev_init_finalize(sd); 617 + if (ret) 618 + goto err_entity_cleanup; 619 + 620 + ret = v4l2_device_register_subdev(&isp->v4l2_dev, sd); 621 + if (ret) 622 + goto err_subdev_cleanup; 623 + 624 + return 0; 625 + 626 + err_subdev_cleanup: 627 + v4l2_subdev_cleanup(sd); 628 + err_entity_cleanup: 629 + media_entity_cleanup(&sd->entity); 630 + return ret; 631 + } 632 + 633 + void c3_isp_core_unregister(struct c3_isp_device *isp) 634 + { 635 + struct c3_isp_core *core = &isp->core; 636 + struct v4l2_subdev *sd = &core->sd; 637 + 638 + v4l2_device_unregister_subdev(sd); 639 + v4l2_subdev_cleanup(sd); 640 + media_entity_cleanup(&sd->entity); 641 + }
+421
drivers/media/platform/amlogic/c3/isp/c3-isp-dev.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + */ 5 + 6 + #include <linux/clk.h> 7 + #include <linux/device.h> 8 + #include <linux/module.h> 9 + #include <linux/mutex.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/pm_runtime.h> 12 + 13 + #include <media/v4l2-common.h> 14 + #include <media/v4l2-device.h> 15 + #include <media/v4l2-fwnode.h> 16 + #include <media/v4l2-mc.h> 17 + 18 + #include "c3-isp-common.h" 19 + #include "c3-isp-regs.h" 20 + 21 + u32 c3_isp_read(struct c3_isp_device *isp, u32 reg) 22 + { 23 + return readl(isp->base + reg); 24 + } 25 + 26 + void c3_isp_write(struct c3_isp_device *isp, u32 reg, u32 val) 27 + { 28 + writel(val, isp->base + reg); 29 + } 30 + 31 + void c3_isp_update_bits(struct c3_isp_device *isp, u32 reg, u32 mask, u32 val) 32 + { 33 + u32 orig, tmp; 34 + 35 + orig = c3_isp_read(isp, reg); 36 + 37 + tmp = orig & ~mask; 38 + tmp |= val & mask; 39 + 40 + if (tmp != orig) 41 + c3_isp_write(isp, reg, tmp); 42 + } 43 + 44 + /* PM runtime suspend */ 45 + static int c3_isp_runtime_suspend(struct device *dev) 46 + { 47 + struct c3_isp_device *isp = dev_get_drvdata(dev); 48 + 49 + clk_bulk_disable_unprepare(isp->info->clock_num, isp->clks); 50 + 51 + return 0; 52 + } 53 + 54 + /* PM runtime resume */ 55 + static int c3_isp_runtime_resume(struct device *dev) 56 + { 57 + struct c3_isp_device *isp = dev_get_drvdata(dev); 58 + 59 + return clk_bulk_prepare_enable(isp->info->clock_num, isp->clks); 60 + } 61 + 62 + static const struct dev_pm_ops c3_isp_pm_ops = { 63 + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 64 + pm_runtime_force_resume) 65 + RUNTIME_PM_OPS(c3_isp_runtime_suspend, 66 + c3_isp_runtime_resume, NULL) 67 + }; 68 + 69 + /* IRQ handling */ 70 + static irqreturn_t c3_isp_irq_handler(int irq, void *dev) 71 + { 72 + struct c3_isp_device *isp = dev; 73 + u32 status; 74 + 75 + /* Get irq status and clear irq status */ 76 + status = c3_isp_read(isp, ISP_TOP_RO_IRQ_STAT); 77 + c3_isp_write(isp, ISP_TOP_IRQ_CLR, status); 78 + 79 + if (status & ISP_TOP_RO_IRQ_STAT_FRM_END_MASK) { 80 + c3_isp_stats_isr(isp); 81 + c3_isp_params_isr(isp); 82 + c3_isp_captures_isr(isp); 83 + isp->frm_sequence++; 84 + } 85 + 86 + if (status & ISP_TOP_RO_IRQ_STAT_FRM_RST_MASK) 87 + c3_isp_core_queue_sof(isp); 88 + 89 + return IRQ_HANDLED; 90 + } 91 + 92 + /* Subdev notifier register */ 93 + static int c3_isp_notify_bound(struct v4l2_async_notifier *notifier, 94 + struct v4l2_subdev *sd, 95 + struct v4l2_async_connection *asc) 96 + { 97 + struct c3_isp_device *isp = 98 + container_of(notifier, struct c3_isp_device, notifier); 99 + struct media_pad *sink = 100 + &isp->core.sd.entity.pads[C3_ISP_CORE_PAD_SINK_VIDEO]; 101 + 102 + return v4l2_create_fwnode_links_to_pad(sd, sink, MEDIA_LNK_FL_ENABLED | 103 + MEDIA_LNK_FL_IMMUTABLE); 104 + } 105 + 106 + static int c3_isp_notify_complete(struct v4l2_async_notifier *notifier) 107 + { 108 + struct c3_isp_device *isp = 109 + container_of(notifier, struct c3_isp_device, notifier); 110 + 111 + return v4l2_device_register_subdev_nodes(&isp->v4l2_dev); 112 + } 113 + 114 + static const struct v4l2_async_notifier_operations c3_isp_notify_ops = { 115 + .bound = c3_isp_notify_bound, 116 + .complete = c3_isp_notify_complete, 117 + }; 118 + 119 + static int c3_isp_async_nf_register(struct c3_isp_device *isp) 120 + { 121 + struct v4l2_async_connection *asc; 122 + struct fwnode_handle *ep; 123 + int ret; 124 + 125 + v4l2_async_nf_init(&isp->notifier, &isp->v4l2_dev); 126 + 127 + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(isp->dev), 0, 0, 128 + FWNODE_GRAPH_ENDPOINT_NEXT); 129 + if (!ep) 130 + return -ENOTCONN; 131 + 132 + asc = v4l2_async_nf_add_fwnode_remote(&isp->notifier, ep, 133 + struct v4l2_async_connection); 134 + fwnode_handle_put(ep); 135 + 136 + if (IS_ERR(asc)) 137 + return PTR_ERR(asc); 138 + 139 + isp->notifier.ops = &c3_isp_notify_ops; 140 + ret = v4l2_async_nf_register(&isp->notifier); 141 + if (ret) 142 + v4l2_async_nf_cleanup(&isp->notifier); 143 + 144 + return ret; 145 + } 146 + 147 + static void c3_isp_async_nf_unregister(struct c3_isp_device *isp) 148 + { 149 + v4l2_async_nf_unregister(&isp->notifier); 150 + v4l2_async_nf_cleanup(&isp->notifier); 151 + } 152 + 153 + static int c3_isp_media_register(struct c3_isp_device *isp) 154 + { 155 + struct media_device *media_dev = &isp->media_dev; 156 + struct v4l2_device *v4l2_dev = &isp->v4l2_dev; 157 + int ret; 158 + 159 + /* Initialize media device */ 160 + strscpy(media_dev->model, C3_ISP_DRIVER_NAME, sizeof(media_dev->model)); 161 + media_dev->dev = isp->dev; 162 + 163 + media_device_init(media_dev); 164 + 165 + /* Initialize v4l2 device */ 166 + v4l2_dev->mdev = media_dev; 167 + strscpy(v4l2_dev->name, C3_ISP_DRIVER_NAME, sizeof(v4l2_dev->name)); 168 + 169 + ret = v4l2_device_register(isp->dev, v4l2_dev); 170 + if (ret) 171 + goto err_media_dev_cleanup; 172 + 173 + ret = media_device_register(&isp->media_dev); 174 + if (ret) { 175 + dev_err(isp->dev, "Failed to register media device: %d\n", ret); 176 + goto err_unreg_v4l2_dev; 177 + } 178 + 179 + return 0; 180 + 181 + err_unreg_v4l2_dev: 182 + v4l2_device_unregister(&isp->v4l2_dev); 183 + err_media_dev_cleanup: 184 + media_device_cleanup(media_dev); 185 + return ret; 186 + } 187 + 188 + static void c3_isp_media_unregister(struct c3_isp_device *isp) 189 + { 190 + media_device_unregister(&isp->media_dev); 191 + v4l2_device_unregister(&isp->v4l2_dev); 192 + media_device_cleanup(&isp->media_dev); 193 + } 194 + 195 + static void c3_isp_remove_links(struct c3_isp_device *isp) 196 + { 197 + unsigned int i; 198 + 199 + media_entity_remove_links(&isp->core.sd.entity); 200 + 201 + for (i = 0; i < C3_ISP_NUM_RSZ; i++) 202 + media_entity_remove_links(&isp->resizers[i].sd.entity); 203 + 204 + for (i = 0; i < C3_ISP_NUM_CAP_DEVS; i++) 205 + media_entity_remove_links(&isp->caps[i].vdev.entity); 206 + } 207 + 208 + static int c3_isp_create_links(struct c3_isp_device *isp) 209 + { 210 + unsigned int i; 211 + int ret; 212 + 213 + for (i = 0; i < C3_ISP_NUM_RSZ; i++) { 214 + ret = media_create_pad_link(&isp->resizers[i].sd.entity, 215 + C3_ISP_RSZ_PAD_SOURCE, 216 + &isp->caps[i].vdev.entity, 0, 217 + MEDIA_LNK_FL_ENABLED | 218 + MEDIA_LNK_FL_IMMUTABLE); 219 + if (ret) { 220 + dev_err(isp->dev, 221 + "Failed to link rsz %u and cap %u\n", i, i); 222 + goto err_remove_links; 223 + } 224 + 225 + ret = media_create_pad_link(&isp->core.sd.entity, 226 + C3_ISP_CORE_PAD_SOURCE_VIDEO_0 + i, 227 + &isp->resizers[i].sd.entity, 228 + C3_ISP_RSZ_PAD_SINK, 229 + MEDIA_LNK_FL_ENABLED); 230 + if (ret) { 231 + dev_err(isp->dev, 232 + "Failed to link core and rsz %u\n", i); 233 + goto err_remove_links; 234 + } 235 + } 236 + 237 + ret = media_create_pad_link(&isp->core.sd.entity, 238 + C3_ISP_CORE_PAD_SOURCE_STATS, 239 + &isp->stats.vdev.entity, 240 + 0, MEDIA_LNK_FL_ENABLED); 241 + if (ret) { 242 + dev_err(isp->dev, "Failed to link core and stats\n"); 243 + goto err_remove_links; 244 + } 245 + 246 + ret = media_create_pad_link(&isp->params.vdev.entity, 0, 247 + &isp->core.sd.entity, 248 + C3_ISP_CORE_PAD_SINK_PARAMS, 249 + MEDIA_LNK_FL_ENABLED); 250 + if (ret) { 251 + dev_err(isp->dev, "Failed to link params and core\n"); 252 + goto err_remove_links; 253 + } 254 + 255 + return 0; 256 + 257 + err_remove_links: 258 + c3_isp_remove_links(isp); 259 + return ret; 260 + } 261 + 262 + static int c3_isp_videos_register(struct c3_isp_device *isp) 263 + { 264 + int ret; 265 + 266 + ret = c3_isp_captures_register(isp); 267 + if (ret) 268 + return ret; 269 + 270 + ret = c3_isp_stats_register(isp); 271 + if (ret) 272 + goto err_captures_unregister; 273 + 274 + ret = c3_isp_params_register(isp); 275 + if (ret) 276 + goto err_stats_unregister; 277 + 278 + ret = c3_isp_create_links(isp); 279 + if (ret) 280 + goto err_params_unregister; 281 + 282 + return 0; 283 + 284 + err_params_unregister: 285 + c3_isp_params_unregister(isp); 286 + err_stats_unregister: 287 + c3_isp_stats_unregister(isp); 288 + err_captures_unregister: 289 + c3_isp_captures_unregister(isp); 290 + return ret; 291 + } 292 + 293 + static void c3_isp_videos_unregister(struct c3_isp_device *isp) 294 + { 295 + c3_isp_remove_links(isp); 296 + c3_isp_params_unregister(isp); 297 + c3_isp_stats_unregister(isp); 298 + c3_isp_captures_unregister(isp); 299 + } 300 + 301 + static int c3_isp_get_clocks(struct c3_isp_device *isp) 302 + { 303 + const struct c3_isp_info *info = isp->info; 304 + 305 + for (unsigned int i = 0; i < info->clock_num; i++) 306 + isp->clks[i].id = info->clocks[i]; 307 + 308 + return devm_clk_bulk_get(isp->dev, info->clock_num, isp->clks); 309 + } 310 + 311 + static int c3_isp_probe(struct platform_device *pdev) 312 + { 313 + struct device *dev = &pdev->dev; 314 + struct c3_isp_device *isp; 315 + int irq; 316 + int ret; 317 + 318 + isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); 319 + if (!isp) 320 + return -ENOMEM; 321 + 322 + isp->info = of_device_get_match_data(dev); 323 + isp->dev = dev; 324 + 325 + isp->base = devm_platform_ioremap_resource_byname(pdev, "isp"); 326 + if (IS_ERR(isp->base)) 327 + return dev_err_probe(dev, PTR_ERR(isp->base), 328 + "Failed to ioremap resource\n"); 329 + 330 + irq = platform_get_irq(pdev, 0); 331 + if (irq < 0) 332 + return irq; 333 + 334 + ret = c3_isp_get_clocks(isp); 335 + if (ret) 336 + return dev_err_probe(dev, ret, "Failed to get clocks\n"); 337 + 338 + platform_set_drvdata(pdev, isp); 339 + 340 + pm_runtime_enable(dev); 341 + 342 + ret = c3_isp_media_register(isp); 343 + if (ret) 344 + goto err_runtime_disable; 345 + 346 + ret = c3_isp_core_register(isp); 347 + if (ret) 348 + goto err_v4l2_unregister; 349 + 350 + ret = c3_isp_resizers_register(isp); 351 + if (ret) 352 + goto err_core_unregister; 353 + 354 + ret = c3_isp_async_nf_register(isp); 355 + if (ret) 356 + goto err_resizers_unregister; 357 + 358 + ret = devm_request_irq(dev, irq, 359 + c3_isp_irq_handler, IRQF_SHARED, 360 + dev_driver_string(dev), isp); 361 + if (ret) 362 + goto err_nf_unregister; 363 + 364 + ret = c3_isp_videos_register(isp); 365 + if (ret) 366 + goto err_nf_unregister; 367 + 368 + return 0; 369 + 370 + err_nf_unregister: 371 + c3_isp_async_nf_unregister(isp); 372 + err_resizers_unregister: 373 + c3_isp_resizers_unregister(isp); 374 + err_core_unregister: 375 + c3_isp_core_unregister(isp); 376 + err_v4l2_unregister: 377 + c3_isp_media_unregister(isp); 378 + err_runtime_disable: 379 + pm_runtime_disable(dev); 380 + return ret; 381 + }; 382 + 383 + static void c3_isp_remove(struct platform_device *pdev) 384 + { 385 + struct c3_isp_device *isp = platform_get_drvdata(pdev); 386 + 387 + c3_isp_videos_unregister(isp); 388 + c3_isp_async_nf_unregister(isp); 389 + c3_isp_core_unregister(isp); 390 + c3_isp_resizers_unregister(isp); 391 + c3_isp_media_unregister(isp); 392 + pm_runtime_disable(isp->dev); 393 + }; 394 + 395 + static const struct c3_isp_info isp_info = { 396 + .clocks = {"vapb", "isp0"}, 397 + .clock_num = 2 398 + }; 399 + 400 + static const struct of_device_id c3_isp_of_match[] = { 401 + { .compatible = "amlogic,c3-isp", 402 + .data = &isp_info }, 403 + { }, 404 + }; 405 + MODULE_DEVICE_TABLE(of, c3_isp_of_match); 406 + 407 + static struct platform_driver c3_isp_driver = { 408 + .probe = c3_isp_probe, 409 + .remove = c3_isp_remove, 410 + .driver = { 411 + .name = "c3-isp", 412 + .of_match_table = c3_isp_of_match, 413 + .pm = pm_ptr(&c3_isp_pm_ops), 414 + }, 415 + }; 416 + 417 + module_platform_driver(c3_isp_driver); 418 + 419 + MODULE_AUTHOR("Keke Li <keke.li@amlogic.com>"); 420 + MODULE_DESCRIPTION("Amlogic C3 ISP pipeline"); 421 + MODULE_LICENSE("GPL");
+1008
drivers/media/platform/amlogic/c3/isp/c3-isp-params.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + */ 5 + 6 + #include <linux/cleanup.h> 7 + #include <linux/media/amlogic/c3-isp-config.h> 8 + #include <linux/pm_runtime.h> 9 + 10 + #include <media/v4l2-ioctl.h> 11 + #include <media/v4l2-mc.h> 12 + #include <media/videobuf2-vmalloc.h> 13 + 14 + #include "c3-isp-common.h" 15 + #include "c3-isp-regs.h" 16 + 17 + /* 18 + * union c3_isp_params_block - Generalisation of a parameter block 19 + * 20 + * This union allows the driver to treat a block as a generic struct to this 21 + * union and safely access the header and block-specific struct without having 22 + * to resort to casting. The header member is accessed first, and the type field 23 + * checked which allows the driver to determine which of the other members 24 + * should be used. 25 + * 26 + * @header: The shared header struct embedded as the first member 27 + * of all the possible other members. This member would be 28 + * accessed first and the type field checked to determine 29 + * which of the other members should be accessed. 30 + * @awb_gains: For header.type == C3_ISP_PARAMS_BLOCK_AWB_GAINS 31 + * @awb_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AWB_CONFIG 32 + * @ae_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AE_CONFIG 33 + * @af_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AF_CONFIG 34 + * @pst_gamma: For header.type == C3_ISP_PARAMS_BLOCK_PST_GAMMA 35 + * @ccm: For header.type == C3_ISP_PARAMS_BLOCK_CCM 36 + * @csc: For header.type == C3_ISP_PARAMS_BLOCK_CSC 37 + * @blc: For header.type == C3_ISP_PARAMS_BLOCK_BLC 38 + */ 39 + union c3_isp_params_block { 40 + struct c3_isp_params_block_header header; 41 + struct c3_isp_params_awb_gains awb_gains; 42 + struct c3_isp_params_awb_config awb_cfg; 43 + struct c3_isp_params_ae_config ae_cfg; 44 + struct c3_isp_params_af_config af_cfg; 45 + struct c3_isp_params_pst_gamma pst_gamma; 46 + struct c3_isp_params_ccm ccm; 47 + struct c3_isp_params_csc csc; 48 + struct c3_isp_params_blc blc; 49 + }; 50 + 51 + typedef void (*c3_isp_block_handler)(struct c3_isp_device *isp, 52 + const union c3_isp_params_block *block); 53 + 54 + struct c3_isp_params_handler { 55 + size_t size; 56 + c3_isp_block_handler handler; 57 + }; 58 + 59 + #define to_c3_isp_params_buffer(vbuf) \ 60 + container_of(vbuf, struct c3_isp_params_buffer, vb) 61 + 62 + /* Hardware configuration */ 63 + 64 + static void c3_isp_params_cfg_awb_gains(struct c3_isp_device *isp, 65 + const union c3_isp_params_block *block) 66 + { 67 + const struct c3_isp_params_awb_gains *awb_gains = &block->awb_gains; 68 + 69 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 70 + c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 71 + ISP_TOP_BEO_CTRL_WB_EN_MASK, 72 + ISP_TOP_BEO_CTRL_WB_DIS); 73 + return; 74 + } 75 + 76 + c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN0, 77 + ISP_LSWB_WB_GAIN0_GR_GAIN_MASK, 78 + ISP_LSWB_WB_GAIN0_GR_GAIN(awb_gains->gr_gain)); 79 + c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN0, 80 + ISP_LSWB_WB_GAIN0_R_GAIN_MASK, 81 + ISP_LSWB_WB_GAIN0_R_GAIN(awb_gains->r_gain)); 82 + c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN1, 83 + ISP_LSWB_WB_GAIN1_B_GAIN_MASK, 84 + ISP_LSWB_WB_GAIN1_B_GAIN(awb_gains->b_gain)); 85 + c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN1, 86 + ISP_LSWB_WB_GAIN1_GB_GAIN_MASK, 87 + ISP_LSWB_WB_GAIN1_GB_GAIN(awb_gains->gb_gain)); 88 + c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN2, 89 + ISP_LSWB_WB_GAIN2_IR_GAIN_MASK, 90 + ISP_LSWB_WB_GAIN2_IR_GAIN(awb_gains->gb_gain)); 91 + 92 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 93 + c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 94 + ISP_TOP_BEO_CTRL_WB_EN_MASK, 95 + ISP_TOP_BEO_CTRL_WB_EN); 96 + } 97 + 98 + static void c3_isp_params_awb_wt(struct c3_isp_device *isp, 99 + const struct c3_isp_params_awb_config *cfg) 100 + { 101 + unsigned int zones_num; 102 + unsigned int base; 103 + unsigned int data; 104 + unsigned int i; 105 + 106 + /* Set the weight address to 0 position */ 107 + c3_isp_write(isp, ISP_AWB_BLK_WT_ADDR, 0); 108 + 109 + zones_num = cfg->horiz_zones_num * cfg->vert_zones_num; 110 + 111 + /* Need to write 8 weights at once */ 112 + for (i = 0; i < zones_num / 8; i++) { 113 + base = i * 8; 114 + data = ISP_AWB_BLK_WT_DATA_WT(0, cfg->zone_weight[base + 0]) | 115 + ISP_AWB_BLK_WT_DATA_WT(1, cfg->zone_weight[base + 1]) | 116 + ISP_AWB_BLK_WT_DATA_WT(2, cfg->zone_weight[base + 2]) | 117 + ISP_AWB_BLK_WT_DATA_WT(3, cfg->zone_weight[base + 3]) | 118 + ISP_AWB_BLK_WT_DATA_WT(4, cfg->zone_weight[base + 4]) | 119 + ISP_AWB_BLK_WT_DATA_WT(5, cfg->zone_weight[base + 5]) | 120 + ISP_AWB_BLK_WT_DATA_WT(6, cfg->zone_weight[base + 6]) | 121 + ISP_AWB_BLK_WT_DATA_WT(7, cfg->zone_weight[base + 7]); 122 + c3_isp_write(isp, ISP_AWB_BLK_WT_DATA, data); 123 + } 124 + 125 + if (zones_num % 8 == 0) 126 + return; 127 + 128 + data = 0; 129 + base = i * 8; 130 + 131 + for (i = 0; i < zones_num % 8; i++) 132 + data |= ISP_AWB_BLK_WT_DATA_WT(i, cfg->zone_weight[base + i]); 133 + 134 + c3_isp_write(isp, ISP_AWB_BLK_WT_DATA, data); 135 + } 136 + 137 + static void c3_isp_params_awb_cood(struct c3_isp_device *isp, 138 + const struct c3_isp_params_awb_config *cfg) 139 + { 140 + unsigned int max_point_num; 141 + 142 + /* The number of points is one more than the number of edges */ 143 + max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1; 144 + 145 + /* Set the index address to 0 position */ 146 + c3_isp_write(isp, ISP_AWB_IDX_ADDR, 0); 147 + 148 + for (unsigned int i = 0; i < max_point_num; i++) 149 + c3_isp_write(isp, ISP_AWB_IDX_DATA, 150 + ISP_AWB_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) | 151 + ISP_AWB_IDX_DATA_VIDX_DATA(cfg->vert_coord[i])); 152 + } 153 + 154 + static void c3_isp_params_cfg_awb_config(struct c3_isp_device *isp, 155 + const union c3_isp_params_block *block) 156 + { 157 + const struct c3_isp_params_awb_config *awb_cfg = &block->awb_cfg; 158 + 159 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 160 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 161 + ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK, 162 + ISP_TOP_3A_STAT_CRTL_AWB_STAT_DIS); 163 + return; 164 + } 165 + 166 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 167 + ISP_TOP_3A_STAT_CRTL_AWB_POINT_MASK, 168 + ISP_TOP_3A_STAT_CRTL_AWB_POINT(awb_cfg->tap_point)); 169 + 170 + c3_isp_update_bits(isp, ISP_AWB_STAT_CTRL2, 171 + ISP_AWB_STAT_CTRL2_SATUR_CTRL_MASK, 172 + ISP_AWB_STAT_CTRL2_SATUR_CTRL(awb_cfg->satur_vald)); 173 + 174 + c3_isp_update_bits(isp, ISP_AWB_HV_BLKNUM, 175 + ISP_AWB_HV_BLKNUM_H_NUM_MASK, 176 + ISP_AWB_HV_BLKNUM_H_NUM(awb_cfg->horiz_zones_num)); 177 + c3_isp_update_bits(isp, ISP_AWB_HV_BLKNUM, 178 + ISP_AWB_HV_BLKNUM_V_NUM_MASK, 179 + ISP_AWB_HV_BLKNUM_V_NUM(awb_cfg->vert_zones_num)); 180 + 181 + c3_isp_update_bits(isp, ISP_AWB_STAT_RG, ISP_AWB_STAT_RG_MIN_VALUE_MASK, 182 + ISP_AWB_STAT_RG_MIN_VALUE(awb_cfg->rg_min)); 183 + c3_isp_update_bits(isp, ISP_AWB_STAT_RG, ISP_AWB_STAT_RG_MAX_VALUE_MASK, 184 + ISP_AWB_STAT_RG_MAX_VALUE(awb_cfg->rg_max)); 185 + 186 + c3_isp_update_bits(isp, ISP_AWB_STAT_BG, ISP_AWB_STAT_BG_MIN_VALUE_MASK, 187 + ISP_AWB_STAT_BG_MIN_VALUE(awb_cfg->bg_min)); 188 + c3_isp_update_bits(isp, ISP_AWB_STAT_BG, ISP_AWB_STAT_BG_MAX_VALUE_MASK, 189 + ISP_AWB_STAT_BG_MAX_VALUE(awb_cfg->bg_max)); 190 + 191 + c3_isp_update_bits(isp, ISP_AWB_STAT_RG_HL, 192 + ISP_AWB_STAT_RG_HL_LOW_VALUE_MASK, 193 + ISP_AWB_STAT_RG_HL_LOW_VALUE(awb_cfg->rg_low)); 194 + c3_isp_update_bits(isp, ISP_AWB_STAT_RG_HL, 195 + ISP_AWB_STAT_RG_HL_HIGH_VALUE_MASK, 196 + ISP_AWB_STAT_RG_HL_HIGH_VALUE(awb_cfg->rg_high)); 197 + 198 + c3_isp_update_bits(isp, ISP_AWB_STAT_BG_HL, 199 + ISP_AWB_STAT_BG_HL_LOW_VALUE_MASK, 200 + ISP_AWB_STAT_BG_HL_LOW_VALUE(awb_cfg->bg_low)); 201 + c3_isp_update_bits(isp, ISP_AWB_STAT_BG_HL, 202 + ISP_AWB_STAT_BG_HL_HIGH_VALUE_MASK, 203 + ISP_AWB_STAT_BG_HL_HIGH_VALUE(awb_cfg->bg_high)); 204 + 205 + c3_isp_params_awb_wt(isp, awb_cfg); 206 + c3_isp_params_awb_cood(isp, awb_cfg); 207 + 208 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 209 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 210 + ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK, 211 + ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN); 212 + } 213 + 214 + static void c3_isp_params_ae_wt(struct c3_isp_device *isp, 215 + const struct c3_isp_params_ae_config *cfg) 216 + { 217 + unsigned int zones_num; 218 + unsigned int base; 219 + unsigned int data; 220 + unsigned int i; 221 + 222 + /* Set the weight address to 0 position */ 223 + c3_isp_write(isp, ISP_AE_BLK_WT_ADDR, 0); 224 + 225 + zones_num = cfg->horiz_zones_num * cfg->vert_zones_num; 226 + 227 + /* Need to write 8 weights at once */ 228 + for (i = 0; i < zones_num / 8; i++) { 229 + base = i * 8; 230 + data = ISP_AE_BLK_WT_DATA_WT(0, cfg->zone_weight[base + 0]) | 231 + ISP_AE_BLK_WT_DATA_WT(1, cfg->zone_weight[base + 1]) | 232 + ISP_AE_BLK_WT_DATA_WT(2, cfg->zone_weight[base + 2]) | 233 + ISP_AE_BLK_WT_DATA_WT(3, cfg->zone_weight[base + 3]) | 234 + ISP_AE_BLK_WT_DATA_WT(4, cfg->zone_weight[base + 4]) | 235 + ISP_AE_BLK_WT_DATA_WT(5, cfg->zone_weight[base + 5]) | 236 + ISP_AE_BLK_WT_DATA_WT(6, cfg->zone_weight[base + 6]) | 237 + ISP_AE_BLK_WT_DATA_WT(7, cfg->zone_weight[base + 7]); 238 + c3_isp_write(isp, ISP_AE_BLK_WT_DATA, data); 239 + } 240 + 241 + if (zones_num % 8 == 0) 242 + return; 243 + 244 + data = 0; 245 + base = i * 8; 246 + 247 + /* Write the last weights data */ 248 + for (i = 0; i < zones_num % 8; i++) 249 + data |= ISP_AE_BLK_WT_DATA_WT(i, cfg->zone_weight[base + i]); 250 + 251 + c3_isp_write(isp, ISP_AE_BLK_WT_DATA, data); 252 + } 253 + 254 + static void c3_isp_params_ae_cood(struct c3_isp_device *isp, 255 + const struct c3_isp_params_ae_config *cfg) 256 + { 257 + unsigned int max_point_num; 258 + 259 + /* The number of points is one more than the number of edges */ 260 + max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1; 261 + 262 + /* Set the index address to 0 position */ 263 + c3_isp_write(isp, ISP_AE_IDX_ADDR, 0); 264 + 265 + for (unsigned int i = 0; i < max_point_num; i++) 266 + c3_isp_write(isp, ISP_AE_IDX_DATA, 267 + ISP_AE_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) | 268 + ISP_AE_IDX_DATA_VIDX_DATA(cfg->vert_coord[i])); 269 + } 270 + 271 + static void c3_isp_params_cfg_ae_config(struct c3_isp_device *isp, 272 + const union c3_isp_params_block *block) 273 + { 274 + const struct c3_isp_params_ae_config *ae_cfg = &block->ae_cfg; 275 + 276 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 277 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 278 + ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK, 279 + ISP_TOP_3A_STAT_CRTL_AE_STAT_DIS); 280 + return; 281 + } 282 + 283 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 284 + ISP_TOP_3A_STAT_CRTL_AE_POINT_MASK, 285 + ISP_TOP_3A_STAT_CRTL_AE_POINT(ae_cfg->tap_point)); 286 + 287 + if (ae_cfg->tap_point == C3_ISP_AE_STATS_TAP_GE) 288 + c3_isp_update_bits(isp, ISP_AE_CTRL, 289 + ISP_AE_CTRL_INPUT_2LINE_MASK, 290 + ISP_AE_CTRL_INPUT_2LINE_EN); 291 + else 292 + c3_isp_update_bits(isp, ISP_AE_CTRL, 293 + ISP_AE_CTRL_INPUT_2LINE_MASK, 294 + ISP_AE_CTRL_INPUT_2LINE_DIS); 295 + 296 + c3_isp_update_bits(isp, ISP_AE_HV_BLKNUM, 297 + ISP_AE_HV_BLKNUM_H_NUM_MASK, 298 + ISP_AE_HV_BLKNUM_H_NUM(ae_cfg->horiz_zones_num)); 299 + c3_isp_update_bits(isp, ISP_AE_HV_BLKNUM, 300 + ISP_AE_HV_BLKNUM_V_NUM_MASK, 301 + ISP_AE_HV_BLKNUM_V_NUM(ae_cfg->vert_zones_num)); 302 + 303 + c3_isp_params_ae_wt(isp, ae_cfg); 304 + c3_isp_params_ae_cood(isp, ae_cfg); 305 + 306 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 307 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 308 + ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK, 309 + ISP_TOP_3A_STAT_CRTL_AE_STAT_EN); 310 + } 311 + 312 + static void c3_isp_params_af_cood(struct c3_isp_device *isp, 313 + const struct c3_isp_params_af_config *cfg) 314 + { 315 + unsigned int max_point_num; 316 + 317 + /* The number of points is one more than the number of edges */ 318 + max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1; 319 + 320 + /* Set the index address to 0 position */ 321 + c3_isp_write(isp, ISP_AF_IDX_ADDR, 0); 322 + 323 + for (unsigned int i = 0; i < max_point_num; i++) 324 + c3_isp_write(isp, ISP_AF_IDX_DATA, 325 + ISP_AF_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) | 326 + ISP_AF_IDX_DATA_VIDX_DATA(cfg->vert_coord[i])); 327 + } 328 + 329 + static void c3_isp_params_cfg_af_config(struct c3_isp_device *isp, 330 + const union c3_isp_params_block *block) 331 + { 332 + const struct c3_isp_params_af_config *af_cfg = &block->af_cfg; 333 + 334 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 335 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 336 + ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK, 337 + ISP_TOP_3A_STAT_CRTL_AF_STAT_DIS); 338 + return; 339 + } 340 + 341 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 342 + ISP_TOP_3A_STAT_CRTL_AF_POINT_MASK, 343 + ISP_TOP_3A_STAT_CRTL_AF_POINT(af_cfg->tap_point)); 344 + 345 + c3_isp_update_bits(isp, ISP_AF_HV_BLKNUM, 346 + ISP_AF_HV_BLKNUM_H_NUM_MASK, 347 + ISP_AF_HV_BLKNUM_H_NUM(af_cfg->horiz_zones_num)); 348 + c3_isp_update_bits(isp, ISP_AF_HV_BLKNUM, 349 + ISP_AF_HV_BLKNUM_V_NUM_MASK, 350 + ISP_AF_HV_BLKNUM_V_NUM(af_cfg->vert_zones_num)); 351 + 352 + c3_isp_params_af_cood(isp, af_cfg); 353 + 354 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 355 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 356 + ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK, 357 + ISP_TOP_3A_STAT_CRTL_AF_STAT_EN); 358 + } 359 + 360 + static void c3_isp_params_cfg_pst_gamma(struct c3_isp_device *isp, 361 + const union c3_isp_params_block *block) 362 + { 363 + const struct c3_isp_params_pst_gamma *gm = &block->pst_gamma; 364 + unsigned int base; 365 + unsigned int i; 366 + 367 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 368 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 369 + ISP_TOP_BED_CTRL_PST_GAMMA_EN_MASK, 370 + ISP_TOP_BED_CTRL_PST_GAMMA_DIS); 371 + return; 372 + } 373 + 374 + /* R, G and B channels use the same gamma lut */ 375 + for (unsigned int j = 0; j < 3; j++) { 376 + /* Set the channel lut address */ 377 + c3_isp_write(isp, ISP_PST_GAMMA_LUT_ADDR, 378 + ISP_PST_GAMMA_LUT_ADDR_IDX_ADDR(j)); 379 + 380 + /* Need to write 2 lut values at once */ 381 + for (i = 0; i < ARRAY_SIZE(gm->lut) / 2; i++) { 382 + base = i * 2; 383 + c3_isp_write(isp, ISP_PST_GAMMA_LUT_DATA, 384 + ISP_PST_GM_LUT_DATA0(gm->lut[base]) | 385 + ISP_PST_GM_LUT_DATA1(gm->lut[base + 1])); 386 + } 387 + 388 + /* Write the last one */ 389 + if (ARRAY_SIZE(gm->lut) % 2) { 390 + base = i * 2; 391 + c3_isp_write(isp, ISP_PST_GAMMA_LUT_DATA, 392 + ISP_PST_GM_LUT_DATA0(gm->lut[base])); 393 + } 394 + } 395 + 396 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 397 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 398 + ISP_TOP_BED_CTRL_PST_GAMMA_EN_MASK, 399 + ISP_TOP_BED_CTRL_PST_GAMMA_EN); 400 + } 401 + 402 + /* Configure 3 x 3 ccm matrix */ 403 + static void c3_isp_params_cfg_ccm(struct c3_isp_device *isp, 404 + const union c3_isp_params_block *block) 405 + { 406 + const struct c3_isp_params_ccm *ccm = &block->ccm; 407 + 408 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 409 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 410 + ISP_TOP_BED_CTRL_CCM_EN_MASK, 411 + ISP_TOP_BED_CTRL_CCM_DIS); 412 + return; 413 + } 414 + 415 + c3_isp_update_bits(isp, ISP_CCM_MTX_00_01, 416 + ISP_CCM_MTX_00_01_MTX_00_MASK, 417 + ISP_CCM_MTX_00_01_MTX_00(ccm->matrix[0][0])); 418 + c3_isp_update_bits(isp, ISP_CCM_MTX_00_01, 419 + ISP_CCM_MTX_00_01_MTX_01_MASK, 420 + ISP_CCM_MTX_00_01_MTX_01(ccm->matrix[0][1])); 421 + c3_isp_update_bits(isp, ISP_CCM_MTX_02_03, 422 + ISP_CCM_MTX_02_03_MTX_02_MASK, 423 + ISP_CCM_MTX_02_03_MTX_02(ccm->matrix[0][2])); 424 + 425 + c3_isp_update_bits(isp, ISP_CCM_MTX_10_11, 426 + ISP_CCM_MTX_10_11_MTX_10_MASK, 427 + ISP_CCM_MTX_10_11_MTX_10(ccm->matrix[1][0])); 428 + c3_isp_update_bits(isp, ISP_CCM_MTX_10_11, 429 + ISP_CCM_MTX_10_11_MTX_11_MASK, 430 + ISP_CCM_MTX_10_11_MTX_11(ccm->matrix[1][1])); 431 + c3_isp_update_bits(isp, ISP_CCM_MTX_12_13, 432 + ISP_CCM_MTX_12_13_MTX_12_MASK, 433 + ISP_CCM_MTX_12_13_MTX_12(ccm->matrix[1][2])); 434 + 435 + c3_isp_update_bits(isp, ISP_CCM_MTX_20_21, 436 + ISP_CCM_MTX_20_21_MTX_20_MASK, 437 + ISP_CCM_MTX_20_21_MTX_20(ccm->matrix[2][0])); 438 + c3_isp_update_bits(isp, ISP_CCM_MTX_20_21, 439 + ISP_CCM_MTX_20_21_MTX_21_MASK, 440 + ISP_CCM_MTX_20_21_MTX_21(ccm->matrix[2][1])); 441 + c3_isp_update_bits(isp, ISP_CCM_MTX_22_23_RS, 442 + ISP_CCM_MTX_22_23_RS_MTX_22_MASK, 443 + ISP_CCM_MTX_22_23_RS_MTX_22(ccm->matrix[2][2])); 444 + 445 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 446 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 447 + ISP_TOP_BED_CTRL_CCM_EN_MASK, 448 + ISP_TOP_BED_CTRL_CCM_EN); 449 + } 450 + 451 + /* Configure color space conversion matrix parameters */ 452 + static void c3_isp_params_cfg_csc(struct c3_isp_device *isp, 453 + const union c3_isp_params_block *block) 454 + { 455 + const struct c3_isp_params_csc *csc = &block->csc; 456 + 457 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 458 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 459 + ISP_TOP_BED_CTRL_CM0_EN_MASK, 460 + ISP_TOP_BED_CTRL_CM0_DIS); 461 + return; 462 + } 463 + 464 + c3_isp_update_bits(isp, ISP_CM0_COEF00_01, 465 + ISP_CM0_COEF00_01_MTX_00_MASK, 466 + ISP_CM0_COEF00_01_MTX_00(csc->matrix[0][0])); 467 + c3_isp_update_bits(isp, ISP_CM0_COEF00_01, 468 + ISP_CM0_COEF00_01_MTX_01_MASK, 469 + ISP_CM0_COEF00_01_MTX_01(csc->matrix[0][1])); 470 + c3_isp_update_bits(isp, ISP_CM0_COEF02_10, 471 + ISP_CM0_COEF02_10_MTX_02_MASK, 472 + ISP_CM0_COEF02_10_MTX_02(csc->matrix[0][2])); 473 + 474 + c3_isp_update_bits(isp, ISP_CM0_COEF02_10, 475 + ISP_CM0_COEF02_10_MTX_10_MASK, 476 + ISP_CM0_COEF02_10_MTX_10(csc->matrix[1][0])); 477 + c3_isp_update_bits(isp, ISP_CM0_COEF11_12, 478 + ISP_CM0_COEF11_12_MTX_11_MASK, 479 + ISP_CM0_COEF11_12_MTX_11(csc->matrix[1][1])); 480 + c3_isp_update_bits(isp, ISP_CM0_COEF11_12, 481 + ISP_CM0_COEF11_12_MTX_12_MASK, 482 + ISP_CM0_COEF11_12_MTX_12(csc->matrix[1][2])); 483 + 484 + c3_isp_update_bits(isp, ISP_CM0_COEF20_21, 485 + ISP_CM0_COEF20_21_MTX_20_MASK, 486 + ISP_CM0_COEF20_21_MTX_20(csc->matrix[2][0])); 487 + c3_isp_update_bits(isp, ISP_CM0_COEF20_21, 488 + ISP_CM0_COEF20_21_MTX_21_MASK, 489 + ISP_CM0_COEF20_21_MTX_21(csc->matrix[2][1])); 490 + c3_isp_update_bits(isp, ISP_CM0_COEF22_OUP_OFST0, 491 + ISP_CM0_COEF22_OUP_OFST0_MTX_22_MASK, 492 + ISP_CM0_COEF22_OUP_OFST0_MTX_22(csc->matrix[2][2])); 493 + 494 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 495 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 496 + ISP_TOP_BED_CTRL_CM0_EN_MASK, 497 + ISP_TOP_BED_CTRL_CM0_EN); 498 + } 499 + 500 + /* Set blc offset of each color channel */ 501 + static void c3_isp_params_cfg_blc(struct c3_isp_device *isp, 502 + const union c3_isp_params_block *block) 503 + { 504 + const struct c3_isp_params_blc *blc = &block->blc; 505 + 506 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 507 + c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 508 + ISP_TOP_BEO_CTRL_BLC_EN_MASK, 509 + ISP_TOP_BEO_CTRL_BLC_DIS); 510 + return; 511 + } 512 + 513 + c3_isp_write(isp, ISP_LSWB_BLC_OFST0, 514 + ISP_LSWB_BLC_OFST0_R_OFST(blc->r_ofst) | 515 + ISP_LSWB_BLC_OFST0_GR_OFST(blc->gr_ofst)); 516 + c3_isp_write(isp, ISP_LSWB_BLC_OFST1, 517 + ISP_LSWB_BLC_OFST1_GB_OFST(blc->gb_ofst) | 518 + ISP_LSWB_BLC_OFST1_B_OFST(blc->b_ofst)); 519 + 520 + if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 521 + c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 522 + ISP_TOP_BEO_CTRL_BLC_EN_MASK, 523 + ISP_TOP_BEO_CTRL_BLC_EN); 524 + } 525 + 526 + static const struct c3_isp_params_handler c3_isp_params_handlers[] = { 527 + [C3_ISP_PARAMS_BLOCK_AWB_GAINS] = { 528 + .size = sizeof(struct c3_isp_params_awb_gains), 529 + .handler = c3_isp_params_cfg_awb_gains, 530 + }, 531 + [C3_ISP_PARAMS_BLOCK_AWB_CONFIG] = { 532 + .size = sizeof(struct c3_isp_params_awb_config), 533 + .handler = c3_isp_params_cfg_awb_config, 534 + }, 535 + [C3_ISP_PARAMS_BLOCK_AE_CONFIG] = { 536 + .size = sizeof(struct c3_isp_params_ae_config), 537 + .handler = c3_isp_params_cfg_ae_config, 538 + }, 539 + [C3_ISP_PARAMS_BLOCK_AF_CONFIG] = { 540 + .size = sizeof(struct c3_isp_params_af_config), 541 + .handler = c3_isp_params_cfg_af_config, 542 + }, 543 + [C3_ISP_PARAMS_BLOCK_PST_GAMMA] = { 544 + .size = sizeof(struct c3_isp_params_pst_gamma), 545 + .handler = c3_isp_params_cfg_pst_gamma, 546 + }, 547 + [C3_ISP_PARAMS_BLOCK_CCM] = { 548 + .size = sizeof(struct c3_isp_params_ccm), 549 + .handler = c3_isp_params_cfg_ccm, 550 + }, 551 + [C3_ISP_PARAMS_BLOCK_CSC] = { 552 + .size = sizeof(struct c3_isp_params_csc), 553 + .handler = c3_isp_params_cfg_csc, 554 + }, 555 + [C3_ISP_PARAMS_BLOCK_BLC] = { 556 + .size = sizeof(struct c3_isp_params_blc), 557 + .handler = c3_isp_params_cfg_blc, 558 + }, 559 + }; 560 + 561 + static void c3_isp_params_cfg_blocks(struct c3_isp_params *params) 562 + { 563 + struct c3_isp_params_cfg *config = params->buff->cfg; 564 + size_t block_offset = 0; 565 + 566 + if (WARN_ON(!config)) 567 + return; 568 + 569 + /* Walk the list of parameter blocks and process them */ 570 + while (block_offset < config->data_size) { 571 + const struct c3_isp_params_handler *block_handler; 572 + const union c3_isp_params_block *block; 573 + 574 + block = (const union c3_isp_params_block *) 575 + &config->data[block_offset]; 576 + 577 + block_handler = &c3_isp_params_handlers[block->header.type]; 578 + block_handler->handler(params->isp, block); 579 + 580 + block_offset += block->header.size; 581 + } 582 + } 583 + 584 + void c3_isp_params_pre_cfg(struct c3_isp_device *isp) 585 + { 586 + struct c3_isp_params *params = &isp->params; 587 + 588 + /* Disable some unused modules */ 589 + c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL0, 590 + ISP_TOP_FEO_CTRL0_INPUT_FMT_EN_MASK, 591 + ISP_TOP_FEO_CTRL0_INPUT_FMT_DIS); 592 + 593 + c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL1_0, 594 + ISP_TOP_FEO_CTRL1_0_DPC_EN_MASK, 595 + ISP_TOP_FEO_CTRL1_0_DPC_DIS); 596 + c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL1_0, 597 + ISP_TOP_FEO_CTRL1_0_OG_EN_MASK, 598 + ISP_TOP_FEO_CTRL1_0_OG_DIS); 599 + 600 + c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_PDPC_EN_MASK, 601 + ISP_TOP_FED_CTRL_PDPC_DIS); 602 + c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, 603 + ISP_TOP_FED_CTRL_RAWCNR_EN_MASK, 604 + ISP_TOP_FED_CTRL_RAWCNR_DIS); 605 + c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_SNR1_EN_MASK, 606 + ISP_TOP_FED_CTRL_SNR1_DIS); 607 + c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_TNR0_EN_MASK, 608 + ISP_TOP_FED_CTRL_TNR0_DIS); 609 + c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, 610 + ISP_TOP_FED_CTRL_CUBIC_CS_EN_MASK, 611 + ISP_TOP_FED_CTRL_CUBIC_CS_DIS); 612 + c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_SQRT_EN_MASK, 613 + ISP_TOP_FED_CTRL_SQRT_DIS); 614 + c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, 615 + ISP_TOP_FED_CTRL_DGAIN_EN_MASK, 616 + ISP_TOP_FED_CTRL_DGAIN_DIS); 617 + 618 + c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 619 + ISP_TOP_BEO_CTRL_INV_DGAIN_EN_MASK, 620 + ISP_TOP_BEO_CTRL_INV_DGAIN_DIS); 621 + c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, ISP_TOP_BEO_CTRL_EOTF_EN_MASK, 622 + ISP_TOP_BEO_CTRL_EOTF_DIS); 623 + 624 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 625 + ISP_TOP_BED_CTRL_YHS_STAT_EN_MASK, 626 + ISP_TOP_BED_CTRL_YHS_STAT_DIS); 627 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 628 + ISP_TOP_BED_CTRL_GRPH_STAT_EN_MASK, 629 + ISP_TOP_BED_CTRL_GRPH_STAT_DIS); 630 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 631 + ISP_TOP_BED_CTRL_FMETER_EN_MASK, 632 + ISP_TOP_BED_CTRL_FMETER_DIS); 633 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_BSC_EN_MASK, 634 + ISP_TOP_BED_CTRL_BSC_DIS); 635 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_CNR2_EN_MASK, 636 + ISP_TOP_BED_CTRL_CNR2_DIS); 637 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_CM1_EN_MASK, 638 + ISP_TOP_BED_CTRL_CM1_DIS); 639 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 640 + ISP_TOP_BED_CTRL_LUT3D_EN_MASK, 641 + ISP_TOP_BED_CTRL_LUT3D_DIS); 642 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 643 + ISP_TOP_BED_CTRL_PST_TNR_LITE_EN_MASK, 644 + ISP_TOP_BED_CTRL_PST_TNR_LITE_DIS); 645 + c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_AMCM_EN_MASK, 646 + ISP_TOP_BED_CTRL_AMCM_DIS); 647 + 648 + /* 649 + * Disable AE, AF and AWB stat module. Please configure the parameters 650 + * in userspace algorithm if need to enable these switch. 651 + */ 652 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 653 + ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK, 654 + ISP_TOP_3A_STAT_CRTL_AE_STAT_DIS); 655 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 656 + ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK, 657 + ISP_TOP_3A_STAT_CRTL_AWB_STAT_DIS); 658 + c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 659 + ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK, 660 + ISP_TOP_3A_STAT_CRTL_AF_STAT_DIS); 661 + 662 + c3_isp_write(isp, ISP_LSWB_WB_LIMIT0, 663 + ISP_LSWB_WB_LIMIT0_WB_LIMIT_R_MAX | 664 + ISP_LSWB_WB_LIMIT0_WB_LIMIT_GR_MAX); 665 + c3_isp_write(isp, ISP_LSWB_WB_LIMIT1, 666 + ISP_LSWB_WB_LIMIT1_WB_LIMIT_GB_MAX | 667 + ISP_LSWB_WB_LIMIT1_WB_LIMIT_B_MAX); 668 + 669 + guard(spinlock_irqsave)(&params->buff_lock); 670 + 671 + /* Only use the first buffer to initialize ISP */ 672 + params->buff = 673 + list_first_entry_or_null(&params->pending, 674 + struct c3_isp_params_buffer, list); 675 + if (params->buff) 676 + c3_isp_params_cfg_blocks(params); 677 + } 678 + 679 + /* V4L2 video operations */ 680 + 681 + static int c3_isp_params_querycap(struct file *file, void *fh, 682 + struct v4l2_capability *cap) 683 + { 684 + strscpy(cap->driver, C3_ISP_DRIVER_NAME, sizeof(cap->driver)); 685 + strscpy(cap->card, "AML C3 ISP", sizeof(cap->card)); 686 + 687 + return 0; 688 + } 689 + 690 + static int c3_isp_params_enum_fmt(struct file *file, void *fh, 691 + struct v4l2_fmtdesc *f) 692 + { 693 + if (f->index) 694 + return -EINVAL; 695 + 696 + f->pixelformat = V4L2_META_FMT_C3ISP_PARAMS; 697 + 698 + return 0; 699 + } 700 + 701 + static int c3_isp_params_g_fmt(struct file *file, void *fh, 702 + struct v4l2_format *f) 703 + { 704 + struct c3_isp_params *params = video_drvdata(file); 705 + 706 + f->fmt.meta = params->vfmt.fmt.meta; 707 + 708 + return 0; 709 + } 710 + 711 + static const struct v4l2_ioctl_ops isp_params_v4l2_ioctl_ops = { 712 + .vidioc_querycap = c3_isp_params_querycap, 713 + .vidioc_enum_fmt_meta_out = c3_isp_params_enum_fmt, 714 + .vidioc_g_fmt_meta_out = c3_isp_params_g_fmt, 715 + .vidioc_s_fmt_meta_out = c3_isp_params_g_fmt, 716 + .vidioc_try_fmt_meta_out = c3_isp_params_g_fmt, 717 + .vidioc_reqbufs = vb2_ioctl_reqbufs, 718 + .vidioc_querybuf = vb2_ioctl_querybuf, 719 + .vidioc_qbuf = vb2_ioctl_qbuf, 720 + .vidioc_expbuf = vb2_ioctl_expbuf, 721 + .vidioc_dqbuf = vb2_ioctl_dqbuf, 722 + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 723 + .vidioc_create_bufs = vb2_ioctl_create_bufs, 724 + .vidioc_streamon = vb2_ioctl_streamon, 725 + .vidioc_streamoff = vb2_ioctl_streamoff, 726 + }; 727 + 728 + static const struct v4l2_file_operations isp_params_v4l2_fops = { 729 + .open = v4l2_fh_open, 730 + .release = vb2_fop_release, 731 + .poll = vb2_fop_poll, 732 + .unlocked_ioctl = video_ioctl2, 733 + .mmap = vb2_fop_mmap, 734 + }; 735 + 736 + static int c3_isp_params_vb2_queue_setup(struct vb2_queue *q, 737 + unsigned int *num_buffers, 738 + unsigned int *num_planes, 739 + unsigned int sizes[], 740 + struct device *alloc_devs[]) 741 + { 742 + if (*num_planes) { 743 + if (*num_planes != 1) 744 + return -EINVAL; 745 + 746 + if (sizes[0] < sizeof(struct c3_isp_params_cfg)) 747 + return -EINVAL; 748 + 749 + return 0; 750 + } 751 + 752 + *num_planes = 1; 753 + sizes[0] = sizeof(struct c3_isp_params_cfg); 754 + 755 + return 0; 756 + } 757 + 758 + static void c3_isp_params_vb2_buf_queue(struct vb2_buffer *vb) 759 + { 760 + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 761 + struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf); 762 + struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue); 763 + 764 + guard(spinlock_irqsave)(&params->buff_lock); 765 + 766 + list_add_tail(&buf->list, &params->pending); 767 + } 768 + 769 + static int c3_isp_params_vb2_buf_prepare(struct vb2_buffer *vb) 770 + { 771 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 772 + struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(vbuf); 773 + struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue); 774 + struct c3_isp_params_cfg *cfg = buf->cfg; 775 + struct c3_isp_params_cfg *usr_cfg = vb2_plane_vaddr(vb, 0); 776 + size_t payload_size = vb2_get_plane_payload(vb, 0); 777 + size_t header_size = offsetof(struct c3_isp_params_cfg, data); 778 + size_t block_offset = 0; 779 + size_t cfg_size; 780 + 781 + /* Payload size can't be greater than the destination buffer size */ 782 + if (payload_size > params->vfmt.fmt.meta.buffersize) { 783 + dev_dbg(params->isp->dev, 784 + "Payload size is too large: %zu\n", payload_size); 785 + return -EINVAL; 786 + } 787 + 788 + /* Payload size can't be smaller than the header size */ 789 + if (payload_size < header_size) { 790 + dev_dbg(params->isp->dev, 791 + "Payload size is too small: %zu\n", payload_size); 792 + return -EINVAL; 793 + } 794 + 795 + /* 796 + * Use the internal scratch buffer to avoid userspace modifying 797 + * the buffer content while the driver is processing it. 798 + */ 799 + memcpy(cfg, usr_cfg, payload_size); 800 + 801 + /* Only v0 is supported at the moment */ 802 + if (cfg->version != C3_ISP_PARAMS_BUFFER_V0) { 803 + dev_dbg(params->isp->dev, 804 + "Invalid params buffer version: %u\n", cfg->version); 805 + return -EINVAL; 806 + } 807 + 808 + /* Validate the size reported in the parameter buffer header */ 809 + cfg_size = header_size + cfg->data_size; 810 + if (cfg_size != payload_size) { 811 + dev_dbg(params->isp->dev, 812 + "Data size %zu and payload size %zu are different\n", 813 + cfg_size, payload_size); 814 + return -EINVAL; 815 + } 816 + 817 + /* Walk the list of parameter blocks and validate them */ 818 + cfg_size = cfg->data_size; 819 + while (cfg_size >= sizeof(struct c3_isp_params_block_header)) { 820 + const struct c3_isp_params_block_header *block; 821 + const struct c3_isp_params_handler *handler; 822 + 823 + block = (struct c3_isp_params_block_header *) 824 + &cfg->data[block_offset]; 825 + 826 + if (block->type >= ARRAY_SIZE(c3_isp_params_handlers)) { 827 + dev_dbg(params->isp->dev, 828 + "Invalid params block type\n"); 829 + return -EINVAL; 830 + } 831 + 832 + if (block->size > cfg_size) { 833 + dev_dbg(params->isp->dev, 834 + "Block size is greater than cfg size\n"); 835 + return -EINVAL; 836 + } 837 + 838 + if ((block->flags & (C3_ISP_PARAMS_BLOCK_FL_ENABLE | 839 + C3_ISP_PARAMS_BLOCK_FL_DISABLE)) == 840 + (C3_ISP_PARAMS_BLOCK_FL_ENABLE | 841 + C3_ISP_PARAMS_BLOCK_FL_DISABLE)) { 842 + dev_dbg(params->isp->dev, 843 + "Invalid parameters block flags\n"); 844 + return -EINVAL; 845 + } 846 + 847 + handler = &c3_isp_params_handlers[block->type]; 848 + if (block->size != handler->size) { 849 + dev_dbg(params->isp->dev, 850 + "Invalid params block size\n"); 851 + return -EINVAL; 852 + } 853 + 854 + block_offset += block->size; 855 + cfg_size -= block->size; 856 + } 857 + 858 + if (cfg_size) { 859 + dev_dbg(params->isp->dev, 860 + "Unexpected data after the params buffer end\n"); 861 + return -EINVAL; 862 + } 863 + 864 + return 0; 865 + } 866 + 867 + static int c3_isp_params_vb2_buf_init(struct vb2_buffer *vb) 868 + { 869 + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 870 + struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue); 871 + struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf); 872 + 873 + buf->cfg = kvmalloc(params->vfmt.fmt.meta.buffersize, GFP_KERNEL); 874 + if (!buf->cfg) 875 + return -ENOMEM; 876 + 877 + return 0; 878 + } 879 + 880 + static void c3_isp_params_vb2_buf_cleanup(struct vb2_buffer *vb) 881 + { 882 + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 883 + struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf); 884 + 885 + kvfree(buf->cfg); 886 + buf->cfg = NULL; 887 + } 888 + 889 + static void c3_isp_params_vb2_stop_streaming(struct vb2_queue *q) 890 + { 891 + struct c3_isp_params *params = vb2_get_drv_priv(q); 892 + struct c3_isp_params_buffer *buff; 893 + 894 + guard(spinlock_irqsave)(&params->buff_lock); 895 + 896 + while (!list_empty(&params->pending)) { 897 + buff = list_first_entry(&params->pending, 898 + struct c3_isp_params_buffer, list); 899 + list_del(&buff->list); 900 + vb2_buffer_done(&buff->vb.vb2_buf, VB2_BUF_STATE_ERROR); 901 + } 902 + } 903 + 904 + static const struct vb2_ops isp_params_vb2_ops = { 905 + .queue_setup = c3_isp_params_vb2_queue_setup, 906 + .buf_queue = c3_isp_params_vb2_buf_queue, 907 + .buf_prepare = c3_isp_params_vb2_buf_prepare, 908 + .buf_init = c3_isp_params_vb2_buf_init, 909 + .buf_cleanup = c3_isp_params_vb2_buf_cleanup, 910 + .stop_streaming = c3_isp_params_vb2_stop_streaming, 911 + }; 912 + 913 + int c3_isp_params_register(struct c3_isp_device *isp) 914 + { 915 + struct c3_isp_params *params = &isp->params; 916 + struct video_device *vdev = &params->vdev; 917 + struct vb2_queue *vb2_q = &params->vb2_q; 918 + int ret; 919 + 920 + memset(params, 0, sizeof(*params)); 921 + params->vfmt.fmt.meta.dataformat = V4L2_META_FMT_C3ISP_PARAMS; 922 + params->vfmt.fmt.meta.buffersize = sizeof(struct c3_isp_params_cfg); 923 + params->isp = isp; 924 + INIT_LIST_HEAD(&params->pending); 925 + spin_lock_init(&params->buff_lock); 926 + mutex_init(&params->lock); 927 + 928 + snprintf(vdev->name, sizeof(vdev->name), "c3-isp-params"); 929 + vdev->fops = &isp_params_v4l2_fops; 930 + vdev->ioctl_ops = &isp_params_v4l2_ioctl_ops; 931 + vdev->v4l2_dev = &isp->v4l2_dev; 932 + vdev->lock = &params->lock; 933 + vdev->minor = -1; 934 + vdev->queue = vb2_q; 935 + vdev->release = video_device_release_empty; 936 + vdev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING; 937 + vdev->vfl_dir = VFL_DIR_TX; 938 + video_set_drvdata(vdev, params); 939 + 940 + vb2_q->drv_priv = params; 941 + vb2_q->mem_ops = &vb2_vmalloc_memops; 942 + vb2_q->ops = &isp_params_vb2_ops; 943 + vb2_q->type = V4L2_BUF_TYPE_META_OUTPUT; 944 + vb2_q->io_modes = VB2_DMABUF | VB2_MMAP; 945 + vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 946 + vb2_q->buf_struct_size = sizeof(struct c3_isp_params_buffer); 947 + vb2_q->dev = isp->dev; 948 + vb2_q->lock = &params->lock; 949 + vb2_q->min_queued_buffers = 1; 950 + 951 + ret = vb2_queue_init(vb2_q); 952 + if (ret) 953 + goto err_detroy; 954 + 955 + params->pad.flags = MEDIA_PAD_FL_SOURCE; 956 + ret = media_entity_pads_init(&vdev->entity, 1, &params->pad); 957 + if (ret) 958 + goto err_queue_release; 959 + 960 + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 961 + if (ret < 0) { 962 + dev_err(isp->dev, 963 + "Failed to register %s: %d\n", vdev->name, ret); 964 + goto err_entity_cleanup; 965 + } 966 + 967 + return 0; 968 + 969 + err_entity_cleanup: 970 + media_entity_cleanup(&vdev->entity); 971 + err_queue_release: 972 + vb2_queue_release(vb2_q); 973 + err_detroy: 974 + mutex_destroy(&params->lock); 975 + return ret; 976 + } 977 + 978 + void c3_isp_params_unregister(struct c3_isp_device *isp) 979 + { 980 + struct c3_isp_params *params = &isp->params; 981 + 982 + vb2_queue_release(&params->vb2_q); 983 + media_entity_cleanup(&params->vdev.entity); 984 + video_unregister_device(&params->vdev); 985 + mutex_destroy(&params->lock); 986 + } 987 + 988 + void c3_isp_params_isr(struct c3_isp_device *isp) 989 + { 990 + struct c3_isp_params *params = &isp->params; 991 + 992 + guard(spinlock_irqsave)(&params->buff_lock); 993 + 994 + params->buff = 995 + list_first_entry_or_null(&params->pending, 996 + struct c3_isp_params_buffer, list); 997 + if (!params->buff) 998 + return; 999 + 1000 + list_del(&params->buff->list); 1001 + 1002 + c3_isp_params_cfg_blocks(params); 1003 + 1004 + params->buff->vb.sequence = params->isp->frm_sequence; 1005 + params->buff->vb.vb2_buf.timestamp = ktime_get(); 1006 + params->buff->vb.field = V4L2_FIELD_NONE; 1007 + vb2_buffer_done(&params->buff->vb.vb2_buf, VB2_BUF_STATE_DONE); 1008 + }
+618
drivers/media/platform/amlogic/c3/isp/c3-isp-regs.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + */ 5 + 6 + #ifndef __C3_ISP_REGS_H__ 7 + #define __C3_ISP_REGS_H__ 8 + 9 + #define ISP_TOP_INPUT_SIZE 0x0000 10 + #define ISP_TOP_INPUT_SIZE_VERT_SIZE_MASK GENMASK(15, 0) 11 + #define ISP_TOP_INPUT_SIZE_VERT_SIZE(x) ((x) << 0) 12 + #define ISP_TOP_INPUT_SIZE_HORIZ_SIZE_MASK GENMASK(31, 16) 13 + #define ISP_TOP_INPUT_SIZE_HORIZ_SIZE(x) ((x) << 16) 14 + 15 + #define ISP_TOP_FRM_SIZE 0x0004 16 + #define ISP_TOP_FRM_SIZE_CORE_VERT_SIZE_MASK GENMASK(15, 0) 17 + #define ISP_TOP_FRM_SIZE_CORE_VERT_SIZE(x) ((x) << 0) 18 + #define ISP_TOP_FRM_SIZE_CORE_HORIZ_SIZE_MASK GENMASK(31, 16) 19 + #define ISP_TOP_FRM_SIZE_CORE_HORIZ_SIZE(x) ((x) << 16) 20 + 21 + #define ISP_TOP_HOLD_SIZE 0x0008 22 + #define ISP_TOP_HOLD_SIZE_CORE_HORIZ_SIZE_MASK GENMASK(31, 16) 23 + #define ISP_TOP_HOLD_SIZE_CORE_HORIZ_SIZE(x) ((x) << 16) 24 + 25 + #define ISP_TOP_PATH_EN 0x0010 26 + #define ISP_TOP_PATH_EN_DISP0_EN_MASK BIT(0) 27 + #define ISP_TOP_PATH_EN_DISP0_EN BIT(0) 28 + #define ISP_TOP_PATH_EN_DISP0_DIS (0 << 0) 29 + #define ISP_TOP_PATH_EN_DISP1_EN_MASK BIT(1) 30 + #define ISP_TOP_PATH_EN_DISP1_EN BIT(1) 31 + #define ISP_TOP_PATH_EN_DISP1_DIS (0 << 1) 32 + #define ISP_TOP_PATH_EN_DISP2_EN_MASK BIT(2) 33 + #define ISP_TOP_PATH_EN_DISP2_EN BIT(2) 34 + #define ISP_TOP_PATH_EN_DISP2_DIS (0 << 2) 35 + #define ISP_TOP_PATH_EN_WRMIF0_EN_MASK BIT(8) 36 + #define ISP_TOP_PATH_EN_WRMIF0_EN BIT(8) 37 + #define ISP_TOP_PATH_EN_WRMIF0_DIS (0 << 8) 38 + #define ISP_TOP_PATH_EN_WRMIF1_EN_MASK BIT(9) 39 + #define ISP_TOP_PATH_EN_WRMIF1_EN BIT(9) 40 + #define ISP_TOP_PATH_EN_WRMIF1_DIS (0 << 9) 41 + #define ISP_TOP_PATH_EN_WRMIF2_EN_MASK BIT(10) 42 + #define ISP_TOP_PATH_EN_WRMIF2_EN BIT(10) 43 + #define ISP_TOP_PATH_EN_WRMIF2_DIS (0 << 10) 44 + 45 + #define ISP_TOP_PATH_SEL 0x0014 46 + #define ISP_TOP_PATH_SEL_CORE_MASK GENMASK(18, 16) 47 + #define ISP_TOP_PATH_SEL_CORE_CORE_DIS (0 << 16) 48 + #define ISP_TOP_PATH_SEL_CORE_MIPI_CORE BIT(16) 49 + 50 + #define ISP_TOP_DISPIN_SEL 0x0018 51 + #define ISP_TOP_DISPIN_SEL_DISP0_MASK GENMASK(3, 0) 52 + #define ISP_TOP_DISPIN_SEL_DISP0_CORE_OUT (0 << 0) 53 + #define ISP_TOP_DISPIN_SEL_DISP0_MIPI_OUT (2 << 0) 54 + #define ISP_TOP_DISPIN_SEL_DISP1_MASK GENMASK(7, 4) 55 + #define ISP_TOP_DISPIN_SEL_DISP1_CORE_OUT (0 << 4) 56 + #define ISP_TOP_DISPIN_SEL_DISP1_MIPI_OUT (2 << 4) 57 + #define ISP_TOP_DISPIN_SEL_DISP2_MASK GENMASK(11, 8) 58 + #define ISP_TOP_DISPIN_SEL_DISP2_CORE_OUT (0 << 8) 59 + #define ISP_TOP_DISPIN_SEL_DISP2_MIPI_OUT (2 << 8) 60 + 61 + #define ISP_TOP_IRQ_EN 0x0080 62 + #define ISP_TOP_IRQ_EN_FRM_END_MASK BIT(0) 63 + #define ISP_TOP_IRQ_EN_FRM_END_EN BIT(0) 64 + #define ISP_TOP_IRQ_EN_FRM_END_DIS (0 << 0) 65 + #define ISP_TOP_IRQ_EN_FRM_RST_MASK BIT(1) 66 + #define ISP_TOP_IRQ_EN_FRM_RST_EN BIT(1) 67 + #define ISP_TOP_IRQ_EN_FRM_RST_DIS (0 << 1) 68 + #define ISP_TOP_IRQ_EN_3A_DMA_ERR_MASK BIT(5) 69 + #define ISP_TOP_IRQ_EN_3A_DMA_ERR_EN BIT(5) 70 + #define ISP_TOP_IRQ_EN_3A_DMA_ERR_DIS (0 << 5) 71 + 72 + #define ISP_TOP_IRQ_CLR 0x0084 73 + #define ISP_TOP_RO_IRQ_STAT 0x01c4 74 + #define ISP_TOP_RO_IRQ_STAT_FRM_END_MASK BIT(0) 75 + #define ISP_TOP_RO_IRQ_STAT_FRM_RST_MASK BIT(1) 76 + #define ISP_TOP_RO_IRQ_STAT_3A_DMA_ERR_MASK BIT(5) 77 + 78 + #define ISP_TOP_MODE_CTRL 0x0400 79 + #define ISP_TOP_FEO_CTRL0 0x040c 80 + #define ISP_TOP_FEO_CTRL0_INPUT_FMT_EN_MASK BIT(8) 81 + #define ISP_TOP_FEO_CTRL0_INPUT_FMT_DIS (0 << 8) 82 + #define ISP_TOP_FEO_CTRL0_INPUT_FMT_EN BIT(8) 83 + 84 + #define ISP_TOP_FEO_CTRL1_0 0x0410 85 + #define ISP_TOP_FEO_CTRL1_0_DPC_EN_MASK BIT(3) 86 + #define ISP_TOP_FEO_CTRL1_0_DPC_DIS (0 << 3) 87 + #define ISP_TOP_FEO_CTRL1_0_DPC_EN BIT(3) 88 + #define ISP_TOP_FEO_CTRL1_0_OG_EN_MASK BIT(5) 89 + #define ISP_TOP_FEO_CTRL1_0_OG_DIS (0 << 5) 90 + #define ISP_TOP_FEO_CTRL1_0_OG_EN BIT(5) 91 + 92 + #define ISP_TOP_FED_CTRL 0x0418 93 + #define ISP_TOP_FED_CTRL_PDPC_EN_MASK BIT(1) 94 + #define ISP_TOP_FED_CTRL_PDPC_DIS (0 << 1) 95 + #define ISP_TOP_FED_CTRL_PDPC_EN BIT(1) 96 + #define ISP_TOP_FED_CTRL_RAWCNR_EN_MASK GENMASK(6, 5) 97 + #define ISP_TOP_FED_CTRL_RAWCNR_DIS (0 << 5) 98 + #define ISP_TOP_FED_CTRL_RAWCNR_EN BIT(5) 99 + #define ISP_TOP_FED_CTRL_SNR1_EN_MASK BIT(9) 100 + #define ISP_TOP_FED_CTRL_SNR1_DIS (0 << 9) 101 + #define ISP_TOP_FED_CTRL_SNR1_EN BIT(9) 102 + #define ISP_TOP_FED_CTRL_TNR0_EN_MASK BIT(11) 103 + #define ISP_TOP_FED_CTRL_TNR0_DIS (0 << 11) 104 + #define ISP_TOP_FED_CTRL_TNR0_EN BIT(11) 105 + #define ISP_TOP_FED_CTRL_CUBIC_CS_EN_MASK BIT(12) 106 + #define ISP_TOP_FED_CTRL_CUBIC_CS_DIS (0 << 12) 107 + #define ISP_TOP_FED_CTRL_CUBIC_CS_EN BIT(12) 108 + #define ISP_TOP_FED_CTRL_SQRT_EN_MASK BIT(14) 109 + #define ISP_TOP_FED_CTRL_SQRT_DIS (0 << 14) 110 + #define ISP_TOP_FED_CTRL_SQRT_EN BIT(14) 111 + #define ISP_TOP_FED_CTRL_DGAIN_EN_MASK BIT(16) 112 + #define ISP_TOP_FED_CTRL_DGAIN_DIS (0 << 16) 113 + #define ISP_TOP_FED_CTRL_DGAIN_EN BIT(16) 114 + 115 + #define ISP_TOP_BEO_CTRL 0x041c 116 + #define ISP_TOP_BEO_CTRL_WB_EN_MASK BIT(6) 117 + #define ISP_TOP_BEO_CTRL_WB_DIS (0 << 6) 118 + #define ISP_TOP_BEO_CTRL_WB_EN BIT(6) 119 + #define ISP_TOP_BEO_CTRL_BLC_EN_MASK BIT(7) 120 + #define ISP_TOP_BEO_CTRL_BLC_DIS (0 << 7) 121 + #define ISP_TOP_BEO_CTRL_BLC_EN BIT(7) 122 + #define ISP_TOP_BEO_CTRL_INV_DGAIN_EN_MASK BIT(8) 123 + #define ISP_TOP_BEO_CTRL_INV_DGAIN_DIS (0 << 8) 124 + #define ISP_TOP_BEO_CTRL_INV_DGAIN_EN BIT(8) 125 + #define ISP_TOP_BEO_CTRL_EOTF_EN_MASK BIT(9) 126 + #define ISP_TOP_BEO_CTRL_EOTF_DIS (0 << 9) 127 + #define ISP_TOP_BEO_CTRL_EOTF_EN BIT(9) 128 + 129 + #define ISP_TOP_BED_CTRL 0x0420 130 + #define ISP_TOP_BED_CTRL_YHS_STAT_EN_MASK GENMASK(1, 0) 131 + #define ISP_TOP_BED_CTRL_YHS_STAT_DIS (0 << 0) 132 + #define ISP_TOP_BED_CTRL_YHS_STAT_EN BIT(0) 133 + #define ISP_TOP_BED_CTRL_GRPH_STAT_EN_MASK BIT(2) 134 + #define ISP_TOP_BED_CTRL_GRPH_STAT_DIS (0 << 2) 135 + #define ISP_TOP_BED_CTRL_GRPH_STAT_EN BIT(2) 136 + #define ISP_TOP_BED_CTRL_FMETER_EN_MASK BIT(3) 137 + #define ISP_TOP_BED_CTRL_FMETER_DIS (0 << 3) 138 + #define ISP_TOP_BED_CTRL_FMETER_EN BIT(3) 139 + #define ISP_TOP_BED_CTRL_BSC_EN_MASK BIT(10) 140 + #define ISP_TOP_BED_CTRL_BSC_DIS (0 << 10) 141 + #define ISP_TOP_BED_CTRL_BSC_EN BIT(10) 142 + #define ISP_TOP_BED_CTRL_CNR2_EN_MASK BIT(11) 143 + #define ISP_TOP_BED_CTRL_CNR2_DIS (0 << 11) 144 + #define ISP_TOP_BED_CTRL_CNR2_EN BIT(11) 145 + #define ISP_TOP_BED_CTRL_CM1_EN_MASK BIT(13) 146 + #define ISP_TOP_BED_CTRL_CM1_DIS (0 << 13) 147 + #define ISP_TOP_BED_CTRL_CM1_EN BIT(13) 148 + #define ISP_TOP_BED_CTRL_CM0_EN_MASK BIT(14) 149 + #define ISP_TOP_BED_CTRL_CM0_DIS (0 << 14) 150 + #define ISP_TOP_BED_CTRL_CM0_EN BIT(14) 151 + #define ISP_TOP_BED_CTRL_PST_GAMMA_EN_MASK BIT(16) 152 + #define ISP_TOP_BED_CTRL_PST_GAMMA_DIS (0 << 16) 153 + #define ISP_TOP_BED_CTRL_PST_GAMMA_EN BIT(16) 154 + #define ISP_TOP_BED_CTRL_LUT3D_EN_MASK BIT(17) 155 + #define ISP_TOP_BED_CTRL_LUT3D_DIS (0 << 17) 156 + #define ISP_TOP_BED_CTRL_LUT3D_EN BIT(17) 157 + #define ISP_TOP_BED_CTRL_CCM_EN_MASK BIT(18) 158 + #define ISP_TOP_BED_CTRL_CCM_DIS (0 << 18) 159 + #define ISP_TOP_BED_CTRL_CCM_EN BIT(18) 160 + #define ISP_TOP_BED_CTRL_PST_TNR_LITE_EN_MASK BIT(21) 161 + #define ISP_TOP_BED_CTRL_PST_TNR_LITE_DIS (0 << 21) 162 + #define ISP_TOP_BED_CTRL_PST_TNR_LITE_EN BIT(21) 163 + #define ISP_TOP_BED_CTRL_AMCM_EN_MASK BIT(25) 164 + #define ISP_TOP_BED_CTRL_AMCM_DIS (0 << 25) 165 + #define ISP_TOP_BED_CTRL_AMCM_EN BIT(25) 166 + 167 + #define ISP_TOP_3A_STAT_CRTL 0x0424 168 + #define ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK BIT(0) 169 + #define ISP_TOP_3A_STAT_CRTL_AE_STAT_DIS (0 << 0) 170 + #define ISP_TOP_3A_STAT_CRTL_AE_STAT_EN BIT(0) 171 + #define ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK BIT(1) 172 + #define ISP_TOP_3A_STAT_CRTL_AWB_STAT_DIS (0 << 1) 173 + #define ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN BIT(1) 174 + #define ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK BIT(2) 175 + #define ISP_TOP_3A_STAT_CRTL_AF_STAT_DIS (0 << 2) 176 + #define ISP_TOP_3A_STAT_CRTL_AF_STAT_EN BIT(2) 177 + #define ISP_TOP_3A_STAT_CRTL_AWB_POINT_MASK GENMASK(6, 4) 178 + #define ISP_TOP_3A_STAT_CRTL_AWB_POINT(x) ((x) << 4) 179 + #define ISP_TOP_3A_STAT_CRTL_AE_POINT_MASK GENMASK(9, 8) 180 + #define ISP_TOP_3A_STAT_CRTL_AE_POINT(x) ((x) << 8) 181 + #define ISP_TOP_3A_STAT_CRTL_AF_POINT_MASK GENMASK(13, 12) 182 + #define ISP_TOP_3A_STAT_CRTL_AF_POINT(x) ((x) << 12) 183 + 184 + #define ISP_LSWB_BLC_OFST0 0x4028 185 + #define ISP_LSWB_BLC_OFST0_R_OFST_MASK GENMASK(15, 0) 186 + #define ISP_LSWB_BLC_OFST0_R_OFST(x) ((x) << 0) 187 + #define ISP_LSWB_BLC_OFST0_GR_OFST_MASK GENMASK(31, 16) 188 + #define ISP_LSWB_BLC_OFST0_GR_OFST(x) ((x) << 16) 189 + 190 + #define ISP_LSWB_BLC_OFST1 0x402c 191 + #define ISP_LSWB_BLC_OFST1_GB_OFST_MASK GENMASK(15, 0) 192 + #define ISP_LSWB_BLC_OFST1_GB_OFST(x) ((x) << 0) 193 + #define ISP_LSWB_BLC_OFST1_B_OFST_MASK GENMASK(31, 16) 194 + #define ISP_LSWB_BLC_OFST1_B_OFST(x) ((x) << 16) 195 + 196 + #define ISP_LSWB_BLC_PHSOFST 0x4034 197 + #define ISP_LSWB_BLC_PHSOFST_VERT_OFST_MASK GENMASK(1, 0) 198 + #define ISP_LSWB_BLC_PHSOFST_VERT_OFST(x) ((x) << 0) 199 + #define ISP_LSWB_BLC_PHSOFST_HORIZ_OFST_MASK GENMASK(3, 2) 200 + #define ISP_LSWB_BLC_PHSOFST_HORIZ_OFST(x) ((x) << 2) 201 + 202 + #define ISP_LSWB_WB_GAIN0 0x4038 203 + #define ISP_LSWB_WB_GAIN0_R_GAIN_MASK GENMASK(11, 0) 204 + #define ISP_LSWB_WB_GAIN0_R_GAIN(x) ((x) << 0) 205 + #define ISP_LSWB_WB_GAIN0_GR_GAIN_MASK GENMASK(27, 16) 206 + #define ISP_LSWB_WB_GAIN0_GR_GAIN(x) ((x) << 16) 207 + 208 + #define ISP_LSWB_WB_GAIN1 0x403c 209 + #define ISP_LSWB_WB_GAIN1_GB_GAIN_MASK GENMASK(11, 0) 210 + #define ISP_LSWB_WB_GAIN1_GB_GAIN(x) ((x) << 0) 211 + #define ISP_LSWB_WB_GAIN1_B_GAIN_MASK GENMASK(27, 16) 212 + #define ISP_LSWB_WB_GAIN1_B_GAIN(x) ((x) << 16) 213 + 214 + #define ISP_LSWB_WB_GAIN2 0x4040 215 + #define ISP_LSWB_WB_GAIN2_IR_GAIN_MASK GENMASK(11, 0) 216 + #define ISP_LSWB_WB_GAIN2_IR_GAIN(x) ((x) << 0) 217 + 218 + #define ISP_LSWB_WB_LIMIT0 0x4044 219 + #define ISP_LSWB_WB_LIMIT0_WB_LIMIT_R_MASK GENMASK(15, 0) 220 + #define ISP_LSWB_WB_LIMIT0_WB_LIMIT_R(x) ((x) << 0) 221 + #define ISP_LSWB_WB_LIMIT0_WB_LIMIT_R_MAX (0x8fff << 0) 222 + #define ISP_LSWB_WB_LIMIT0_WB_LIMIT_GR_MASK GENMASK(31, 16) 223 + #define ISP_LSWB_WB_LIMIT0_WB_LIMIT_GR(x) ((x) << 16) 224 + #define ISP_LSWB_WB_LIMIT0_WB_LIMIT_GR_MAX (0x8fff << 16) 225 + 226 + #define ISP_LSWB_WB_LIMIT1 0x4048 227 + #define ISP_LSWB_WB_LIMIT1_WB_LIMIT_GB_MASK GENMASK(15, 0) 228 + #define ISP_LSWB_WB_LIMIT1_WB_LIMIT_GB(x) ((x) << 0) 229 + #define ISP_LSWB_WB_LIMIT1_WB_LIMIT_GB_MAX (0x8fff << 0) 230 + #define ISP_LSWB_WB_LIMIT1_WB_LIMIT_B_MASK GENMASK(31, 16) 231 + #define ISP_LSWB_WB_LIMIT1_WB_LIMIT_B(x) ((x) << 16) 232 + #define ISP_LSWB_WB_LIMIT1_WB_LIMIT_B_MAX (0x8fff << 16) 233 + 234 + #define ISP_LSWB_WB_PHSOFST 0x4050 235 + #define ISP_LSWB_WB_PHSOFST_VERT_OFST_MASK GENMASK(1, 0) 236 + #define ISP_LSWB_WB_PHSOFST_VERT_OFST(x) ((x) << 0) 237 + #define ISP_LSWB_WB_PHSOFST_HORIZ_OFST_MASK GENMASK(3, 2) 238 + #define ISP_LSWB_WB_PHSOFST_HORIZ_OFST(x) ((x) << 2) 239 + 240 + #define ISP_LSWB_LNS_PHSOFST 0x4054 241 + #define ISP_LSWB_LNS_PHSOFST_VERT_OFST_MASK GENMASK(1, 0) 242 + #define ISP_LSWB_LNS_PHSOFST_VERT_OFST(x) ((x) << 0) 243 + #define ISP_LSWB_LNS_PHSOFST_HORIZ_OFST_MASK GENMASK(3, 2) 244 + #define ISP_LSWB_LNS_PHSOFST_HORIZ_OFST(x) ((x) << 2) 245 + 246 + #define ISP_DMS_COMMON_PARAM0 0x5000 247 + #define ISP_DMS_COMMON_PARAM0_VERT_PHS_OFST_MASK GENMASK(1, 0) 248 + #define ISP_DMS_COMMON_PARAM0_VERT_PHS_OFST(x) ((x) << 0) 249 + #define ISP_DMS_COMMON_PARAM0_HORIZ_PHS_OFST_MASK GENMASK(3, 2) 250 + #define ISP_DMS_COMMON_PARAM0_HORIZ_PHS_OFST(x) ((x) << 2) 251 + 252 + #define ISP_CM0_COEF00_01 0x6048 253 + #define ISP_CM0_COEF00_01_MTX_00_MASK GENMASK(12, 0) 254 + #define ISP_CM0_COEF00_01_MTX_00(x) ((x) << 0) 255 + #define ISP_CM0_COEF00_01_MTX_01_MASK GENMASK(28, 16) 256 + #define ISP_CM0_COEF00_01_MTX_01(x) ((x) << 16) 257 + 258 + #define ISP_CM0_COEF02_10 0x604c 259 + #define ISP_CM0_COEF02_10_MTX_02_MASK GENMASK(12, 0) 260 + #define ISP_CM0_COEF02_10_MTX_02(x) ((x) << 0) 261 + #define ISP_CM0_COEF02_10_MTX_10_MASK GENMASK(28, 16) 262 + #define ISP_CM0_COEF02_10_MTX_10(x) ((x) << 16) 263 + 264 + #define ISP_CM0_COEF11_12 0x6050 265 + #define ISP_CM0_COEF11_12_MTX_11_MASK GENMASK(12, 0) 266 + #define ISP_CM0_COEF11_12_MTX_11(x) ((x) << 0) 267 + #define ISP_CM0_COEF11_12_MTX_12_MASK GENMASK(28, 16) 268 + #define ISP_CM0_COEF11_12_MTX_12(x) ((x) << 16) 269 + 270 + #define ISP_CM0_COEF20_21 0x6054 271 + #define ISP_CM0_COEF20_21_MTX_20_MASK GENMASK(12, 0) 272 + #define ISP_CM0_COEF20_21_MTX_20(x) ((x) << 0) 273 + #define ISP_CM0_COEF20_21_MTX_21_MASK GENMASK(28, 16) 274 + #define ISP_CM0_COEF20_21_MTX_21(x) ((x) << 16) 275 + 276 + #define ISP_CM0_COEF22_OUP_OFST0 0x6058 277 + #define ISP_CM0_COEF22_OUP_OFST0_MTX_22_MASK GENMASK(12, 0) 278 + #define ISP_CM0_COEF22_OUP_OFST0_MTX_22(x) ((x) << 0) 279 + 280 + #define ISP_CCM_MTX_00_01 0x6098 281 + #define ISP_CCM_MTX_00_01_MTX_00_MASK GENMASK(12, 0) 282 + #define ISP_CCM_MTX_00_01_MTX_00(x) ((x) << 0) 283 + #define ISP_CCM_MTX_00_01_MTX_01_MASK GENMASK(28, 16) 284 + #define ISP_CCM_MTX_00_01_MTX_01(x) ((x) << 16) 285 + 286 + #define ISP_CCM_MTX_02_03 0x609c 287 + #define ISP_CCM_MTX_02_03_MTX_02_MASK GENMASK(12, 0) 288 + #define ISP_CCM_MTX_02_03_MTX_02(x) ((x) << 0) 289 + 290 + #define ISP_CCM_MTX_10_11 0x60A0 291 + #define ISP_CCM_MTX_10_11_MTX_10_MASK GENMASK(12, 0) 292 + #define ISP_CCM_MTX_10_11_MTX_10(x) ((x) << 0) 293 + #define ISP_CCM_MTX_10_11_MTX_11_MASK GENMASK(28, 16) 294 + #define ISP_CCM_MTX_10_11_MTX_11(x) ((x) << 16) 295 + 296 + #define ISP_CCM_MTX_12_13 0x60A4 297 + #define ISP_CCM_MTX_12_13_MTX_12_MASK GENMASK(12, 0) 298 + #define ISP_CCM_MTX_12_13_MTX_12(x) ((x) << 0) 299 + 300 + #define ISP_CCM_MTX_20_21 0x60A8 301 + #define ISP_CCM_MTX_20_21_MTX_20_MASK GENMASK(12, 0) 302 + #define ISP_CCM_MTX_20_21_MTX_20(x) ((x) << 0) 303 + #define ISP_CCM_MTX_20_21_MTX_21_MASK GENMASK(28, 16) 304 + #define ISP_CCM_MTX_20_21_MTX_21(x) ((x) << 16) 305 + 306 + #define ISP_CCM_MTX_22_23_RS 0x60Ac 307 + #define ISP_CCM_MTX_22_23_RS_MTX_22_MASK GENMASK(12, 0) 308 + #define ISP_CCM_MTX_22_23_RS_MTX_22(x) ((x) << 0) 309 + 310 + #define ISP_PST_GAMMA_LUT_ADDR 0x60cc 311 + #define ISP_PST_GAMMA_LUT_ADDR_IDX_ADDR(x) ((x) << 7) 312 + 313 + #define ISP_PST_GAMMA_LUT_DATA 0x60d0 314 + #define ISP_PST_GM_LUT_DATA0(x) (((x) & GENMASK(15, 0)) << 0) 315 + #define ISP_PST_GM_LUT_DATA1(x) (((x) & GENMASK(15, 0)) << 16) 316 + 317 + #define DISP0_TOP_TOP_CTRL 0x8000 318 + #define DISP0_TOP_TOP_CTRL_CROP2_EN_MASK BIT(5) 319 + #define DISP0_TOP_TOP_CTRL_CROP2_EN BIT(5) 320 + #define DISP0_TOP_TOP_CTRL_CROP2_DIS (0 << 5) 321 + 322 + #define DISP0_TOP_CRP2_START 0x8004 323 + #define DISP0_TOP_CRP2_START_V_START_MASK GENMASK(15, 0) 324 + #define DISP0_TOP_CRP2_START_V_START(x) ((x) << 0) 325 + #define DISP0_TOP_CRP2_START_H_START_MASK GENMASK(31, 16) 326 + #define DISP0_TOP_CRP2_START_H_START(x) ((x) << 16) 327 + 328 + #define DISP0_TOP_CRP2_SIZE 0x8008 329 + #define DISP0_TOP_CRP2_SIZE_V_SIZE_MASK GENMASK(15, 0) 330 + #define DISP0_TOP_CRP2_SIZE_V_SIZE(x) ((x) << 0) 331 + #define DISP0_TOP_CRP2_SIZE_H_SIZE_MASK GENMASK(31, 16) 332 + #define DISP0_TOP_CRP2_SIZE_H_SIZE(x) ((x) << 16) 333 + 334 + #define DISP0_TOP_OUT_SIZE 0x800c 335 + #define DISP0_TOP_OUT_SIZE_SCL_OUT_HEIGHT_MASK GENMASK(12, 0) 336 + #define DISP0_TOP_OUT_SIZE_SCL_OUT_HEIGHT(x) ((x) << 0) 337 + #define DISP0_TOP_OUT_SIZE_SCL_OUT_WIDTH_MASK GENMASK(28, 16) 338 + #define DISP0_TOP_OUT_SIZE_SCL_OUT_WIDTH(x) ((x) << 16) 339 + 340 + #define ISP_DISP0_TOP_IN_SIZE 0x804c 341 + #define ISP_DISP0_TOP_IN_SIZE_VSIZE_MASK GENMASK(12, 0) 342 + #define ISP_DISP0_TOP_IN_SIZE_VSIZE(x) ((x) << 0) 343 + #define ISP_DISP0_TOP_IN_SIZE_HSIZE_MASK GENMASK(28, 16) 344 + #define ISP_DISP0_TOP_IN_SIZE_HSIZE(x) ((x) << 16) 345 + 346 + #define DISP0_PPS_SCALE_EN 0x8200 347 + #define DISP0_PPS_SCALE_EN_VSC_TAP_NUM_MASK GENMASK(3, 0) 348 + #define DISP0_PPS_SCALE_EN_VSC_TAP_NUM(x) ((x) << 0) 349 + #define DISP0_PPS_SCALE_EN_HSC_TAP_NUM_MASK GENMASK(7, 4) 350 + #define DISP0_PPS_SCALE_EN_HSC_TAP_NUM(x) ((x) << 4) 351 + #define DISP0_PPS_SCALE_EN_PREVSC_FLT_NUM_MASK GENMASK(11, 8) 352 + #define DISP0_PPS_SCALE_EN_PREVSC_FLT_NUM(x) ((x) << 8) 353 + #define DISP0_PPS_SCALE_EN_PREHSC_FLT_NUM_MASK GENMASK(15, 12) 354 + #define DISP0_PPS_SCALE_EN_PREHSC_FLT_NUM(x) ((x) << 12) 355 + #define DISP0_PPS_SCALE_EN_PREVSC_RATE_MASK GENMASK(17, 16) 356 + #define DISP0_PPS_SCALE_EN_PREVSC_RATE(x) ((x) << 16) 357 + #define DISP0_PPS_SCALE_EN_PREHSC_RATE_MASK GENMASK(19, 18) 358 + #define DISP0_PPS_SCALE_EN_PREHSC_RATE(x) ((x) << 18) 359 + #define DISP0_PPS_SCALE_EN_HSC_EN_MASK BIT(20) 360 + #define DISP0_PPS_SCALE_EN_HSC_EN(x) ((x) << 20) 361 + #define DISP0_PPS_SCALE_EN_HSC_DIS (0 << 20) 362 + #define DISP0_PPS_SCALE_EN_VSC_EN_MASK BIT(21) 363 + #define DISP0_PPS_SCALE_EN_VSC_EN(x) ((x) << 21) 364 + #define DISP0_PPS_SCALE_EN_VSC_DIS (0 << 21) 365 + #define DISP0_PPS_SCALE_EN_PREVSC_EN_MASK BIT(22) 366 + #define DISP0_PPS_SCALE_EN_PREVSC_EN(x) ((x) << 22) 367 + #define DISP0_PPS_SCALE_EN_PREVSC_DIS (0 << 22) 368 + #define DISP0_PPS_SCALE_EN_PREHSC_EN_MASK BIT(23) 369 + #define DISP0_PPS_SCALE_EN_PREHSC_EN(x) ((x) << 23) 370 + #define DISP0_PPS_SCALE_EN_PREHSC_DIS (0 << 23) 371 + #define DISP0_PPS_SCALE_EN_HSC_NOR_RS_BITS_MASK GENMASK(27, 24) 372 + #define DISP0_PPS_SCALE_EN_HSC_NOR_RS_BITS(x) ((x) << 24) 373 + #define DISP0_PPS_SCALE_EN_VSC_NOR_RS_BITS_MASK GENMASK(31, 28) 374 + #define DISP0_PPS_SCALE_EN_VSC_NOR_RS_BITS(x) ((x) << 28) 375 + 376 + #define DISP0_PPS_VSC_START_PHASE_STEP 0x8224 377 + #define DISP0_PPS_VSC_START_PHASE_STEP_VERT_FRAC_MASK GENMASK(23, 0) 378 + #define DISP0_PPS_VSC_START_PHASE_STEP_VERT_FRAC(x) ((x) << 0) 379 + #define DISP0_PPS_VSC_START_PHASE_STEP_VERT_INTE_MASK GENMASK(27, 24) 380 + #define DISP0_PPS_VSC_START_PHASE_STEP_VERT_INTE(x) ((x) << 24) 381 + 382 + #define DISP0_PPS_HSC_START_PHASE_STEP 0x8230 383 + #define DISP0_PPS_HSC_START_PHASE_STEP_HORIZ_FRAC_MASK GENMASK(23, 0) 384 + #define DISP0_PPS_HSC_START_PHASE_STEP_HORIZ_FRAC(x) ((x) << 0) 385 + #define DISP0_PPS_HSC_START_PHASE_STEP_HORIZ_INTE_MASK GENMASK(27, 24) 386 + #define DISP0_PPS_HSC_START_PHASE_STEP_HORIZ_INTE(x) ((x) << 24) 387 + 388 + #define DISP0_PPS_444TO422 0x823c 389 + #define DISP0_PPS_444TO422_EN_MASK BIT(0) 390 + #define DISP0_PPS_444TO422_EN(x) ((x) << 0) 391 + 392 + #define ISP_SCALE0_COEF_IDX_LUMA 0x8240 393 + #define ISP_SCALE0_COEF_IDX_LUMA_COEF_S11_MODE_MASK BIT(9) 394 + #define ISP_SCALE0_COEF_IDX_LUMA_COEF_S11_MODE_EN BIT(9) 395 + #define ISP_SCALE0_COEF_IDX_LUMA_COEF_S11_MODE_DIS (0 << 9) 396 + #define ISP_SCALE0_COEF_IDX_LUMA_CTYPE_MASK GENMASK(12, 10) 397 + #define ISP_SCALE0_COEF_IDX_LUMA_CTYPE(x) ((x) << 10) 398 + 399 + #define ISP_SCALE0_COEF_LUMA 0x8244 400 + #define ISP_SCALE0_COEF_LUMA_DATA1(x) (((x) & GENMASK(10, 0)) << 0) 401 + #define ISP_SCALE0_COEF_LUMA_DATA0(x) (((x) & GENMASK(10, 0)) << 16) 402 + 403 + #define ISP_SCALE0_COEF_IDX_CHRO 0x8248 404 + #define ISP_SCALE0_COEF_IDX_CHRO_COEF_S11_MODE_MASK BIT(9) 405 + #define ISP_SCALE0_COEF_IDX_CHRO_COEF_S11_MODE_EN BIT(9) 406 + #define ISP_SCALE0_COEF_IDX_CHRO_COEF_S11_MODE_DIS (0 << 9) 407 + #define ISP_SCALE0_COEF_IDX_CHRO_CTYPE_MASK GENMASK(12, 10) 408 + #define ISP_SCALE0_COEF_IDX_CHRO_CTYPE(x) ((x) << 10) 409 + 410 + #define ISP_SCALE0_COEF_CHRO 0x824c 411 + #define ISP_SCALE0_COEF_CHRO_DATA1(x) (((x) & GENMASK(10, 0)) << 0) 412 + #define ISP_SCALE0_COEF_CHRO_DATA0(x) (((x) & GENMASK(10, 0)) << 16) 413 + 414 + #define ISP_AF_CTRL 0xa044 415 + #define ISP_AF_CTRL_VERT_OFST_MASK GENMASK(15, 14) 416 + #define ISP_AF_CTRL_VERT_OFST(x) ((x) << 14) 417 + #define ISP_AF_CTRL_HORIZ_OFST_MASK GENMASK(17, 16) 418 + #define ISP_AF_CTRL_HORIZ_OFST(x) ((x) << 16) 419 + 420 + #define ISP_AF_HV_SIZE 0xa04c 421 + #define ISP_AF_HV_SIZE_GLB_WIN_YSIZE_MASK GENMASK(15, 0) 422 + #define ISP_AF_HV_SIZE_GLB_WIN_YSIZE(x) ((x) << 0) 423 + #define ISP_AF_HV_SIZE_GLB_WIN_XSIZE_MASK GENMASK(31, 16) 424 + #define ISP_AF_HV_SIZE_GLB_WIN_XSIZE(x) ((x) << 16) 425 + 426 + #define ISP_AF_HV_BLKNUM 0xa050 427 + #define ISP_AF_HV_BLKNUM_V_NUM_MASK GENMASK(5, 0) 428 + #define ISP_AF_HV_BLKNUM_V_NUM(x) ((x) << 0) 429 + #define ISP_AF_HV_BLKNUM_H_NUM_MASK GENMASK(21, 16) 430 + #define ISP_AF_HV_BLKNUM_H_NUM(x) ((x) << 16) 431 + 432 + #define ISP_AF_EN_CTRL 0xa054 433 + #define ISP_AF_EN_CTRL_STAT_SEL_MASK BIT(21) 434 + #define ISP_AF_EN_CTRL_STAT_SEL_OLD (0 << 21) 435 + #define ISP_AF_EN_CTRL_STAT_SEL_NEW BIT(21) 436 + 437 + #define ISP_AF_IDX_ADDR 0xa1c0 438 + #define ISP_AF_IDX_DATA 0xa1c4 439 + #define ISP_AF_IDX_DATA_VIDX_DATA(x) (((x) & GENMASK(15, 0)) << 0) 440 + #define ISP_AF_IDX_DATA_HIDX_DATA(x) (((x) & GENMASK(15, 0)) << 16) 441 + 442 + #define ISP_AE_CTRL 0xa448 443 + #define ISP_AE_CTRL_INPUT_2LINE_MASK BIT(7) 444 + #define ISP_AE_CTRL_INPUT_2LINE_EN BIT(7) 445 + #define ISP_AE_CTRL_INPUT_2LINE_DIS (0 << 7) 446 + #define ISP_AE_CTRL_LUMA_MODE_MASK GENMASK(9, 8) 447 + #define ISP_AE_CTRL_LUMA_MODE_CUR (0 << 8) 448 + #define ISP_AE_CTRL_LUMA_MODE_MAX BIT(8) 449 + #define ISP_AE_CTRL_LUMA_MODE_FILTER (2 << 8) 450 + #define ISP_AE_CTRL_VERT_OFST_MASK GENMASK(25, 24) 451 + #define ISP_AE_CTRL_VERT_OFST(x) ((x) << 24) 452 + #define ISP_AE_CTRL_HORIZ_OFST_MASK GENMASK(27, 26) 453 + #define ISP_AE_CTRL_HORIZ_OFST(x) ((x) << 26) 454 + 455 + #define ISP_AE_HV_SIZE 0xa464 456 + #define ISP_AE_HV_SIZE_VERT_SIZE_MASK GENMASK(15, 0) 457 + #define ISP_AE_HV_SIZE_VERT_SIZE(x) ((x) << 0) 458 + #define ISP_AE_HV_SIZE_HORIZ_SIZE_MASK GENMASK(31, 16) 459 + #define ISP_AE_HV_SIZE_HORIZ_SIZE(x) ((x) << 16) 460 + 461 + #define ISP_AE_HV_BLKNUM 0xa468 462 + #define ISP_AE_HV_BLKNUM_V_NUM_MASK GENMASK(6, 0) 463 + #define ISP_AE_HV_BLKNUM_V_NUM(x) ((x) << 0) 464 + #define ISP_AE_HV_BLKNUM_H_NUM_MASK GENMASK(22, 16) 465 + #define ISP_AE_HV_BLKNUM_H_NUM(x) ((x) << 16) 466 + 467 + #define ISP_AE_IDX_ADDR 0xa600 468 + #define ISP_AE_IDX_DATA 0xa604 469 + #define ISP_AE_IDX_DATA_VIDX_DATA(x) (((x) & GENMASK(15, 0)) << 0) 470 + #define ISP_AE_IDX_DATA_HIDX_DATA(x) (((x) & GENMASK(15, 0)) << 16) 471 + 472 + #define ISP_AE_BLK_WT_ADDR 0xa608 473 + #define ISP_AE_BLK_WT_DATA 0xa60c 474 + #define ISP_AE_BLK_WT_DATA_WT(i, x) (((x) & GENMASK(3, 0)) << ((i) * 4)) 475 + 476 + #define ISP_AWB_CTRL 0xa834 477 + #define ISP_AWB_CTRL_VERT_OFST_MASK GENMASK(1, 0) 478 + #define ISP_AWB_CTRL_VERT_OFST(x) ((x) << 0) 479 + #define ISP_AWB_CTRL_HORIZ_OFST_MASK GENMASK(3, 2) 480 + #define ISP_AWB_CTRL_HORIZ_OFST(x) ((x) << 2) 481 + 482 + #define ISP_AWB_HV_SIZE 0xa83c 483 + #define ISP_AWB_HV_SIZE_VERT_SIZE_MASK GENMASK(15, 0) 484 + #define ISP_AWB_HV_SIZE_VERT_SIZE(x) ((x) << 0) 485 + #define ISP_AWB_HV_SIZE_HORIZ_SIZE_MASK GENMASK(31, 16) 486 + #define ISP_AWB_HV_SIZE_HORIZ_SIZE(x) ((x) << 16) 487 + 488 + #define ISP_AWB_HV_BLKNUM 0xa840 489 + #define ISP_AWB_HV_BLKNUM_V_NUM_MASK GENMASK(5, 0) 490 + #define ISP_AWB_HV_BLKNUM_V_NUM(x) ((x) << 0) 491 + #define ISP_AWB_HV_BLKNUM_H_NUM_MASK GENMASK(21, 16) 492 + #define ISP_AWB_HV_BLKNUM_H_NUM(x) ((x) << 16) 493 + 494 + #define ISP_AWB_STAT_RG 0xa848 495 + #define ISP_AWB_STAT_RG_MIN_VALUE_MASK GENMASK(11, 0) 496 + #define ISP_AWB_STAT_RG_MIN_VALUE(x) ((x) << 0) 497 + #define ISP_AWB_STAT_RG_MAX_VALUE_MASK GENMASK(27, 16) 498 + #define ISP_AWB_STAT_RG_MAX_VALUE(x) ((x) << 16) 499 + 500 + #define ISP_AWB_STAT_BG 0xa84c 501 + #define ISP_AWB_STAT_BG_MIN_VALUE_MASK GENMASK(11, 0) 502 + #define ISP_AWB_STAT_BG_MIN_VALUE(x) ((x) << 0) 503 + #define ISP_AWB_STAT_BG_MAX_VALUE_MASK GENMASK(27, 16) 504 + #define ISP_AWB_STAT_BG_MAX_VALUE(x) ((x) << 16) 505 + 506 + #define ISP_AWB_STAT_RG_HL 0xa850 507 + #define ISP_AWB_STAT_RG_HL_LOW_VALUE_MASK GENMASK(11, 0) 508 + #define ISP_AWB_STAT_RG_HL_LOW_VALUE(x) ((x) << 0) 509 + #define ISP_AWB_STAT_RG_HL_HIGH_VALUE_MASK GENMASK(27, 16) 510 + #define ISP_AWB_STAT_RG_HL_HIGH_VALUE(x) ((x) << 16) 511 + 512 + #define ISP_AWB_STAT_BG_HL 0xa854 513 + #define ISP_AWB_STAT_BG_HL_LOW_VALUE_MASK GENMASK(11, 0) 514 + #define ISP_AWB_STAT_BG_HL_LOW_VALUE(x) ((x) << 0) 515 + #define ISP_AWB_STAT_BG_HL_HIGH_VALUE_MASK GENMASK(27, 16) 516 + #define ISP_AWB_STAT_BG_HL_HIGH_VALUE(x) ((x) << 16) 517 + 518 + #define ISP_AWB_STAT_CTRL2 0xa858 519 + #define ISP_AWB_STAT_CTRL2_SATUR_CTRL_MASK BIT(0) 520 + #define ISP_AWB_STAT_CTRL2_SATUR_CTRL(x) ((x) << 0) 521 + 522 + #define ISP_AWB_IDX_ADDR 0xaa00 523 + #define ISP_AWB_IDX_DATA 0xaa04 524 + #define ISP_AWB_IDX_DATA_VIDX_DATA(x) (((x) & GENMASK(15, 0)) << 0) 525 + #define ISP_AWB_IDX_DATA_HIDX_DATA(x) (((x) & GENMASK(15, 0)) << 16) 526 + 527 + #define ISP_AWB_BLK_WT_ADDR 0xaa08 528 + #define ISP_AWB_BLK_WT_DATA 0xaa0c 529 + #define ISP_AWB_BLK_WT_DATA_WT(i, x) (((x) & GENMASK(3, 0)) << ((i) * 4)) 530 + 531 + #define ISP_WRMIFX3_0_CH0_CTRL0 0xc400 532 + #define ISP_WRMIFX3_0_CH0_CTRL0_STRIDE_MASK GENMASK(28, 16) 533 + #define ISP_WRMIFX3_0_CH0_CTRL0_STRIDE(x) ((x) << 16) 534 + 535 + #define ISP_WRMIFX3_0_CH0_CTRL1 0xc404 536 + #define ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_MODE_MASK GENMASK(30, 27) 537 + #define ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_8BITS BIT(27) 538 + #define ISP_WRMIFX3_0_CH0_CTRL1_PIX_BITS_16BITS (2 << 27) 539 + 540 + #define ISP_WRMIFX3_0_CH1_CTRL0 0xc408 541 + #define ISP_WRMIFX3_0_CH1_CTRL0_STRIDE_MASK GENMASK(28, 16) 542 + #define ISP_WRMIFX3_0_CH1_CTRL0_STRIDE(x) ((x) << 16) 543 + 544 + #define ISP_WRMIFX3_0_CH1_CTRL1 0xc40c 545 + #define ISP_WRMIFX3_0_CH1_CTRL1_PIX_BITS_MODE_MASK GENMASK(30, 27) 546 + #define ISP_WRMIFX3_0_CH1_CTRL1_PIX_BITS_8BITS BIT(27) 547 + #define ISP_WRMIFX3_0_CH1_CTRL1_PIX_BITS_16BITS (2 << 27) 548 + #define ISP_WRMIFX3_0_CH1_CTRL1_PIX_BITS_32BITS (3 << 27) 549 + 550 + #define ISP_WRMIFX3_0_WIN_LUMA_H 0xc420 551 + #define ISP_WRMIFX3_0_WIN_LUMA_H_LUMA_HEND_MASK GENMASK(28, 16) 552 + #define ISP_WRMIFX3_0_WIN_LUMA_H_LUMA_HEND(x) (((x) - 1) << 16) 553 + 554 + #define ISP_WRMIFX3_0_WIN_LUMA_V 0xc424 555 + #define ISP_WRMIFX3_0_WIN_LUMA_V_LUMA_VEND_MASK GENMASK(28, 16) 556 + #define ISP_WRMIFX3_0_WIN_LUMA_V_LUMA_VEND(x) (((x) - 1) << 16) 557 + 558 + #define ISP_WRMIFX3_0_WIN_CHROM_H 0xc428 559 + #define ISP_WRMIFX3_0_WIN_CHROM_H_CHROM_HEND_MASK GENMASK(28, 16) 560 + #define ISP_WRMIFX3_0_WIN_CHROM_H_CHROM_HEND(x) (((x) - 1) << 16) 561 + 562 + #define ISP_WRMIFX3_0_WIN_CHROM_V 0xc42c 563 + #define ISP_WRMIFX3_0_WIN_CHROM_V_CHROM_VEND_MASK GENMASK(28, 16) 564 + #define ISP_WRMIFX3_0_WIN_CHROM_V_CHROM_VEND(x) (((x) - 1) << 16) 565 + 566 + #define ISP_WRMIFX3_0_CH0_BADDR 0xc440 567 + #define ISP_WRMIFX3_0_CH0_BASE_ADDR(x) ((x) >> 4) 568 + 569 + #define ISP_WRMIFX3_0_CH1_BADDR 0xc444 570 + #define ISP_WRMIFX3_0_CH1_BASE_ADDR(x) ((x) >> 4) 571 + 572 + #define ISP_WRMIFX3_0_FMT_SIZE 0xc464 573 + #define ISP_WRMIFX3_0_FMT_SIZE_HSIZE_MASK GENMASK(15, 0) 574 + #define ISP_WRMIFX3_0_FMT_SIZE_HSIZE(x) ((x) << 0) 575 + #define ISP_WRMIFX3_0_FMT_SIZE_VSIZE_MASK GENMASK(31, 16) 576 + #define ISP_WRMIFX3_0_FMT_SIZE_VSIZE(x) ((x) << 16) 577 + 578 + #define ISP_WRMIFX3_0_FMT_CTRL 0xc468 579 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_MASK GENMASK(1, 0) 580 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_8BIT (0 << 0) 581 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_10BIT BIT(0) 582 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_12BIT (2 << 0) 583 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_IBITS_16BIT (3 << 0) 584 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_MASK BIT(2) 585 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_VU (0 << 2) 586 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_UV_SWAP_UV BIT(2) 587 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_MASK GENMASK(5, 4) 588 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X1 (0 << 4) 589 + #define ISP_WRMIFX3_0_FMT_CTRL_MTX_PLANE_X2 BIT(4) 590 + #define ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_MASK GENMASK(18, 16) 591 + #define ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_YUV422 BIT(16) 592 + #define ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_YUV420 (2 << 16) 593 + #define ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_Y_ONLY (3 << 16) 594 + #define ISP_WRMIFX3_0_FMT_CTRL_MODE_OUT_RAW (4 << 16) 595 + 596 + #define VIU_DMAWR_BADDR0 0xc840 597 + #define VIU_DMAWR_BADDR0_AF_STATS_BASE_ADDR_MASK GENMASK(27, 0) 598 + #define VIU_DMAWR_BADDR0_AF_STATS_BASE_ADDR(x) ((x) >> 4) 599 + 600 + #define VIU_DMAWR_BADDR1 0xc844 601 + #define VIU_DMAWR_BADDR1_AWB_STATS_BASE_ADDR_MASK GENMASK(27, 0) 602 + #define VIU_DMAWR_BADDR1_AWB_STATS_BASE_ADDR(x) ((x) >> 4) 603 + 604 + #define VIU_DMAWR_BADDR2 0xc848 605 + #define VIU_DMAWR_BADDR2_AE_STATS_BASE_ADDR_MASK GENMASK(27, 0) 606 + #define VIU_DMAWR_BADDR2_AE_STATS_BASE_ADDR(x) ((x) >> 4) 607 + 608 + #define VIU_DMAWR_SIZE0 0xc854 609 + #define VIU_DMAWR_SIZE0_AF_STATS_SIZE_MASK GENMASK(15, 0) 610 + #define VIU_DMAWR_SIZE0_AF_STATS_SIZE(x) ((x) << 0) 611 + #define VIU_DMAWR_SIZE0_AWB_STATS_SIZE_MASK GENMASK(31, 16) 612 + #define VIU_DMAWR_SIZE0_AWB_STATS_SIZE(x) ((x) << 16) 613 + 614 + #define VIU_DMAWR_SIZE1 0xc858 615 + #define VIU_DMAWR_SIZE1_AE_STATS_SIZE_MASK GENMASK(15, 0) 616 + #define VIU_DMAWR_SIZE1_AE_STATS_SIZE(x) ((x) << 0) 617 + 618 + #endif
+892
drivers/media/platform/amlogic/c3/isp/c3-isp-resizer.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + */ 5 + 6 + #include <linux/pm_runtime.h> 7 + 8 + #include "c3-isp-common.h" 9 + #include "c3-isp-regs.h" 10 + 11 + #define C3_ISP_RSZ_DEF_PAD_FMT MEDIA_BUS_FMT_YUV10_1X30 12 + #define C3_ISP_DISP_REG(base, id) ((base) + (id) * 0x400) 13 + #define C3_ISP_PPS_LUT_H_NUM 33 14 + #define C3_ISP_PPS_LUT_CTYPE_0 0 15 + #define C3_ISP_PPS_LUT_CTYPE_2 2 16 + #define C3_ISP_SCL_EN 1 17 + #define C3_ISP_SCL_DIS 0 18 + 19 + /* 20 + * struct c3_isp_rsz_format_info - ISP resizer format information 21 + * 22 + * @mbus_code: the mbus code 23 + * @pads: bitmask detailing valid pads for this mbus_code 24 + * @is_raw: the raw format flag of mbus code 25 + */ 26 + struct c3_isp_rsz_format_info { 27 + u32 mbus_code; 28 + u32 pads; 29 + bool is_raw; 30 + }; 31 + 32 + static const struct c3_isp_rsz_format_info c3_isp_rsz_fmts[] = { 33 + /* RAW formats */ 34 + { 35 + .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, 36 + .pads = BIT(C3_ISP_RSZ_PAD_SINK) 37 + | BIT(C3_ISP_RSZ_PAD_SOURCE), 38 + .is_raw = true, 39 + }, { 40 + .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, 41 + .pads = BIT(C3_ISP_RSZ_PAD_SINK) 42 + | BIT(C3_ISP_RSZ_PAD_SOURCE), 43 + .is_raw = true, 44 + }, { 45 + .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, 46 + .pads = BIT(C3_ISP_RSZ_PAD_SINK) 47 + | BIT(C3_ISP_RSZ_PAD_SOURCE), 48 + .is_raw = true, 49 + }, { 50 + .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, 51 + .pads = BIT(C3_ISP_RSZ_PAD_SINK) 52 + | BIT(C3_ISP_RSZ_PAD_SOURCE), 53 + .is_raw = true, 54 + }, 55 + /* YUV formats */ 56 + { 57 + .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 58 + .pads = BIT(C3_ISP_RSZ_PAD_SINK) 59 + | BIT(C3_ISP_RSZ_PAD_SOURCE), 60 + .is_raw = false, 61 + }, 62 + }; 63 + 64 + /* 65 + * struct c3_isp_pps_io_size - ISP scaler input and output size 66 + * 67 + * @thsize: input horizontal size of after preprocessing 68 + * @tvsize: input vertical size of after preprocessing 69 + * @ohsize: output horizontal size 70 + * @ovsize: output vertical size 71 + * @ihsize: input horizontal size 72 + * @max_hsize: maximum horizontal size 73 + */ 74 + struct c3_isp_pps_io_size { 75 + u32 thsize; 76 + u32 tvsize; 77 + u32 ohsize; 78 + u32 ovsize; 79 + u32 ihsize; 80 + u32 max_hsize; 81 + }; 82 + 83 + /* The normal parameters of pps module */ 84 + static const int c3_isp_pps_lut[C3_ISP_PPS_LUT_H_NUM][4] = { 85 + { 0, 511, 0, 0}, { -5, 511, 5, 0}, {-10, 511, 11, 0}, 86 + {-14, 510, 17, -1}, {-18, 508, 23, -1}, {-22, 506, 29, -1}, 87 + {-25, 503, 36, -2}, {-28, 500, 43, -3}, {-32, 496, 51, -3}, 88 + {-34, 491, 59, -4}, {-37, 487, 67, -5}, {-39, 482, 75, -6}, 89 + {-41, 476, 84, -7}, {-42, 470, 92, -8}, {-44, 463, 102, -9}, 90 + {-45, 456, 111, -10}, {-45, 449, 120, -12}, {-47, 442, 130, -13}, 91 + {-47, 434, 140, -15}, {-47, 425, 151, -17}, {-47, 416, 161, -18}, 92 + {-47, 407, 172, -20}, {-47, 398, 182, -21}, {-47, 389, 193, -23}, 93 + {-46, 379, 204, -25}, {-45, 369, 215, -27}, {-44, 358, 226, -28}, 94 + {-43, 348, 237, -30}, {-43, 337, 249, -31}, {-41, 326, 260, -33}, 95 + {-40, 316, 271, -35}, {-39, 305, 282, -36}, {-37, 293, 293, -37} 96 + }; 97 + 98 + static const struct c3_isp_rsz_format_info 99 + *rsz_find_format_by_code(u32 code, u32 pad) 100 + { 101 + for (unsigned int i = 0; i < ARRAY_SIZE(c3_isp_rsz_fmts); i++) { 102 + const struct c3_isp_rsz_format_info *info = &c3_isp_rsz_fmts[i]; 103 + 104 + if (info->mbus_code == code && info->pads & BIT(pad)) 105 + return info; 106 + } 107 + 108 + return NULL; 109 + } 110 + 111 + static const struct c3_isp_rsz_format_info 112 + *rsz_find_format_by_index(u32 index, u32 pad) 113 + { 114 + for (unsigned int i = 0; i < ARRAY_SIZE(c3_isp_rsz_fmts); i++) { 115 + const struct c3_isp_rsz_format_info *info = &c3_isp_rsz_fmts[i]; 116 + 117 + if (!(info->pads & BIT(pad))) 118 + continue; 119 + 120 + if (!index) 121 + return info; 122 + 123 + index--; 124 + } 125 + 126 + return NULL; 127 + } 128 + 129 + static void c3_isp_rsz_pps_size(struct c3_isp_resizer *rsz, 130 + struct c3_isp_pps_io_size *io_size) 131 + { 132 + int thsize = io_size->thsize; 133 + int tvsize = io_size->tvsize; 134 + u32 ohsize = io_size->ohsize; 135 + u32 ovsize = io_size->ovsize; 136 + u32 ihsize = io_size->ihsize; 137 + u32 max_hsize = io_size->max_hsize; 138 + int h_int; 139 + int v_int; 140 + int h_fract; 141 + int v_fract; 142 + int yuv444to422_en; 143 + 144 + /* Calculate the integer part of horizonal scaler step */ 145 + h_int = thsize / ohsize; 146 + 147 + /* Calculate the vertical part of horizonal scaler step */ 148 + v_int = tvsize / ovsize; 149 + 150 + /* 151 + * Calculate the fraction part of horizonal scaler step. 152 + * step_h_fraction = (source / dest) * 2^24, 153 + * so step_h_fraction = ((source << 12) / dest) << 12. 154 + */ 155 + h_fract = ((thsize << 12) / ohsize) << 12; 156 + 157 + /* 158 + * Calculate the fraction part of vertical scaler step 159 + * step_v_fraction = (source / dest) * 2^24, 160 + * so step_v_fraction = ((source << 12) / dest) << 12. 161 + */ 162 + v_fract = ((tvsize << 12) / ovsize) << 12; 163 + 164 + yuv444to422_en = ihsize > (max_hsize / 2) ? 1 : 0; 165 + 166 + c3_isp_update_bits(rsz->isp, 167 + C3_ISP_DISP_REG(DISP0_PPS_444TO422, rsz->id), 168 + DISP0_PPS_444TO422_EN_MASK, 169 + DISP0_PPS_444TO422_EN(yuv444to422_en)); 170 + 171 + c3_isp_write(rsz->isp, 172 + C3_ISP_DISP_REG(DISP0_PPS_VSC_START_PHASE_STEP, rsz->id), 173 + DISP0_PPS_VSC_START_PHASE_STEP_VERT_FRAC(v_fract) | 174 + DISP0_PPS_VSC_START_PHASE_STEP_VERT_INTE(v_int)); 175 + 176 + c3_isp_write(rsz->isp, 177 + C3_ISP_DISP_REG(DISP0_PPS_HSC_START_PHASE_STEP, rsz->id), 178 + DISP0_PPS_HSC_START_PHASE_STEP_HORIZ_FRAC(h_fract) | 179 + DISP0_PPS_HSC_START_PHASE_STEP_HORIZ_INTE(h_int)); 180 + } 181 + 182 + static void c3_isp_rsz_pps_lut(struct c3_isp_resizer *rsz, u32 ctype) 183 + { 184 + unsigned int i; 185 + 186 + /* 187 + * Default value of this register is 0, so only need to set 188 + * SCALE_LUMA_COEF_S11_MODE and SCALE_LUMA_CTYPE. This register needs 189 + * to be written in one time. 190 + */ 191 + c3_isp_write(rsz->isp, 192 + C3_ISP_DISP_REG(ISP_SCALE0_COEF_IDX_LUMA, rsz->id), 193 + ISP_SCALE0_COEF_IDX_LUMA_COEF_S11_MODE_EN | 194 + ISP_SCALE0_COEF_IDX_LUMA_CTYPE(ctype)); 195 + 196 + for (i = 0; i < C3_ISP_PPS_LUT_H_NUM; i++) { 197 + c3_isp_write(rsz->isp, 198 + C3_ISP_DISP_REG(ISP_SCALE0_COEF_LUMA, rsz->id), 199 + ISP_SCALE0_COEF_LUMA_DATA0(c3_isp_pps_lut[i][0]) | 200 + ISP_SCALE0_COEF_LUMA_DATA1(c3_isp_pps_lut[i][1])); 201 + c3_isp_write(rsz->isp, 202 + C3_ISP_DISP_REG(ISP_SCALE0_COEF_LUMA, rsz->id), 203 + ISP_SCALE0_COEF_LUMA_DATA0(c3_isp_pps_lut[i][2]) | 204 + ISP_SCALE0_COEF_LUMA_DATA1(c3_isp_pps_lut[i][3])); 205 + } 206 + 207 + /* 208 + * Default value of this register is 0, so only need to set 209 + * SCALE_CHRO_COEF_S11_MODE and SCALE_CHRO_CTYPE. This register needs 210 + * to be written in one time. 211 + */ 212 + c3_isp_write(rsz->isp, 213 + C3_ISP_DISP_REG(ISP_SCALE0_COEF_IDX_CHRO, rsz->id), 214 + ISP_SCALE0_COEF_IDX_CHRO_COEF_S11_MODE_EN | 215 + ISP_SCALE0_COEF_IDX_CHRO_CTYPE(ctype)); 216 + 217 + for (i = 0; i < C3_ISP_PPS_LUT_H_NUM; i++) { 218 + c3_isp_write(rsz->isp, 219 + C3_ISP_DISP_REG(ISP_SCALE0_COEF_CHRO, rsz->id), 220 + ISP_SCALE0_COEF_CHRO_DATA0(c3_isp_pps_lut[i][0]) | 221 + ISP_SCALE0_COEF_CHRO_DATA1(c3_isp_pps_lut[i][1])); 222 + c3_isp_write(rsz->isp, 223 + C3_ISP_DISP_REG(ISP_SCALE0_COEF_CHRO, rsz->id), 224 + ISP_SCALE0_COEF_CHRO_DATA0(c3_isp_pps_lut[i][2]) | 225 + ISP_SCALE0_COEF_CHRO_DATA1(c3_isp_pps_lut[i][3])); 226 + } 227 + } 228 + 229 + static void c3_isp_rsz_pps_disable(struct c3_isp_resizer *rsz) 230 + { 231 + c3_isp_update_bits(rsz->isp, 232 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 233 + DISP0_PPS_SCALE_EN_HSC_EN_MASK, 234 + DISP0_PPS_SCALE_EN_HSC_DIS); 235 + c3_isp_update_bits(rsz->isp, 236 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 237 + DISP0_PPS_SCALE_EN_VSC_EN_MASK, 238 + DISP0_PPS_SCALE_EN_VSC_DIS); 239 + c3_isp_update_bits(rsz->isp, 240 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 241 + DISP0_PPS_SCALE_EN_PREVSC_EN_MASK, 242 + DISP0_PPS_SCALE_EN_PREVSC_DIS); 243 + c3_isp_update_bits(rsz->isp, 244 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 245 + DISP0_PPS_SCALE_EN_PREHSC_EN_MASK, 246 + DISP0_PPS_SCALE_EN_PREHSC_DIS); 247 + } 248 + 249 + static int c3_isp_rsz_pps_enable(struct c3_isp_resizer *rsz, 250 + struct v4l2_subdev_state *state) 251 + { 252 + struct v4l2_rect *crop; 253 + struct v4l2_rect *cmps; 254 + int max_hsize; 255 + int hsc_en, vsc_en; 256 + int preh_en, prev_en; 257 + u32 prehsc_rate; 258 + u32 prevsc_flt_num; 259 + int pre_vscale_max_hsize; 260 + u32 ihsize_after_pre_hsc; 261 + u32 ihsize_after_pre_hsc_alt; 262 + u32 vsc_tap_num_alt; 263 + u32 ihsize; 264 + u32 ivsize; 265 + struct c3_isp_pps_io_size io_size; 266 + 267 + crop = v4l2_subdev_state_get_crop(state, C3_ISP_RSZ_PAD_SINK); 268 + cmps = v4l2_subdev_state_get_compose(state, C3_ISP_RSZ_PAD_SINK); 269 + 270 + ihsize = crop->width; 271 + ivsize = crop->height; 272 + 273 + hsc_en = (ihsize == cmps->width) ? C3_ISP_SCL_DIS : C3_ISP_SCL_EN; 274 + vsc_en = (ivsize == cmps->height) ? C3_ISP_SCL_DIS : C3_ISP_SCL_EN; 275 + 276 + /* Disable pps when there no need to use pps */ 277 + if (!hsc_en && !vsc_en) { 278 + c3_isp_rsz_pps_disable(rsz); 279 + return 0; 280 + } 281 + 282 + /* Pre-scale needs to be enable if the down scaling factor exceeds 4 */ 283 + preh_en = (ihsize > cmps->width * 4) ? C3_ISP_SCL_EN : C3_ISP_SCL_DIS; 284 + prev_en = (ivsize > cmps->height * 4) ? C3_ISP_SCL_EN : C3_ISP_SCL_DIS; 285 + 286 + if (rsz->id == C3_ISP_RSZ_2) { 287 + max_hsize = C3_ISP_MAX_WIDTH; 288 + 289 + /* Set vertical tap number */ 290 + prevsc_flt_num = 4; 291 + 292 + /* Set the max hsize of pre-vertical scale */ 293 + pre_vscale_max_hsize = max_hsize / 2; 294 + } else { 295 + max_hsize = C3_ISP_DEFAULT_WIDTH; 296 + 297 + /* Set vertical tap number and the max hsize of pre-vertical */ 298 + if (ihsize > (max_hsize / 2) && 299 + ihsize <= max_hsize && prev_en) { 300 + prevsc_flt_num = 2; 301 + pre_vscale_max_hsize = max_hsize; 302 + } else { 303 + prevsc_flt_num = 4; 304 + pre_vscale_max_hsize = max_hsize / 2; 305 + } 306 + } 307 + 308 + /* 309 + * Set pre-horizonal scale rate and the hsize of after 310 + * pre-horizonal scale. 311 + */ 312 + if (preh_en) { 313 + prehsc_rate = 1; 314 + ihsize_after_pre_hsc = DIV_ROUND_UP(ihsize, 2); 315 + } else { 316 + prehsc_rate = 0; 317 + ihsize_after_pre_hsc = ihsize; 318 + } 319 + 320 + /* Change pre-horizonal scale rate */ 321 + if (prev_en && ihsize_after_pre_hsc >= pre_vscale_max_hsize) 322 + prehsc_rate += 1; 323 + 324 + /* Set the actual hsize of after pre-horizonal scale */ 325 + if (preh_en) 326 + ihsize_after_pre_hsc_alt = 327 + DIV_ROUND_UP(ihsize, 1 << prehsc_rate); 328 + else 329 + ihsize_after_pre_hsc_alt = ihsize; 330 + 331 + /* Set vertical scaler bank length */ 332 + if (ihsize_after_pre_hsc_alt <= (max_hsize / 2)) 333 + vsc_tap_num_alt = 4; 334 + else if (ihsize_after_pre_hsc_alt <= max_hsize) 335 + vsc_tap_num_alt = prev_en ? 2 : 4; 336 + else 337 + vsc_tap_num_alt = prev_en ? 4 : 2; 338 + 339 + io_size.thsize = ihsize_after_pre_hsc_alt; 340 + io_size.tvsize = prev_en ? DIV_ROUND_UP(ivsize, 2) : ivsize; 341 + io_size.ohsize = cmps->width; 342 + io_size.ovsize = cmps->height; 343 + io_size.ihsize = ihsize; 344 + io_size.max_hsize = max_hsize; 345 + 346 + c3_isp_rsz_pps_size(rsz, &io_size); 347 + c3_isp_rsz_pps_lut(rsz, C3_ISP_PPS_LUT_CTYPE_0); 348 + c3_isp_rsz_pps_lut(rsz, C3_ISP_PPS_LUT_CTYPE_2); 349 + 350 + c3_isp_update_bits(rsz->isp, 351 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 352 + DISP0_PPS_SCALE_EN_VSC_TAP_NUM_MASK, 353 + DISP0_PPS_SCALE_EN_VSC_TAP_NUM(vsc_tap_num_alt)); 354 + c3_isp_update_bits(rsz->isp, 355 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 356 + DISP0_PPS_SCALE_EN_PREVSC_FLT_NUM_MASK, 357 + DISP0_PPS_SCALE_EN_PREVSC_FLT_NUM(prevsc_flt_num)); 358 + 359 + c3_isp_update_bits(rsz->isp, 360 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 361 + DISP0_PPS_SCALE_EN_PREVSC_RATE_MASK, 362 + DISP0_PPS_SCALE_EN_PREVSC_RATE(prev_en)); 363 + c3_isp_update_bits(rsz->isp, 364 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 365 + DISP0_PPS_SCALE_EN_PREHSC_RATE_MASK, 366 + DISP0_PPS_SCALE_EN_PREHSC_RATE(prehsc_rate)); 367 + 368 + c3_isp_update_bits(rsz->isp, 369 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 370 + DISP0_PPS_SCALE_EN_HSC_EN_MASK, 371 + DISP0_PPS_SCALE_EN_HSC_EN(hsc_en)); 372 + c3_isp_update_bits(rsz->isp, 373 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 374 + DISP0_PPS_SCALE_EN_VSC_EN_MASK, 375 + DISP0_PPS_SCALE_EN_VSC_EN(vsc_en)); 376 + c3_isp_update_bits(rsz->isp, 377 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 378 + DISP0_PPS_SCALE_EN_PREVSC_EN_MASK, 379 + DISP0_PPS_SCALE_EN_PREVSC_EN(prev_en)); 380 + c3_isp_update_bits(rsz->isp, 381 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 382 + DISP0_PPS_SCALE_EN_PREHSC_EN_MASK, 383 + DISP0_PPS_SCALE_EN_PREHSC_EN(preh_en)); 384 + 385 + c3_isp_update_bits(rsz->isp, 386 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 387 + DISP0_PPS_SCALE_EN_HSC_NOR_RS_BITS_MASK, 388 + DISP0_PPS_SCALE_EN_HSC_NOR_RS_BITS(9)); 389 + c3_isp_update_bits(rsz->isp, 390 + C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 391 + DISP0_PPS_SCALE_EN_VSC_NOR_RS_BITS_MASK, 392 + DISP0_PPS_SCALE_EN_VSC_NOR_RS_BITS(9)); 393 + 394 + return 0; 395 + } 396 + 397 + static void c3_isp_rsz_start(struct c3_isp_resizer *rsz, 398 + struct v4l2_subdev_state *state) 399 + { 400 + struct v4l2_mbus_framefmt *sink_fmt; 401 + struct v4l2_mbus_framefmt *src_fmt; 402 + const struct c3_isp_rsz_format_info *rsz_fmt; 403 + struct v4l2_rect *sink_crop; 404 + u32 mask; 405 + u32 val; 406 + 407 + sink_fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SINK); 408 + sink_crop = v4l2_subdev_state_get_crop(state, C3_ISP_RSZ_PAD_SINK); 409 + src_fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SOURCE); 410 + rsz_fmt = rsz_find_format_by_code(sink_fmt->code, C3_ISP_RSZ_PAD_SINK); 411 + 412 + if (rsz->id == C3_ISP_RSZ_0) { 413 + mask = ISP_TOP_DISPIN_SEL_DISP0_MASK; 414 + val = rsz_fmt->is_raw ? ISP_TOP_DISPIN_SEL_DISP0_MIPI_OUT 415 + : ISP_TOP_DISPIN_SEL_DISP0_CORE_OUT; 416 + } else if (rsz->id == C3_ISP_RSZ_1) { 417 + mask = ISP_TOP_DISPIN_SEL_DISP1_MASK; 418 + val = rsz_fmt->is_raw ? ISP_TOP_DISPIN_SEL_DISP1_MIPI_OUT 419 + : ISP_TOP_DISPIN_SEL_DISP1_CORE_OUT; 420 + } else { 421 + mask = ISP_TOP_DISPIN_SEL_DISP2_MASK; 422 + val = rsz_fmt->is_raw ? ISP_TOP_DISPIN_SEL_DISP2_MIPI_OUT 423 + : ISP_TOP_DISPIN_SEL_DISP2_CORE_OUT; 424 + } 425 + 426 + c3_isp_update_bits(rsz->isp, ISP_TOP_DISPIN_SEL, mask, val); 427 + 428 + c3_isp_write(rsz->isp, C3_ISP_DISP_REG(ISP_DISP0_TOP_IN_SIZE, rsz->id), 429 + ISP_DISP0_TOP_IN_SIZE_HSIZE(sink_fmt->width) | 430 + ISP_DISP0_TOP_IN_SIZE_VSIZE(sink_fmt->height)); 431 + 432 + c3_isp_write(rsz->isp, C3_ISP_DISP_REG(DISP0_TOP_CRP2_START, rsz->id), 433 + DISP0_TOP_CRP2_START_V_START(sink_crop->top) | 434 + DISP0_TOP_CRP2_START_H_START(sink_crop->left)); 435 + 436 + c3_isp_write(rsz->isp, C3_ISP_DISP_REG(DISP0_TOP_CRP2_SIZE, rsz->id), 437 + DISP0_TOP_CRP2_SIZE_V_SIZE(sink_crop->height) | 438 + DISP0_TOP_CRP2_SIZE_H_SIZE(sink_crop->width)); 439 + 440 + c3_isp_update_bits(rsz->isp, 441 + C3_ISP_DISP_REG(DISP0_TOP_TOP_CTRL, rsz->id), 442 + DISP0_TOP_TOP_CTRL_CROP2_EN_MASK, 443 + DISP0_TOP_TOP_CTRL_CROP2_EN); 444 + 445 + if (!rsz_fmt->is_raw) 446 + c3_isp_rsz_pps_enable(rsz, state); 447 + 448 + c3_isp_update_bits(rsz->isp, 449 + C3_ISP_DISP_REG(DISP0_TOP_OUT_SIZE, rsz->id), 450 + DISP0_TOP_OUT_SIZE_SCL_OUT_HEIGHT_MASK, 451 + DISP0_TOP_OUT_SIZE_SCL_OUT_HEIGHT(src_fmt->height)); 452 + c3_isp_update_bits(rsz->isp, 453 + C3_ISP_DISP_REG(DISP0_TOP_OUT_SIZE, rsz->id), 454 + DISP0_TOP_OUT_SIZE_SCL_OUT_WIDTH_MASK, 455 + DISP0_TOP_OUT_SIZE_SCL_OUT_WIDTH(src_fmt->width)); 456 + 457 + if (rsz->id == C3_ISP_RSZ_0) { 458 + mask = ISP_TOP_PATH_EN_DISP0_EN_MASK; 459 + val = ISP_TOP_PATH_EN_DISP0_EN; 460 + } else if (rsz->id == C3_ISP_RSZ_1) { 461 + mask = ISP_TOP_PATH_EN_DISP1_EN_MASK; 462 + val = ISP_TOP_PATH_EN_DISP1_EN; 463 + } else { 464 + mask = ISP_TOP_PATH_EN_DISP2_EN_MASK; 465 + val = ISP_TOP_PATH_EN_DISP2_EN; 466 + } 467 + 468 + c3_isp_update_bits(rsz->isp, ISP_TOP_PATH_EN, mask, val); 469 + } 470 + 471 + static void c3_isp_rsz_stop(struct c3_isp_resizer *rsz) 472 + { 473 + u32 mask; 474 + u32 val; 475 + 476 + if (rsz->id == C3_ISP_RSZ_0) { 477 + mask = ISP_TOP_PATH_EN_DISP0_EN_MASK; 478 + val = ISP_TOP_PATH_EN_DISP0_DIS; 479 + } else if (rsz->id == C3_ISP_RSZ_1) { 480 + mask = ISP_TOP_PATH_EN_DISP1_EN_MASK; 481 + val = ISP_TOP_PATH_EN_DISP1_DIS; 482 + } else { 483 + mask = ISP_TOP_PATH_EN_DISP2_EN_MASK; 484 + val = ISP_TOP_PATH_EN_DISP2_DIS; 485 + } 486 + 487 + c3_isp_update_bits(rsz->isp, ISP_TOP_PATH_EN, mask, val); 488 + 489 + c3_isp_update_bits(rsz->isp, 490 + C3_ISP_DISP_REG(DISP0_TOP_TOP_CTRL, rsz->id), 491 + DISP0_TOP_TOP_CTRL_CROP2_EN_MASK, 492 + DISP0_TOP_TOP_CTRL_CROP2_DIS); 493 + 494 + c3_isp_rsz_pps_disable(rsz); 495 + } 496 + 497 + static int c3_isp_rsz_enable_streams(struct v4l2_subdev *sd, 498 + struct v4l2_subdev_state *state, 499 + u32 pad, u64 streams_mask) 500 + { 501 + struct c3_isp_resizer *rsz = v4l2_get_subdevdata(sd); 502 + 503 + c3_isp_rsz_start(rsz, state); 504 + 505 + c3_isp_params_pre_cfg(rsz->isp); 506 + c3_isp_stats_pre_cfg(rsz->isp); 507 + 508 + return v4l2_subdev_enable_streams(rsz->src_sd, rsz->src_pad, BIT(0)); 509 + } 510 + 511 + static int c3_isp_rsz_disable_streams(struct v4l2_subdev *sd, 512 + struct v4l2_subdev_state *state, 513 + u32 pad, u64 streams_mask) 514 + { 515 + struct c3_isp_resizer *rsz = v4l2_get_subdevdata(sd); 516 + 517 + c3_isp_rsz_stop(rsz); 518 + 519 + return v4l2_subdev_disable_streams(rsz->src_sd, rsz->src_pad, BIT(0)); 520 + } 521 + 522 + static int c3_isp_rsz_enum_mbus_code(struct v4l2_subdev *sd, 523 + struct v4l2_subdev_state *state, 524 + struct v4l2_subdev_mbus_code_enum *code) 525 + { 526 + const struct c3_isp_rsz_format_info *info; 527 + 528 + info = rsz_find_format_by_index(code->index, code->pad); 529 + if (!info) 530 + return -EINVAL; 531 + 532 + code->code = info->mbus_code; 533 + 534 + return 0; 535 + } 536 + 537 + static void c3_isp_rsz_set_sink_fmt(struct v4l2_subdev_state *state, 538 + struct v4l2_subdev_format *format) 539 + { 540 + struct v4l2_mbus_framefmt *sink_fmt; 541 + struct v4l2_mbus_framefmt *src_fmt; 542 + struct v4l2_rect *sink_crop; 543 + struct v4l2_rect *sink_cmps; 544 + const struct c3_isp_rsz_format_info *rsz_fmt; 545 + 546 + sink_fmt = v4l2_subdev_state_get_format(state, format->pad); 547 + sink_crop = v4l2_subdev_state_get_crop(state, format->pad); 548 + sink_cmps = v4l2_subdev_state_get_compose(state, format->pad); 549 + src_fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SOURCE); 550 + 551 + rsz_fmt = rsz_find_format_by_code(format->format.code, format->pad); 552 + if (rsz_fmt) 553 + sink_fmt->code = format->format.code; 554 + else 555 + sink_fmt->code = C3_ISP_RSZ_DEF_PAD_FMT; 556 + 557 + sink_fmt->width = clamp_t(u32, format->format.width, 558 + C3_ISP_MIN_WIDTH, C3_ISP_MAX_WIDTH); 559 + sink_fmt->height = clamp_t(u32, format->format.height, 560 + C3_ISP_MIN_HEIGHT, C3_ISP_MAX_HEIGHT); 561 + sink_fmt->field = V4L2_FIELD_NONE; 562 + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 563 + 564 + if (rsz_fmt && rsz_fmt->is_raw) { 565 + sink_fmt->colorspace = V4L2_COLORSPACE_RAW; 566 + sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 567 + sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 568 + } else { 569 + sink_fmt->colorspace = V4L2_COLORSPACE_SRGB; 570 + sink_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 571 + sink_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 572 + } 573 + 574 + sink_crop->width = sink_fmt->width; 575 + sink_crop->height = sink_fmt->height; 576 + sink_crop->left = 0; 577 + sink_crop->top = 0; 578 + 579 + sink_cmps->width = sink_crop->width; 580 + sink_cmps->height = sink_crop->height; 581 + sink_cmps->left = 0; 582 + sink_cmps->top = 0; 583 + 584 + src_fmt->code = sink_fmt->code; 585 + src_fmt->width = sink_cmps->width; 586 + src_fmt->height = sink_cmps->height; 587 + 588 + format->format = *sink_fmt; 589 + } 590 + 591 + static void c3_isp_rsz_set_source_fmt(struct v4l2_subdev_state *state, 592 + struct v4l2_subdev_format *format) 593 + { 594 + struct v4l2_mbus_framefmt *src_fmt; 595 + struct v4l2_mbus_framefmt *sink_fmt; 596 + struct v4l2_rect *sink_cmps; 597 + const struct c3_isp_rsz_format_info *rsz_fmt; 598 + 599 + src_fmt = v4l2_subdev_state_get_format(state, format->pad); 600 + sink_fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SINK); 601 + sink_cmps = v4l2_subdev_state_get_compose(state, C3_ISP_RSZ_PAD_SINK); 602 + 603 + src_fmt->code = sink_fmt->code; 604 + src_fmt->width = sink_cmps->width; 605 + src_fmt->height = sink_cmps->height; 606 + src_fmt->field = V4L2_FIELD_NONE; 607 + src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 608 + 609 + rsz_fmt = rsz_find_format_by_code(src_fmt->code, format->pad); 610 + if (rsz_fmt->is_raw) { 611 + src_fmt->colorspace = V4L2_COLORSPACE_RAW; 612 + src_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 613 + src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 614 + } else { 615 + src_fmt->colorspace = V4L2_COLORSPACE_SRGB; 616 + src_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 617 + src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 618 + } 619 + 620 + format->format = *src_fmt; 621 + } 622 + 623 + static int c3_isp_rsz_set_fmt(struct v4l2_subdev *sd, 624 + struct v4l2_subdev_state *state, 625 + struct v4l2_subdev_format *format) 626 + { 627 + if (format->pad == C3_ISP_RSZ_PAD_SINK) 628 + c3_isp_rsz_set_sink_fmt(state, format); 629 + else 630 + c3_isp_rsz_set_source_fmt(state, format); 631 + 632 + return 0; 633 + } 634 + 635 + static int c3_isp_rsz_get_selection(struct v4l2_subdev *sd, 636 + struct v4l2_subdev_state *state, 637 + struct v4l2_subdev_selection *sel) 638 + { 639 + struct v4l2_mbus_framefmt *fmt; 640 + struct v4l2_rect *crop; 641 + struct v4l2_rect *cmps; 642 + 643 + if (sel->pad == C3_ISP_RSZ_PAD_SOURCE) 644 + return -EINVAL; 645 + 646 + switch (sel->target) { 647 + case V4L2_SEL_TGT_CROP_BOUNDS: 648 + fmt = v4l2_subdev_state_get_format(state, sel->pad); 649 + sel->r.width = fmt->width; 650 + sel->r.height = fmt->height; 651 + sel->r.left = 0; 652 + sel->r.top = 0; 653 + break; 654 + case V4L2_SEL_TGT_COMPOSE_BOUNDS: 655 + crop = v4l2_subdev_state_get_crop(state, sel->pad); 656 + sel->r.width = crop->width; 657 + sel->r.height = crop->height; 658 + sel->r.left = 0; 659 + sel->r.top = 0; 660 + break; 661 + case V4L2_SEL_TGT_CROP: 662 + crop = v4l2_subdev_state_get_crop(state, sel->pad); 663 + sel->r = *crop; 664 + break; 665 + case V4L2_SEL_TGT_COMPOSE: 666 + cmps = v4l2_subdev_state_get_compose(state, sel->pad); 667 + sel->r = *cmps; 668 + break; 669 + default: 670 + return -EINVAL; 671 + } 672 + 673 + return 0; 674 + } 675 + 676 + static int c3_isp_rsz_set_selection(struct v4l2_subdev *sd, 677 + struct v4l2_subdev_state *state, 678 + struct v4l2_subdev_selection *sel) 679 + { 680 + struct v4l2_mbus_framefmt *fmt; 681 + struct v4l2_mbus_framefmt *src_fmt; 682 + struct v4l2_rect *crop; 683 + struct v4l2_rect *cmps; 684 + 685 + if (sel->pad == C3_ISP_RSZ_PAD_SOURCE) 686 + return -EINVAL; 687 + 688 + switch (sel->target) { 689 + case V4L2_SEL_TGT_CROP: 690 + fmt = v4l2_subdev_state_get_format(state, sel->pad); 691 + crop = v4l2_subdev_state_get_crop(state, sel->pad); 692 + cmps = v4l2_subdev_state_get_compose(state, sel->pad); 693 + src_fmt = v4l2_subdev_state_get_format(state, 694 + C3_ISP_RSZ_PAD_SOURCE); 695 + 696 + sel->r.left = clamp_t(s32, sel->r.left, 0, fmt->width - 1); 697 + sel->r.top = clamp_t(s32, sel->r.top, 0, fmt->height - 1); 698 + sel->r.width = clamp(sel->r.width, C3_ISP_MIN_WIDTH, 699 + fmt->width - sel->r.left); 700 + sel->r.height = clamp(sel->r.height, C3_ISP_MIN_HEIGHT, 701 + fmt->height - sel->r.top); 702 + 703 + crop->width = ALIGN(sel->r.width, 2); 704 + crop->height = ALIGN(sel->r.height, 2); 705 + crop->left = sel->r.left; 706 + crop->top = sel->r.top; 707 + 708 + *cmps = *crop; 709 + 710 + src_fmt->code = fmt->code; 711 + src_fmt->width = cmps->width; 712 + src_fmt->height = cmps->height; 713 + 714 + sel->r = *crop; 715 + break; 716 + case V4L2_SEL_TGT_COMPOSE: 717 + crop = v4l2_subdev_state_get_crop(state, sel->pad); 718 + cmps = v4l2_subdev_state_get_compose(state, sel->pad); 719 + 720 + sel->r.left = 0; 721 + sel->r.top = 0; 722 + sel->r.width = clamp(sel->r.width, C3_ISP_MIN_WIDTH, 723 + crop->width); 724 + sel->r.height = clamp(sel->r.height, C3_ISP_MIN_HEIGHT, 725 + crop->height); 726 + 727 + cmps->width = ALIGN(sel->r.width, 2); 728 + cmps->height = ALIGN(sel->r.height, 2); 729 + cmps->left = sel->r.left; 730 + cmps->top = sel->r.top; 731 + 732 + sel->r = *cmps; 733 + 734 + fmt = v4l2_subdev_state_get_format(state, 735 + C3_ISP_RSZ_PAD_SOURCE); 736 + fmt->width = cmps->width; 737 + fmt->height = cmps->height; 738 + break; 739 + default: 740 + return -EINVAL; 741 + } 742 + 743 + return 0; 744 + } 745 + 746 + static int c3_isp_rsz_init_state(struct v4l2_subdev *sd, 747 + struct v4l2_subdev_state *state) 748 + { 749 + struct v4l2_mbus_framefmt *fmt; 750 + struct v4l2_rect *crop; 751 + struct v4l2_rect *cmps; 752 + 753 + fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SINK); 754 + fmt->width = C3_ISP_DEFAULT_WIDTH; 755 + fmt->height = C3_ISP_DEFAULT_HEIGHT; 756 + fmt->field = V4L2_FIELD_NONE; 757 + fmt->code = C3_ISP_RSZ_DEF_PAD_FMT; 758 + fmt->colorspace = V4L2_COLORSPACE_SRGB; 759 + fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 760 + fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 761 + fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 762 + 763 + crop = v4l2_subdev_state_get_crop(state, C3_ISP_RSZ_PAD_SINK); 764 + crop->width = C3_ISP_DEFAULT_WIDTH; 765 + crop->height = C3_ISP_DEFAULT_HEIGHT; 766 + crop->left = 0; 767 + crop->top = 0; 768 + 769 + cmps = v4l2_subdev_state_get_compose(state, C3_ISP_RSZ_PAD_SINK); 770 + cmps->width = C3_ISP_DEFAULT_WIDTH; 771 + cmps->height = C3_ISP_DEFAULT_HEIGHT; 772 + cmps->left = 0; 773 + cmps->top = 0; 774 + 775 + fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SOURCE); 776 + fmt->width = cmps->width; 777 + fmt->height = cmps->height; 778 + fmt->field = V4L2_FIELD_NONE; 779 + fmt->code = C3_ISP_RSZ_DEF_PAD_FMT; 780 + fmt->colorspace = V4L2_COLORSPACE_SRGB; 781 + fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 782 + fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 783 + fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 784 + 785 + return 0; 786 + } 787 + 788 + static const struct v4l2_subdev_pad_ops c3_isp_rsz_pad_ops = { 789 + .enum_mbus_code = c3_isp_rsz_enum_mbus_code, 790 + .get_fmt = v4l2_subdev_get_fmt, 791 + .set_fmt = c3_isp_rsz_set_fmt, 792 + .get_selection = c3_isp_rsz_get_selection, 793 + .set_selection = c3_isp_rsz_set_selection, 794 + .enable_streams = c3_isp_rsz_enable_streams, 795 + .disable_streams = c3_isp_rsz_disable_streams, 796 + }; 797 + 798 + static const struct v4l2_subdev_ops c3_isp_rsz_subdev_ops = { 799 + .pad = &c3_isp_rsz_pad_ops, 800 + }; 801 + 802 + static const struct v4l2_subdev_internal_ops c3_isp_rsz_internal_ops = { 803 + .init_state = c3_isp_rsz_init_state, 804 + }; 805 + 806 + /* Media entity operations */ 807 + static const struct media_entity_operations c3_isp_rsz_entity_ops = { 808 + .link_validate = v4l2_subdev_link_validate, 809 + }; 810 + 811 + static int c3_isp_rsz_register(struct c3_isp_resizer *rsz) 812 + { 813 + struct v4l2_subdev *sd = &rsz->sd; 814 + int ret; 815 + 816 + v4l2_subdev_init(sd, &c3_isp_rsz_subdev_ops); 817 + sd->owner = THIS_MODULE; 818 + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 819 + sd->internal_ops = &c3_isp_rsz_internal_ops; 820 + snprintf(sd->name, sizeof(sd->name), "c3-isp-resizer%u", rsz->id); 821 + 822 + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; 823 + sd->entity.ops = &c3_isp_rsz_entity_ops; 824 + 825 + sd->dev = rsz->isp->dev; 826 + v4l2_set_subdevdata(sd, rsz); 827 + 828 + rsz->pads[C3_ISP_RSZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 829 + rsz->pads[C3_ISP_RSZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 830 + ret = media_entity_pads_init(&sd->entity, C3_ISP_RSZ_PAD_MAX, 831 + rsz->pads); 832 + if (ret) 833 + return ret; 834 + 835 + ret = v4l2_subdev_init_finalize(sd); 836 + if (ret) 837 + goto err_entity_cleanup; 838 + 839 + ret = v4l2_device_register_subdev(&rsz->isp->v4l2_dev, sd); 840 + if (ret) 841 + goto err_subdev_cleanup; 842 + 843 + return 0; 844 + 845 + err_subdev_cleanup: 846 + v4l2_subdev_cleanup(sd); 847 + err_entity_cleanup: 848 + media_entity_cleanup(&sd->entity); 849 + return ret; 850 + } 851 + 852 + static void c3_isp_rsz_unregister(struct c3_isp_resizer *rsz) 853 + { 854 + struct v4l2_subdev *sd = &rsz->sd; 855 + 856 + v4l2_device_unregister_subdev(sd); 857 + v4l2_subdev_cleanup(sd); 858 + media_entity_cleanup(&sd->entity); 859 + } 860 + 861 + int c3_isp_resizers_register(struct c3_isp_device *isp) 862 + { 863 + int ret; 864 + 865 + for (unsigned int i = C3_ISP_RSZ_0; i < C3_ISP_NUM_RSZ; i++) { 866 + struct c3_isp_resizer *rsz = &isp->resizers[i]; 867 + 868 + rsz->id = i; 869 + rsz->isp = isp; 870 + rsz->src_sd = &isp->core.sd; 871 + rsz->src_pad = C3_ISP_CORE_PAD_SOURCE_VIDEO_0 + i; 872 + 873 + ret = c3_isp_rsz_register(rsz); 874 + if (ret) { 875 + rsz->isp = NULL; 876 + c3_isp_resizers_unregister(isp); 877 + return ret; 878 + } 879 + } 880 + 881 + return 0; 882 + } 883 + 884 + void c3_isp_resizers_unregister(struct c3_isp_device *isp) 885 + { 886 + for (unsigned int i = C3_ISP_RSZ_0; i < C3_ISP_NUM_RSZ; i++) { 887 + struct c3_isp_resizer *rsz = &isp->resizers[i]; 888 + 889 + if (rsz->isp) 890 + c3_isp_rsz_unregister(rsz); 891 + } 892 + }
+326
drivers/media/platform/amlogic/c3/isp/c3-isp-stats.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + */ 5 + 6 + #include <linux/cleanup.h> 7 + #include <linux/media/amlogic/c3-isp-config.h> 8 + #include <linux/pm_runtime.h> 9 + 10 + #include <media/v4l2-ioctl.h> 11 + #include <media/v4l2-mc.h> 12 + #include <media/videobuf2-dma-contig.h> 13 + 14 + #include "c3-isp-common.h" 15 + #include "c3-isp-regs.h" 16 + 17 + /* Hardware configuration */ 18 + 19 + static void c3_isp_stats_cfg_dmawr_addr(struct c3_isp_stats *stats) 20 + { 21 + u32 awb_dma_size = sizeof(struct c3_isp_awb_stats); 22 + u32 ae_dma_size = sizeof(struct c3_isp_ae_stats); 23 + u32 awb_dma_addr = stats->buff->dma_addr; 24 + u32 af_dma_addr; 25 + u32 ae_dma_addr; 26 + 27 + ae_dma_addr = awb_dma_addr + awb_dma_size; 28 + af_dma_addr = ae_dma_addr + ae_dma_size; 29 + 30 + c3_isp_update_bits(stats->isp, VIU_DMAWR_BADDR0, 31 + VIU_DMAWR_BADDR0_AF_STATS_BASE_ADDR_MASK, 32 + VIU_DMAWR_BADDR0_AF_STATS_BASE_ADDR(af_dma_addr)); 33 + 34 + c3_isp_update_bits(stats->isp, VIU_DMAWR_BADDR1, 35 + VIU_DMAWR_BADDR1_AWB_STATS_BASE_ADDR_MASK, 36 + VIU_DMAWR_BADDR1_AWB_STATS_BASE_ADDR(awb_dma_addr)); 37 + 38 + c3_isp_update_bits(stats->isp, VIU_DMAWR_BADDR2, 39 + VIU_DMAWR_BADDR2_AE_STATS_BASE_ADDR_MASK, 40 + VIU_DMAWR_BADDR2_AE_STATS_BASE_ADDR(ae_dma_addr)); 41 + } 42 + 43 + static void c3_isp_stats_cfg_buff(struct c3_isp_stats *stats) 44 + { 45 + stats->buff = 46 + list_first_entry_or_null(&stats->pending, 47 + struct c3_isp_stats_buffer, list); 48 + if (stats->buff) { 49 + c3_isp_stats_cfg_dmawr_addr(stats); 50 + list_del(&stats->buff->list); 51 + } 52 + } 53 + 54 + void c3_isp_stats_pre_cfg(struct c3_isp_device *isp) 55 + { 56 + struct c3_isp_stats *stats = &isp->stats; 57 + u32 dma_size; 58 + 59 + c3_isp_update_bits(stats->isp, ISP_AF_EN_CTRL, 60 + ISP_AF_EN_CTRL_STAT_SEL_MASK, 61 + ISP_AF_EN_CTRL_STAT_SEL_NEW); 62 + c3_isp_update_bits(stats->isp, ISP_AE_CTRL, 63 + ISP_AE_CTRL_LUMA_MODE_MASK, 64 + ISP_AE_CTRL_LUMA_MODE_FILTER); 65 + 66 + /* The unit of dma_size is 16 bytes */ 67 + dma_size = sizeof(struct c3_isp_af_stats) / C3_ISP_DMA_SIZE_ALIGN_BYTES; 68 + c3_isp_update_bits(stats->isp, VIU_DMAWR_SIZE0, 69 + VIU_DMAWR_SIZE0_AF_STATS_SIZE_MASK, 70 + VIU_DMAWR_SIZE0_AF_STATS_SIZE(dma_size)); 71 + 72 + dma_size = sizeof(struct c3_isp_awb_stats) / 73 + C3_ISP_DMA_SIZE_ALIGN_BYTES; 74 + c3_isp_update_bits(stats->isp, VIU_DMAWR_SIZE0, 75 + VIU_DMAWR_SIZE0_AWB_STATS_SIZE_MASK, 76 + VIU_DMAWR_SIZE0_AWB_STATS_SIZE(dma_size)); 77 + 78 + dma_size = sizeof(struct c3_isp_ae_stats) / C3_ISP_DMA_SIZE_ALIGN_BYTES; 79 + c3_isp_update_bits(stats->isp, VIU_DMAWR_SIZE1, 80 + VIU_DMAWR_SIZE1_AE_STATS_SIZE_MASK, 81 + VIU_DMAWR_SIZE1_AE_STATS_SIZE(dma_size)); 82 + 83 + guard(spinlock_irqsave)(&stats->buff_lock); 84 + 85 + c3_isp_stats_cfg_buff(stats); 86 + } 87 + 88 + static int c3_isp_stats_querycap(struct file *file, void *fh, 89 + struct v4l2_capability *cap) 90 + { 91 + strscpy(cap->driver, C3_ISP_DRIVER_NAME, sizeof(cap->driver)); 92 + strscpy(cap->card, "AML C3 ISP", sizeof(cap->card)); 93 + 94 + return 0; 95 + } 96 + 97 + static int c3_isp_stats_enum_fmt(struct file *file, void *fh, 98 + struct v4l2_fmtdesc *f) 99 + { 100 + struct c3_isp_stats *stats = video_drvdata(file); 101 + 102 + if (f->index > 0 || f->type != stats->vb2_q.type) 103 + return -EINVAL; 104 + 105 + f->pixelformat = V4L2_META_FMT_C3ISP_STATS; 106 + 107 + return 0; 108 + } 109 + 110 + static int c3_isp_stats_g_fmt(struct file *file, void *fh, 111 + struct v4l2_format *f) 112 + { 113 + struct c3_isp_stats *stats = video_drvdata(file); 114 + 115 + f->fmt.meta = stats->vfmt.fmt.meta; 116 + 117 + return 0; 118 + } 119 + 120 + static const struct v4l2_ioctl_ops isp_stats_v4l2_ioctl_ops = { 121 + .vidioc_querycap = c3_isp_stats_querycap, 122 + .vidioc_enum_fmt_meta_cap = c3_isp_stats_enum_fmt, 123 + .vidioc_g_fmt_meta_cap = c3_isp_stats_g_fmt, 124 + .vidioc_s_fmt_meta_cap = c3_isp_stats_g_fmt, 125 + .vidioc_try_fmt_meta_cap = c3_isp_stats_g_fmt, 126 + .vidioc_reqbufs = vb2_ioctl_reqbufs, 127 + .vidioc_querybuf = vb2_ioctl_querybuf, 128 + .vidioc_qbuf = vb2_ioctl_qbuf, 129 + .vidioc_expbuf = vb2_ioctl_expbuf, 130 + .vidioc_dqbuf = vb2_ioctl_dqbuf, 131 + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 132 + .vidioc_create_bufs = vb2_ioctl_create_bufs, 133 + .vidioc_streamon = vb2_ioctl_streamon, 134 + .vidioc_streamoff = vb2_ioctl_streamoff, 135 + }; 136 + 137 + static const struct v4l2_file_operations isp_stats_v4l2_fops = { 138 + .open = v4l2_fh_open, 139 + .release = vb2_fop_release, 140 + .poll = vb2_fop_poll, 141 + .unlocked_ioctl = video_ioctl2, 142 + .mmap = vb2_fop_mmap, 143 + }; 144 + 145 + static int c3_isp_stats_vb2_queue_setup(struct vb2_queue *q, 146 + unsigned int *num_buffers, 147 + unsigned int *num_planes, 148 + unsigned int sizes[], 149 + struct device *alloc_devs[]) 150 + { 151 + if (*num_planes) { 152 + if (*num_planes != 1) 153 + return -EINVAL; 154 + 155 + if (sizes[0] < sizeof(struct c3_isp_stats_info)) 156 + return -EINVAL; 157 + 158 + return 0; 159 + } 160 + 161 + *num_planes = 1; 162 + sizes[0] = sizeof(struct c3_isp_stats_info); 163 + 164 + return 0; 165 + } 166 + 167 + static void c3_isp_stats_vb2_buf_queue(struct vb2_buffer *vb) 168 + { 169 + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 170 + struct c3_isp_stats_buffer *buf = 171 + container_of(v4l2_buf, struct c3_isp_stats_buffer, vb); 172 + struct c3_isp_stats *stats = vb2_get_drv_priv(vb->vb2_queue); 173 + 174 + guard(spinlock_irqsave)(&stats->buff_lock); 175 + 176 + list_add_tail(&buf->list, &stats->pending); 177 + } 178 + 179 + static int c3_isp_stats_vb2_buf_prepare(struct vb2_buffer *vb) 180 + { 181 + struct c3_isp_stats *stats = vb2_get_drv_priv(vb->vb2_queue); 182 + unsigned int size = stats->vfmt.fmt.meta.buffersize; 183 + 184 + if (vb2_plane_size(vb, 0) < size) { 185 + dev_err(stats->isp->dev, 186 + "User buffer too small (%ld < %u)\n", 187 + vb2_plane_size(vb, 0), size); 188 + return -EINVAL; 189 + } 190 + 191 + vb2_set_plane_payload(vb, 0, size); 192 + 193 + return 0; 194 + } 195 + 196 + static int c3_isp_stats_vb2_buf_init(struct vb2_buffer *vb) 197 + { 198 + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 199 + struct c3_isp_stats_buffer *buf = 200 + container_of(v4l2_buf, struct c3_isp_stats_buffer, vb); 201 + 202 + buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); 203 + 204 + return 0; 205 + } 206 + 207 + static void c3_isp_stats_vb2_stop_streaming(struct vb2_queue *q) 208 + { 209 + struct c3_isp_stats *stats = vb2_get_drv_priv(q); 210 + 211 + guard(spinlock_irqsave)(&stats->buff_lock); 212 + 213 + if (stats->buff) { 214 + vb2_buffer_done(&stats->buff->vb.vb2_buf, VB2_BUF_STATE_ERROR); 215 + stats->buff = NULL; 216 + } 217 + 218 + while (!list_empty(&stats->pending)) { 219 + struct c3_isp_stats_buffer *buff; 220 + 221 + buff = list_first_entry(&stats->pending, 222 + struct c3_isp_stats_buffer, list); 223 + list_del(&buff->list); 224 + vb2_buffer_done(&buff->vb.vb2_buf, VB2_BUF_STATE_ERROR); 225 + } 226 + } 227 + 228 + static const struct vb2_ops isp_stats_vb2_ops = { 229 + .queue_setup = c3_isp_stats_vb2_queue_setup, 230 + .buf_queue = c3_isp_stats_vb2_buf_queue, 231 + .buf_prepare = c3_isp_stats_vb2_buf_prepare, 232 + .buf_init = c3_isp_stats_vb2_buf_init, 233 + .stop_streaming = c3_isp_stats_vb2_stop_streaming, 234 + }; 235 + 236 + int c3_isp_stats_register(struct c3_isp_device *isp) 237 + { 238 + struct c3_isp_stats *stats = &isp->stats; 239 + struct video_device *vdev = &stats->vdev; 240 + struct vb2_queue *vb2_q = &stats->vb2_q; 241 + int ret; 242 + 243 + memset(stats, 0, sizeof(*stats)); 244 + stats->vfmt.fmt.meta.dataformat = V4L2_META_FMT_C3ISP_STATS; 245 + stats->vfmt.fmt.meta.buffersize = sizeof(struct c3_isp_stats_info); 246 + stats->isp = isp; 247 + INIT_LIST_HEAD(&stats->pending); 248 + spin_lock_init(&stats->buff_lock); 249 + 250 + mutex_init(&stats->lock); 251 + 252 + snprintf(vdev->name, sizeof(vdev->name), "c3-isp-stats"); 253 + vdev->fops = &isp_stats_v4l2_fops; 254 + vdev->ioctl_ops = &isp_stats_v4l2_ioctl_ops; 255 + vdev->v4l2_dev = &isp->v4l2_dev; 256 + vdev->lock = &stats->lock; 257 + vdev->minor = -1; 258 + vdev->queue = vb2_q; 259 + vdev->release = video_device_release_empty; 260 + vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; 261 + vdev->vfl_dir = VFL_DIR_RX; 262 + video_set_drvdata(vdev, stats); 263 + 264 + vb2_q->drv_priv = stats; 265 + vb2_q->mem_ops = &vb2_dma_contig_memops; 266 + vb2_q->ops = &isp_stats_vb2_ops; 267 + vb2_q->type = V4L2_BUF_TYPE_META_CAPTURE; 268 + vb2_q->io_modes = VB2_DMABUF | VB2_MMAP; 269 + vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 270 + vb2_q->buf_struct_size = sizeof(struct c3_isp_stats_buffer); 271 + vb2_q->dev = isp->dev; 272 + vb2_q->lock = &stats->lock; 273 + vb2_q->min_queued_buffers = 2; 274 + 275 + ret = vb2_queue_init(vb2_q); 276 + if (ret) 277 + goto err_destroy; 278 + 279 + stats->pad.flags = MEDIA_PAD_FL_SINK; 280 + ret = media_entity_pads_init(&vdev->entity, 1, &stats->pad); 281 + if (ret) 282 + goto err_queue_release; 283 + 284 + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 285 + if (ret) { 286 + dev_err(isp->dev, 287 + "Failed to register %s: %d\n", vdev->name, ret); 288 + goto err_entity_cleanup; 289 + } 290 + 291 + return 0; 292 + 293 + err_entity_cleanup: 294 + media_entity_cleanup(&vdev->entity); 295 + err_queue_release: 296 + vb2_queue_release(vb2_q); 297 + err_destroy: 298 + mutex_destroy(&stats->lock); 299 + return ret; 300 + } 301 + 302 + void c3_isp_stats_unregister(struct c3_isp_device *isp) 303 + { 304 + struct c3_isp_stats *stats = &isp->stats; 305 + 306 + vb2_queue_release(&stats->vb2_q); 307 + media_entity_cleanup(&stats->vdev.entity); 308 + video_unregister_device(&stats->vdev); 309 + mutex_destroy(&stats->lock); 310 + } 311 + 312 + void c3_isp_stats_isr(struct c3_isp_device *isp) 313 + { 314 + struct c3_isp_stats *stats = &isp->stats; 315 + 316 + guard(spinlock_irqsave)(&stats->buff_lock); 317 + 318 + if (stats->buff) { 319 + stats->buff->vb.sequence = stats->isp->frm_sequence; 320 + stats->buff->vb.vb2_buf.timestamp = ktime_get(); 321 + stats->buff->vb.field = V4L2_FIELD_NONE; 322 + vb2_buffer_done(&stats->buff->vb.vb2_buf, VB2_BUF_STATE_DONE); 323 + } 324 + 325 + c3_isp_stats_cfg_buff(stats); 326 + }