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

Configure Feed

Select the types of activity you want to include in your feed.

media: platform: Add mali-c55 parameters video node

Add a new code file to the mali-c55 driver that registers an output
video node for userspace to queue buffers of parameters to. Handlers
are included to program the statistics generation plus the white
balance, black level correction and mesh shading correction blocks.

Update the rest of the driver to register and link the new video node

Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Acked-by: Nayden Kanchev <nayden.kanchev@arm.com>
Co-developed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
[hverkuil: remove deprecated vb2_ops_wait_prepare/finish callbacks]

authored by

Daniel Scally and committed by
Hans Verkuil
01535ea0 08a99369

+1021 -1
+1
drivers/media/platform/arm/mali-c55/Kconfig
··· 7 7 select GENERIC_PHY_MIPI_DPHY 8 8 select MEDIA_CONTROLLER 9 9 select V4L2_FWNODE 10 + select V4L2_ISP 10 11 select VIDEO_V4L2_SUBDEV_API 11 12 select VIDEOBUF2_DMA_CONTIG 12 13 select VIDEOBUF2_VMALLOC
+1
drivers/media/platform/arm/mali-c55/Makefile
··· 3 3 mali-c55-y := mali-c55-capture.o \ 4 4 mali-c55-core.o \ 5 5 mali-c55-isp.o \ 6 + mali-c55-params.o \ 6 7 mali-c55-resizer.o \ 7 8 mali-c55-stats.o \ 8 9 mali-c55-tpg.o
+28
drivers/media/platform/arm/mali-c55/mali-c55-common.h
··· 21 21 #include <media/v4l2-ctrls.h> 22 22 #include <media/v4l2-dev.h> 23 23 #include <media/v4l2-device.h> 24 + #include <media/v4l2-isp.h> 24 25 #include <media/v4l2-subdev.h> 25 26 #include <media/videobuf2-core.h> 26 27 #include <media/videobuf2-v4l2.h> ··· 45 44 struct mali_c55; 46 45 struct mali_c55_cap_dev; 47 46 struct media_pipeline; 47 + struct mali_c55_params_buffer; 48 48 struct platform_device; 49 49 struct resource; 50 50 ··· 54 52 MALI_C55_ISP_PAD_SOURCE_VIDEO, 55 53 MALI_C55_ISP_PAD_SOURCE_BYPASS, 56 54 MALI_C55_ISP_PAD_SOURCE_STATS, 55 + MALI_C55_ISP_PAD_SINK_PARAMS, 57 56 MALI_C55_ISP_NUM_PADS, 58 57 }; 59 58 ··· 173 170 bool failed; 174 171 }; 175 172 173 + struct mali_c55_params_buf { 174 + struct vb2_v4l2_buffer vb; 175 + struct list_head queue; 176 + struct v4l2_isp_params_buffer *config; 177 + }; 178 + 176 179 struct mali_c55_stats { 180 + struct mali_c55 *mali_c55; 181 + struct video_device vdev; 182 + struct vb2_queue queue; 183 + struct media_pad pad; 184 + /* Mutex to provide to vb2 */ 185 + struct mutex lock; 186 + 187 + struct { 188 + /* Spinlock to guard buffer queue */ 189 + spinlock_t lock; 190 + struct list_head queue; 191 + } buffers; 192 + }; 193 + 194 + struct mali_c55_params { 177 195 struct mali_c55 *mali_c55; 178 196 struct video_device vdev; 179 197 struct vb2_queue queue; ··· 252 228 struct mali_c55_isp isp; 253 229 struct mali_c55_resizer resizers[MALI_C55_NUM_RSZS]; 254 230 struct mali_c55_cap_dev cap_devs[MALI_C55_NUM_CAP_DEVS]; 231 + struct mali_c55_params params; 255 232 struct mali_c55_stats stats; 256 233 257 234 struct mali_c55_context context; ··· 284 259 void mali_c55_unregister_capture_devs(struct mali_c55 *mali_c55); 285 260 int mali_c55_register_stats(struct mali_c55 *mali_c55); 286 261 void mali_c55_unregister_stats(struct mali_c55 *mali_c55); 262 + int mali_c55_register_params(struct mali_c55 *mali_c55); 263 + void mali_c55_unregister_params(struct mali_c55 *mali_c55); 287 264 struct mali_c55_context *mali_c55_get_active_context(struct mali_c55 *mali_c55); 288 265 void mali_c55_set_plane_done(struct mali_c55_cap_dev *cap_dev, 289 266 enum mali_c55_planes plane); ··· 305 278 bool mali_c55_pipeline_ready(struct mali_c55 *mali_c55); 306 279 void mali_c55_stats_fill_buffer(struct mali_c55 *mali_c55, 307 280 enum mali_c55_config_spaces cfg_space); 281 + void mali_c55_params_write_config(struct mali_c55 *mali_c55); 308 282 309 283 #endif /* _MALI_C55_COMMON_H */
+26
drivers/media/platform/arm/mali-c55/mali-c55-core.c
··· 294 294 goto err_remove_links; 295 295 } 296 296 297 + ret = media_create_pad_link(&mali_c55->params.vdev.entity, 0, 298 + &mali_c55->isp.sd.entity, 299 + MALI_C55_ISP_PAD_SINK_PARAMS, 300 + MEDIA_LNK_FL_ENABLED); 301 + if (ret) { 302 + dev_err(mali_c55->dev, 303 + "failed to link ISP and parameters video node\n"); 304 + goto err_remove_links; 305 + } 306 + 297 307 return 0; 298 308 299 309 err_remove_links: ··· 318 308 mali_c55_unregister_isp(mali_c55); 319 309 mali_c55_unregister_resizers(mali_c55); 320 310 mali_c55_unregister_capture_devs(mali_c55); 311 + mali_c55_unregister_params(mali_c55); 321 312 mali_c55_unregister_stats(mali_c55); 322 313 } 323 314 ··· 352 341 goto err_unregister_entities; 353 342 354 343 ret = mali_c55_register_capture_devs(mali_c55); 344 + if (ret) 345 + goto err_unregister_entities; 346 + 347 + ret = mali_c55_register_params(mali_c55); 355 348 if (ret) 356 349 goto err_unregister_entities; 357 350 ··· 448 433 sizeof(mali_c55->media_dev.model)); 449 434 450 435 media_device_init(&mali_c55->media_dev); 436 + 451 437 ret = media_device_register(&mali_c55->media_dev); 452 438 if (ret) 453 439 goto err_cleanup_media_device; ··· 508 492 { 509 493 struct mali_c55_cap_dev *fr = &mali_c55->cap_devs[MALI_C55_CAP_DEV_FR]; 510 494 struct mali_c55_cap_dev *ds = &mali_c55->cap_devs[MALI_C55_CAP_DEV_DS]; 495 + struct mali_c55_params *params = &mali_c55->params; 511 496 struct mali_c55_stats *stats = &mali_c55->stats; 512 497 513 498 return vb2_start_streaming_called(&fr->queue) && 514 499 (!(mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) || 515 500 vb2_start_streaming_called(&ds->queue)) && 501 + vb2_start_streaming_called(&params->queue) && 516 502 vb2_start_streaming_called(&stats->queue); 517 503 } 518 504 ··· 591 573 curr_config &= MALI_C55_REG_PING_PONG_READ_MASK; 592 574 curr_config >>= ffs(MALI_C55_REG_PING_PONG_READ_MASK) - 1; 593 575 mali_c55->next_config = curr_config ^ 1; 576 + 577 + /* 578 + * Write the configuration parameters received from 579 + * userspace into the configuration buffer, which will 580 + * be transferred to the 'next' active config space at 581 + * by mali_c55_swap_next_config(). 582 + */ 583 + mali_c55_params_write_config(mali_c55); 594 584 595 585 mali_c55_stats_fill_buffer(mali_c55, 596 586 mali_c55->next_config ^ 1);
+22 -1
drivers/media/platform/arm/mali-c55/mali-c55-isp.c
··· 151 151 cfg->bypass ? MALI_C55_ISP_RAW_BYPASS_BYPASS_MASK : 152 152 0x00); 153 153 154 + mali_c55_params_write_config(mali_c55); 154 155 ret = mali_c55_config_write(ctx, MALI_C55_CONFIG_PING, true); 155 156 if (ret) { 156 157 dev_err(mali_c55->dev, "failed to write ISP config\n"); ··· 495 494 496 495 src_fmt = v4l2_subdev_state_get_format(state, 497 496 MALI_C55_ISP_PAD_SOURCE_STATS); 497 + sink_fmt = v4l2_subdev_state_get_format(state, 498 + MALI_C55_ISP_PAD_SINK_PARAMS); 498 499 499 500 src_fmt->width = 0; 500 501 src_fmt->height = 0; 501 502 src_fmt->field = V4L2_FIELD_NONE; 502 503 src_fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; 504 + 505 + sink_fmt->width = 0; 506 + sink_fmt->height = 0; 507 + sink_fmt->field = V4L2_FIELD_NONE; 508 + sink_fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; 503 509 504 510 return 0; 505 511 } ··· 515 507 .init_state = mali_c55_isp_init_state, 516 508 }; 517 509 510 + static int mali_c55_subdev_link_validate(struct media_link *link) 511 + { 512 + /* 513 + * Skip validation for the parameters sink pad, as the source is not 514 + * a subdevice. 515 + */ 516 + if (link->sink->index == MALI_C55_ISP_PAD_SINK_PARAMS) 517 + return 0; 518 + 519 + return v4l2_subdev_link_validate(link); 520 + } 521 + 518 522 static const struct media_entity_operations mali_c55_isp_media_ops = { 519 - .link_validate = v4l2_subdev_link_validate, 523 + .link_validate = mali_c55_subdev_link_validate, 520 524 }; 521 525 522 526 static int mali_c55_isp_s_ctrl(struct v4l2_ctrl *ctrl) ··· 617 597 isp->pads[MALI_C55_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; 618 598 isp->pads[MALI_C55_ISP_PAD_SOURCE_BYPASS].flags = MEDIA_PAD_FL_SOURCE; 619 599 isp->pads[MALI_C55_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; 600 + isp->pads[MALI_C55_ISP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK; 620 601 621 602 ret = media_entity_pads_init(&sd->entity, MALI_C55_ISP_NUM_PADS, 622 603 isp->pads);
+815
drivers/media/platform/arm/mali-c55/mali-c55-params.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * ARM Mali-C55 ISP Driver - Configuration parameters output device 4 + * 5 + * Copyright (C) 2025 Ideas on Board Oy 6 + */ 7 + #include <linux/media/arm/mali-c55-config.h> 8 + #include <linux/pm_runtime.h> 9 + 10 + #include <media/media-entity.h> 11 + #include <media/v4l2-dev.h> 12 + #include <media/v4l2-event.h> 13 + #include <media/v4l2-fh.h> 14 + #include <media/v4l2-ioctl.h> 15 + #include <media/v4l2-isp.h> 16 + #include <media/videobuf2-core.h> 17 + #include <media/videobuf2-dma-contig.h> 18 + 19 + #include "mali-c55-common.h" 20 + #include "mali-c55-registers.h" 21 + 22 + /** 23 + * union mali_c55_params_block - Generalisation of a parameter block 24 + * 25 + * This union allows the driver to treat a block as a generic pointer to this 26 + * union and safely access the header and block-specific struct without having 27 + * to resort to casting. The header member is accessed first, and the type field 28 + * checked which allows the driver to determine which of the other members 29 + * should be used. The data member at the end allows a pointer to an address 30 + * within the data member of :c:type:`mali_c55_params_buffer` to initialise a 31 + * union variable. 32 + * 33 + * @header: Pointer to the shared header struct embedded as the 34 + * first member of all the possible other members (except 35 + * @data). This member would be accessed first and the type 36 + * field checked to determine which of the other members 37 + * should be accessed. 38 + * @sensor_offs: For header->type == MALI_C55_PARAM_BLOCK_SENSOR_OFFS 39 + * @aexp_hist: For header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST and 40 + * header->type == MALI_C55_PARAM_BLOCK_AEXP_IHIST 41 + * @aexp_weights: For header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS 42 + * and header->type = MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS 43 + * @digital_gain: For header->type == MALI_C55_PARAM_BLOCK_DIGITAL_GAIN 44 + * @awb_gains: For header->type == MALI_C55_PARAM_BLOCK_AWB_GAINS and 45 + * header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP 46 + * @awb_config: For header->type == MALI_C55_PARAM_MESH_SHADING_CONFIG 47 + * @shading_config: For header->type == MALI_C55_PARAM_MESH_SHADING_SELECTION 48 + * @shading_selection: For header->type == MALI_C55_PARAM_BLOCK_SENSOR_OFFS 49 + * @data: Allows easy initialisation of a union variable with a 50 + * pointer into a __u8 array. 51 + */ 52 + union mali_c55_params_block { 53 + const struct v4l2_isp_params_block_header *header; 54 + const struct mali_c55_params_sensor_off_preshading *sensor_offs; 55 + const struct mali_c55_params_aexp_hist *aexp_hist; 56 + const struct mali_c55_params_aexp_weights *aexp_weights; 57 + const struct mali_c55_params_digital_gain *digital_gain; 58 + const struct mali_c55_params_awb_gains *awb_gains; 59 + const struct mali_c55_params_awb_config *awb_config; 60 + const struct mali_c55_params_mesh_shading_config *shading_config; 61 + const struct mali_c55_params_mesh_shading_selection *shading_selection; 62 + const __u8 *data; 63 + }; 64 + 65 + typedef void (*mali_c55_params_handler)(struct mali_c55 *mali_c55, 66 + union mali_c55_params_block block); 67 + 68 + #define to_mali_c55_params_buf(vbuf) \ 69 + container_of(vbuf, struct mali_c55_params_buf, vb) 70 + 71 + static void mali_c55_params_sensor_offs(struct mali_c55 *mali_c55, 72 + union mali_c55_params_block block) 73 + { 74 + const struct mali_c55_params_sensor_off_preshading *p; 75 + __u32 global_offset; 76 + 77 + p = block.sensor_offs; 78 + 79 + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { 80 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BYPASS_3, 81 + MALI_C55_REG_BYPASS_3_SENSOR_OFFSET_PRE_SH, 82 + MALI_C55_REG_BYPASS_3_SENSOR_OFFSET_PRE_SH); 83 + return; 84 + } 85 + 86 + if (!(p->chan00 || p->chan01 || p->chan10 || p->chan11)) 87 + return; 88 + 89 + mali_c55_ctx_write(mali_c55, MALI_C55_REG_SENSOR_OFF_PRE_SHA_00, 90 + p->chan00 & MALI_C55_SENSOR_OFF_PRE_SHA_MASK); 91 + mali_c55_ctx_write(mali_c55, MALI_C55_REG_SENSOR_OFF_PRE_SHA_01, 92 + p->chan01 & MALI_C55_SENSOR_OFF_PRE_SHA_MASK); 93 + mali_c55_ctx_write(mali_c55, MALI_C55_REG_SENSOR_OFF_PRE_SHA_10, 94 + p->chan10 & MALI_C55_SENSOR_OFF_PRE_SHA_MASK); 95 + mali_c55_ctx_write(mali_c55, MALI_C55_REG_SENSOR_OFF_PRE_SHA_11, 96 + p->chan11 & MALI_C55_SENSOR_OFF_PRE_SHA_MASK); 97 + 98 + /* 99 + * The average offset is applied as a global offset for the digital 100 + * gain block 101 + */ 102 + global_offset = (p->chan00 + p->chan01 + p->chan10 + p->chan11) >> 2; 103 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_DIGITAL_GAIN_OFFSET, 104 + MALI_C55_DIGITAL_GAIN_OFFSET_MASK, 105 + global_offset); 106 + 107 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BYPASS_3, 108 + MALI_C55_REG_BYPASS_3_SENSOR_OFFSET_PRE_SH, 109 + 0x00); 110 + } 111 + 112 + static void mali_c55_params_aexp_hist(struct mali_c55 *mali_c55, 113 + union mali_c55_params_block block) 114 + { 115 + const struct mali_c55_params_aexp_hist *params; 116 + u32 disable_mask; 117 + u32 disable_val; 118 + u32 base; 119 + 120 + if (block.header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST) { 121 + disable_mask = MALI_C55_AEXP_HIST_DISABLE_MASK; 122 + disable_val = MALI_C55_AEXP_HIST_DISABLE; 123 + base = MALI_C55_REG_AEXP_HIST_BASE; 124 + } else { 125 + disable_mask = MALI_C55_AEXP_IHIST_DISABLE_MASK; 126 + disable_val = MALI_C55_AEXP_IHIST_DISABLE; 127 + base = MALI_C55_REG_AEXP_IHIST_BASE; 128 + } 129 + 130 + params = block.aexp_hist; 131 + 132 + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { 133 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, 134 + disable_mask, disable_val); 135 + return; 136 + } 137 + 138 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, 139 + disable_mask, false); 140 + 141 + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SKIP_OFFSET, 142 + MALI_C55_AEXP_HIST_SKIP_X_MASK, params->skip_x); 143 + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SKIP_OFFSET, 144 + MALI_C55_AEXP_HIST_OFFSET_X_MASK, 145 + MALI_C55_AEXP_HIST_OFFSET_X(params->offset_x)); 146 + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SKIP_OFFSET, 147 + MALI_C55_AEXP_HIST_SKIP_Y_MASK, 148 + MALI_C55_AEXP_HIST_SKIP_Y(params->skip_y)); 149 + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SKIP_OFFSET, 150 + MALI_C55_AEXP_HIST_OFFSET_Y_MASK, 151 + MALI_C55_AEXP_HIST_OFFSET_Y(params->offset_y)); 152 + 153 + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SCALE_OFFSET, 154 + MALI_C55_AEXP_HIST_SCALE_BOTTOM_MASK, 155 + params->scale_bottom); 156 + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SCALE_OFFSET, 157 + MALI_C55_AEXP_HIST_SCALE_TOP_MASK, 158 + MALI_C55_AEXP_HIST_SCALE_TOP(params->scale_top)); 159 + 160 + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_PLANE_MODE_OFFSET, 161 + MALI_C55_AEXP_HIST_PLANE_MODE_MASK, 162 + params->plane_mode); 163 + 164 + if (block.header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST) 165 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, 166 + MALI_C55_AEXP_HIST_SWITCH_MASK, 167 + MALI_C55_AEXP_HIST_SWITCH(params->tap_point)); 168 + } 169 + 170 + static void 171 + mali_c55_params_aexp_hist_weights(struct mali_c55 *mali_c55, 172 + union mali_c55_params_block block) 173 + { 174 + const struct mali_c55_params_aexp_weights *params; 175 + u32 base, val, addr; 176 + 177 + params = block.aexp_weights; 178 + 179 + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) 180 + return; 181 + 182 + base = block.header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS ? 183 + MALI_C55_REG_AEXP_HIST_BASE : 184 + MALI_C55_REG_AEXP_IHIST_BASE; 185 + 186 + mali_c55_ctx_update_bits(mali_c55, 187 + base + MALI_C55_AEXP_HIST_NODES_USED_OFFSET, 188 + MALI_C55_AEXP_HIST_NODES_USED_HORIZ_MASK, 189 + params->nodes_used_horiz); 190 + mali_c55_ctx_update_bits(mali_c55, 191 + base + MALI_C55_AEXP_HIST_NODES_USED_OFFSET, 192 + MALI_C55_AEXP_HIST_NODES_USED_VERT_MASK, 193 + MALI_C55_AEXP_HIST_NODES_USED_VERT(params->nodes_used_vert)); 194 + 195 + /* 196 + * The zone weights array is a 225-element array of u8 values, but that 197 + * is a bit annoying to handle given the ISP expects 32-bit writes. We 198 + * just reinterpret it as 56-element array of 32-bit values for the 199 + * purposes of this transaction. The last register is handled separately 200 + * to stop static analysers worrying about buffer overflow. The 3 bytes 201 + * of additional space at the end of the write is just padding for the 202 + * array of weights in the ISP memory space anyway, so there's no risk 203 + * of overwriting other registers. 204 + */ 205 + for (unsigned int i = 0; i < 56; i++) { 206 + val = ((u32 *)params->zone_weights)[i] 207 + & MALI_C55_AEXP_HIST_ZONE_WEIGHT_MASK; 208 + addr = base + MALI_C55_AEXP_HIST_ZONE_WEIGHTS_OFFSET + (4 * i); 209 + 210 + mali_c55_ctx_write(mali_c55, addr, val); 211 + } 212 + 213 + val = params->zone_weights[MALI_C55_MAX_ZONES - 1]; 214 + addr = base + MALI_C55_AEXP_HIST_ZONE_WEIGHTS_OFFSET + (4 * 56); 215 + } 216 + 217 + static void mali_c55_params_digital_gain(struct mali_c55 *mali_c55, 218 + union mali_c55_params_block block) 219 + { 220 + const struct mali_c55_params_digital_gain *dgain; 221 + u32 gain; 222 + 223 + dgain = block.digital_gain; 224 + 225 + /* 226 + * If the block is flagged as disabled we write a gain of 1.0, which in 227 + * Q5.8 format is 256. 228 + */ 229 + gain = block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE ? 230 + 256 : dgain->gain; 231 + 232 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_DIGITAL_GAIN, 233 + MALI_C55_DIGITAL_GAIN_MASK, 234 + gain); 235 + } 236 + 237 + static void mali_c55_params_awb_gains(struct mali_c55 *mali_c55, 238 + union mali_c55_params_block block) 239 + { 240 + const struct mali_c55_params_awb_gains *gains; 241 + u32 gain00, gain01, gain10, gain11; 242 + 243 + gains = block.awb_gains; 244 + 245 + /* 246 + * There are two places AWB gains can be set in the ISP; one affects the 247 + * image output data and the other affects the statistics for the 248 + * AEXP-0 tap point. 249 + */ 250 + u32 addr1 = block.header->type == MALI_C55_PARAM_BLOCK_AWB_GAINS ? 251 + MALI_C55_REG_AWB_GAINS1 : 252 + MALI_C55_REG_AWB_GAINS1_AEXP; 253 + u32 addr2 = block.header->type == MALI_C55_PARAM_BLOCK_AWB_GAINS ? 254 + MALI_C55_REG_AWB_GAINS2 : 255 + MALI_C55_REG_AWB_GAINS2_AEXP; 256 + 257 + /* If the block is flagged disabled, set all of the gains to 1.0 */ 258 + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { 259 + gain00 = 256; 260 + gain01 = 256; 261 + gain10 = 256; 262 + gain11 = 256; 263 + } else { 264 + gain00 = gains->gain00; 265 + gain01 = gains->gain01; 266 + gain10 = gains->gain10; 267 + gain11 = gains->gain11; 268 + } 269 + 270 + mali_c55_ctx_update_bits(mali_c55, addr1, MALI_C55_AWB_GAIN00_MASK, 271 + gain00); 272 + mali_c55_ctx_update_bits(mali_c55, addr1, MALI_C55_AWB_GAIN01_MASK, 273 + MALI_C55_AWB_GAIN01(gain01)); 274 + mali_c55_ctx_update_bits(mali_c55, addr2, MALI_C55_AWB_GAIN10_MASK, 275 + gain10); 276 + mali_c55_ctx_update_bits(mali_c55, addr2, MALI_C55_AWB_GAIN11_MASK, 277 + MALI_C55_AWB_GAIN11(gain11)); 278 + } 279 + 280 + static void mali_c55_params_awb_config(struct mali_c55 *mali_c55, 281 + union mali_c55_params_block block) 282 + { 283 + const struct mali_c55_params_awb_config *params; 284 + 285 + params = block.awb_config; 286 + 287 + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { 288 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, 289 + MALI_C55_AWB_DISABLE_MASK, 290 + MALI_C55_AWB_DISABLE_MASK); 291 + return; 292 + } 293 + 294 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, 295 + MALI_C55_AWB_DISABLE_MASK, false); 296 + 297 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_STATS_MODE, 298 + MALI_C55_AWB_STATS_MODE_MASK, params->stats_mode); 299 + 300 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_WHITE_LEVEL, 301 + MALI_C55_AWB_WHITE_LEVEL_MASK, params->white_level); 302 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_BLACK_LEVEL, 303 + MALI_C55_AWB_BLACK_LEVEL_MASK, params->black_level); 304 + 305 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CR_MAX, 306 + MALI_C55_AWB_CR_MAX_MASK, params->cr_max); 307 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CR_MIN, 308 + MALI_C55_AWB_CR_MIN_MASK, params->cr_min); 309 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CB_MAX, 310 + MALI_C55_AWB_CB_MAX_MASK, params->cb_max); 311 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CB_MIN, 312 + MALI_C55_AWB_CB_MIN_MASK, params->cb_min); 313 + 314 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_NODES_USED, 315 + MALI_C55_AWB_NODES_USED_HORIZ_MASK, 316 + params->nodes_used_horiz); 317 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_NODES_USED, 318 + MALI_C55_AWB_NODES_USED_VERT_MASK, 319 + MALI_C55_AWB_NODES_USED_VERT(params->nodes_used_vert)); 320 + 321 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CR_HIGH, 322 + MALI_C55_AWB_CR_HIGH_MASK, params->cr_high); 323 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CR_LOW, 324 + MALI_C55_AWB_CR_LOW_MASK, params->cr_low); 325 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CB_HIGH, 326 + MALI_C55_AWB_CB_HIGH_MASK, params->cb_high); 327 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CB_LOW, 328 + MALI_C55_AWB_CB_LOW_MASK, params->cb_low); 329 + 330 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, 331 + MALI_C55_AWB_SWITCH_MASK, 332 + MALI_C55_AWB_SWITCH(params->tap_point)); 333 + } 334 + 335 + static void mali_c55_params_lsc_config(struct mali_c55 *mali_c55, 336 + union mali_c55_params_block block) 337 + { 338 + const struct mali_c55_params_mesh_shading_config *params; 339 + unsigned int i; 340 + u32 addr; 341 + 342 + params = block.shading_config; 343 + 344 + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { 345 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 346 + MALI_C55_MESH_SHADING_ENABLE_MASK, 347 + false); 348 + return; 349 + } 350 + 351 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 352 + MALI_C55_MESH_SHADING_ENABLE_MASK, true); 353 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 354 + MALI_C55_MESH_SHADING_MESH_SHOW_MASK, 355 + MALI_C55_MESH_SHADING_MESH_SHOW(params->mesh_show)); 356 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 357 + MALI_C55_MESH_SHADING_SCALE_MASK, 358 + MALI_C55_MESH_SHADING_SCALE(params->mesh_scale)); 359 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 360 + MALI_C55_MESH_SHADING_PAGE_R_MASK, 361 + MALI_C55_MESH_SHADING_PAGE_R(params->mesh_page_r)); 362 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 363 + MALI_C55_MESH_SHADING_PAGE_G_MASK, 364 + MALI_C55_MESH_SHADING_PAGE_G(params->mesh_page_g)); 365 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 366 + MALI_C55_MESH_SHADING_PAGE_B_MASK, 367 + MALI_C55_MESH_SHADING_PAGE_B(params->mesh_page_b)); 368 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 369 + MALI_C55_MESH_SHADING_MESH_WIDTH_MASK, 370 + MALI_C55_MESH_SHADING_MESH_WIDTH(params->mesh_width)); 371 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, 372 + MALI_C55_MESH_SHADING_MESH_HEIGHT_MASK, 373 + MALI_C55_MESH_SHADING_MESH_HEIGHT(params->mesh_height)); 374 + 375 + for (i = 0; i < MALI_C55_NUM_MESH_SHADING_ELEMENTS; i++) { 376 + addr = MALI_C55_REG_MESH_SHADING_TABLES + (i * 4); 377 + mali_c55_ctx_write(mali_c55, addr, params->mesh[i]); 378 + } 379 + } 380 + 381 + static void mali_c55_params_lsc_selection(struct mali_c55 *mali_c55, 382 + union mali_c55_params_block block) 383 + { 384 + const struct mali_c55_params_mesh_shading_selection *params; 385 + 386 + params = block.shading_selection; 387 + 388 + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) 389 + return; 390 + 391 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA_BANK, 392 + MALI_C55_MESH_SHADING_ALPHA_BANK_R_MASK, 393 + params->mesh_alpha_bank_r); 394 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA_BANK, 395 + MALI_C55_MESH_SHADING_ALPHA_BANK_G_MASK, 396 + MALI_C55_MESH_SHADING_ALPHA_BANK_G(params->mesh_alpha_bank_g)); 397 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA_BANK, 398 + MALI_C55_MESH_SHADING_ALPHA_BANK_B_MASK, 399 + MALI_C55_MESH_SHADING_ALPHA_BANK_B(params->mesh_alpha_bank_b)); 400 + 401 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA, 402 + MALI_C55_MESH_SHADING_ALPHA_R_MASK, 403 + params->mesh_alpha_r); 404 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA, 405 + MALI_C55_MESH_SHADING_ALPHA_G_MASK, 406 + MALI_C55_MESH_SHADING_ALPHA_G(params->mesh_alpha_g)); 407 + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA, 408 + MALI_C55_MESH_SHADING_ALPHA_B_MASK, 409 + MALI_C55_MESH_SHADING_ALPHA_B(params->mesh_alpha_b)); 410 + 411 + mali_c55_ctx_update_bits(mali_c55, 412 + MALI_C55_REG_MESH_SHADING_MESH_STRENGTH, 413 + MALI_c55_MESH_STRENGTH_MASK, 414 + params->mesh_strength); 415 + } 416 + 417 + static const mali_c55_params_handler mali_c55_params_handlers[] = { 418 + [MALI_C55_PARAM_BLOCK_SENSOR_OFFS] = &mali_c55_params_sensor_offs, 419 + [MALI_C55_PARAM_BLOCK_AEXP_HIST] = &mali_c55_params_aexp_hist, 420 + [MALI_C55_PARAM_BLOCK_AEXP_IHIST] = &mali_c55_params_aexp_hist, 421 + [MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS] = &mali_c55_params_aexp_hist_weights, 422 + [MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS] = &mali_c55_params_aexp_hist_weights, 423 + [MALI_C55_PARAM_BLOCK_DIGITAL_GAIN] = &mali_c55_params_digital_gain, 424 + [MALI_C55_PARAM_BLOCK_AWB_GAINS] = &mali_c55_params_awb_gains, 425 + [MALI_C55_PARAM_BLOCK_AWB_CONFIG] = &mali_c55_params_awb_config, 426 + [MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP] = &mali_c55_params_awb_gains, 427 + [MALI_C55_PARAM_MESH_SHADING_CONFIG] = &mali_c55_params_lsc_config, 428 + [MALI_C55_PARAM_MESH_SHADING_SELECTION] = &mali_c55_params_lsc_selection, 429 + }; 430 + 431 + static const struct v4l2_isp_params_block_info mali_c55_params_blocks_info[] = { 432 + [MALI_C55_PARAM_BLOCK_SENSOR_OFFS] = { 433 + .size = sizeof(struct mali_c55_params_sensor_off_preshading), 434 + }, 435 + [MALI_C55_PARAM_BLOCK_AEXP_HIST] = { 436 + .size = sizeof(struct mali_c55_params_aexp_hist), 437 + }, 438 + [MALI_C55_PARAM_BLOCK_AEXP_IHIST] = { 439 + .size = sizeof(struct mali_c55_params_aexp_hist), 440 + }, 441 + [MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS] = { 442 + .size = sizeof(struct mali_c55_params_aexp_weights), 443 + }, 444 + [MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS] = { 445 + .size = sizeof(struct mali_c55_params_aexp_weights), 446 + }, 447 + [MALI_C55_PARAM_BLOCK_DIGITAL_GAIN] = { 448 + .size = sizeof(struct mali_c55_params_digital_gain), 449 + }, 450 + [MALI_C55_PARAM_BLOCK_AWB_GAINS] = { 451 + .size = sizeof(struct mali_c55_params_awb_gains), 452 + }, 453 + [MALI_C55_PARAM_BLOCK_AWB_CONFIG] = { 454 + .size = sizeof(struct mali_c55_params_awb_config), 455 + }, 456 + [MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP] = { 457 + .size = sizeof(struct mali_c55_params_awb_gains), 458 + }, 459 + [MALI_C55_PARAM_MESH_SHADING_CONFIG] = { 460 + .size = sizeof(struct mali_c55_params_mesh_shading_config), 461 + }, 462 + [MALI_C55_PARAM_MESH_SHADING_SELECTION] = { 463 + .size = sizeof(struct mali_c55_params_mesh_shading_selection), 464 + }, 465 + }; 466 + 467 + static int mali_c55_params_enum_fmt_meta_out(struct file *file, void *fh, 468 + struct v4l2_fmtdesc *f) 469 + { 470 + if (f->index) 471 + return -EINVAL; 472 + 473 + if (f->mbus_code && f->mbus_code != MEDIA_BUS_FMT_METADATA_FIXED) 474 + return -EINVAL; 475 + 476 + f->pixelformat = V4L2_META_FMT_MALI_C55_PARAMS; 477 + 478 + return 0; 479 + } 480 + 481 + static int mali_c55_params_g_fmt_meta_out(struct file *file, void *fh, 482 + struct v4l2_format *f) 483 + { 484 + static const struct v4l2_meta_format mfmt = { 485 + .dataformat = V4L2_META_FMT_MALI_C55_PARAMS, 486 + .buffersize = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE), 487 + }; 488 + 489 + f->fmt.meta = mfmt; 490 + 491 + return 0; 492 + } 493 + 494 + static int mali_c55_params_querycap(struct file *file, 495 + void *priv, struct v4l2_capability *cap) 496 + { 497 + strscpy(cap->driver, MALI_C55_DRIVER_NAME, sizeof(cap->driver)); 498 + strscpy(cap->card, "ARM Mali-C55 ISP", sizeof(cap->card)); 499 + 500 + return 0; 501 + } 502 + 503 + static const struct v4l2_ioctl_ops mali_c55_params_v4l2_ioctl_ops = { 504 + .vidioc_reqbufs = vb2_ioctl_reqbufs, 505 + .vidioc_querybuf = vb2_ioctl_querybuf, 506 + .vidioc_create_bufs = vb2_ioctl_create_bufs, 507 + .vidioc_qbuf = vb2_ioctl_qbuf, 508 + .vidioc_expbuf = vb2_ioctl_expbuf, 509 + .vidioc_dqbuf = vb2_ioctl_dqbuf, 510 + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 511 + .vidioc_streamon = vb2_ioctl_streamon, 512 + .vidioc_streamoff = vb2_ioctl_streamoff, 513 + .vidioc_enum_fmt_meta_out = mali_c55_params_enum_fmt_meta_out, 514 + .vidioc_g_fmt_meta_out = mali_c55_params_g_fmt_meta_out, 515 + .vidioc_s_fmt_meta_out = mali_c55_params_g_fmt_meta_out, 516 + .vidioc_try_fmt_meta_out = mali_c55_params_g_fmt_meta_out, 517 + .vidioc_querycap = mali_c55_params_querycap, 518 + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 519 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 520 + }; 521 + 522 + static const struct v4l2_file_operations mali_c55_params_v4l2_fops = { 523 + .owner = THIS_MODULE, 524 + .unlocked_ioctl = video_ioctl2, 525 + .open = v4l2_fh_open, 526 + .release = vb2_fop_release, 527 + .poll = vb2_fop_poll, 528 + .mmap = vb2_fop_mmap, 529 + }; 530 + 531 + static int 532 + mali_c55_params_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, 533 + unsigned int *num_planes, unsigned int sizes[], 534 + struct device *alloc_devs[]) 535 + { 536 + if (*num_planes && *num_planes > 1) 537 + return -EINVAL; 538 + 539 + if (sizes[0] && sizes[0] < v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)) 540 + return -EINVAL; 541 + 542 + *num_planes = 1; 543 + 544 + if (!sizes[0]) 545 + sizes[0] = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE); 546 + 547 + return 0; 548 + } 549 + 550 + static int mali_c55_params_buf_init(struct vb2_buffer *vb) 551 + { 552 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 553 + struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); 554 + 555 + buf->config = kvmalloc(v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE), 556 + GFP_KERNEL); 557 + if (!buf->config) 558 + return -ENOMEM; 559 + 560 + return 0; 561 + } 562 + 563 + static void mali_c55_params_buf_cleanup(struct vb2_buffer *vb) 564 + { 565 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 566 + struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); 567 + 568 + kvfree(buf->config); 569 + buf->config = NULL; 570 + } 571 + 572 + static int mali_c55_params_buf_prepare(struct vb2_buffer *vb) 573 + { 574 + struct mali_c55_params *params = vb2_get_drv_priv(vb->vb2_queue); 575 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 576 + struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); 577 + struct v4l2_isp_params_buffer *config = vb2_plane_vaddr(vb, 0); 578 + struct mali_c55 *mali_c55 = params->mali_c55; 579 + int ret; 580 + 581 + if (config->version != MALI_C55_PARAM_BUFFER_V1) { 582 + dev_dbg(mali_c55->dev, 583 + "Unsupported extensible format version: %u\n", 584 + config->version); 585 + return -EINVAL; 586 + } 587 + 588 + ret = v4l2_isp_params_validate_buffer_size(mali_c55->dev, vb, 589 + v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); 590 + if (ret) 591 + return ret; 592 + 593 + /* 594 + * Copy the parameters buffer provided by userspace to the internal 595 + * scratch buffer. This protects against the chance of userspace making 596 + * changed to the buffer content whilst the driver processes it. 597 + */ 598 + 599 + memcpy(buf->config, config, v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); 600 + 601 + return v4l2_isp_params_validate_buffer(mali_c55->dev, vb, buf->config, 602 + mali_c55_params_blocks_info, 603 + ARRAY_SIZE(mali_c55_params_blocks_info)); 604 + } 605 + 606 + static void mali_c55_params_buf_queue(struct vb2_buffer *vb) 607 + { 608 + struct mali_c55_params *params = vb2_get_drv_priv(vb->vb2_queue); 609 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 610 + struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); 611 + 612 + spin_lock(&params->buffers.lock); 613 + list_add_tail(&buf->queue, &params->buffers.queue); 614 + spin_unlock(&params->buffers.lock); 615 + } 616 + 617 + static void mali_c55_params_return_buffers(struct mali_c55_params *params, 618 + enum vb2_buffer_state state) 619 + { 620 + struct mali_c55_params_buf *buf, *tmp; 621 + 622 + guard(spinlock)(&params->buffers.lock); 623 + 624 + list_for_each_entry_safe(buf, tmp, &params->buffers.queue, queue) { 625 + list_del(&buf->queue); 626 + vb2_buffer_done(&buf->vb.vb2_buf, state); 627 + } 628 + } 629 + 630 + static int mali_c55_params_start_streaming(struct vb2_queue *q, 631 + unsigned int count) 632 + { 633 + struct mali_c55_params *params = vb2_get_drv_priv(q); 634 + struct mali_c55 *mali_c55 = params->mali_c55; 635 + int ret; 636 + 637 + ret = pm_runtime_resume_and_get(mali_c55->dev); 638 + if (ret) 639 + goto err_return_buffers; 640 + 641 + ret = video_device_pipeline_alloc_start(&params->vdev); 642 + if (ret) 643 + goto err_pm_put; 644 + 645 + if (mali_c55_pipeline_ready(mali_c55)) { 646 + ret = v4l2_subdev_enable_streams(&mali_c55->isp.sd, 647 + MALI_C55_ISP_PAD_SOURCE_VIDEO, 648 + BIT(0)); 649 + if (ret < 0) 650 + goto err_stop_pipeline; 651 + } 652 + 653 + return 0; 654 + 655 + err_stop_pipeline: 656 + video_device_pipeline_stop(&params->vdev); 657 + err_pm_put: 658 + pm_runtime_put_autosuspend(mali_c55->dev); 659 + err_return_buffers: 660 + mali_c55_params_return_buffers(params, VB2_BUF_STATE_QUEUED); 661 + 662 + return ret; 663 + } 664 + 665 + static void mali_c55_params_stop_streaming(struct vb2_queue *q) 666 + { 667 + struct mali_c55_params *params = vb2_get_drv_priv(q); 668 + struct mali_c55 *mali_c55 = params->mali_c55; 669 + struct mali_c55_isp *isp = &mali_c55->isp; 670 + 671 + if (mali_c55_pipeline_ready(mali_c55)) { 672 + if (v4l2_subdev_is_streaming(&isp->sd)) 673 + v4l2_subdev_disable_streams(&isp->sd, 674 + MALI_C55_ISP_PAD_SOURCE_VIDEO, 675 + BIT(0)); 676 + } 677 + 678 + video_device_pipeline_stop(&params->vdev); 679 + mali_c55_params_return_buffers(params, VB2_BUF_STATE_ERROR); 680 + pm_runtime_put_autosuspend(params->mali_c55->dev); 681 + } 682 + 683 + static const struct vb2_ops mali_c55_params_vb2_ops = { 684 + .queue_setup = mali_c55_params_queue_setup, 685 + .buf_init = mali_c55_params_buf_init, 686 + .buf_cleanup = mali_c55_params_buf_cleanup, 687 + .buf_queue = mali_c55_params_buf_queue, 688 + .buf_prepare = mali_c55_params_buf_prepare, 689 + .start_streaming = mali_c55_params_start_streaming, 690 + .stop_streaming = mali_c55_params_stop_streaming, 691 + }; 692 + 693 + void mali_c55_params_write_config(struct mali_c55 *mali_c55) 694 + { 695 + struct mali_c55_params *params = &mali_c55->params; 696 + struct v4l2_isp_params_buffer *config; 697 + struct mali_c55_params_buf *buf; 698 + size_t block_offset = 0; 699 + size_t max_offset; 700 + 701 + spin_lock(&params->buffers.lock); 702 + 703 + buf = list_first_entry_or_null(&params->buffers.queue, 704 + struct mali_c55_params_buf, queue); 705 + if (buf) 706 + list_del(&buf->queue); 707 + spin_unlock(&params->buffers.lock); 708 + 709 + if (!buf) 710 + return; 711 + 712 + buf->vb.sequence = mali_c55->isp.frame_sequence; 713 + config = buf->config; 714 + 715 + max_offset = config->data_size; 716 + 717 + /* 718 + * Walk the list of parameter blocks and process them. No validation is 719 + * done here, as the contents of the config buffer are already checked 720 + * when the buffer is queued. 721 + */ 722 + while (max_offset && block_offset < max_offset) { 723 + union mali_c55_params_block block; 724 + mali_c55_params_handler handler; 725 + 726 + block.data = &config->data[block_offset]; 727 + 728 + /* We checked the array index already in .buf_queue() */ 729 + handler = mali_c55_params_handlers[block.header->type]; 730 + handler(mali_c55, block); 731 + 732 + block_offset += block.header->size; 733 + } 734 + 735 + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); 736 + } 737 + 738 + void mali_c55_unregister_params(struct mali_c55 *mali_c55) 739 + { 740 + struct mali_c55_params *params = &mali_c55->params; 741 + 742 + if (!video_is_registered(&params->vdev)) 743 + return; 744 + 745 + vb2_video_unregister_device(&params->vdev); 746 + media_entity_cleanup(&params->vdev.entity); 747 + mutex_destroy(&params->lock); 748 + } 749 + 750 + int mali_c55_register_params(struct mali_c55 *mali_c55) 751 + { 752 + struct mali_c55_params *params = &mali_c55->params; 753 + struct video_device *vdev = &params->vdev; 754 + struct vb2_queue *vb2q = &params->queue; 755 + int ret; 756 + 757 + mutex_init(&params->lock); 758 + INIT_LIST_HEAD(&params->buffers.queue); 759 + spin_lock_init(&params->buffers.lock); 760 + 761 + params->pad.flags = MEDIA_PAD_FL_SOURCE; 762 + ret = media_entity_pads_init(&params->vdev.entity, 1, &params->pad); 763 + if (ret) 764 + goto err_destroy_mutex; 765 + 766 + vb2q->type = V4L2_BUF_TYPE_META_OUTPUT; 767 + vb2q->io_modes = VB2_MMAP | VB2_DMABUF; 768 + vb2q->drv_priv = params; 769 + vb2q->mem_ops = &vb2_dma_contig_memops; 770 + vb2q->ops = &mali_c55_params_vb2_ops; 771 + vb2q->buf_struct_size = sizeof(struct mali_c55_params_buf); 772 + vb2q->min_queued_buffers = 1; 773 + vb2q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 774 + vb2q->lock = &params->lock; 775 + vb2q->dev = mali_c55->dev; 776 + 777 + ret = vb2_queue_init(vb2q); 778 + if (ret) { 779 + dev_err(mali_c55->dev, "params vb2 queue init failed\n"); 780 + goto err_cleanup_entity; 781 + } 782 + 783 + strscpy(params->vdev.name, "mali-c55 3a params", 784 + sizeof(params->vdev.name)); 785 + vdev->release = video_device_release_empty; 786 + vdev->fops = &mali_c55_params_v4l2_fops; 787 + vdev->ioctl_ops = &mali_c55_params_v4l2_ioctl_ops; 788 + vdev->lock = &params->lock; 789 + vdev->v4l2_dev = &mali_c55->v4l2_dev; 790 + vdev->queue = &params->queue; 791 + vdev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING | 792 + V4L2_CAP_IO_MC; 793 + vdev->vfl_dir = VFL_DIR_TX; 794 + video_set_drvdata(vdev, params); 795 + 796 + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 797 + if (ret) { 798 + dev_err(mali_c55->dev, 799 + "failed to register params video device\n"); 800 + goto err_release_vb2q; 801 + } 802 + 803 + params->mali_c55 = mali_c55; 804 + 805 + return 0; 806 + 807 + err_release_vb2q: 808 + vb2_queue_release(vb2q); 809 + err_cleanup_entity: 810 + media_entity_cleanup(&params->vdev.entity); 811 + err_destroy_mutex: 812 + mutex_destroy(&params->lock); 813 + 814 + return ret; 815 + }
+128
drivers/media/platform/arm/mali-c55/mali-c55-registers.h
··· 159 159 #define MALI_C55_BAYER_ORDER_GBRG 2 160 160 #define MALI_C55_BAYER_ORDER_BGGR 3 161 161 162 + #define MALI_C55_REG_METERING_CONFIG 0x18ed0 163 + #define MALI_C55_5BIN_HIST_DISABLE_MASK BIT(0) 164 + #define MALI_C55_5BIN_HIST_SWITCH_MASK GENMASK(2, 1) 165 + #define MALI_C55_5BIN_HIST_SWITCH(x) ((x) << 1) 166 + #define MALI_C55_AF_DISABLE_MASK BIT(4) 167 + #define MALI_C55_AF_SWITCH_MASK BIT(5) 168 + #define MALI_C55_AWB_DISABLE_MASK BIT(8) 169 + #define MALI_C55_AWB_SWITCH_MASK BIT(9) 170 + #define MALI_C55_AWB_SWITCH(x) ((x) << 9) 171 + #define MALI_C55_AEXP_HIST_DISABLE_MASK BIT(12) 172 + #define MALI_C55_AEXP_HIST_DISABLE (0x01 << 12) 173 + #define MALI_C55_AEXP_HIST_SWITCH_MASK GENMASK(14, 13) 174 + #define MALI_C55_AEXP_HIST_SWITCH(x) ((x) << 13) 175 + #define MALI_C55_AEXP_IHIST_DISABLE_MASK BIT(16) 176 + #define MALI_C55_AEXP_IHIST_DISABLE (0x01 << 12) 177 + #define MALI_C55_AEXP_SRC_MASK BIT(24) 178 + 162 179 #define MALI_C55_REG_TPG_CH0 0x18ed8 163 180 #define MALI_C55_TEST_PATTERN_ON_OFF BIT(0) 164 181 #define MALI_C55_TEST_PATTERN_RGB_MASK BIT(1) ··· 196 179 #define MALI_C55_REG_CONFIG_SPACES_OFFSET 0x0ab6c 197 180 #define MALI_C55_CONFIG_SPACE_SIZE 0x1231c 198 181 182 + #define MALI_C55_REG_DIGITAL_GAIN 0x1926c 183 + #define MALI_C55_DIGITAL_GAIN_MASK GENMASK(12, 0) 184 + #define MALI_C55_REG_DIGITAL_GAIN_OFFSET 0x19270 185 + #define MALI_C55_DIGITAL_GAIN_OFFSET_MASK GENMASK(19, 0) 186 + 199 187 #define MALI_C55_REG_SINTER_CONFIG 0x19348 200 188 #define MALI_C55_SINTER_VIEW_FILTER_MASK GENMASK(1, 0) 201 189 #define MALI_C55_SINTER_SCALE_MODE_MASK GENMASK(3, 2) ··· 213 191 #define MALI_C55_REG_TEMPER_DMA_IO 0x1ab78 214 192 #define MALI_C55_TEMPER_DMA_WRITE_ON BIT(0) 215 193 #define MALI_C55_TEMPER_DMA_READ_ON BIT(1) 194 + 195 + /* Black Level Correction Configuration */ 196 + #define MALI_C55_REG_SENSOR_OFF_PRE_SHA_00 0x1abcc 197 + #define MALI_C55_REG_SENSOR_OFF_PRE_SHA_01 0x1abd0 198 + #define MALI_C55_REG_SENSOR_OFF_PRE_SHA_10 0x1abd4 199 + #define MALI_C55_REG_SENSOR_OFF_PRE_SHA_11 0x1abd8 200 + #define MALI_C55_SENSOR_OFF_PRE_SHA_MASK 0xfffff 201 + 202 + /* Lens Mesh Shading Configuration */ 203 + #define MALI_C55_REG_MESH_SHADING_TABLES 0x13074 204 + #define MALI_C55_REG_MESH_SHADING_CONFIG 0x1abfc 205 + #define MALI_C55_MESH_SHADING_ENABLE_MASK BIT(0) 206 + #define MALI_C55_MESH_SHADING_MESH_SHOW_MASK BIT(1) 207 + #define MALI_C55_MESH_SHADING_MESH_SHOW(x) ((x) << 1) 208 + #define MALI_C55_MESH_SHADING_SCALE_MASK GENMASK(4, 2) 209 + #define MALI_C55_MESH_SHADING_SCALE(x) ((x) << 2) 210 + #define MALI_C55_MESH_SHADING_PAGE_R_MASK GENMASK(9, 8) 211 + #define MALI_C55_MESH_SHADING_PAGE_R(x) ((x) << 8) 212 + #define MALI_C55_MESH_SHADING_PAGE_G_MASK GENMASK(11, 10) 213 + #define MALI_C55_MESH_SHADING_PAGE_G(x) ((x) << 10) 214 + #define MALI_C55_MESH_SHADING_PAGE_B_MASK GENMASK(13, 12) 215 + #define MALI_C55_MESH_SHADING_PAGE_B(x) ((x) << 12) 216 + #define MALI_C55_MESH_SHADING_MESH_WIDTH_MASK GENMASK(21, 16) 217 + #define MALI_C55_MESH_SHADING_MESH_WIDTH(x) ((x) << 16) 218 + #define MALI_C55_MESH_SHADING_MESH_HEIGHT_MASK GENMASK(29, 24) 219 + #define MALI_C55_MESH_SHADING_MESH_HEIGHT(x) ((x) << 24) 220 + 221 + #define MALI_C55_REG_MESH_SHADING_ALPHA_BANK 0x1ac04 222 + #define MALI_C55_MESH_SHADING_ALPHA_BANK_R_MASK GENMASK(2, 0) 223 + #define MALI_C55_MESH_SHADING_ALPHA_BANK_G_MASK GENMASK(5, 3) 224 + #define MALI_C55_MESH_SHADING_ALPHA_BANK_G(x) ((x) << 3) 225 + #define MALI_C55_MESH_SHADING_ALPHA_BANK_B_MASK GENMASK(8, 6) 226 + #define MALI_C55_MESH_SHADING_ALPHA_BANK_B(x) ((x) << 6) 227 + #define MALI_C55_REG_MESH_SHADING_ALPHA 0x1ac08 228 + #define MALI_C55_MESH_SHADING_ALPHA_R_MASK GENMASK(7, 0) 229 + #define MALI_C55_MESH_SHADING_ALPHA_G_MASK GENMASK(15, 8) 230 + #define MALI_C55_MESH_SHADING_ALPHA_G(x) ((x) << 8) 231 + #define MALI_C55_MESH_SHADING_ALPHA_B_MASK GENMASK(23, 16) 232 + #define MALI_C55_MESH_SHADING_ALPHA_B(x) ((x) << 16) 233 + #define MALI_C55_REG_MESH_SHADING_MESH_STRENGTH 0x1ac0c 234 + #define MALI_c55_MESH_STRENGTH_MASK GENMASK(15, 0) 235 + 236 + /* AWB Gains Configuration */ 237 + #define MALI_C55_REG_AWB_GAINS1 0x1ac10 238 + #define MALI_C55_AWB_GAIN00_MASK GENMASK(11, 0) 239 + #define MALI_C55_AWB_GAIN01_MASK GENMASK(27, 16) 240 + #define MALI_C55_AWB_GAIN01(x) ((x) << 16) 241 + #define MALI_C55_REG_AWB_GAINS2 0x1ac14 242 + #define MALI_C55_AWB_GAIN10_MASK GENMASK(11, 0) 243 + #define MALI_C55_AWB_GAIN11_MASK GENMASK(27, 16) 244 + #define MALI_C55_AWB_GAIN11(x) ((x) << 16) 245 + #define MALI_C55_REG_AWB_GAINS1_AEXP 0x1ac18 246 + #define MALI_C55_REG_AWB_GAINS2_AEXP 0x1ac1c 216 247 217 248 /* Colour Correction Matrix Configuration */ 218 249 #define MALI_C55_REG_CCM_ENABLE 0x1b07c ··· 288 213 #define MALI_C55_REG_CCM_ANTIFOG_OFFSET_G 0x1b0c4 289 214 #define MALI_C55_REG_CCM_ANTIFOG_OFFSET_B 0x1b0c8 290 215 #define MALI_C55_CCM_ANTIFOG_OFFSET_MASK GENMASK(11, 0) 216 + 217 + /* AWB Statistics Configuration */ 218 + #define MALI_C55_REG_AWB_STATS_MODE 0x1b29c 219 + #define MALI_C55_AWB_STATS_MODE_MASK BIT(0) 220 + #define MALI_C55_REG_AWB_WHITE_LEVEL 0x1b2a0 221 + #define MALI_C55_AWB_WHITE_LEVEL_MASK GENMASK(9, 0) 222 + #define MALI_C55_REG_AWB_BLACK_LEVEL 0x1b2a4 223 + #define MALI_C55_AWB_BLACK_LEVEL_MASK GENMASK(9, 0) 224 + #define MALI_C55_REG_AWB_CR_MAX 0x1b2a8 225 + #define MALI_C55_AWB_CR_MAX_MASK GENMASK(11, 0) 226 + #define MALI_C55_REG_AWB_CR_MIN 0x1b2ac 227 + #define MALI_C55_AWB_CR_MIN_MASK GENMASK(11, 0) 228 + #define MALI_C55_REG_AWB_CB_MAX 0x1b2b0 229 + #define MALI_C55_AWB_CB_MAX_MASK GENMASK(11, 0) 230 + #define MALI_C55_REG_AWB_CB_MIN 0x1b2b4 231 + #define MALI_C55_AWB_CB_MIN_MASK GENMASK(11, 0) 232 + #define MALI_C55_REG_AWB_NODES_USED 0x1b2c4 233 + #define MALI_C55_AWB_NODES_USED_HORIZ_MASK GENMASK(7, 0) 234 + #define MALI_C55_AWB_NODES_USED_VERT_MASK GENMASK(15, 8) 235 + #define MALI_C55_AWB_NODES_USED_VERT(x) ((x) << 8) 236 + #define MALI_C55_REG_AWB_CR_HIGH 0x1b2c8 237 + #define MALI_C55_AWB_CR_HIGH_MASK GENMASK(11, 0) 238 + #define MALI_C55_REG_AWB_CR_LOW 0x1b2cc 239 + #define MALI_C55_AWB_CR_LOW_MASK GENMASK(11, 0) 240 + #define MALI_C55_REG_AWB_CB_HIGH 0x1b2d0 241 + #define MALI_C55_AWB_CB_HIGH_MASK GENMASK(11, 0) 242 + #define MALI_C55_REG_AWB_CB_LOW 0x1b2d4 243 + #define MALI_C55_AWB_CB_LOW_MASK GENMASK(11, 0) 244 + 245 + /* AEXP Metering Histogram Configuration */ 246 + #define MALI_C55_REG_AEXP_HIST_BASE 0x1b730 247 + #define MALI_C55_REG_AEXP_IHIST_BASE 0x1bbac 248 + #define MALI_C55_AEXP_HIST_SKIP_OFFSET 0 249 + #define MALI_C55_AEXP_HIST_SKIP_X_MASK GENMASK(2, 0) 250 + #define MALI_C55_AEXP_HIST_SKIP_X(x) ((x) << 0) 251 + #define MALI_C55_AEXP_HIST_OFFSET_X_MASK BIT(3) 252 + #define MALI_C55_AEXP_HIST_OFFSET_X(x) ((x) << 3) 253 + #define MALI_C55_AEXP_HIST_SKIP_Y_MASK GENMASK(6, 4) 254 + #define MALI_C55_AEXP_HIST_SKIP_Y(x) ((x) << 4) 255 + #define MALI_C55_AEXP_HIST_OFFSET_Y_MASK BIT(7) 256 + #define MALI_C55_AEXP_HIST_OFFSET_Y(x) ((x) << 7) 257 + #define MALI_C55_AEXP_HIST_SCALE_OFFSET 4 258 + #define MALI_C55_AEXP_HIST_SCALE_BOTTOM_MASK GENMASK(3, 0) 259 + #define MALI_C55_AEXP_HIST_SCALE_TOP_MASK GENMASK(7, 4) 260 + #define MALI_C55_AEXP_HIST_SCALE_TOP(x) ((x) << 4) 261 + #define MALI_C55_AEXP_HIST_PLANE_MODE_OFFSET 16 262 + #define MALI_C55_AEXP_HIST_PLANE_MODE_MASK GENMASK(2, 0) 263 + #define MALI_C55_AEXP_HIST_NODES_USED_OFFSET 52 264 + #define MALI_C55_AEXP_HIST_NODES_USED_HORIZ_MASK GENMASK(7, 0) 265 + #define MALI_C55_AEXP_HIST_NODES_USED_VERT_MASK GENMASK(15, 8) 266 + #define MALI_C55_AEXP_HIST_NODES_USED_VERT(x) ((x) << 8) 267 + #define MALI_C55_AEXP_HIST_ZONE_WEIGHTS_OFFSET 56 268 + #define MALI_C55_AEXP_HIST_ZONE_WEIGHT_MASK 0x0f0f0f0f 291 269 292 270 /* 293 271 * The Mali-C55 ISP has up to two output pipes; known as full resolution and