From patchwork Wed Feb 4 20:37:25 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: 26089 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 53833BD78E for ; Wed, 4 Feb 2026 20:38:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0133762048; Wed, 4 Feb 2026 21:38:15 +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="i9ex0h32"; dkim-atps=neutral Received: from mail-pl1-x630.google.com (mail-pl1-x630.google.com [IPv6:2607:f8b0:4864:20::630]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E526262043 for ; Wed, 4 Feb 2026 21:38:12 +0100 (CET) Received: by mail-pl1-x630.google.com with SMTP id d9443c01a7336-2a097cc08d5so572565ad.0 for ; Wed, 04 Feb 2026 12:38:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770237491; x=1770842291; 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=+YiPQWXH9LfFe5Ipw86gccMFuVs2bYaP/flxUeZTgEw=; b=i9ex0h32t/IeSVCPcVS6hqEHj/1TdN+wC9B4qpNhaUr4ZABLqvrHDr+BetyOoV6cbD +jxwmqIDx8Mz5AlOGBO7EniQUsC7Cr07Jow4v9l8wvPhnQKJpVOLx019+epGeu9zhVAw aLHy5J4o0lqVyb5bDWIUp0fC8DSfoW032HfURinei5ed9H+JwjiO3r1UZTM6US5+iEN0 MqhQlEnbs5wmv0ytVUJ00kV7vnSOkf4EN7oDcdZNRfRNJx9WMuFA4zm5EFvYT5KQtjT9 h4flx5dbBwWQXmKZDeYm4ofe6INsnE5O9PnbwT8qJPV8Z8YnDbJeE1t4Ldm6mVaZl20E pTXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770237491; x=1770842291; 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=+YiPQWXH9LfFe5Ipw86gccMFuVs2bYaP/flxUeZTgEw=; b=w25ldTcKYLJajZZvrZn39lnemvnLwnOZkZEHAIR7ePgqnAK5etVe2cOO9pqHjss+H+ 7Nli+pwFOXj53AQzSt0sks1ry+iK9m7dvR9oa9G1MHWPnFOPC20PGJ7+h0xT1G7hCCGK QF/GSqtX17/U55TGfj2CttU299sNNApJuyRqGo4lUPJhQ7vr9xInYwN0XLtFt1QGqL2M 1vKemu+iqvVV2Qw53QqG/b3VVTZHuf6L4HBpZMWmRe3EhFB0LV2xLDOUcYXGknt3j8ni S7+EAgCxXzi5WwotnGdezqxOVDaxJ5RRSvGVkJ0FiwyoumbtS9zqTA5MR598RlbeG9rJ wF5g== X-Forwarded-Encrypted: i=1; AJvYcCXzrnllGdbKJ6EdCtdG214x0DoMzH+Z81PME/mYlfBQUJ/AX2kYwXcFmEbQYlrqZSIr3EJd6QbgiFXBlqmifTQ=@lists.libcamera.org X-Gm-Message-State: AOJu0Yx5bI3JWg0M7d2TbZaAHrzNBAaxJd18rQ3zYnz/DclbC4ftPZcV hCnghJWY5MOBOyKQqerzfhrfU2GprFzoBt6t4YjhP/1q93NSXKfTvZjS X-Gm-Gg: AZuq6aJam2F6Re42qJTH8T2cXrQLjQv0vUMa5Ma79ze7WCNR0V7nYPuvVhdQka6m8+H 9VmDxgdg1nChDam8HnNetgRrK2PWM7Y+OLTkIdqHCrI+r9hDUm0sRj0aT3VQPBM+Vw3lUEqBBtU UwC0KD5CgkKFc0yiQM30zOOukHKlR1xWRqQ0fNseA2ZH5zih6ANwm22vwPtIV97ndgZeRllCtgA vkmbCHivcqgiqWuIVfCfbT/y50Kyvtz+Ie5gIL1bjp5p0kO/8yc7ovwNSAPWYq0jP8C1d/pDpM3 +nJtBWMiEQkZK82IkLiaPEOvKKNrAzKnrxVSDCbMI7mJhaagqtTbkcTlCqQw/NOzcWLod0OPopm Dj9UI5ZrEwhQk0JJJhDx6kqjx0eTIkn9VIB9wUM9LqzFBC8A6pLFBPf8DMmEuQCRJ2zUwm5cTtQ Q6t2sSSyWb8qAL8+mA1mn7REIuokzjRQR9Xaq/FKbwzIfL X-Received: by 2002:a17:902:cf07:b0:29a:56a:8b81 with SMTP id d9443c01a7336-2a93400b5c5mr30910985ad.8.1770237491410; Wed, 04 Feb 2026 12:38:11 -0800 (PST) Received: from FAIZEL-KB.. ([2001:569:5999:dc00:876b:c389:85e5:7957]) by smtp.googlemail.com with ESMTPSA id d9443c01a7336-2a933974884sm31136955ad.83.2026.02.04.12.38.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Feb 2026 12:38:10 -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 v3 2/3] media: vimc: sensor: Add pixel_rate, vblank and hblank configuration Date: Wed, 4 Feb 2026 12:37:25 -0800 Message-ID: <20260204203726.1820226-3-faizel.kb@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260204203726.1820226-1-faizel.kb@gmail.com> References: <20260204203726.1820226-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 | 88 +++++++++++++++++++ 2 files changed, 101 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..6c3e6066eaa5 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,24 @@ 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; + u64 vts; + + target_fps = (width * height <= VIMC_PIXELS_THRESHOLD_30FPS) ? 30 : 10; + + vts = (u64)pixel_rate; + do_div(vts, target_fps * hts); + + if (vts > height) + return clamp((u32)(vts - height), VIMC_VBLANK_MIN, VIMC_VBLANK_MAX); + + return VIMC_VBLANK_MIN; +} + static int vimc_sensor_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -137,6 +180,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 +279,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 +352,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 +445,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;