1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2021-2022 Bootlin 4 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> 5 */ 6 7#include <media/v4l2-device.h> 8#include <media/v4l2-event.h> 9#include <media/v4l2-ioctl.h> 10#include <media/v4l2-mc.h> 11#include <media/videobuf2-vmalloc.h> 12#include <media/videobuf2-v4l2.h> 13 14#include "sun6i_isp.h" 15#include "sun6i_isp_params.h" 16#include "sun6i_isp_reg.h" 17#include "uapi/sun6i-isp-config.h" 18 19/* Params */ 20 21static const struct sun6i_isp_params_config sun6i_isp_params_config_default = { 22 .modules_used = SUN6I_ISP_MODULE_BAYER, 23 24 .bayer = { 25 .offset_r = 32, 26 .offset_gr = 32, 27 .offset_gb = 32, 28 .offset_b = 32, 29 30 .gain_r = 256, 31 .gain_gr = 256, 32 .gain_gb = 256, 33 .gain_b = 256, 34 35 }, 36 37 .bdnf = { 38 .in_dis_min = 8, 39 .in_dis_max = 16, 40 41 .coefficients_g = { 15, 4, 1 }, 42 .coefficients_rb = { 15, 4 }, 43 }, 44}; 45 46static void sun6i_isp_params_configure_ob(struct sun6i_isp_device *isp_dev) 47{ 48 unsigned int width, height; 49 50 sun6i_isp_proc_dimensions(isp_dev, &width, &height); 51 52 sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_SIZE_REG, 53 SUN6I_ISP_OB_SIZE_WIDTH(width) | 54 SUN6I_ISP_OB_SIZE_HEIGHT(height)); 55 56 sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_VALID_REG, 57 SUN6I_ISP_OB_VALID_WIDTH(width) | 58 SUN6I_ISP_OB_VALID_HEIGHT(height)); 59 60 sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_SRC0_VALID_START_REG, 61 SUN6I_ISP_OB_SRC0_VALID_START_HORZ(0) | 62 SUN6I_ISP_OB_SRC0_VALID_START_VERT(0)); 63} 64 65static void sun6i_isp_params_configure_ae(struct sun6i_isp_device *isp_dev) 66{ 67 /* These are default values that need to be set to get an output. */ 68 69 sun6i_isp_load_write(isp_dev, SUN6I_ISP_AE_CFG_REG, 70 SUN6I_ISP_AE_CFG_LOW_BRI_TH(0xff) | 71 SUN6I_ISP_AE_CFG_HORZ_NUM(8) | 72 SUN6I_ISP_AE_CFG_HIGH_BRI_TH(0xf00) | 73 SUN6I_ISP_AE_CFG_VERT_NUM(8)); 74} 75 76static void 77sun6i_isp_params_configure_bayer(struct sun6i_isp_device *isp_dev, 78 const struct sun6i_isp_params_config *config) 79{ 80 const struct sun6i_isp_params_config_bayer *bayer = &config->bayer; 81 82 sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_OFFSET0_REG, 83 SUN6I_ISP_BAYER_OFFSET0_R(bayer->offset_r) | 84 SUN6I_ISP_BAYER_OFFSET0_GR(bayer->offset_gr)); 85 86 sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_OFFSET1_REG, 87 SUN6I_ISP_BAYER_OFFSET1_GB(bayer->offset_gb) | 88 SUN6I_ISP_BAYER_OFFSET1_B(bayer->offset_b)); 89 90 sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_GAIN0_REG, 91 SUN6I_ISP_BAYER_GAIN0_R(bayer->gain_r) | 92 SUN6I_ISP_BAYER_GAIN0_GR(bayer->gain_gr)); 93 94 sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_GAIN1_REG, 95 SUN6I_ISP_BAYER_GAIN1_GB(bayer->gain_gb) | 96 SUN6I_ISP_BAYER_GAIN1_B(bayer->gain_b)); 97} 98 99static void sun6i_isp_params_configure_wb(struct sun6i_isp_device *isp_dev) 100{ 101 /* These are default values that need to be set to get an output. */ 102 103 sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_GAIN0_REG, 104 SUN6I_ISP_WB_GAIN0_R(256) | 105 SUN6I_ISP_WB_GAIN0_GR(256)); 106 107 sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_GAIN1_REG, 108 SUN6I_ISP_WB_GAIN1_GB(256) | 109 SUN6I_ISP_WB_GAIN1_B(256)); 110 111 sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_CFG_REG, 112 SUN6I_ISP_WB_CFG_CLIP(0xfff)); 113} 114 115static void sun6i_isp_params_configure_base(struct sun6i_isp_device *isp_dev) 116{ 117 sun6i_isp_params_configure_ae(isp_dev); 118 sun6i_isp_params_configure_ob(isp_dev); 119 sun6i_isp_params_configure_wb(isp_dev); 120} 121 122static void 123sun6i_isp_params_configure_bdnf(struct sun6i_isp_device *isp_dev, 124 const struct sun6i_isp_params_config *config) 125{ 126 const struct sun6i_isp_params_config_bdnf *bdnf = &config->bdnf; 127 128 sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_CFG_REG, 129 SUN6I_ISP_BDNF_CFG_IN_DIS_MIN(bdnf->in_dis_min) | 130 SUN6I_ISP_BDNF_CFG_IN_DIS_MAX(bdnf->in_dis_max)); 131 132 sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_COEF_RB_REG, 133 SUN6I_ISP_BDNF_COEF_RB(0, bdnf->coefficients_rb[0]) | 134 SUN6I_ISP_BDNF_COEF_RB(1, bdnf->coefficients_rb[1]) | 135 SUN6I_ISP_BDNF_COEF_RB(2, bdnf->coefficients_rb[2]) | 136 SUN6I_ISP_BDNF_COEF_RB(3, bdnf->coefficients_rb[3]) | 137 SUN6I_ISP_BDNF_COEF_RB(4, bdnf->coefficients_rb[4])); 138 139 sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_COEF_G_REG, 140 SUN6I_ISP_BDNF_COEF_G(0, bdnf->coefficients_g[0]) | 141 SUN6I_ISP_BDNF_COEF_G(1, bdnf->coefficients_g[1]) | 142 SUN6I_ISP_BDNF_COEF_G(2, bdnf->coefficients_g[2]) | 143 SUN6I_ISP_BDNF_COEF_G(3, bdnf->coefficients_g[3]) | 144 SUN6I_ISP_BDNF_COEF_G(4, bdnf->coefficients_g[4]) | 145 SUN6I_ISP_BDNF_COEF_G(5, bdnf->coefficients_g[5]) | 146 SUN6I_ISP_BDNF_COEF_G(6, bdnf->coefficients_g[6])); 147} 148 149static void 150sun6i_isp_params_configure_modules(struct sun6i_isp_device *isp_dev, 151 const struct sun6i_isp_params_config *config) 152{ 153 u32 value; 154 155 if (config->modules_used & SUN6I_ISP_MODULE_BDNF) 156 sun6i_isp_params_configure_bdnf(isp_dev, config); 157 158 if (config->modules_used & SUN6I_ISP_MODULE_BAYER) 159 sun6i_isp_params_configure_bayer(isp_dev, config); 160 161 value = sun6i_isp_load_read(isp_dev, SUN6I_ISP_MODULE_EN_REG); 162 /* Clear all modules but keep input configuration. */ 163 value &= SUN6I_ISP_MODULE_EN_SRC0 | SUN6I_ISP_MODULE_EN_SRC1; 164 165 if (config->modules_used & SUN6I_ISP_MODULE_BDNF) 166 value |= SUN6I_ISP_MODULE_EN_BDNF; 167 168 /* Bayer stage is always enabled. */ 169 170 sun6i_isp_load_write(isp_dev, SUN6I_ISP_MODULE_EN_REG, value); 171} 172 173void sun6i_isp_params_configure(struct sun6i_isp_device *isp_dev) 174{ 175 struct sun6i_isp_params_state *state = &isp_dev->params.state; 176 unsigned long flags; 177 178 spin_lock_irqsave(&state->lock, flags); 179 180 sun6i_isp_params_configure_base(isp_dev); 181 182 /* Default config is only applied at the very first stream start. */ 183 if (state->configured) 184 goto complete; 185 186 sun6i_isp_params_configure_modules(isp_dev, 187 &sun6i_isp_params_config_default); 188 189 state->configured = true; 190 191complete: 192 spin_unlock_irqrestore(&state->lock, flags); 193} 194 195/* State */ 196 197static void sun6i_isp_params_state_cleanup(struct sun6i_isp_device *isp_dev, 198 bool error) 199{ 200 struct sun6i_isp_params_state *state = &isp_dev->params.state; 201 struct sun6i_isp_buffer *isp_buffer; 202 struct vb2_buffer *vb2_buffer; 203 unsigned long flags; 204 205 spin_lock_irqsave(&state->lock, flags); 206 207 if (state->pending) { 208 vb2_buffer = &state->pending->v4l2_buffer.vb2_buf; 209 vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR : 210 VB2_BUF_STATE_QUEUED); 211 212 state->pending = NULL; 213 } 214 215 list_for_each_entry(isp_buffer, &state->queue, list) { 216 vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf; 217 vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR : 218 VB2_BUF_STATE_QUEUED); 219 } 220 221 INIT_LIST_HEAD(&state->queue); 222 223 spin_unlock_irqrestore(&state->lock, flags); 224} 225 226void sun6i_isp_params_state_update(struct sun6i_isp_device *isp_dev, 227 bool *update) 228{ 229 struct sun6i_isp_params_state *state = &isp_dev->params.state; 230 struct sun6i_isp_buffer *isp_buffer; 231 struct vb2_buffer *vb2_buffer; 232 const struct sun6i_isp_params_config *config; 233 unsigned long flags; 234 235 spin_lock_irqsave(&state->lock, flags); 236 237 if (list_empty(&state->queue)) 238 goto complete; 239 240 if (state->pending) 241 goto complete; 242 243 isp_buffer = list_first_entry(&state->queue, struct sun6i_isp_buffer, 244 list); 245 246 vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf; 247 config = vb2_plane_vaddr(vb2_buffer, 0); 248 249 sun6i_isp_params_configure_modules(isp_dev, config); 250 251 list_del(&isp_buffer->list); 252 253 state->pending = isp_buffer; 254 255 if (update) 256 *update = true; 257 258complete: 259 spin_unlock_irqrestore(&state->lock, flags); 260} 261 262void sun6i_isp_params_state_complete(struct sun6i_isp_device *isp_dev) 263{ 264 struct sun6i_isp_params_state *state = &isp_dev->params.state; 265 struct sun6i_isp_buffer *isp_buffer; 266 struct vb2_buffer *vb2_buffer; 267 unsigned long flags; 268 269 spin_lock_irqsave(&state->lock, flags); 270 271 if (!state->pending) 272 goto complete; 273 274 isp_buffer = state->pending; 275 vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf; 276 277 vb2_buffer->timestamp = ktime_get_ns(); 278 279 /* Parameters will be applied starting from the next frame. */ 280 isp_buffer->v4l2_buffer.sequence = isp_dev->capture.state.sequence + 1; 281 282 vb2_buffer_done(vb2_buffer, VB2_BUF_STATE_DONE); 283 284 state->pending = NULL; 285 286complete: 287 spin_unlock_irqrestore(&state->lock, flags); 288} 289 290/* Queue */ 291 292static int sun6i_isp_params_queue_setup(struct vb2_queue *queue, 293 unsigned int *buffers_count, 294 unsigned int *planes_count, 295 unsigned int sizes[], 296 struct device *alloc_devs[]) 297{ 298 struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue); 299 unsigned int size = isp_dev->params.format.fmt.meta.buffersize; 300 301 if (*planes_count) 302 return sizes[0] < size ? -EINVAL : 0; 303 304 *planes_count = 1; 305 sizes[0] = size; 306 307 return 0; 308} 309 310static int sun6i_isp_params_buffer_prepare(struct vb2_buffer *vb2_buffer) 311{ 312 struct sun6i_isp_device *isp_dev = 313 vb2_get_drv_priv(vb2_buffer->vb2_queue); 314 struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev; 315 unsigned int size = isp_dev->params.format.fmt.meta.buffersize; 316 317 if (vb2_plane_size(vb2_buffer, 0) < size) { 318 v4l2_err(v4l2_dev, "buffer too small (%lu < %u)\n", 319 vb2_plane_size(vb2_buffer, 0), size); 320 return -EINVAL; 321 } 322 323 vb2_set_plane_payload(vb2_buffer, 0, size); 324 325 return 0; 326} 327 328static void sun6i_isp_params_buffer_queue(struct vb2_buffer *vb2_buffer) 329{ 330 struct sun6i_isp_device *isp_dev = 331 vb2_get_drv_priv(vb2_buffer->vb2_queue); 332 struct sun6i_isp_params_state *state = &isp_dev->params.state; 333 struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(vb2_buffer); 334 struct sun6i_isp_buffer *isp_buffer = 335 container_of(v4l2_buffer, struct sun6i_isp_buffer, v4l2_buffer); 336 bool capture_streaming = isp_dev->capture.state.streaming; 337 unsigned long flags; 338 339 spin_lock_irqsave(&state->lock, flags); 340 list_add_tail(&isp_buffer->list, &state->queue); 341 spin_unlock_irqrestore(&state->lock, flags); 342 343 if (state->streaming && capture_streaming) 344 sun6i_isp_state_update(isp_dev, false); 345} 346 347static int sun6i_isp_params_start_streaming(struct vb2_queue *queue, 348 unsigned int count) 349{ 350 struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue); 351 struct sun6i_isp_params_state *state = &isp_dev->params.state; 352 bool capture_streaming = isp_dev->capture.state.streaming; 353 354 state->streaming = true; 355 356 /* 357 * Update the state as soon as possible if capture is streaming, 358 * otherwise it will be applied when capture starts streaming. 359 */ 360 361 if (capture_streaming) 362 sun6i_isp_state_update(isp_dev, false); 363 364 return 0; 365} 366 367static void sun6i_isp_params_stop_streaming(struct vb2_queue *queue) 368{ 369 struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue); 370 struct sun6i_isp_params_state *state = &isp_dev->params.state; 371 372 state->streaming = false; 373 sun6i_isp_params_state_cleanup(isp_dev, true); 374} 375 376static const struct vb2_ops sun6i_isp_params_queue_ops = { 377 .queue_setup = sun6i_isp_params_queue_setup, 378 .buf_prepare = sun6i_isp_params_buffer_prepare, 379 .buf_queue = sun6i_isp_params_buffer_queue, 380 .start_streaming = sun6i_isp_params_start_streaming, 381 .stop_streaming = sun6i_isp_params_stop_streaming, 382 .wait_prepare = vb2_ops_wait_prepare, 383 .wait_finish = vb2_ops_wait_finish, 384}; 385 386/* Video Device */ 387 388static int sun6i_isp_params_querycap(struct file *file, void *private, 389 struct v4l2_capability *capability) 390{ 391 struct sun6i_isp_device *isp_dev = video_drvdata(file); 392 struct video_device *video_dev = &isp_dev->params.video_dev; 393 394 strscpy(capability->driver, SUN6I_ISP_NAME, sizeof(capability->driver)); 395 strscpy(capability->card, video_dev->name, sizeof(capability->card)); 396 snprintf(capability->bus_info, sizeof(capability->bus_info), 397 "platform:%s", dev_name(isp_dev->dev)); 398 399 return 0; 400} 401 402static int sun6i_isp_params_enum_fmt(struct file *file, void *private, 403 struct v4l2_fmtdesc *fmtdesc) 404{ 405 struct sun6i_isp_device *isp_dev = video_drvdata(file); 406 struct v4l2_meta_format *params_format = 407 &isp_dev->params.format.fmt.meta; 408 409 if (fmtdesc->index > 0) 410 return -EINVAL; 411 412 fmtdesc->pixelformat = params_format->dataformat; 413 414 return 0; 415} 416 417static int sun6i_isp_params_g_fmt(struct file *file, void *private, 418 struct v4l2_format *format) 419{ 420 struct sun6i_isp_device *isp_dev = video_drvdata(file); 421 422 *format = isp_dev->params.format; 423 424 return 0; 425} 426 427static const struct v4l2_ioctl_ops sun6i_isp_params_ioctl_ops = { 428 .vidioc_querycap = sun6i_isp_params_querycap, 429 430 .vidioc_enum_fmt_meta_out = sun6i_isp_params_enum_fmt, 431 .vidioc_g_fmt_meta_out = sun6i_isp_params_g_fmt, 432 .vidioc_s_fmt_meta_out = sun6i_isp_params_g_fmt, 433 .vidioc_try_fmt_meta_out = sun6i_isp_params_g_fmt, 434 435 .vidioc_create_bufs = vb2_ioctl_create_bufs, 436 .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 437 .vidioc_reqbufs = vb2_ioctl_reqbufs, 438 .vidioc_querybuf = vb2_ioctl_querybuf, 439 .vidioc_expbuf = vb2_ioctl_expbuf, 440 .vidioc_qbuf = vb2_ioctl_qbuf, 441 .vidioc_dqbuf = vb2_ioctl_dqbuf, 442 .vidioc_streamon = vb2_ioctl_streamon, 443 .vidioc_streamoff = vb2_ioctl_streamoff, 444}; 445 446static const struct v4l2_file_operations sun6i_isp_params_fops = { 447 .owner = THIS_MODULE, 448 .unlocked_ioctl = video_ioctl2, 449 .open = v4l2_fh_open, 450 .release = vb2_fop_release, 451 .mmap = vb2_fop_mmap, 452 .poll = vb2_fop_poll, 453}; 454 455/* Params */ 456 457int sun6i_isp_params_setup(struct sun6i_isp_device *isp_dev) 458{ 459 struct sun6i_isp_params *params = &isp_dev->params; 460 struct sun6i_isp_params_state *state = ¶ms->state; 461 struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev; 462 struct v4l2_subdev *proc_subdev = &isp_dev->proc.subdev; 463 struct video_device *video_dev = ¶ms->video_dev; 464 struct vb2_queue *queue = &isp_dev->params.queue; 465 struct media_pad *pad = &isp_dev->params.pad; 466 struct v4l2_format *format = &isp_dev->params.format; 467 struct v4l2_meta_format *params_format = &format->fmt.meta; 468 int ret; 469 470 /* State */ 471 472 INIT_LIST_HEAD(&state->queue); 473 spin_lock_init(&state->lock); 474 475 /* Media Pads */ 476 477 pad->flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; 478 479 ret = media_entity_pads_init(&video_dev->entity, 1, pad); 480 if (ret) 481 goto error_mutex; 482 483 /* Queue */ 484 485 mutex_init(¶ms->lock); 486 487 queue->type = V4L2_BUF_TYPE_META_OUTPUT; 488 queue->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 489 queue->buf_struct_size = sizeof(struct sun6i_isp_buffer); 490 queue->ops = &sun6i_isp_params_queue_ops; 491 queue->mem_ops = &vb2_vmalloc_memops; 492 queue->min_queued_buffers = 1; 493 queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 494 queue->lock = ¶ms->lock; 495 queue->dev = isp_dev->dev; 496 queue->drv_priv = isp_dev; 497 498 ret = vb2_queue_init(queue); 499 if (ret) { 500 v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret); 501 goto error_media_entity; 502 } 503 504 /* V4L2 Format */ 505 506 format->type = queue->type; 507 params_format->dataformat = V4L2_META_FMT_SUN6I_ISP_PARAMS; 508 params_format->buffersize = sizeof(struct sun6i_isp_params_config); 509 510 /* Video Device */ 511 512 strscpy(video_dev->name, SUN6I_ISP_PARAMS_NAME, 513 sizeof(video_dev->name)); 514 video_dev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING; 515 video_dev->vfl_dir = VFL_DIR_TX; 516 video_dev->release = video_device_release_empty; 517 video_dev->fops = &sun6i_isp_params_fops; 518 video_dev->ioctl_ops = &sun6i_isp_params_ioctl_ops; 519 video_dev->v4l2_dev = v4l2_dev; 520 video_dev->queue = queue; 521 video_dev->lock = ¶ms->lock; 522 523 video_set_drvdata(video_dev, isp_dev); 524 525 ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1); 526 if (ret) { 527 v4l2_err(v4l2_dev, "failed to register video device: %d\n", 528 ret); 529 goto error_media_entity; 530 } 531 532 /* Media Pad Link */ 533 534 ret = media_create_pad_link(&video_dev->entity, 0, 535 &proc_subdev->entity, 536 SUN6I_ISP_PROC_PAD_SINK_PARAMS, 537 MEDIA_LNK_FL_ENABLED | 538 MEDIA_LNK_FL_IMMUTABLE); 539 if (ret < 0) { 540 v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n", 541 video_dev->entity.name, 0, proc_subdev->entity.name, 542 SUN6I_ISP_PROC_PAD_SINK_PARAMS); 543 goto error_video_device; 544 } 545 546 return 0; 547 548error_video_device: 549 vb2_video_unregister_device(video_dev); 550 551error_media_entity: 552 media_entity_cleanup(&video_dev->entity); 553 554error_mutex: 555 mutex_destroy(¶ms->lock); 556 557 return ret; 558} 559 560void sun6i_isp_params_cleanup(struct sun6i_isp_device *isp_dev) 561{ 562 struct sun6i_isp_params *params = &isp_dev->params; 563 struct video_device *video_dev = ¶ms->video_dev; 564 565 vb2_video_unregister_device(video_dev); 566 media_entity_cleanup(&video_dev->entity); 567 mutex_destroy(¶ms->lock); 568} 569