From patchwork Mon Feb 2 19:46:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faizel K B X-Patchwork-Id: 26081 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 1AF63C3226 for ; Mon, 2 Feb 2026 19:47:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B62D562007; Mon, 2 Feb 2026 20:47:11 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="BnE7XNCs"; dkim-atps=neutral Received: from mail-pg1-x52c.google.com (mail-pg1-x52c.google.com [IPv6:2607:f8b0:4864:20::52c]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3E9CA62000 for ; Mon, 2 Feb 2026 20:47:10 +0100 (CET) Received: by mail-pg1-x52c.google.com with SMTP id 41be03b00d2f7-c634be422b2so304832a12.1 for ; Mon, 02 Feb 2026 11:47:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770061629; x=1770666429; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BkX201pGc8zZ3+cPLNIedhLkaj9hw8wjTG/zVIPjTJE=; b=BnE7XNCsnCd1QsvwWzyIt83vDeoTKaEztJCdpo224RezJao6SIsYzpeyUOVQWIoFJK 0ZvJlCoFqMvBYoPaprHRSAMI3hjAjFX2SL8VvBpA70dHNE8ArT9TdVzjDxe1e4Rs0Kej exhEffIT9EdOIhh323WAcynkLnnvmyxwMLLQTBVQOM6AqVeQrPVJdWWkred+QDanIpRq 3zOGkPIKtfvIsIAccxpFRP7LUC8ev3qsCyEHWhNmUDuJMkM1l082+3R/0QUEIZFhc/vp irKT8OkBdGAG1W9amqmqi1fWpmQnEJ5V8qXE/vpSwJEjcKiFvHgzx9qx767sWqxrAxOP DKog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770061629; x=1770666429; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=BkX201pGc8zZ3+cPLNIedhLkaj9hw8wjTG/zVIPjTJE=; b=gcwixGtNZrbw4t4K+b+MTFMqga1apVNbZzEmH/M0JUUi9kQJqg0lNHS/edxgwh901t 5KfTEFFzHtN9WDMZGcD/PAx7dshAAHpJUVc3CQAfn6LMUaTI5oQ34X1I6eSeRRW6lfpb LQKjSwea1j/PlRFUNXxeOnfKpnyYGPl+EV63dNWDdNwvk2FbnF/4gppIP10PLkiIP7oQ /aCm9EFaGHK3lfsc6YcatR1ST+qBNKwD+cYRTydKmKBKMk8clX1py8IEcMiX401IK1Fj 3hK458u0f6tzC8whD0n5eKxrhZ5YnxPt/J7XvDPG4aPNjTdIR4OJrHdv1LUsOli7eO0t JGeA== X-Forwarded-Encrypted: i=1; AJvYcCXcBLmsx5K2FkvUNtrrLvxsNa/fbiwFIfzUlRVve22c9t5ibyZj80SWDkTNXeqxITx7qAOkTpl8ZDWOwEYEMLQ=@lists.libcamera.org X-Gm-Message-State: AOJu0Yxdxf/YIc/BvRve26Fs2ZHV9SPt0COUyza7rOjDNG5BopuqUgC+ Bc04jBYU47L/GkiMAE2y4yBYN7esbcMUqytO2b/Yc2TtWJYgINoNMEcq X-Gm-Gg: AZuq6aLHHl7J1wlP7KdioGQLm07MwMhVGwZrPzx8ICj4eRyuY+SSY4Jey9UeWUfGjE+ mGqtSRs2+oaMAPEGwPByCe5fScbymtdI4dbE2ThZJMXAfIpvcdKNSzGsb+BhnrtCaYu6kYy6s/g PMWR0u4b1mP5jcXBsOzRG0KSEQDkUhavjmzHM8x+/XKMV/E1tQR0Ktyj+sv8obE53GJpAhZXiho ygmsP/VW390oBTDtqtjUYvd5SR7okpSVEcPminlikTcg6y1W3LaqIYnCT7EUvadqmJ1+2gNLcov WXvA3JMr41/AiIUKRhLcNuERCmW9ig3COvfQLgvXm9sDJfN+0Lj+yzwwd6tAbfCi7fVqXB06PrT ZuKmcLhBAaUWS/xGKLmnOJQB+vZR8m/H0rJpL68b5GtkdDJbjX+S/VBl+EQ4Go1x2HF6RR9a+5j DOt+pGr1Y2k8VjoY8SEpmGWOwjWkq6UBEPDWvHCevhtweM2wPZXM6EaQ== X-Received: by 2002:a05:6a20:734b:b0:38e:9a8b:248d with SMTP id adf61e73a8af0-392e0163a22mr9055261637.5.1770061628779; Mon, 02 Feb 2026 11:47:08 -0800 (PST) Received: from FAIZEL-KB.. ([2001:569:5999:dc00:af0:4465:b482:1e01]) by smtp.googlemail.com with ESMTPSA id d2e1a72fcca58-82379b1bc68sm16667416b3a.2.2026.02.02.11.47.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Feb 2026 11:47:08 -0800 (PST) From: Faizel K B To: Shuah Khan , Laurent Pinchart , Kieran Bingham , linux-media@vger.kernel.org Cc: Mauro Carvalho Chehab , libcamera-devel@lists.libcamera.org, Faizel K B Subject: [PATCH v2 2/3] media: vimc: sensor: Add pixel_rate, vblank and hblank configuration Date: Mon, 2 Feb 2026 11:46:44 -0800 Message-ID: <20260202194645.1287757-3-faizel.kb@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202194645.1287757-1-faizel.kb@gmail.com> References: <20260202194645.1287757-1-faizel.kb@gmail.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" pixel_rate and hblank as read only parameter. vblank can be configured to match the desired frame rate. Default values are, pixel_rate - 160 MHz, hblank - 800. vblank defaults to an equivalent value of 30 fps for resolutions less than or equal to 1920x1080 and 10 fps for higher resolutions. For higher resolutions, modify pixel_rate in the driver code. fps = pixel_rate / ((width + hblank) * (height + vblank)) minimum vblank - 4, maximum vblank - 65535 The configured fps delay is pre-calculated into jiffies and stored in the sensor's hw structure for efficient access by the streamer thread. Signed-off-by: Faizel K B --- drivers/media/test-drivers/vimc/vimc-common.h | 13 +++ drivers/media/test-drivers/vimc/vimc-sensor.c | 82 +++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/drivers/media/test-drivers/vimc/vimc-common.h b/drivers/media/test-drivers/vimc/vimc-common.h index 35789add6b4a..861b334ffc65 100644 --- a/drivers/media/test-drivers/vimc/vimc-common.h +++ b/drivers/media/test-drivers/vimc/vimc-common.h @@ -29,6 +29,15 @@ #define VIMC_FRAME_MIN_WIDTH 16 #define VIMC_FRAME_MIN_HEIGHT 16 +#define VIMC_PIXEL_RATE_FIXED 160000000 /* 160 MHz */ +#define VIMC_HBLANK_FIXED 800 +/* VBLANK - vertical blanking (primary FPS control) */ +#define VIMC_VBLANK_MIN 4 +#define VIMC_VBLANK_MAX 65535 +#define VIMC_VBLANK_STEP 1 +#define VIMC_VBLANK_DEFAULT 3223 /* 30fps vga */ +#define VIMC_PIXELS_THRESHOLD_30FPS (1920 * 1080) /* 2073600 pixels */ + #define VIMC_FRAME_INDEX(lin, col, width, bpp) ((lin * width + col) * bpp) /* Source and sink pad checks */ @@ -173,6 +182,9 @@ struct vimc_sensor_device { struct tpg_data tpg; struct v4l2_ctrl_handler hdl; struct media_pad pad; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; u8 *frame; @@ -184,6 +196,7 @@ struct vimc_sensor_device { struct v4l2_area size; enum vimc_sensor_osd_mode osd_value; u64 start_stream_ts; + unsigned long fps_jiffies; } hw; }; diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c index 2b07dc1f1278..84cef55b68f8 100644 --- a/drivers/media/test-drivers/vimc/vimc-sensor.c +++ b/drivers/media/test-drivers/vimc/vimc-sensor.c @@ -25,10 +25,15 @@ static const struct v4l2_mbus_framefmt fmt_default = { static int vimc_sensor_init_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { + struct vimc_sensor_device *vsensor = + container_of(sd, struct vimc_sensor_device, sd); + struct v4l2_mbus_framefmt *mf; mf = v4l2_subdev_state_get_format(sd_state, 0); *mf = fmt_default; + vsensor->hw.size.width = fmt_default.width; + vsensor->hw.size.height = fmt_default.height; return 0; } @@ -87,6 +92,26 @@ static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor, tpg_s_xfer_func(&vsensor->tpg, format->xfer_func); } +static int vimc_sensor_update_frame_timing(struct v4l2_subdev *sd, + u32 width, u32 height) +{ + struct vimc_sensor_device *vsensor = + container_of(sd, struct vimc_sensor_device, sd); + u64 pixel_rate = vsensor->pixel_rate->val; + u32 hts = width + vsensor->hblank->val; + u32 vts = height + vsensor->vblank->val; + u64 total_pixels = (u64)hts * vts; + u64 frame_interval_ns; + + frame_interval_ns = total_pixels * NSEC_PER_SEC; + do_div(frame_interval_ns, pixel_rate); + vsensor->hw.fps_jiffies = nsecs_to_jiffies(frame_interval_ns); + if (vsensor->hw.fps_jiffies == 0) + vsensor->hw.fps_jiffies = 1; + + return 0; +} + static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt) { const struct vimc_pix_map *vpix; @@ -108,6 +133,18 @@ static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt) vimc_colorimetry_clamp(fmt); } +static u32 vimc_calc_vblank(u32 width, u32 height, + s64 pixel_rate, s32 hblank) +{ + u32 hts = width + hblank; + u32 target_fps; + u32 vblank_def; + + target_fps = (width * height <= VIMC_PIXELS_THRESHOLD_30FPS) ? 30 : 10; + vblank_def = (pixel_rate / (target_fps * hts)) - height; + return clamp(vblank_def, VIMC_VBLANK_MIN, VIMC_VBLANK_MAX); +} + static int vimc_sensor_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -137,6 +174,20 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd, fmt->format.xfer_func, fmt->format.ycbcr_enc); *mf = fmt->format; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + u32 vblank_def = vimc_calc_vblank(fmt->format.width, + fmt->format.height, + vsensor->pixel_rate->val, + vsensor->hblank->val); + vsensor->hw.size.width = fmt->format.width; + vsensor->hw.size.height = fmt->format.height; + __v4l2_ctrl_modify_range(vsensor->vblank, + VIMC_VBLANK_MIN, + VIMC_VBLANK_MAX, + VIMC_VBLANK_STEP, + vblank_def); + __v4l2_ctrl_s_ctrl(vsensor->vblank, vblank_def); + } return 0; } @@ -222,6 +273,8 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable) vsensor->hw.size.width = format->width; vsensor->hw.size.height = format->height; + vimc_sensor_update_frame_timing(sd, format->width, + format->height); v4l2_subdev_unlock_state(state); @@ -293,6 +346,15 @@ static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl) case VIMC_CID_OSD_TEXT_MODE: vsensor->hw.osd_value = ctrl->val; break; + case V4L2_CID_PIXEL_RATE: + break; + case V4L2_CID_HBLANK: + break; + case V4L2_CID_VBLANK: + vimc_sensor_update_frame_timing(&vsensor->sd, + vsensor->hw.size.width, + vsensor->hw.size.height); + break; default: return -EINVAL; } @@ -377,6 +439,26 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc, V4L2_CID_HUE, -128, 127, 1, 0); v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_SATURATION, 0, 255, 1, 128); + /* Timing controls for frame interval configuration */ + vsensor->pixel_rate = v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, + V4L2_CID_PIXEL_RATE, + VIMC_PIXEL_RATE_FIXED, VIMC_PIXEL_RATE_FIXED, + 1, VIMC_PIXEL_RATE_FIXED); + if (vsensor->pixel_rate) + vsensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vsensor->hblank = v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, + V4L2_CID_HBLANK, + VIMC_HBLANK_FIXED, VIMC_HBLANK_FIXED, + 1, VIMC_HBLANK_FIXED); + if (vsensor->hblank) + vsensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vsensor->vblank = v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, + V4L2_CID_VBLANK, + VIMC_VBLANK_MIN, VIMC_VBLANK_MAX, + VIMC_VBLANK_STEP, VIMC_VBLANK_DEFAULT); + vsensor->sd.ctrl_handler = &vsensor->hdl; if (vsensor->hdl.error) { ret = vsensor->hdl.error;