From patchwork Thu Mar 12 23:16:15 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: 26281 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 EB0FFBDCC1 for ; Thu, 12 Mar 2026 23:17:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8E1D262675; Fri, 13 Mar 2026 00:17:40 +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="buzgabCd"; dkim-atps=neutral Received: from mail-pj1-x1032.google.com (mail-pj1-x1032.google.com [IPv6:2607:f8b0:4864:20::1032]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A62F76261B for ; Fri, 13 Mar 2026 00:17:39 +0100 (CET) Received: by mail-pj1-x1032.google.com with SMTP id 98e67ed59e1d1-3538952a464so139353a91.2 for ; Thu, 12 Mar 2026 16:17:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773357458; x=1773962258; 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=dIaf3x8xjAlsrE68JYAsh8jSNNqCyGPC00OSVKpEMxc=; b=buzgabCd/ZDflvw7k/NSPm10S/SIs+T9+kNrSqNjIXGKyqYTRplOnGlR8mRKQOuZqR 1XSxAouGZt3vSqJNnu6B2KrEpLAX37cVXY5SuXVygITxTpXqqw+iGeFijPIS4buRV2yL ekeN9wV7izBc8SJhp5ANJhS4fn2CqYrhJ1dhNkyIlHOC4CyG0OpAEFwFOOZ5eFmRi/rP Se+Wut/7DUR2BclqH6RJXVl++sclLRjoUA6E1z+Dfi3RHqj6tbjuEs2scIQFpvRikHEP Hq8njNC6Q1ojapufA61i7bHnUlFxVU1BVJ3D7kaUGQNqPDq39Aj24uUMqMcyEFNRorlj LFww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773357458; x=1773962258; 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=dIaf3x8xjAlsrE68JYAsh8jSNNqCyGPC00OSVKpEMxc=; b=bTEDb/39FhJsE+Uojq+zfkpNn1itHZZxtJnuePhZLSnAp6KFbUfp4aHBi3yJy8HHW6 fJmZAM8IZa4LrkKDfJL+Id+Bl7HB/SbMmhPO7ENVMGAvvGrauW6SUJNyzW3za4Op9cpT 5lau6AcIKOt/g5rJkiPqJ9rO/yRroWkAmFHqh0lbVFNc1ax3zIcOiJ5TYRCZ/pHSeM6I 2eFS3iMn/rxFnwQ6Fda8Ix0eME88qwrAuC1iYaV2xB+nfBUHuBaSXip557jO0PB/u38Z eKlOA+dvv6giiakrI2lQuwxglCOzIAqz5ucV7dz8ewGscJhgfnd86lYimqJ4zvWkT5Er lnBQ== X-Forwarded-Encrypted: i=1; AJvYcCVn/8s5Yv/64ts80r6HkQjyCf/lb0jq5oyyk6gazBrGim3UIe0WitqRx1gT/cVBtNJ+CvfVsX7TkWlyNIWHrDI=@lists.libcamera.org X-Gm-Message-State: AOJu0YxToHhnuSp1ttqVgMoJLfboit5mAArBiIBkZ81fbjmnY7NgBIoz wSH+0Wy6MxhWDhnyJvsBryEpXUM01ivjCEyXdNJLWjDifxdE2Q97Oiby X-Gm-Gg: ATEYQzyLJuR5ZgThViJ5UTnPjW4YUOEtdeatLi+ZkQlMr8B28qDsYwm2XagNo1JwB+2 4322f2W2hRcm1vXl+bAgP4DQ/rTvYkPsLe4jn9S5zncATwvXCugTDAiuvNvRBY3LrLX8wHSK16j fDf6ySTRXHhmjdUMtg63BTIfEQcPOZp2xkxoinCWo49yFRj+De6iUMm0W/kCpsjWGDzfFwEIpZr 5JkxUCS/ECILKePExJWq3VD/K/vNL0glgg8ftpccGqqVwH8eyvjLj8rn2633jLke4ZKZ3B2Yc8d /YLlw7GFhH/t6sRPvDmi9Bz3xXw1A3wKHfBRxQizkydkm2qoQQ+gwIw3ePXRuLu/+NvJ/fKHiE/ nLgo1mNOy8qm/pThCSp1zlSVlJ8x7OG9xYKdiQ6S6gxCu7SpdfkANpockU95vRLOmbPG/leUGft rMyf0Iab/jv1P2cEEg+nFMMQhTUIaZNjDPELDEqzYubZMkySCV2gPfYQk= X-Received: by 2002:a17:902:e810:b0:2ae:44dd:3377 with SMTP id d9443c01a7336-2aeca90943bmr7406165ad.1.1773357458023; Thu, 12 Mar 2026 16:17:38 -0700 (PDT) Received: from FAIZEL-KB.. ([2001:569:5b64:e100:3685:315:53bf:61fc]) by smtp.googlemail.com with ESMTPSA id d9443c01a7336-2aece81cde8sm619395ad.70.2026.03.12.16.17.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 12 Mar 2026 16:17:37 -0700 (PDT) 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 RESEND v3 2/3] media: vimc: sensor: Add pixel_rate, vblank and hblank configuration Date: Thu, 12 Mar 2026 16:16:15 -0700 Message-ID: <20260312231616.3590215-3-faizel.kb@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260312231616.3590215-1-faizel.kb@gmail.com> References: <20260312231616.3590215-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 4c64cdab8cda..5deebcc78a33 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;