From patchwork Wed May 14 11:25:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890079 Received: from fllvem-ot04.ext.ti.com (fllvem-ot04.ext.ti.com [198.47.19.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D833D274FEE; Wed, 14 May 2025 11:26:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.19.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221973; cv=none; b=GPSbJlwCVRX2T5fKSsZV5fwEEHppO116lpwgRPpuJpSbw/LkZEjBst+Dtc1Lq/EG2UF4eUQE9QaEiOpbzTDixfIk9/p0pj1TTt2T+JobM2aNr9CmzO6nGykgyLct9UI0I3VyN7uleDBtorkDzderUWcZoftV06gGKpnVKKurjhY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221973; c=relaxed/simple; bh=nfAR/AUDrZuYvugAQMm+3h89czk1ZmKRlR4nCZXTCHw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tn1M/ENRAsRhl0I2aH3TWaTFQcCAvnixyvSGweuKLD40bl452CRBrclmuFWZ1nYST6kTStgannNgMJ/h7tH5OLHGqN+6WKwZBt0FBJ8vciDF1mY8QuwcYAZslQTcn8Ih90byDcg4cHJtGqXAyRV8ycm2DUTHdMDfjuCEG1exXJw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=fBJp93IZ; arc=none smtp.client-ip=198.47.19.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="fBJp93IZ" Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllvem-ot04.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBPfAN3126770 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:25:41 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221941; bh=6b2JaUrryYTuC8lOEgCSmmlQ9k7ivzyLoDXAQW395ZY=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=fBJp93IZIfokMuBh48EejLOJqpshu8jN069X3ll4+ywlN9eWmwEMlvkuN1NwD1taN xersEXTqsXF019zcEvdnxzPtg4lgvNToZJIIDdDG/EOv84Y5pK6IPSX2mx1D7PjlNu CzweWrF6iHk2Sbl5WN9X52G3FAct1qQ5r/9i18cM= Received: from DLEE113.ent.ti.com (dlee113.ent.ti.com [157.170.170.24]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBPf85119998 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:25:41 -0500 Received: from DLEE109.ent.ti.com (157.170.170.41) by DLEE113.ent.ti.com (157.170.170.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:25:41 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DLEE109.ent.ti.com (157.170.170.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:25:40 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSV7107507; Wed, 14 May 2025 06:25:35 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 01/12] dt-bindings: media: ti, j721e-csi2rx-shim: Support 32 dma chans Date: Wed, 14 May 2025 16:55:16 +0530 Message-ID: <20250514112527.1983068-2-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Jai Luthra The CSI2RX SHIM IP can support 32x DMA channels. These can be used to split incoming "streams" of data on the CSI-RX port, distinguished by MIPI Virtual Channel (or Data Type), into different locations in memory. Actual number of DMA channels allocated to CSI-RX is dependent on the usecase, and can be modified using the K3 Resource Partitioning tool [1]. So set the minimum channels as 1 and maximum as 32. Link: https://software-dl.ti.com/processor-sdk-linux/esd/AM62X/10_00_07_04/exports/docs/linux/How_to_Guides/Host/K3_Resource_Partitioning_Tool.html [1] Link: https://www.ti.com/lit/pdf/spruiv7 Signed-off-by: Jai Luthra Reviewed-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Reviewed-by: Rob Herring (Arm) Signed-off-by: Rishikesh Donadkar --- .../bindings/media/ti,j721e-csi2rx-shim.yaml | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml b/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml index b9f033f2f3ce4..bf62998b0445a 100644 --- a/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml +++ b/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml @@ -20,11 +20,44 @@ properties: const: ti,j721e-csi2rx-shim dmas: - maxItems: 1 + minItems: 1 + maxItems: 32 dma-names: + minItems: 1 items: - const: rx0 + - const: rx1 + - const: rx2 + - const: rx3 + - const: rx4 + - const: rx5 + - const: rx6 + - const: rx7 + - const: rx8 + - const: rx9 + - const: rx10 + - const: rx11 + - const: rx12 + - const: rx13 + - const: rx14 + - const: rx15 + - const: rx16 + - const: rx17 + - const: rx18 + - const: rx19 + - const: rx20 + - const: rx21 + - const: rx22 + - const: rx23 + - const: rx24 + - const: rx25 + - const: rx26 + - const: rx27 + - const: rx28 + - const: rx29 + - const: rx30 + - const: rx31 reg: maxItems: 1 @@ -62,8 +95,8 @@ examples: ti_csi2rx0: ticsi2rx@4500000 { compatible = "ti,j721e-csi2rx-shim"; - dmas = <&main_udmap 0x4940>; - dma-names = "rx0"; + dmas = <&main_udmap 0x4940>, <&main_udmap 0x4941>; + dma-names = "rx0", "rx1"; reg = <0x4500000 0x1000>; power-domains = <&k3_pds 26 TI_SCI_PD_EXCLUSIVE>; #address-cells = <1>; From patchwork Wed May 14 11:25:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890470 Received: from lelvem-ot01.ext.ti.com (lelvem-ot01.ext.ti.com [198.47.23.234]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D557F2741D3; Wed, 14 May 2025 11:26:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.234 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221971; cv=none; b=PJw8X55r4QkmAeOetp1xMZwUSC3MYn51+NjYlEu7vae4kPLFKyh4pVcPSvLDHRIAs/8YfxnAq5/YqGwwmCyBdcRxjx4ZSc/Q2Z3vcza6IwvxPGqvU6x5MBJYVsT9xb3MFnafx1/IBS/++25sSegrq3EPmOxPaIYvq+sdRUWdGVI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221971; c=relaxed/simple; bh=XY5ymHxdaxSILqV8wfl0T0bfQ2nnQz2KMVxfFRgnR/s=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=aVGa5GHunb+x8kbUTRIRuxrLxt/f5XrxIO9neaF/DIk5AKqchINpn/XG7tTLYDzzxiAa9ulN90SUntawfHSAVUza0hKNc1PtsR5oLDg1UWQ8oiWdOxlFaog0Zwyr2EA1EPkjckT5sEOyOYoOcNjp8N9TPpeuOIZXttwDiuLgJ5Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=bPHT34R2; arc=none smtp.client-ip=198.47.23.234 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="bPHT34R2" Received: from fllv0035.itg.ti.com ([10.64.41.0]) by lelvem-ot01.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBPl322604734 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:25:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221947; bh=iSF8l/S50T/HfVanPXXBuHy/0yWUU82QjX8I/yMhA9s=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=bPHT34R28wYRfTf+pPuI9Po42I/3dBQrpHvdv589xHjWJ+Mi3OD7Q+HV8A5gES+FK /6l7qYzXrya02VyFQdqA46JaHguSa4pExoZdBJO1grtzdRx3rXWjs1hpfrQt7FVMx9 tO7/NyZL64yv7CTECGeVAxjFcpgSejKIAFPm3v8s= Received: from DFLE109.ent.ti.com (dfle109.ent.ti.com [10.64.6.30]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBPlaI120036 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:25:47 -0500 Received: from DFLE106.ent.ti.com (10.64.6.27) by DFLE109.ent.ti.com (10.64.6.30) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:25:47 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DFLE106.ent.ti.com (10.64.6.27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:25:47 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSV8107507; Wed, 14 May 2025 06:25:41 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 02/12] media: ti: j721e-csi2rx: separate out device and context Date: Wed, 14 May 2025 16:55:17 +0530 Message-ID: <20250514112527.1983068-3-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Jai Luthra The TI CSI2RX wrapper has two parts: the main device and the DMA contexts. The driver was originally written with single camera capture in mind, so only one DMA context was needed. For the sake of simplicity, the context specific stuff was not modeled different to the main device. To enable multiplexed stream capture, the contexts need to be separated out from the main device. Create a struct ti_csi2rx_ctx that holds the DMA context specific things. Separate out functions handling the device and context related functionality. Co-developed-by: Pratyush Yadav Signed-off-by: Pratyush Yadav Signed-off-by: Jai Luthra Signed-off-by: Rishikesh Donadkar --- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 412 ++++++++++-------- 1 file changed, 228 insertions(+), 184 deletions(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 6412a00be8eab..36cde2e87aabb 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -40,6 +40,8 @@ #define SHIM_PSI_CFG0_DST_TAG GENMASK(31, 16) #define PSIL_WORD_SIZE_BYTES 16 +#define TI_CSI2RX_NUM_CTX 1 + /* * There are no hard limits on the width or height. The DMA engine can handle * all sizes. The max width and height are arbitrary numbers for this driver. @@ -64,7 +66,7 @@ struct ti_csi2rx_buffer { /* Common v4l2 buffer. Must be first. */ struct vb2_v4l2_buffer vb; struct list_head list; - struct ti_csi2rx_dev *csi; + struct ti_csi2rx_ctx *ctx; }; enum ti_csi2rx_dma_state { @@ -84,29 +86,37 @@ struct ti_csi2rx_dma { * Queue of buffers submitted to DMA engine. */ struct list_head submitted; - /* Buffer to drain stale data from PSI-L endpoint */ - struct { - void *vaddr; - dma_addr_t paddr; - size_t len; - } drain; +}; + +struct ti_csi2rx_dev; + +struct ti_csi2rx_ctx { + struct ti_csi2rx_dev *csi; + struct video_device vdev; + struct vb2_queue vidq; + struct mutex mutex; /* To serialize ioctls. */ + struct v4l2_format v_fmt; + struct ti_csi2rx_dma dma; + u32 sequence; + u32 idx; }; struct ti_csi2rx_dev { struct device *dev; void __iomem *shim; struct v4l2_device v4l2_dev; - struct video_device vdev; struct media_device mdev; struct media_pipeline pipe; struct media_pad pad; struct v4l2_async_notifier notifier; struct v4l2_subdev *source; - struct vb2_queue vidq; - struct mutex mutex; /* To serialize ioctls. */ - struct v4l2_format v_fmt; - struct ti_csi2rx_dma dma; - u32 sequence; + struct ti_csi2rx_ctx ctx[TI_CSI2RX_NUM_CTX]; + /* Buffer to drain stale data from PSI-L endpoint */ + struct { + void *vaddr; + dma_addr_t paddr; + size_t len; + } drain; }; static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { @@ -212,7 +222,7 @@ static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { }; /* Forward declaration needed by ti_csi2rx_dma_callback. */ -static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, +static int ti_csi2rx_start_dma(struct ti_csi2rx_ctx *ctx, struct ti_csi2rx_buffer *buf); static const struct ti_csi2rx_fmt *find_format_by_fourcc(u32 pixelformat) @@ -302,7 +312,7 @@ static int ti_csi2rx_enum_fmt_vid_cap(struct file *file, void *priv, static int ti_csi2rx_g_fmt_vid_cap(struct file *file, void *prov, struct v4l2_format *f) { - struct ti_csi2rx_dev *csi = video_drvdata(file); + struct ti_csi2rx_ctx *csi = video_drvdata(file); *f = csi->v_fmt; @@ -333,7 +343,7 @@ static int ti_csi2rx_try_fmt_vid_cap(struct file *file, void *priv, static int ti_csi2rx_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct ti_csi2rx_dev *csi = video_drvdata(file); + struct ti_csi2rx_ctx *csi = video_drvdata(file); struct vb2_queue *q = &csi->vidq; int ret; @@ -419,25 +429,33 @@ static int csi_async_notifier_bound(struct v4l2_async_notifier *notifier, static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) { struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); - struct video_device *vdev = &csi->vdev; - int ret; + int ret, i; - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); - if (ret) - return ret; - - ret = v4l2_create_fwnode_links_to_pad(csi->source, &csi->pad, - MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + for (i = 0; i < TI_CSI2RX_NUM_CTX; i++) { + struct ti_csi2rx_ctx *ctx = &csi->ctx[i]; + struct video_device *vdev = &ctx->vdev; - if (ret) { - video_unregister_device(vdev); - return ret; + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) + goto unregister_dev; } + ret = v4l2_create_fwnode_links_to_pad(csi->source, &csi->pad, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + goto unregister_dev; + ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); if (ret) - video_unregister_device(vdev); + goto unregister_dev; + return 0; + +unregister_dev: + i--; + for (; i >= 0; i--) + video_unregister_device(&csi->ctx[i].vdev); return ret; } @@ -483,12 +501,13 @@ static int ti_csi2rx_notifier_register(struct ti_csi2rx_dev *csi) return 0; } -static void ti_csi2rx_setup_shim(struct ti_csi2rx_dev *csi) +static void ti_csi2rx_setup_shim(struct ti_csi2rx_ctx *ctx) { + struct ti_csi2rx_dev *csi = ctx->csi; const struct ti_csi2rx_fmt *fmt; unsigned int reg; - fmt = find_format_by_fourcc(csi->v_fmt.fmt.pix.pixelformat); + fmt = find_format_by_fourcc(ctx->v_fmt.fmt.pix.pixelformat); /* De-assert the pixel interface reset. */ reg = SHIM_CNTL_PIX_RST; @@ -555,8 +574,9 @@ static void ti_csi2rx_drain_callback(void *param) * To prevent that stale data corrupting the subsequent transactions, it is * required to issue DMA requests to drain it out. */ -static int ti_csi2rx_drain_dma(struct ti_csi2rx_dev *csi) +static int ti_csi2rx_drain_dma(struct ti_csi2rx_ctx *ctx) { + struct ti_csi2rx_dev *csi = ctx->csi; struct dma_async_tx_descriptor *desc; struct completion drain_complete; dma_cookie_t cookie; @@ -564,8 +584,8 @@ static int ti_csi2rx_drain_dma(struct ti_csi2rx_dev *csi) init_completion(&drain_complete); - desc = dmaengine_prep_slave_single(csi->dma.chan, csi->dma.drain.paddr, - csi->dma.drain.len, DMA_DEV_TO_MEM, + desc = dmaengine_prep_slave_single(ctx->dma.chan, csi->drain.paddr, + csi->drain.len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { ret = -EIO; @@ -580,11 +600,11 @@ static int ti_csi2rx_drain_dma(struct ti_csi2rx_dev *csi) if (ret) goto out; - dma_async_issue_pending(csi->dma.chan); + dma_async_issue_pending(ctx->dma.chan); if (!wait_for_completion_timeout(&drain_complete, msecs_to_jiffies(DRAIN_TIMEOUT_MS))) { - dmaengine_terminate_sync(csi->dma.chan); + dmaengine_terminate_sync(ctx->dma.chan); dev_dbg(csi->dev, "DMA transfer timed out for drain buffer\n"); ret = -ETIMEDOUT; goto out; @@ -596,8 +616,8 @@ static int ti_csi2rx_drain_dma(struct ti_csi2rx_dev *csi) static void ti_csi2rx_dma_callback(void *param) { struct ti_csi2rx_buffer *buf = param; - struct ti_csi2rx_dev *csi = buf->csi; - struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_ctx *ctx = buf->ctx; + struct ti_csi2rx_dma *dma = &ctx->dma; unsigned long flags; /* @@ -605,7 +625,7 @@ static void ti_csi2rx_dma_callback(void *param) * hardware monitor registers. */ buf->vb.vb2_buf.timestamp = ktime_get_ns(); - buf->vb.sequence = csi->sequence++; + buf->vb.sequence = ctx->sequence++; spin_lock_irqsave(&dma->lock, flags); @@ -617,8 +637,9 @@ static void ti_csi2rx_dma_callback(void *param) while (!list_empty(&dma->queue)) { buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); - if (ti_csi2rx_start_dma(csi, buf)) { - dev_err(csi->dev, "Failed to queue the next buffer for DMA\n"); + if (ti_csi2rx_start_dma(ctx, buf)) { + dev_err(ctx->csi->dev, + "Failed to queue the next buffer for DMA\n"); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } else { list_move_tail(&buf->list, &dma->submitted); @@ -631,17 +652,17 @@ static void ti_csi2rx_dma_callback(void *param) spin_unlock_irqrestore(&dma->lock, flags); } -static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, +static int ti_csi2rx_start_dma(struct ti_csi2rx_ctx *ctx, struct ti_csi2rx_buffer *buf) { unsigned long addr; struct dma_async_tx_descriptor *desc; - size_t len = csi->v_fmt.fmt.pix.sizeimage; + size_t len = ctx->v_fmt.fmt.pix.sizeimage; dma_cookie_t cookie; int ret = 0; addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); - desc = dmaengine_prep_slave_single(csi->dma.chan, addr, len, + desc = dmaengine_prep_slave_single(ctx->dma.chan, addr, len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) @@ -655,20 +676,20 @@ static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, if (ret) return ret; - dma_async_issue_pending(csi->dma.chan); + dma_async_issue_pending(ctx->dma.chan); return 0; } -static void ti_csi2rx_stop_dma(struct ti_csi2rx_dev *csi) +static void ti_csi2rx_stop_dma(struct ti_csi2rx_ctx *ctx) { - struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_dma *dma = &ctx->dma; enum ti_csi2rx_dma_state state; unsigned long flags; int ret; spin_lock_irqsave(&dma->lock, flags); - state = csi->dma.state; + state = ctx->dma.state; dma->state = TI_CSI2RX_DMA_STOPPED; spin_unlock_irqrestore(&dma->lock, flags); @@ -679,30 +700,30 @@ static void ti_csi2rx_stop_dma(struct ti_csi2rx_dev *csi) * is stopped, as the module-level pixel reset cannot be * enforced before terminating DMA. */ - ret = ti_csi2rx_drain_dma(csi); + ret = ti_csi2rx_drain_dma(ctx); if (ret && ret != -ETIMEDOUT) - dev_warn(csi->dev, + dev_warn(ctx->csi->dev, "Failed to drain DMA. Next frame might be bogus\n"); } - ret = dmaengine_terminate_sync(csi->dma.chan); + ret = dmaengine_terminate_sync(ctx->dma.chan); if (ret) - dev_err(csi->dev, "Failed to stop DMA: %d\n", ret); + dev_err(ctx->csi->dev, "Failed to stop DMA: %d\n", ret); } -static void ti_csi2rx_cleanup_buffers(struct ti_csi2rx_dev *csi, +static void ti_csi2rx_cleanup_buffers(struct ti_csi2rx_ctx *ctx, enum vb2_buffer_state state) { - struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_dma *dma = &ctx->dma; struct ti_csi2rx_buffer *buf, *tmp; unsigned long flags; spin_lock_irqsave(&dma->lock, flags); - list_for_each_entry_safe(buf, tmp, &csi->dma.queue, list) { + list_for_each_entry_safe(buf, tmp, &ctx->dma.queue, list) { list_del(&buf->list); vb2_buffer_done(&buf->vb.vb2_buf, state); } - list_for_each_entry_safe(buf, tmp, &csi->dma.submitted, list) { + list_for_each_entry_safe(buf, tmp, &ctx->dma.submitted, list) { list_del(&buf->list); vb2_buffer_done(&buf->vb.vb2_buf, state); } @@ -713,8 +734,8 @@ static int ti_csi2rx_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { - struct ti_csi2rx_dev *csi = vb2_get_drv_priv(q); - unsigned int size = csi->v_fmt.fmt.pix.sizeimage; + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(q); + unsigned int size = ctx->v_fmt.fmt.pix.sizeimage; if (*nplanes) { if (sizes[0] < size) @@ -730,11 +751,11 @@ static int ti_csi2rx_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, static int ti_csi2rx_buffer_prepare(struct vb2_buffer *vb) { - struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = csi->v_fmt.fmt.pix.sizeimage; + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = ctx->v_fmt.fmt.pix.sizeimage; if (vb2_plane_size(vb, 0) < size) { - dev_err(csi->dev, "Data will not fit into plane\n"); + dev_err(ctx->csi->dev, "Data will not fit into plane\n"); return -EINVAL; } @@ -744,15 +765,15 @@ static int ti_csi2rx_buffer_prepare(struct vb2_buffer *vb) static void ti_csi2rx_buffer_queue(struct vb2_buffer *vb) { - struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vb->vb2_queue); + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct ti_csi2rx_buffer *buf; - struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_dma *dma = &ctx->dma; bool restart_dma = false; unsigned long flags = 0; int ret; buf = container_of(vb, struct ti_csi2rx_buffer, vb.vb2_buf); - buf->csi = csi; + buf->ctx = ctx; spin_lock_irqsave(&dma->lock, flags); /* @@ -781,18 +802,18 @@ static void ti_csi2rx_buffer_queue(struct vb2_buffer *vb) * the application and will only confuse it. Issue a DMA * transaction to drain that up. */ - ret = ti_csi2rx_drain_dma(csi); + ret = ti_csi2rx_drain_dma(ctx); if (ret && ret != -ETIMEDOUT) - dev_warn(csi->dev, + dev_warn(ctx->csi->dev, "Failed to drain DMA. Next frame might be bogus\n"); spin_lock_irqsave(&dma->lock, flags); - ret = ti_csi2rx_start_dma(csi, buf); + ret = ti_csi2rx_start_dma(ctx, buf); if (ret) { vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); dma->state = TI_CSI2RX_DMA_IDLE; spin_unlock_irqrestore(&dma->lock, flags); - dev_err(csi->dev, "Failed to start DMA: %d\n", ret); + dev_err(ctx->csi->dev, "Failed to start DMA: %d\n", ret); } else { list_add_tail(&buf->list, &dma->submitted); spin_unlock_irqrestore(&dma->lock, flags); @@ -802,8 +823,9 @@ static void ti_csi2rx_buffer_queue(struct vb2_buffer *vb) static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) { - struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vq); - struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vq); + struct ti_csi2rx_dev *csi = ctx->csi; + struct ti_csi2rx_dma *dma = &ctx->dma; struct ti_csi2rx_buffer *buf; unsigned long flags; int ret = 0; @@ -815,18 +837,18 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) if (ret) return ret; - ret = video_device_pipeline_start(&csi->vdev, &csi->pipe); + ret = video_device_pipeline_start(&ctx->vdev, &csi->pipe); if (ret) goto err; - ti_csi2rx_setup_shim(csi); + ti_csi2rx_setup_shim(ctx); - csi->sequence = 0; + ctx->sequence = 0; spin_lock_irqsave(&dma->lock, flags); buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); - ret = ti_csi2rx_start_dma(csi, buf); + ret = ti_csi2rx_start_dma(ctx, buf); if (ret) { dev_err(csi->dev, "Failed to start DMA: %d\n", ret); spin_unlock_irqrestore(&dma->lock, flags); @@ -844,22 +866,23 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; err_dma: - ti_csi2rx_stop_dma(csi); + ti_csi2rx_stop_dma(ctx); err_pipeline: - video_device_pipeline_stop(&csi->vdev); + video_device_pipeline_stop(&ctx->vdev); writel(0, csi->shim + SHIM_CNTL); writel(0, csi->shim + SHIM_DMACNTX); err: - ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_QUEUED); + ti_csi2rx_cleanup_buffers(ctx, VB2_BUF_STATE_QUEUED); return ret; } static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) { - struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vq); + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vq); + struct ti_csi2rx_dev *csi = ctx->csi; int ret; - video_device_pipeline_stop(&csi->vdev); + video_device_pipeline_stop(&ctx->vdev); writel(0, csi->shim + SHIM_CNTL); writel(0, csi->shim + SHIM_DMACNTX); @@ -868,8 +891,8 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) if (ret) dev_err(csi->dev, "Failed to stop subdev stream\n"); - ti_csi2rx_stop_dma(csi); - ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_ERROR); + ti_csi2rx_stop_dma(ctx); + ti_csi2rx_cleanup_buffers(ctx, VB2_BUF_STATE_ERROR); } static const struct vb2_ops csi_vb2_qops = { @@ -880,27 +903,50 @@ static const struct vb2_ops csi_vb2_qops = { .stop_streaming = ti_csi2rx_stop_streaming, }; -static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi) +static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) { - struct vb2_queue *q = &csi->vidq; + media_device_unregister(&csi->mdev); + v4l2_device_unregister(&csi->v4l2_dev); + media_device_cleanup(&csi->mdev); +} + +static void ti_csi2rx_cleanup_notifier(struct ti_csi2rx_dev *csi) +{ + v4l2_async_nf_unregister(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); +} + +static void ti_csi2rx_cleanup_ctx(struct ti_csi2rx_ctx *ctx) +{ + dma_release_channel(ctx->dma.chan); + vb2_queue_release(&ctx->vidq); + + video_unregister_device(&ctx->vdev); + + mutex_destroy(&ctx->mutex); +} + +static int ti_csi2rx_init_vb2q(struct ti_csi2rx_ctx *ctx) +{ + struct vb2_queue *q = &ctx->vidq; int ret; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_DMABUF; - q->drv_priv = csi; + q->drv_priv = ctx; q->buf_struct_size = sizeof(struct ti_csi2rx_buffer); q->ops = &csi_vb2_qops; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->dev = dmaengine_get_dma_device(csi->dma.chan); - q->lock = &csi->mutex; + q->dev = dmaengine_get_dma_device(ctx->dma.chan); + q->lock = &ctx->mutex; q->min_queued_buffers = 1; ret = vb2_queue_init(q); if (ret) return ret; - csi->vdev.queue = q; + ctx->vdev.queue = q; return 0; } @@ -909,8 +955,9 @@ static int ti_csi2rx_link_validate(struct media_link *link) { struct media_entity *entity = link->sink->entity; struct video_device *vdev = media_entity_to_video_device(entity); - struct ti_csi2rx_dev *csi = container_of(vdev, struct ti_csi2rx_dev, vdev); - struct v4l2_pix_format *csi_fmt = &csi->v_fmt.fmt.pix; + struct ti_csi2rx_ctx *ctx = container_of(vdev, struct ti_csi2rx_ctx, vdev); + struct ti_csi2rx_dev *csi = ctx->csi; + struct v4l2_pix_format *csi_fmt = &ctx->v_fmt.fmt.pix; struct v4l2_subdev_format source_fmt = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, .pad = link->source->index, @@ -963,47 +1010,69 @@ static const struct media_entity_operations ti_csi2rx_video_entity_ops = { .link_validate = ti_csi2rx_link_validate, }; -static int ti_csi2rx_init_dma(struct ti_csi2rx_dev *csi) +static int ti_csi2rx_init_dma(struct ti_csi2rx_ctx *ctx) { struct dma_slave_config cfg = { .src_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES, }; int ret; - INIT_LIST_HEAD(&csi->dma.queue); - INIT_LIST_HEAD(&csi->dma.submitted); - spin_lock_init(&csi->dma.lock); + INIT_LIST_HEAD(&ctx->dma.queue); + INIT_LIST_HEAD(&ctx->dma.submitted); + spin_lock_init(&ctx->dma.lock); - csi->dma.state = TI_CSI2RX_DMA_STOPPED; + ctx->dma.state = TI_CSI2RX_DMA_STOPPED; - csi->dma.chan = dma_request_chan(csi->dev, "rx0"); - if (IS_ERR(csi->dma.chan)) - return PTR_ERR(csi->dma.chan); + ctx->dma.chan = dma_request_chan(ctx->csi->dev, "rx0"); + if (IS_ERR(ctx->dma.chan)) + return PTR_ERR(ctx->dma.chan); - ret = dmaengine_slave_config(csi->dma.chan, &cfg); + ret = dmaengine_slave_config(ctx->dma.chan, &cfg); if (ret) { - dma_release_channel(csi->dma.chan); + dma_release_channel(ctx->dma.chan); return ret; } - csi->dma.drain.len = DRAIN_BUFFER_SIZE; - csi->dma.drain.vaddr = dma_alloc_coherent(csi->dev, csi->dma.drain.len, - &csi->dma.drain.paddr, - GFP_KERNEL); - if (!csi->dma.drain.vaddr) - return -ENOMEM; - return 0; } static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) { struct media_device *mdev = &csi->mdev; - struct video_device *vdev = &csi->vdev; + int ret; + + mdev->dev = csi->dev; + mdev->hw_revision = 1; + strscpy(mdev->model, "TI-CSI2RX", sizeof(mdev->model)); + + media_device_init(mdev); + + csi->v4l2_dev.mdev = mdev; + + ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + if (ret) + return ret; + + ret = media_device_register(mdev); + if (ret) { + v4l2_device_unregister(&csi->v4l2_dev); + media_device_cleanup(mdev); + return ret; + } + + return 0; +} + +static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dev *csi = ctx->csi; + struct video_device *vdev = &ctx->vdev; const struct ti_csi2rx_fmt *fmt; - struct v4l2_pix_format *pix_fmt = &csi->v_fmt.fmt.pix; + struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix; int ret; + mutex_init(&ctx->mutex); + fmt = find_format_by_fourcc(V4L2_PIX_FMT_UYVY); if (!fmt) return -EINVAL; @@ -1012,19 +1081,20 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) pix_fmt->height = 480; pix_fmt->field = V4L2_FIELD_NONE; pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; - pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; - pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; - pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601, + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE, + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB, - ti_csi2rx_fill_fmt(fmt, &csi->v_fmt); + ti_csi2rx_fill_fmt(fmt, &ctx->v_fmt); - mdev->dev = csi->dev; - mdev->hw_revision = 1; - strscpy(mdev->model, "TI-CSI2RX", sizeof(mdev->model)); - - media_device_init(mdev); + csi->pad.flags = MEDIA_PAD_FL_SINK; + vdev->entity.ops = &ti_csi2rx_video_entity_ops; + ret = media_entity_pads_init(&ctx->vdev.entity, 1, &csi->pad); + if (ret) + return ret; - strscpy(vdev->name, TI_CSI2RX_MODULE_NAME, sizeof(vdev->name)); + snprintf(vdev->name, sizeof(vdev->name), "%s context %u", + dev_name(csi->dev), ctx->idx); vdev->v4l2_dev = &csi->v4l2_dev; vdev->vfl_dir = VFL_DIR_RX; vdev->fops = &csi_fops; @@ -1032,61 +1102,28 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) vdev->release = video_device_release_empty; vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; - vdev->lock = &csi->mutex; - video_set_drvdata(vdev, csi); + vdev->lock = &ctx->mutex; + video_set_drvdata(vdev, ctx); - csi->pad.flags = MEDIA_PAD_FL_SINK; - vdev->entity.ops = &ti_csi2rx_video_entity_ops; - ret = media_entity_pads_init(&csi->vdev.entity, 1, &csi->pad); + ret = ti_csi2rx_init_dma(ctx); if (ret) return ret; - csi->v4l2_dev.mdev = mdev; - - ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + ret = ti_csi2rx_init_vb2q(ctx); if (ret) - return ret; - - ret = media_device_register(mdev); - if (ret) { - v4l2_device_unregister(&csi->v4l2_dev); - media_device_cleanup(mdev); - return ret; - } + goto cleanup_dma; return 0; -} - -static void ti_csi2rx_cleanup_dma(struct ti_csi2rx_dev *csi) -{ - dma_free_coherent(csi->dev, csi->dma.drain.len, - csi->dma.drain.vaddr, csi->dma.drain.paddr); - csi->dma.drain.vaddr = NULL; - dma_release_channel(csi->dma.chan); -} - -static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) -{ - media_device_unregister(&csi->mdev); - v4l2_device_unregister(&csi->v4l2_dev); - media_device_cleanup(&csi->mdev); -} -static void ti_csi2rx_cleanup_subdev(struct ti_csi2rx_dev *csi) -{ - v4l2_async_nf_unregister(&csi->notifier); - v4l2_async_nf_cleanup(&csi->notifier); -} - -static void ti_csi2rx_cleanup_vb2q(struct ti_csi2rx_dev *csi) -{ - vb2_queue_release(&csi->vidq); +cleanup_dma: + dma_release_channel(ctx->dma.chan); + return ret; } static int ti_csi2rx_probe(struct platform_device *pdev) { struct ti_csi2rx_dev *csi; - int ret; + int ret, i; csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); if (!csi) @@ -1095,62 +1132,69 @@ static int ti_csi2rx_probe(struct platform_device *pdev) csi->dev = &pdev->dev; platform_set_drvdata(pdev, csi); - mutex_init(&csi->mutex); csi->shim = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(csi->shim)) { ret = PTR_ERR(csi->shim); - goto err_mutex; + return ret; } - ret = ti_csi2rx_init_dma(csi); - if (ret) - goto err_mutex; + csi->drain.len = DRAIN_BUFFER_SIZE; + csi->drain.vaddr = dma_alloc_coherent(csi->dev, csi->drain.len, + &csi->drain.paddr, + GFP_KERNEL); + if (!csi->drain.vaddr) + return -ENOMEM; ret = ti_csi2rx_v4l2_init(csi); - if (ret) - goto err_dma; - - ret = ti_csi2rx_init_vb2q(csi); if (ret) goto err_v4l2; + for (i = 0; i < TI_CSI2RX_NUM_CTX; i++) { + csi->ctx[i].idx = i; + csi->ctx[i].csi = csi; + ret = ti_csi2rx_init_ctx(&csi->ctx[i]); + if (ret) + goto err_ctx; + } + ret = ti_csi2rx_notifier_register(csi); if (ret) - goto err_vb2q; + goto err_ctx; ret = of_platform_populate(csi->dev->of_node, NULL, NULL, csi->dev); if (ret) { dev_err(csi->dev, "Failed to create children: %d\n", ret); - goto err_subdev; + goto err_notifier; } return 0; -err_subdev: - ti_csi2rx_cleanup_subdev(csi); -err_vb2q: - ti_csi2rx_cleanup_vb2q(csi); -err_v4l2: +err_notifier: + ti_csi2rx_cleanup_notifier(csi); +err_ctx: + i--; + for (; i >= 0; i--) + ti_csi2rx_cleanup_ctx(&csi->ctx[i]); ti_csi2rx_cleanup_v4l2(csi); -err_dma: - ti_csi2rx_cleanup_dma(csi); -err_mutex: - mutex_destroy(&csi->mutex); +err_v4l2: + dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, + csi->drain.paddr); return ret; } static void ti_csi2rx_remove(struct platform_device *pdev) { struct ti_csi2rx_dev *csi = platform_get_drvdata(pdev); + unsigned int i; - video_unregister_device(&csi->vdev); + for (i = 0; i < TI_CSI2RX_NUM_CTX; i++) + ti_csi2rx_cleanup_ctx(&csi->ctx[i]); - ti_csi2rx_cleanup_vb2q(csi); - ti_csi2rx_cleanup_subdev(csi); + ti_csi2rx_cleanup_notifier(csi); ti_csi2rx_cleanup_v4l2(csi); - ti_csi2rx_cleanup_dma(csi); - mutex_destroy(&csi->mutex); + dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, + csi->drain.paddr); } static const struct of_device_id ti_csi2rx_of_match[] = { From patchwork Wed May 14 11:25:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890469 Received: from lelvem-ot02.ext.ti.com (lelvem-ot02.ext.ti.com [198.47.23.235]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2EBF3276052; Wed, 14 May 2025 11:26:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.235 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221978; cv=none; b=Tbo9OzxFwCUhR1M6sz8UuRutVjB9QSjUAvGwQcqU2ClnuBo+zzLL7ekna6mGGg2lSNYHw8pesiLblycKtVttMcONg01iw5aJByoesVulZwD5CaKpuOIouxMrSGp7MrzHkUZ7T4GGnDmYzs9MfLV4IGdVsTUpI56eFUUOPx9UfbI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221978; c=relaxed/simple; bh=uZrs4eRpxebfNlXFH2iCeTDpuufUDWXRw/1GhKmX1dw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LY4xlI5VOqZ624AC/1FXivuk0Tuvds6tAOEhtoHOsVJ+9njsi53ajQK4Pk97ngnKPXeIKQyZmQS272diQQy/qGCJrMNNkFwNV+PhlGnTodIaVWKRJ3zb17coAiGW0/3JRb8jwwd8xPtk3GV+rPpSwDqWv+rJSR8KEp6wdjJQx4I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=kPKO8E3o; arc=none smtp.client-ip=198.47.23.235 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="kPKO8E3o" Received: from fllv0035.itg.ti.com ([10.64.41.0]) by lelvem-ot02.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBPsuu3406921 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:25:54 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221954; bh=4Z6ururS/ElJviHNbIVAid8G8M11T2CVoQH8BoMipsk=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=kPKO8E3oD9s1zrPJvnOF0jm076VSeHssPc3LKzSCoOWD2W6jb32jkbkj7bUx3Vrc7 nFvajvNM4PuqASzf9ENcdcUBDwH7xiCeciA8ld8svKdi9gUcWwxnOdqE7VQYDVBzqZ ilXgU6s8169rZpPqHBdJvs1fRUfClOGCc2xwTtEs= Received: from DFLE114.ent.ti.com (dfle114.ent.ti.com [10.64.6.35]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBPs6p120062 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:25:54 -0500 Received: from DFLE105.ent.ti.com (10.64.6.26) by DFLE114.ent.ti.com (10.64.6.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:25:53 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DFLE105.ent.ti.com (10.64.6.26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:25:53 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSV9107507; Wed, 14 May 2025 06:25:47 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 03/12] media: ti: j721e-csi2rx: prepare SHIM code for multiple contexts Date: Wed, 14 May 2025 16:55:18 +0530 Message-ID: <20250514112527.1983068-4-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Pratyush Yadav Currently the SHIM code to configure the context only touches the first context. Add support for writing to the context's registers based on the context index. Signed-off-by: Pratyush Yadav Signed-off-by: Jai Luthra Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Rishikesh Donadkar --- .../media/platform/ti/j721e-csi2rx/j721e-csi2rx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 36cde2e87aabb..d03dc4e56d306 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -25,7 +25,7 @@ #define SHIM_CNTL 0x10 #define SHIM_CNTL_PIX_RST BIT(0) -#define SHIM_DMACNTX 0x20 +#define SHIM_DMACNTX(i) (0x20 + ((i) * 0x20)) #define SHIM_DMACNTX_EN BIT(31) #define SHIM_DMACNTX_YUV422 GENMASK(27, 26) #define SHIM_DMACNTX_SIZE GENMASK(21, 20) @@ -35,7 +35,7 @@ #define SHIM_DMACNTX_SIZE_16 1 #define SHIM_DMACNTX_SIZE_32 2 -#define SHIM_PSI_CFG0 0x24 +#define SHIM_PSI_CFG0(i) (0x24 + ((i) * 0x20)) #define SHIM_PSI_CFG0_SRC_TAG GENMASK(15, 0) #define SHIM_PSI_CFG0_DST_TAG GENMASK(31, 16) @@ -549,11 +549,11 @@ static void ti_csi2rx_setup_shim(struct ti_csi2rx_ctx *ctx) reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size); - writel(reg, csi->shim + SHIM_DMACNTX); + writel(reg, csi->shim + SHIM_DMACNTX(ctx->idx)); reg = FIELD_PREP(SHIM_PSI_CFG0_SRC_TAG, 0) | FIELD_PREP(SHIM_PSI_CFG0_DST_TAG, 0); - writel(reg, csi->shim + SHIM_PSI_CFG0); + writel(reg, csi->shim + SHIM_PSI_CFG0(ctx->idx)); } static void ti_csi2rx_drain_callback(void *param) @@ -870,7 +870,7 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) err_pipeline: video_device_pipeline_stop(&ctx->vdev); writel(0, csi->shim + SHIM_CNTL); - writel(0, csi->shim + SHIM_DMACNTX); + writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); err: ti_csi2rx_cleanup_buffers(ctx, VB2_BUF_STATE_QUEUED); return ret; @@ -885,7 +885,7 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) video_device_pipeline_stop(&ctx->vdev); writel(0, csi->shim + SHIM_CNTL); - writel(0, csi->shim + SHIM_DMACNTX); + writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); ret = v4l2_subdev_call(csi->source, video, s_stream, 0); if (ret) From patchwork Wed May 14 11:25:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890467 Received: from fllvem-ot03.ext.ti.com (fllvem-ot03.ext.ti.com [198.47.19.245]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE9B127511E; Wed, 14 May 2025 11:26:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.19.245 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222007; cv=none; b=A1nQZMOeF7PnMYw4pXkvx9gVY+BEnv1aAVOfmVXYE30i+dyVkQ8UrMi1hzBmZnsByf942zmN/1Yn3HOs3f3TjhPRJ3mjvr4JvtYvCWc13KbHMZ/HAz1O96ei60o1DgukIXaZkwPMmWWQs9ps9QJSqsYRRb1ITr9uIMAYFpGSOuw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222007; c=relaxed/simple; bh=5X49EdTlas5+pqoGitR3eXq6roebrmXk5tAhFltQjwY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YUvQRcmXs1iiwk7eXV+bkKfBTZEjUd8q95xybWgemjVD39HDW6yIbLrErM8e3k05JAL40AM/Ky0cXR2FHTD5A4Bkh0o71ICtkbuw8sd96dbsUhw1Yuz40NFNQ4DhQlh1LOxcGGg5o363g/mau6V6jb//0aoYo0YcRK3qyEfRMfk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=xF4lIfjh; arc=none smtp.client-ip=198.47.19.245 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="xF4lIfjh" Received: from fllv0034.itg.ti.com ([10.64.40.246]) by fllvem-ot03.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQ0bP2575214 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:26:00 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221960; bh=tnEdl/bWMrlfpbkkoreMrdnsvPseyxB7h8xOZqGijyc=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=xF4lIfjhaCMRapbvNt6BGBvj31NchjywfQKjerxVVXHQuuIjtfOg9IQPmBTGJewiW cXLoasgPsW3bQxlOqpq1y0KebHgkUOvSPARlDaTecwd7bSGFIJQyzd6MOyi3ZpP51v McNhcf+dWz2NYuy+tqN/15YdLol9rXnJ+MzxUOiM= Received: from DFLE114.ent.ti.com (dfle114.ent.ti.com [10.64.6.35]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQ0SM085264 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:26:00 -0500 Received: from DFLE104.ent.ti.com (10.64.6.25) by DFLE114.ent.ti.com (10.64.6.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:25:59 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DFLE104.ent.ti.com (10.64.6.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:25:59 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVA107507; Wed, 14 May 2025 06:25:53 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 04/12] media: ti: j721e-csi2rx: allocate DMA channel based on context index Date: Wed, 14 May 2025 16:55:19 +0530 Message-ID: <20250514112527.1983068-5-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Pratyush Yadav With multiple contexts, there needs to be a different DMA channel for each context. Earlier, the DMA channel name was hard coded to "rx0" for the sake of simplicity. Generate the DMA channel name based on its index and get the channel corresponding to the context. Signed-off-by: Pratyush Yadav Signed-off-by: Jai Luthra Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Rishikesh Donadkar --- drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index d03dc4e56d306..cc6eb3d4c2b26 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -1015,6 +1015,7 @@ static int ti_csi2rx_init_dma(struct ti_csi2rx_ctx *ctx) struct dma_slave_config cfg = { .src_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES, }; + char name[5]; int ret; INIT_LIST_HEAD(&ctx->dma.queue); @@ -1023,7 +1024,8 @@ static int ti_csi2rx_init_dma(struct ti_csi2rx_ctx *ctx) ctx->dma.state = TI_CSI2RX_DMA_STOPPED; - ctx->dma.chan = dma_request_chan(ctx->csi->dev, "rx0"); + snprintf(name, sizeof(name), "rx%u", ctx->idx); + ctx->dma.chan = dma_request_chan(ctx->csi->dev, name); if (IS_ERR(ctx->dma.chan)) return PTR_ERR(ctx->dma.chan); From patchwork Wed May 14 11:25:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890078 Received: from lelvem-ot02.ext.ti.com (lelvem-ot02.ext.ti.com [198.47.23.235]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F23D2749D5; Wed, 14 May 2025 11:26:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.235 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221986; cv=none; b=hvc95QKBV/R4SEL+m/2LHyyzG23s7IQb5ql5ZsuKTM1Tn06L6BbjAF3vkZbuDqK/GEaADa8yHKwksr0GDXLHtlBCGnxf+eT0OCZMIsp1C71inKc1PjB3B9cvVtfspIHx00MS54rRtZe5mJEyrh6X+q3Pxqn/Goq3E5zlNqFitAs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221986; c=relaxed/simple; bh=4+CILGuA7xGYxH6MhZVzyfO4DR4XQUmk97j/AfauT90=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=gNY0fsJ1K/QDsDUoWkzwMOHiNTP+5ko+TRazbQNDw3ggLWEzB1PxJmdHWWdyxlRqyv3/m+1KH32KndWER3LLcVsa6dIdfvcMwy4q8JuHdL/5rTm7eAJaAqWCAKkp48lPmJu5d+gJFkl2WqtLX4drSxpXf7Ac0fiKDHeQ5FVjNVo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=qS66D8+r; arc=none smtp.client-ip=198.47.23.235 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="qS66D8+r" Received: from fllvem-sh03.itg.ti.com ([10.64.41.86]) by lelvem-ot02.ext.ti.com (8.15.2/8.15.2) with ESMTP id 54EBQ6GW3406933; Wed, 14 May 2025 06:26:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221967; bh=qga3nr/uJekmxSccKab/E9T1v75t9SfxJckU/+vcThM=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=qS66D8+rvrmJElJRjHPsdvSHBG66hW+bJ/AVOhPtJijl4iEUxSUxPMCuGdYwk8Hr2 Mud0HHjmxax+Wcgf3TwhhdR612YacY1SZR4ZKszNmQh8t7Ax3HkQVdMiqF2DcX2qAl LVeLTdQAwAEbQ2HjYp549FQlNnUuNPVHTUJfgtxQ= Received: from DLEE114.ent.ti.com (dlee114.ent.ti.com [157.170.170.25]) by fllvem-sh03.itg.ti.com (8.18.1/8.18.1) with ESMTPS id 54EBQ6Tt3213144 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA256 bits=128 verify=FAIL); Wed, 14 May 2025 06:26:06 -0500 Received: from DLEE102.ent.ti.com (157.170.170.32) by DLEE114.ent.ti.com (157.170.170.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:26:06 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DLEE102.ent.ti.com (157.170.170.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:26:05 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVB107507; Wed, 14 May 2025 06:26:00 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 05/12] media: ti: j721e-csi2rx: add a subdev for the core device Date: Wed, 14 May 2025 16:55:20 +0530 Message-ID: <20250514112527.1983068-6-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Jai Luthra With single stream capture, it was simpler to use the video device as the media entity representing the main TI CSI2RX device. Now with multi stream capture coming into the picture, the model has shifted to each video device having a link to the main device's subdev. The routing would then be set on this subdev. Add this subdev, link each context to this subdev's entity and link the subdev's entity to the source. Also add an array of media pads. It will have one sink pad and source pads equal to the number of contexts. Co-developed-by: Pratyush Yadav Signed-off-by: Pratyush Yadav Signed-off-by: Jai Luthra Signed-off-by: Rishikesh Donadkar --- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 248 ++++++++++++++++-- 1 file changed, 223 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index cc6eb3d4c2b26..d746a3ff25934 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -51,6 +51,11 @@ #define MAX_WIDTH_BYTES SZ_16K #define MAX_HEIGHT_LINES SZ_16K +#define TI_CSI2RX_PAD_SINK 0 +#define TI_CSI2RX_PAD_FIRST_SOURCE 1 +#define TI_CSI2RX_NUM_SOURCE_PADS 1 +#define TI_CSI2RX_NUM_PADS (1 + TI_CSI2RX_NUM_SOURCE_PADS) + #define DRAIN_TIMEOUT_MS 50 #define DRAIN_BUFFER_SIZE SZ_32K @@ -97,6 +102,7 @@ struct ti_csi2rx_ctx { struct mutex mutex; /* To serialize ioctls. */ struct v4l2_format v_fmt; struct ti_csi2rx_dma dma; + struct media_pad pad; u32 sequence; u32 idx; }; @@ -104,12 +110,15 @@ struct ti_csi2rx_ctx { struct ti_csi2rx_dev { struct device *dev; void __iomem *shim; + struct mutex mutex; /* To serialize ioctls. */ + unsigned int enable_count; struct v4l2_device v4l2_dev; struct media_device mdev; struct media_pipeline pipe; - struct media_pad pad; + struct media_pad pads[TI_CSI2RX_NUM_PADS]; struct v4l2_async_notifier notifier; struct v4l2_subdev *source; + struct v4l2_subdev subdev; struct ti_csi2rx_ctx ctx[TI_CSI2RX_NUM_CTX]; /* Buffer to drain stale data from PSI-L endpoint */ struct { @@ -119,6 +128,22 @@ struct ti_csi2rx_dev { } drain; }; +static inline struct ti_csi2rx_dev *to_csi2rx_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ti_csi2rx_dev, subdev); +} + +static const struct v4l2_mbus_framefmt ti_csi2rx_default_fmt = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, +}; + static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { { .fourcc = V4L2_PIX_FMT_YUYV, @@ -431,6 +456,15 @@ static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); int ret, i; + /* Create link from source to subdev */ + ret = v4l2_create_fwnode_links_to_pad(csi->source, + &csi->pads[TI_CSI2RX_PAD_SINK], + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + /* Create and link video nodes for all DMA contexts */ for (i = 0; i < TI_CSI2RX_NUM_CTX; i++) { struct ti_csi2rx_ctx *ctx = &csi->ctx[i]; struct video_device *vdev = &ctx->vdev; @@ -438,13 +472,17 @@ static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) goto unregister_dev; - } - ret = v4l2_create_fwnode_links_to_pad(csi->source, &csi->pad, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (ret) - goto unregister_dev; + ret = media_create_pad_link(&csi->subdev.entity, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + &vdev->entity, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) { + video_unregister_device(vdev); + goto unregister_dev; + } + } ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); if (ret) @@ -454,8 +492,10 @@ static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) unregister_dev: i--; - for (; i >= 0; i--) + for (; i >= 0; i--) { + media_entity_remove_links(&csi->ctx[i].vdev.entity); video_unregister_device(&csi->ctx[i].vdev); + } return ret; } @@ -859,7 +899,7 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) dma->state = TI_CSI2RX_DMA_ACTIVE; spin_unlock_irqrestore(&dma->lock, flags); - ret = v4l2_subdev_call(csi->source, video, s_stream, 1); + ret = v4l2_subdev_call(&csi->subdev, video, s_stream, 1); if (ret) goto err_dma; @@ -887,7 +927,7 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) writel(0, csi->shim + SHIM_CNTL); writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); - ret = v4l2_subdev_call(csi->source, video, s_stream, 0); + ret = v4l2_subdev_call(&csi->subdev, video, s_stream, 0); if (ret) dev_err(csi->dev, "Failed to stop subdev stream\n"); @@ -903,8 +943,114 @@ static const struct vb2_ops csi_vb2_qops = { .stop_streaming = ti_csi2rx_stop_streaming, }; +static int ti_csi2rx_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(ti_csi2rx_formats)) + return -EINVAL; + + code_enum->code = ti_csi2rx_formats[code_enum->index].code; + + return 0; +} + +static int ti_csi2rx_sd_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + + /* No transcoding, don't allow setting source fmt */ + if (format->pad > TI_CSI2RX_PAD_SINK) + return v4l2_subdev_get_fmt(sd, state, format); + + if (!find_format_by_code(format->format.code)) + format->format.code = ti_csi2rx_formats[0].code; + + format->format.field = V4L2_FIELD_NONE; + + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); + *fmt = format->format; + + fmt = v4l2_subdev_state_get_format(state, TI_CSI2RX_PAD_FIRST_SOURCE, + format->stream); + *fmt = format->format; + + return 0; +} + +static int ti_csi2rx_sd_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_state_get_format(state, TI_CSI2RX_PAD_SINK); + *fmt = ti_csi2rx_default_fmt; + + fmt = v4l2_subdev_state_get_format(state, TI_CSI2RX_PAD_FIRST_SOURCE); + *fmt = ti_csi2rx_default_fmt; + + return 0; +} + +static int ti_csi2rx_sd_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd); + int ret = 0; + + mutex_lock(&csi->mutex); + + if (enable) { + if (csi->enable_count > 0) { + csi->enable_count++; + goto out; + } + + ret = v4l2_subdev_call(csi->source, video, s_stream, 1); + if (ret) + goto out; + + csi->enable_count++; + } else { + if (csi->enable_count == 0) { + ret = -EINVAL; + goto out; + } + + if (--csi->enable_count > 0) + goto out; + + ret = v4l2_subdev_call(csi->source, video, s_stream, 0); + } + +out: + mutex_unlock(&csi->mutex); + return ret; +} + +static const struct v4l2_subdev_pad_ops ti_csi2rx_subdev_pad_ops = { + .enum_mbus_code = ti_csi2rx_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ti_csi2rx_sd_set_fmt, +}; + +static const struct v4l2_subdev_video_ops ti_csi2rx_subdev_video_ops = { + .s_stream = ti_csi2rx_sd_s_stream, +}; + +static const struct v4l2_subdev_ops ti_csi2rx_subdev_ops = { + .video = &ti_csi2rx_subdev_video_ops, + .pad = &ti_csi2rx_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ti_csi2rx_internal_ops = { + .init_state = ti_csi2rx_sd_init_state, +}; + static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) { + v4l2_subdev_cleanup(&csi->subdev); media_device_unregister(&csi->mdev); v4l2_device_unregister(&csi->v4l2_dev); media_device_cleanup(&csi->mdev); @@ -961,14 +1107,22 @@ static int ti_csi2rx_link_validate(struct media_link *link) struct v4l2_subdev_format source_fmt = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, .pad = link->source->index, + .stream = 0, }; + struct v4l2_subdev_state *state; const struct ti_csi2rx_fmt *ti_fmt; int ret; - ret = v4l2_subdev_call_state_active(csi->source, pad, - get_fmt, &source_fmt); - if (ret) - return ret; + state = v4l2_subdev_lock_and_get_active_state(&csi->subdev); + ret = v4l2_subdev_call(&csi->subdev, pad, get_fmt, state, &source_fmt); + v4l2_subdev_unlock_state(state); + + if (ret) { + dev_dbg(csi->dev, + "Skipping validation as no format present on \"%s\":%u:0\n", + link->source->entity->name, link->source->index); + return 0; + } if (source_fmt.format.width != csi_fmt->width) { dev_dbg(csi->dev, "Width does not match (source %u, sink %u)\n", @@ -998,8 +1152,9 @@ static int ti_csi2rx_link_validate(struct media_link *link) if (ti_fmt->fourcc != csi_fmt->pixelformat) { dev_dbg(csi->dev, - "Cannot transform source fmt 0x%x to sink fmt 0x%x\n", - ti_fmt->fourcc, csi_fmt->pixelformat); + "Cannot transform \"%s\":%u format %p4cc to %p4cc\n", + link->source->entity->name, link->source->index, + &ti_fmt->fourcc, &csi_fmt->pixelformat); return -EPIPE; } @@ -1010,6 +1165,10 @@ static const struct media_entity_operations ti_csi2rx_video_entity_ops = { .link_validate = ti_csi2rx_link_validate, }; +static const struct media_entity_operations ti_csi2rx_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + static int ti_csi2rx_init_dma(struct ti_csi2rx_ctx *ctx) { struct dma_slave_config cfg = { @@ -1041,6 +1200,7 @@ static int ti_csi2rx_init_dma(struct ti_csi2rx_ctx *ctx) static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) { struct media_device *mdev = &csi->mdev; + struct v4l2_subdev *sd = &csi->subdev; int ret; mdev->dev = csi->dev; @@ -1053,16 +1213,51 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); if (ret) - return ret; + goto cleanup_media; ret = media_device_register(mdev); - if (ret) { - v4l2_device_unregister(&csi->v4l2_dev); - media_device_cleanup(mdev); - return ret; - } + if (ret) + goto unregister_v4l2; + + v4l2_subdev_init(sd, &ti_csi2rx_subdev_ops); + sd->internal_ops = &ti_csi2rx_internal_ops; + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + strscpy(sd->name, dev_name(csi->dev), sizeof(sd->name)); + sd->dev = csi->dev; + sd->entity.ops = &ti_csi2rx_subdev_entity_ops; + + csi->pads[TI_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + + for (unsigned int i = TI_CSI2RX_PAD_FIRST_SOURCE; + i < TI_CSI2RX_NUM_PADS; i++) + csi->pads[i].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(csi->pads), + csi->pads); + if (ret) + goto unregister_media; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto unregister_media; + + ret = v4l2_device_register_subdev(&csi->v4l2_dev, sd); + if (ret) + goto cleanup_subdev; return 0; + +cleanup_subdev: + v4l2_subdev_cleanup(sd); +unregister_media: + media_device_unregister(mdev); +unregister_v4l2: + v4l2_device_unregister(&csi->v4l2_dev); +cleanup_media: + media_device_cleanup(mdev); + + return ret; } static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) @@ -1089,9 +1284,9 @@ static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) ti_csi2rx_fill_fmt(fmt, &ctx->v_fmt); - csi->pad.flags = MEDIA_PAD_FL_SINK; + ctx->pad.flags = MEDIA_PAD_FL_SINK; vdev->entity.ops = &ti_csi2rx_video_entity_ops; - ret = media_entity_pads_init(&ctx->vdev.entity, 1, &csi->pad); + ret = media_entity_pads_init(&ctx->vdev.entity, 1, &ctx->pad); if (ret) return ret; @@ -1147,6 +1342,8 @@ static int ti_csi2rx_probe(struct platform_device *pdev) if (!csi->drain.vaddr) return -ENOMEM; + mutex_init(&csi->mutex); + ret = ti_csi2rx_v4l2_init(csi); if (ret) goto err_v4l2; @@ -1179,6 +1376,7 @@ static int ti_csi2rx_probe(struct platform_device *pdev) ti_csi2rx_cleanup_ctx(&csi->ctx[i]); ti_csi2rx_cleanup_v4l2(csi); err_v4l2: + mutex_destroy(&csi->mutex); dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, csi->drain.paddr); return ret; @@ -1194,7 +1392,7 @@ static void ti_csi2rx_remove(struct platform_device *pdev) ti_csi2rx_cleanup_notifier(csi); ti_csi2rx_cleanup_v4l2(csi); - + mutex_destroy(&csi->mutex); dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, csi->drain.paddr); } From patchwork Wed May 14 11:25:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890466 Received: from lelvem-ot01.ext.ti.com (lelvem-ot01.ext.ti.com [198.47.23.234]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA53F2797A0; Wed, 14 May 2025 11:26:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.234 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222008; cv=none; b=Dam3AsH32aOvGGbIcgt7LVrHwdseLCa18GT0306RZm+196GL6GgdCbv9paRp+3KKSXuvmLjv1R0bqgVR7h9FHKIMYtbfR4+zOVP+0Vi+6LiXPYSSBtDOkyRvnpafXUGibeLW9bC6t4fbpVMFluNpcLf2dwTYcZS0N+2974hWwKw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222008; c=relaxed/simple; bh=nYa1HXHYoTDVfTS0DvP76k8pJ8ov7xg5VLEV+9+7dEU=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=OhpbJh3ElE4+KPE83/Y42A/ECSD7hPo8WZ9RRSMHZPorQQqZDfR7kjftB6r/PDQO1+AvK9gdwrKNrUBWrzqGW6dfjL9myMKFszMJk4V8uiGmrw3MHVh68Kr+XMzjq1kBCjsOcDaNjzUcoirY4CgfAwbgTHYQEg96SYsye6LNrrM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=LJ79LJd4; arc=none smtp.client-ip=198.47.23.234 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="LJ79LJd4" Received: from fllv0035.itg.ti.com ([10.64.41.0]) by lelvem-ot01.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQCJw2604816 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:26:12 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221972; bh=FGs2f1X5/aEXT5kHV9JLISeGz3eTzxZUqAooC1BrEdo=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=LJ79LJd4ZXmg6KrPL0zwCrThKa17MluJDJPkymEzAM4r+m0effJUPqYjkCIX7M4Sf EoFxi4Jwbpu3YuV/c97jnnUKYgmHD44lZppMP3UeT+DzMfUv/AYjORuo0xoCdZisn3 ZFL6qI+jmi7A9U8xe29jgP6/gS72iHmUysrq6Ork= Received: from DLEE112.ent.ti.com (dlee112.ent.ti.com [157.170.170.23]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQCsY120156 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:26:12 -0500 Received: from DLEE108.ent.ti.com (157.170.170.38) by DLEE112.ent.ti.com (157.170.170.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:26:12 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DLEE108.ent.ti.com (157.170.170.38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:26:12 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVC107507; Wed, 14 May 2025 06:26:06 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 06/12] media: ti: j721e-csi2rx: get number of contexts from device tree Date: Wed, 14 May 2025 16:55:21 +0530 Message-ID: <20250514112527.1983068-7-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Pratyush Yadav Different platforms that use this driver might have different number of DMA channels allocated for CSI. So only as many DMA contexts can be used as the number of DMA channels available. Get the number of channels provided via device tree and only configure that many contexts, and hence only that many pads. Signed-off-by: Pratyush Yadav Co-developed-by: Jai Luthra Signed-off-by: Jai Luthra Signed-off-by: Rishikesh Donadkar --- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index d746a3ff25934..9c20a5421fa20 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -40,7 +40,7 @@ #define SHIM_PSI_CFG0_DST_TAG GENMASK(31, 16) #define PSIL_WORD_SIZE_BYTES 16 -#define TI_CSI2RX_NUM_CTX 1 +#define TI_CSI2RX_MAX_CTX 32 /* * There are no hard limits on the width or height. The DMA engine can handle @@ -53,8 +53,8 @@ #define TI_CSI2RX_PAD_SINK 0 #define TI_CSI2RX_PAD_FIRST_SOURCE 1 -#define TI_CSI2RX_NUM_SOURCE_PADS 1 -#define TI_CSI2RX_NUM_PADS (1 + TI_CSI2RX_NUM_SOURCE_PADS) +#define TI_CSI2RX_MAX_SOURCE_PADS TI_CSI2RX_MAX_CTX +#define TI_CSI2RX_MAX_PADS (1 + TI_CSI2RX_MAX_SOURCE_PADS) #define DRAIN_TIMEOUT_MS 50 #define DRAIN_BUFFER_SIZE SZ_32K @@ -112,14 +112,15 @@ struct ti_csi2rx_dev { void __iomem *shim; struct mutex mutex; /* To serialize ioctls. */ unsigned int enable_count; + unsigned int num_ctx; struct v4l2_device v4l2_dev; struct media_device mdev; struct media_pipeline pipe; - struct media_pad pads[TI_CSI2RX_NUM_PADS]; + struct media_pad pads[TI_CSI2RX_MAX_PADS]; struct v4l2_async_notifier notifier; struct v4l2_subdev *source; struct v4l2_subdev subdev; - struct ti_csi2rx_ctx ctx[TI_CSI2RX_NUM_CTX]; + struct ti_csi2rx_ctx ctx[TI_CSI2RX_MAX_CTX]; /* Buffer to drain stale data from PSI-L endpoint */ struct { void *vaddr; @@ -465,7 +466,7 @@ static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) return ret; /* Create and link video nodes for all DMA contexts */ - for (i = 0; i < TI_CSI2RX_NUM_CTX; i++) { + for (i = 0; i < csi->num_ctx; i++) { struct ti_csi2rx_ctx *ctx = &csi->ctx[i]; struct video_device *vdev = &ctx->vdev; @@ -1230,10 +1231,11 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) csi->pads[TI_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; for (unsigned int i = TI_CSI2RX_PAD_FIRST_SOURCE; - i < TI_CSI2RX_NUM_PADS; i++) + i < TI_CSI2RX_PAD_FIRST_SOURCE + csi->num_ctx; i++) csi->pads[i].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(csi->pads), + ret = media_entity_pads_init(&sd->entity, + TI_CSI2RX_PAD_FIRST_SOURCE + csi->num_ctx, csi->pads); if (ret) goto unregister_media; @@ -1319,8 +1321,9 @@ static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) static int ti_csi2rx_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct ti_csi2rx_dev *csi; - int ret, i; + int ret, i, count; csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); if (!csi) @@ -1342,13 +1345,29 @@ static int ti_csi2rx_probe(struct platform_device *pdev) if (!csi->drain.vaddr) return -ENOMEM; + /* Only use as many contexts as the number of DMA channels allocated. */ + count = of_property_count_strings(np, "dma-names"); + if (count < 0) { + dev_err(csi->dev, "Failed to get DMA channel count: %d\n", count); + ret = count; + goto err_dma_chan; + } + + csi->num_ctx = count; + if (csi->num_ctx > TI_CSI2RX_MAX_CTX) { + dev_err(csi->dev, + "%u DMA channels passed. Maximum is %u.\n", + csi->num_ctx, TI_CSI2RX_MAX_CTX); + goto err_dma_chan; + } + mutex_init(&csi->mutex); ret = ti_csi2rx_v4l2_init(csi); if (ret) goto err_v4l2; - for (i = 0; i < TI_CSI2RX_NUM_CTX; i++) { + for (i = 0; i < csi->num_ctx; i++) { csi->ctx[i].idx = i; csi->ctx[i].csi = csi; ret = ti_csi2rx_init_ctx(&csi->ctx[i]); @@ -1377,6 +1396,7 @@ static int ti_csi2rx_probe(struct platform_device *pdev) ti_csi2rx_cleanup_v4l2(csi); err_v4l2: mutex_destroy(&csi->mutex); +err_dma_chan: dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, csi->drain.paddr); return ret; @@ -1387,7 +1407,7 @@ static void ti_csi2rx_remove(struct platform_device *pdev) struct ti_csi2rx_dev *csi = platform_get_drvdata(pdev); unsigned int i; - for (i = 0; i < TI_CSI2RX_NUM_CTX; i++) + for (i = 0; i < csi->num_ctx; i++) ti_csi2rx_cleanup_ctx(&csi->ctx[i]); ti_csi2rx_cleanup_notifier(csi); From patchwork Wed May 14 11:25:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890468 Received: from lelvem-ot02.ext.ti.com (lelvem-ot02.ext.ti.com [198.47.23.235]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3CA0A278170; Wed, 14 May 2025 11:26:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.235 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221992; cv=none; b=AKlWLi3kZxcg470boUwZoE7CafZQq23n9Yk4V+CvMj+rKEtbiPmsiP6+TCapS2iDBRGNuCROcQxQX+yNfHLSlHgVUPlaVFr8Qj6cb4hX61MQ3fRZHRIiahmJ+LHDQiliPfsB6wlT86cJ4X4yvY4IrsZhL4hzrLeMM4NMXU9Iteg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747221992; c=relaxed/simple; bh=uY19SxKJsun9vbw+kZZm3sPu+hZf/UP9kmI0iogft7I=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ralD+aDbieFL15PqMh580mr7d+s1KEYwBXWz5YIC3sARCm4ErRmlpzJTplD4bmyaeCR3bBGItIJsYT/8VdAu2slcCrfOX3jE7faTtL4yzGS+0QmPuCi1pKThN5Ve57UtdUyxUHAVOpJH++KcyF3hGV+yfhZgjt4PI3wNDmMWvAo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=O/8OiEVZ; arc=none smtp.client-ip=198.47.23.235 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="O/8OiEVZ" Received: from lelvem-sh01.itg.ti.com ([10.180.77.71]) by lelvem-ot02.ext.ti.com (8.15.2/8.15.2) with ESMTP id 54EBQJVp3406970; Wed, 14 May 2025 06:26:19 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221979; bh=4A+V+fK8yy5t7Vy4nEMh8vE+sCdcC1IM7nYwdWD9X+8=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=O/8OiEVZIzDU9SkpPTik1/ahpbk4sON3tyi+3t6v40al4ZvmegkG5rz7mT1Uah6SY d4mUgSqzS2Dz0D6nllTyg7ruphPIcJKiTqNXeozjqRZwcWGGao2TB9dIR+IuFGOx3l p3HBPR9KFKVMsonkz0nFyrNqLPjODTMK1ApjJ3Jc= Received: from DFLE105.ent.ti.com (dfle105.ent.ti.com [10.64.6.26]) by lelvem-sh01.itg.ti.com (8.18.1/8.18.1) with ESMTPS id 54EBQJf42184577 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA256 bits=128 verify=FAIL); Wed, 14 May 2025 06:26:19 -0500 Received: from DFLE112.ent.ti.com (10.64.6.33) by DFLE105.ent.ti.com (10.64.6.26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:26:18 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DFLE112.ent.ti.com (10.64.6.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:26:18 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVD107507; Wed, 14 May 2025 06:26:12 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 07/12] media: cadence: csi2rx: add get_frame_desc wrapper Date: Wed, 14 May 2025 16:55:22 +0530 Message-ID: <20250514112527.1983068-8-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Pratyush Yadav J721E wrapper CSI2RX driver needs to get the frame descriptor from the source to find out info about virtual channel. This driver itself does not touch the routing or virtual channels in any way. So simply pass the descriptor through from the source. Signed-off-by: Pratyush Yadav Signed-off-by: Jai Luthra Reviewed-by: Jacopo Mondi Reviewed-by: Changhuang Liang Reviewed-by: Laurent Pinchart Signed-off-by: Rishikesh Donadkar --- drivers/media/platform/cadence/cdns-csi2rx.c | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index cebcae196eecc..b7e9225f66a41 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -135,6 +135,21 @@ static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code) return NULL; } +static int csi2rx_get_frame_desc_from_source(struct csi2rx_priv *csi2rx, + struct v4l2_mbus_frame_desc *fd) +{ + struct media_pad *remote_pad; + + remote_pad = media_entity_remote_source_pad_unique(&csi2rx->subdev.entity); + if (!remote_pad) { + dev_err(csi2rx->dev, "No remote pad found for sink\n"); + return -ENODEV; + } + + return v4l2_subdev_call(csi2rx->source_subdev, pad, get_frame_desc, + remote_pad->index, fd); +} + static inline struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct v4l2_subdev *subdev) { @@ -458,10 +473,19 @@ static int csi2rx_init_state(struct v4l2_subdev *subdev, return csi2rx_set_fmt(subdev, state, &format); } +static int csi2rx_get_frame_desc(struct v4l2_subdev *subdev, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + + return csi2rx_get_frame_desc_from_source(csi2rx, fd); +} + static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { .enum_mbus_code = csi2rx_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = csi2rx_set_fmt, + .get_frame_desc = csi2rx_get_frame_desc, }; static const struct v4l2_subdev_video_ops csi2rx_video_ops = { From patchwork Wed May 14 11:25:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890077 Received: from lelvem-ot02.ext.ti.com (lelvem-ot02.ext.ti.com [198.47.23.235]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 98F482750F0; Wed, 14 May 2025 11:26:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.235 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222005; cv=none; b=TF5sNPp1Fd9e+FVI0yJHPghk/JtLfC4DvULB37qJ86qYE6JL7QggljMSGUsZAqTj27n0+/bJl0CjQfHiRlFVYZxCpwBwhRP7yMTH0ooFauAfl21rC3L+8ycypdBgPvdO+gtuBN9gih4jkmQAxRdd4F3VHQHEXeutsLClursJYXc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222005; c=relaxed/simple; bh=n5Ufeif/Vtoouec0Oiocz1KQKlEuYZeBr7EJb3Eg/Ac=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=oxQwH+FZKzO0V5fvpVnWWszD9GmmcgpRGicIwM83ixt6dnZY4rEW2MaDDvRc/AcqkRtn7akMNZ1978uTDSVulNE2FrP/RJZCBq3g4vaZPPZRxQCfetKzLypr2vq5Oxsns5bhnzuNQw1ahF44ZC1nu4HC6Hom4ql12qoit1VGCbs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=V0rrr4sI; arc=none smtp.client-ip=198.47.23.235 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="V0rrr4sI" Received: from fllv0035.itg.ti.com ([10.64.41.0]) by lelvem-ot02.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQPbf3406984 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:26:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221985; bh=s1t2Ls3kaaA0ClH3kBbhoTZCO6f2rFZnfsKqpbcZ8H8=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=V0rrr4sI6u7mVz2dCuO2qLsb60337IbqectbwSl9Cl+E30az/MniH9fUS8nSoDQxu Z7jtPhBFbwVZXS6d05OPtI6xFq666ZXD7r7zy/bRkcGQzqU0Goy1S17NcrpmQyxJDV 3H7OzpwT8n2wSP/DaJ31//eyiNI08byxlio+iM0E= Received: from DLEE113.ent.ti.com (dlee113.ent.ti.com [157.170.170.24]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQP2X120200 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:26:25 -0500 Received: from DLEE106.ent.ti.com (157.170.170.36) by DLEE113.ent.ti.com (157.170.170.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:26:24 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DLEE106.ent.ti.com (157.170.170.36) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:26:24 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVE107507; Wed, 14 May 2025 06:26:19 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 08/12] media: ti: j721e-csi2rx: add support for processing virtual channels Date: Wed, 14 May 2025 16:55:23 +0530 Message-ID: <20250514112527.1983068-9-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Jai Luthra Use get_frame_desc() to get the frame desc from the connected source, and use the provided virtual channel instead of hardcoded one. get_frame_desc() returns the same information when called on each stream start, so instead get the VCs for all the routed stream at first stream start and cache this information in the driver. get_frame_desc() works per stream, but as we don't support multiple streams yet, we will just always use stream 0. If the source doesn't support get_frame_desc(), fall back to the previous method of always capturing virtual channel 0. Co-developed-by: Pratyush Yadav Signed-off-by: Pratyush Yadav Signed-off-by: Jai Luthra Signed-off-by: Rishikesh Donadkar --- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 9c20a5421fa20..9f05d16ef8c1d 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -29,6 +29,7 @@ #define SHIM_DMACNTX_EN BIT(31) #define SHIM_DMACNTX_YUV422 GENMASK(27, 26) #define SHIM_DMACNTX_SIZE GENMASK(21, 20) +#define SHIM_DMACNTX_VC GENMASK(9, 6) #define SHIM_DMACNTX_FMT GENMASK(5, 0) #define SHIM_DMACNTX_YUV422_MODE_11 3 #define SHIM_DMACNTX_SIZE_8 0 @@ -97,6 +98,7 @@ struct ti_csi2rx_dev; struct ti_csi2rx_ctx { struct ti_csi2rx_dev *csi; + struct v4l2_subdev_route *route; struct video_device vdev; struct vb2_queue vidq; struct mutex mutex; /* To serialize ioctls. */ @@ -105,6 +107,8 @@ struct ti_csi2rx_ctx { struct media_pad pad; u32 sequence; u32 idx; + u32 vc; + u32 stream; }; struct ti_csi2rx_dev { @@ -127,6 +131,7 @@ struct ti_csi2rx_dev { dma_addr_t paddr; size_t len; } drain; + bool vc_cached; }; static inline struct ti_csi2rx_dev *to_csi2rx_dev(struct v4l2_subdev *sd) @@ -589,6 +594,7 @@ static void ti_csi2rx_setup_shim(struct ti_csi2rx_ctx *ctx) } reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size); + reg |= FIELD_PREP(SHIM_DMACNTX_VC, ctx->vc); writel(reg, csi->shim + SHIM_DMACNTX(ctx->idx)); @@ -862,6 +868,83 @@ static void ti_csi2rx_buffer_queue(struct vb2_buffer *vb) } } +static int ti_csi2rx_get_route(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dev *csi = ctx->csi; + struct media_pad *pad; + struct v4l2_subdev_state *state; + struct v4l2_subdev_route *r; + + /* Get the source pad connected to this ctx */ + pad = media_entity_remote_source_pad_unique(ctx->pad.entity); + if (!pad) { + dev_err(csi->dev, "No pad connected to ctx %d\n", ctx->idx); + v4l2_subdev_unlock_state(state); + return -ENODEV; + } + + state = v4l2_subdev_lock_and_get_active_state(&csi->subdev); + + for_each_active_route(&state->routing, r) { + if (!(r->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) + continue; + if (r->source_pad != pad->index) + continue; + + ctx->route = r; + } + + v4l2_subdev_unlock_state(state); + + if (!ctx->route) + return -ENODEV; + + return 0; +} + +static int ti_csi2rx_get_vc(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dev *csi = ctx->csi; + struct ti_csi2rx_ctx *curr_ctx; + struct v4l2_mbus_frame_desc fd; + struct media_pad *source_pad; + struct v4l2_subdev_route *curr_route; + int ret; + unsigned int i, j; + + /* Get the frame desc form source */ + source_pad = media_entity_remote_pad_unique(&csi->subdev.entity, MEDIA_PAD_FL_SOURCE); + if (!source_pad) + return -ENODEV; + + ret = v4l2_subdev_call(csi->source, pad, get_frame_desc, source_pad->index, &fd); + if (ret) + return ret; + + if (fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) + return -EINVAL; + + for (i = 0; i < csi->num_ctx; i++) { + curr_ctx = &csi->ctx[i]; + + /* Capture VC 0 by default */ + curr_ctx->vc = 0; + + ret = ti_csi2rx_get_route(curr_ctx); + if (ret) + continue; + + curr_route = curr_ctx->route; + curr_ctx->stream = curr_route->sink_stream; + + for (j = 0; j < fd.num_entries; j++) + if (curr_ctx->stream == fd.entry[j].stream) + curr_ctx->vc = fd.entry[j].bus.csi2.vc; + } + + return 0; +} + static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) { struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vq); @@ -882,6 +965,25 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) if (ret) goto err; + /* If no stream is routed to this ctx, exit early */ + ret = ti_csi2rx_get_route(ctx); + if (ret) + goto err; + + /* Get the VC for all enabled ctx on first stream start */ + mutex_lock(&csi->mutex); + if (!csi->vc_cached) { + ret = ti_csi2rx_get_vc(ctx); + if (ret == -ENOIOCTLCMD) { + ctx->vc = 0; + } else if (ret < 0) { + mutex_unlock(&csi->mutex); + goto err; + } + csi->vc_cached = true; + } + mutex_unlock(&csi->mutex); + ti_csi2rx_setup_shim(ctx); ctx->sequence = 0; @@ -928,6 +1030,10 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) writel(0, csi->shim + SHIM_CNTL); writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); + mutex_lock(&csi->mutex); + csi->vc_cached = false; + mutex_unlock(&csi->mutex); + ret = v4l2_subdev_call(&csi->subdev, video, s_stream, 0); if (ret) dev_err(csi->dev, "Failed to stop subdev stream\n"); @@ -1286,6 +1392,8 @@ static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) ti_csi2rx_fill_fmt(fmt, &ctx->v_fmt); + ctx->route = NULL; + ctx->pad.flags = MEDIA_PAD_FL_SINK; vdev->entity.ops = &ti_csi2rx_video_entity_ops; ret = media_entity_pads_init(&ctx->vdev.entity, 1, &ctx->pad); From patchwork Wed May 14 11:25:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890076 Received: from lelvem-ot01.ext.ti.com (lelvem-ot01.ext.ti.com [198.47.23.234]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E8AB5270572; Wed, 14 May 2025 11:26:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.234 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222008; cv=none; b=qWSGLmUyur/FpG7Vta8/+jcQVSY5hYYA7We8NZqrqder9bV5Cc+Dk28ocflDxL9Pix+QaeYlC1SqHNcx0k4mYfGOpLW8KQiE52sLxyPelILN8buoBiz9YCtCM2ZTxtdIMDkBOVhIBb50MYJ6s+MTISjvPGvyHJdkt5qmCt6oZNg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222008; c=relaxed/simple; bh=CSHXV3EadsjvkdiHCaKvpUa7eAsZ1q2YkRu6It6HUHo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=puo+N8t7YqgRL7pfdzb+F1/cB/2Wb9FKkxdAJrcmpHEKN38RMsFqjnDlkppHnysgoP20U9G4w14vFwPuajjCTe2EALj5T1BPmyCP4u5oeh0Ou/IcKxYmN1YJIPrgqyDvF50gvhDmvDC2VMtc2N8f0HoHs6WbRhGB4jjk6uzfbQE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=O33zdEur; arc=none smtp.client-ip=198.47.23.234 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="O33zdEur" Received: from lelv0265.itg.ti.com ([10.180.67.224]) by lelvem-ot01.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQVgI2604854 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:26:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221991; bh=hHHsvAB2qhpUPs/VSqeejQWzaVBiODFnez8w0yCPsg8=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=O33zdEurHJQlY3iPtQij2jI7QE1jSLlw4XSvACB7IZpSy07xBmFlZtf+h1VgpI9to OY8VuRcXaBRixaINMlGpvFs53N+kRnLDphxpXhaxPUrXfet12mGJ/CHPW6IPYj7tcu Ohst1YecGd3ztB56gkwDUtazMJxtxIUN8iHj3xNg= Received: from DLEE110.ent.ti.com (dlee110.ent.ti.com [157.170.170.21]) by lelv0265.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQVem031131 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:26:31 -0500 Received: from DLEE105.ent.ti.com (157.170.170.35) by DLEE110.ent.ti.com (157.170.170.21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:26:31 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DLEE105.ent.ti.com (157.170.170.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:26:31 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVF107507; Wed, 14 May 2025 06:26:25 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 09/12] media: cadence: csi2rx: add multistream support Date: Wed, 14 May 2025 16:55:24 +0530 Message-ID: <20250514112527.1983068-10-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Jai Luthra Cadence CSI-2 bridge IP supports capturing multiple virtual "streams" of data over the same physical interface using MIPI Virtual Channels. While the hardware IP supports usecases where streams coming in the sink pad can be broadcasted to multiple source pads, the driver will need significant re-architecture to make that possible. The two users of this IP in mainline linux are TI Shim and StarFive JH7110 CAMSS, and both have only integrated the first source pad i.e stream0 of this IP. So for now keep it simple and only allow 1-to-1 mapping of streams from sink to source, without any broadcasting. The enable_streams() API in v4l2 supports passing a bitmask to enable each pad/stream combination individually on any media subdev. Use this API instead of s_stream() API. Implement the enable_stream and disable_stream hooks in place of the stream-unaware s_stream hook. Implement a fallback s_stream hook that internally calls enable_stream on each source pad, for consumer drivers that don't use multi-stream APIs to still work. The helper function v4l2_subdev_s_stream_helper() form the v4l2 framework is not used here as it is meant only for the subedvs that have a single source pad and this hardware IP supports having multiple source pads. Signed-off-by: Jai Luthra Reviewed-by: Changhuang Liang Co-developed-by: Rishikesh Donadkar Signed-off-by: Rishikesh Donadkar --- drivers/media/platform/cadence/cdns-csi2rx.c | 352 +++++++++++++++---- 1 file changed, 275 insertions(+), 77 deletions(-) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index b7e9225f66a41..103c3bda653b9 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -90,6 +90,7 @@ struct csi2rx_priv { struct reset_control *pixel_rst[CSI2RX_STREAMS_MAX]; struct phy *dphy; + u32 vc_select[CSI2RX_STREAMS_MAX]; u8 lanes[CSI2RX_LANES_MAX]; u8 num_lanes; u8 max_lanes; @@ -179,29 +180,43 @@ static void csi2rx_reset(struct csi2rx_priv *csi2rx) static int csi2rx_configure_ext_dphy(struct csi2rx_priv *csi2rx) { - struct media_pad *src_pad = - &csi2rx->source_subdev->entity.pads[csi2rx->source_pad]; union phy_configure_opts opts = { }; struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; - struct v4l2_subdev_format sd_fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .pad = CSI2RX_PAD_SINK, - }; + struct v4l2_mbus_framefmt *framefmt; + struct v4l2_subdev_state *state; const struct csi2rx_fmt *fmt; + int source_pad = csi2rx->source_pad; + struct media_pad *pad = &csi2rx->source_subdev->entity.pads[source_pad]; s64 link_freq; int ret; + u32 bpp; - ret = v4l2_subdev_call_state_active(&csi2rx->subdev, pad, get_fmt, - &sd_fmt); - if (ret < 0) - return ret; + state = v4l2_subdev_get_locked_active_state(&csi2rx->subdev); + + /* + * For multi-stream transmitters there is no single pixel rate. + * + * In multistream usecase pass bpp as 0 so that v4l2_get_link_freq() + * returns an error if it falls back to V4L2_CID_PIXEL_RATE. + */ + if (state->routing.num_routes > 1) { + bpp = 0; + } else { + framefmt = v4l2_subdev_state_get_format(state, CSI2RX_PAD_SINK, 0); + if (!framefmt) { + dev_err(csi2rx->dev, "Did not find active sink format\n"); + return -EINVAL; + } - fmt = csi2rx_get_fmt_by_code(sd_fmt.format.code); + fmt = csi2rx_get_fmt_by_code(framefmt->code); + bpp = fmt->bpp; + } - link_freq = v4l2_get_link_freq(src_pad, - fmt->bpp, 2 * csi2rx->num_lanes); - if (link_freq < 0) + link_freq = v4l2_get_link_freq(pad, bpp, 2 * csi2rx->num_lanes); + if (link_freq < 0) { + dev_err(csi2rx->dev, "Unable to calculate link frequency\n"); return link_freq; + } ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq, csi2rx->num_lanes, cfg); @@ -294,11 +309,7 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF, csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); - /* - * Enable one virtual channel. When multiple virtual channels - * are supported this will have to be changed. - */ - writel(CSI2RX_STREAM_DATA_CFG_VC_SELECT(0), + writel(csi2rx->vc_select[i], csi2rx->base + CSI2RX_STREAM_DATA_CFG_REG(i)); writel(CSI2RX_STREAM_CTRL_START, @@ -311,16 +322,10 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) reset_control_deassert(csi2rx->sys_rst); - ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true); - if (ret) - goto err_disable_sysclk; - clk_disable_unprepare(csi2rx->p_clk); return 0; -err_disable_sysclk: - clk_disable_unprepare(csi2rx->sys_clk); err_disable_pixclk: for (; i > 0; i--) { reset_control_assert(csi2rx->pixel_rst[i - 1]); @@ -367,9 +372,6 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx) reset_control_assert(csi2rx->p_rst); clk_disable_unprepare(csi2rx->p_clk); - if (v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, false)) - dev_warn(csi2rx->dev, "Couldn't disable our subdev\n"); - if (csi2rx->dphy) { writel(0, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); @@ -378,37 +380,134 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx) } } -static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) +static void csi2rx_update_vc_select(struct csi2rx_priv *csi2rx, + struct v4l2_subdev_state *state) { - struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); - int ret = 0; - - mutex_lock(&csi2rx->lock); - - if (enable) { - /* - * If we're not the first users, there's no need to - * enable the whole controller. - */ - if (!csi2rx->count) { - ret = csi2rx_start(csi2rx); - if (ret) - goto out; + struct v4l2_mbus_frame_desc fd = {0}; + struct v4l2_subdev_route *route; + unsigned int i; + int ret; + + /* Capture VC=0 by default */ + for (i = 0; i < CSI2RX_STREAMS_MAX; i++) + csi2rx->vc_select[i] = CSI2RX_STREAM_DATA_CFG_VC_SELECT(0); + + ret = csi2rx_get_frame_desc_from_source(csi2rx, &fd); + if (ret || fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_dbg(csi2rx->dev, + "Failed to get source frame desc, allowing only VC=0\n"); + return; + } + + /* If source provides per-stream VC info, use it to filter by VC */ + memset(csi2rx->vc_select, 0, sizeof(csi2rx->vc_select)); + + for_each_active_route(&state->routing, route) { + u32 cdns_stream = route->source_pad - CSI2RX_PAD_SOURCE_STREAM0; + + for (i = 0; i < fd.num_entries; i++) { + if (fd.entry[i].stream != route->sink_stream) + continue; + + csi2rx->vc_select[cdns_stream] |= + CSI2RX_STREAM_DATA_CFG_VC_SELECT(fd.entry[i].bus.csi2.vc); } + } +} - csi2rx->count++; - } else { - csi2rx->count--; +static int csi2rx_enable_streams(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + u64 sink_streams; + int ret; + + sink_streams = v4l2_subdev_state_xlate_streams(state, pad, + CSI2RX_PAD_SINK, + &streams_mask); + + guard(mutex)(&csi2rx->lock); + /* + * If we're not the first users, there's no need to + * enable the whole controller. + */ + if (!csi2rx->count) { + csi2rx_update_vc_select(csi2rx, state); + ret = csi2rx_start(csi2rx); + if (ret) + return ret; + } - /* - * Let the last user turn off the lights. - */ + /* Start streaming on the source */ + ret = v4l2_subdev_enable_streams(csi2rx->source_subdev, csi2rx->source_pad, + sink_streams); + if (ret) { + dev_err(csi2rx->dev, + "Failed to start streams %#llx on subdev\n", + sink_streams); if (!csi2rx->count) csi2rx_stop(csi2rx); + return ret; + } + + csi2rx->count++; + return 0; +} + +static int csi2rx_disable_streams(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + u64 sink_streams; + + sink_streams = v4l2_subdev_state_xlate_streams(state, pad, + CSI2RX_PAD_SINK, + &streams_mask); + + if (v4l2_subdev_disable_streams(csi2rx->source_subdev, + csi2rx->source_pad, sink_streams)) { + dev_err(csi2rx->dev, "Couldn't disable our subdev\n"); + } + + guard(mutex)(&csi2rx->lock); + csi2rx->count--; + + /* Let the last user turn off the lights. */ + if (!csi2rx->count) + csi2rx_stop(csi2rx); + + return 0; +} + +static int csi2rx_s_stream_fallback(struct v4l2_subdev *sd, int enable) +{ + struct v4l2_subdev_state *state; + struct v4l2_subdev_route *route; + u64 mask[CSI2RX_PAD_MAX] = {0}; + int i, ret; + + /* Find the stream mask on all source pads */ + state = v4l2_subdev_lock_and_get_active_state(sd); + for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { + for_each_active_route(&state->routing, route) { + if (route->source_pad == i) + mask[i] |= BIT_ULL(route->source_stream); + } + } + v4l2_subdev_unlock_state(state); + + /* Start streaming on each pad */ + for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { + if (enable) + ret = v4l2_subdev_enable_streams(sd, i, mask[i]); + else + ret = v4l2_subdev_disable_streams(sd, i, mask[i]); + if (ret) + return ret; } -out: - mutex_unlock(&csi2rx->lock); return ret; } @@ -424,12 +523,56 @@ static int csi2rx_enum_mbus_code(struct v4l2_subdev *subdev, return 0; } +static int _csi2rx_set_routing(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_krouting *routing) +{ + static const struct v4l2_mbus_framefmt format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }; + int ret; + + if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) + return -EINVAL; + + ret = v4l2_subdev_routing_validate(subdev, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); + if (ret) + return ret; + + return v4l2_subdev_set_routing_with_fmt(subdev, state, routing, &format); +} + +static int csi2rx_set_routing(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + int ret; + + if (which == V4L2_SUBDEV_FORMAT_ACTIVE && csi2rx->count) + return -EBUSY; + + ret = _csi2rx_set_routing(subdev, state, routing); + if (ret) + return ret; + + return 0; +} + static int csi2rx_set_fmt(struct v4l2_subdev *subdev, struct v4l2_subdev_state *state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt; - unsigned int i; /* No transcoding, source and sink formats must match. */ if (format->pad != CSI2RX_PAD_SINK) @@ -441,14 +584,16 @@ static int csi2rx_set_fmt(struct v4l2_subdev *subdev, format->format.field = V4L2_FIELD_NONE; /* Set sink format */ - fmt = v4l2_subdev_state_get_format(state, format->pad); + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); *fmt = format->format; - /* Propagate to source formats */ - for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { - fmt = v4l2_subdev_state_get_format(state, i); - *fmt = format->format; - } + /* Propagate to source format */ + fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, + format->stream); + if (!fmt) + return -EINVAL; + + *fmt = format->format; return 0; } @@ -456,40 +601,92 @@ static int csi2rx_set_fmt(struct v4l2_subdev *subdev, static int csi2rx_init_state(struct v4l2_subdev *subdev, struct v4l2_subdev_state *state) { - struct v4l2_subdev_format format = { - .pad = CSI2RX_PAD_SINK, - .format = { - .width = 640, - .height = 480, - .code = MEDIA_BUS_FMT_UYVY8_1X16, - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, - .ycbcr_enc = V4L2_YCBCR_ENC_601, - .quantization = V4L2_QUANTIZATION_LIM_RANGE, - .xfer_func = V4L2_XFER_FUNC_SRGB, + struct v4l2_subdev_route routes[] = { + { + .sink_pad = CSI2RX_PAD_SINK, + .sink_stream = 0, + .source_pad = CSI2RX_PAD_SOURCE_STREAM0, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, }, }; - return csi2rx_set_fmt(subdev, state, &format); + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + return _csi2rx_set_routing(subdev, state, &routing); } static int csi2rx_get_frame_desc(struct v4l2_subdev *subdev, unsigned int pad, struct v4l2_mbus_frame_desc *fd) { struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + struct v4l2_mbus_frame_desc source_fd = {0}; + struct v4l2_subdev_route *route; + struct v4l2_subdev_state *state; + int ret; + + ret = csi2rx_get_frame_desc_from_source(csi2rx, &source_fd); + if (ret) + return ret; + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; - return csi2rx_get_frame_desc_from_source(csi2rx, fd); + state = v4l2_subdev_lock_and_get_active_state(subdev); + + for_each_active_route(&state->routing, route) { + struct v4l2_mbus_frame_desc_entry *source_entry = NULL; + unsigned int i; + + if (route->source_pad != pad) + continue; + + for (i = 0; i < source_fd.num_entries; i++) { + if (source_fd.entry[i].stream == route->sink_stream) { + source_entry = &source_fd.entry[i]; + break; + } + } + + if (!source_entry) { + dev_err(csi2rx->dev, + "Failed to find stream from source frame desc\n"); + ret = -EPIPE; + goto err_missing_stream; + } + + fd->entry[fd->num_entries].stream = route->source_stream; + fd->entry[fd->num_entries].flags = source_entry->flags; + fd->entry[fd->num_entries].length = source_entry->length; + fd->entry[fd->num_entries].pixelcode = source_entry->pixelcode; + fd->entry[fd->num_entries].bus.csi2.vc = + source_entry->bus.csi2.vc; + fd->entry[fd->num_entries].bus.csi2.dt = + source_entry->bus.csi2.dt; + + fd->num_entries++; + } + +err_missing_stream: + v4l2_subdev_unlock_state(state); + + return ret; } static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { - .enum_mbus_code = csi2rx_enum_mbus_code, - .get_fmt = v4l2_subdev_get_fmt, - .set_fmt = csi2rx_set_fmt, - .get_frame_desc = csi2rx_get_frame_desc, + .enum_mbus_code = csi2rx_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = csi2rx_set_fmt, + .get_frame_desc = csi2rx_get_frame_desc, + .set_routing = csi2rx_set_routing, + .enable_streams = csi2rx_enable_streams, + .disable_streams = csi2rx_disable_streams, }; static const struct v4l2_subdev_video_ops csi2rx_video_ops = { - .s_stream = csi2rx_s_stream, + .s_stream = csi2rx_s_stream_fallback, }; static const struct v4l2_subdev_ops csi2rx_subdev_ops = { @@ -721,7 +918,8 @@ static int csi2rx_probe(struct platform_device *pdev) csi2rx->pads[CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) csi2rx->pads[i].flags = MEDIA_PAD_FL_SOURCE; - csi2rx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + csi2rx->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_STREAMS; csi2rx->subdev.entity.ops = &csi2rx_media_ops; ret = media_entity_pads_init(&csi2rx->subdev.entity, CSI2RX_PAD_MAX, From patchwork Wed May 14 11:25:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890075 Received: from lelvem-ot01.ext.ti.com (lelvem-ot01.ext.ti.com [198.47.23.234]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA08227A93F; Wed, 14 May 2025 11:26:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.234 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222013; cv=none; b=vFs3quYCPq72/wn7py4RzuJ+SLU9Womh5V/rB3P757InD1FHGRO4O1psRPTdtZjmHAekgF/qqBziqofy5lyU38mVHqH/NPUsmjBH8WHKX46jiObC8TSyBJMedBMRHWgQYCxYfV4ztHlYrIbRTcR4KLV/KFv6fE88xwa64uUbGKw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222013; c=relaxed/simple; bh=HkBVUxifAB1SUr26KhSmuWcUM0Lp/lZHKrRLvsXAt8E=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=nRrmEm+EMPm5NRYMJRDJ5QZS3ZKNcASRMaZNH995CMtGkLj1yBxtZPErb8p1xpV6prW+A/a2btjH0Gp7Zp7dEXw6hVOwk4UYuIZ7lSPIHEHtBD0FwuLeONcAzXheWJPzjrB+eKikOhD3T9NmyS90sa4qzhlbPu3yYbUbHQBf5U8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=aRkt5aP8; arc=none smtp.client-ip=198.47.23.234 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="aRkt5aP8" Received: from fllv0035.itg.ti.com ([10.64.41.0]) by lelvem-ot01.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQccf2604874 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:26:38 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747221998; bh=JjW1FzN92T/T4pJB9n2KuGW89RMEjxErV98P0GevYpo=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=aRkt5aP8w3DkWOSe68BRvD7kpAX1Gowqo87m6xnMjkZvo4LOgnhIt6mw1I2H7pvzC BHqMrqI1Rs8fq3nFmW1rwFR8IAGx8sXbzrrdl7TgS92Zf07i6NtZhzfNk+EL7pEwa8 1weJU9OCed0cZ8tXcZegp8HJlt5RGObVWwWNRjLE= Received: from DFLE106.ent.ti.com (dfle106.ent.ti.com [10.64.6.27]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQc2N120232 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:26:38 -0500 Received: from DFLE107.ent.ti.com (10.64.6.28) by DFLE106.ent.ti.com (10.64.6.27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:26:37 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DFLE107.ent.ti.com (10.64.6.28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:26:37 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVG107507; Wed, 14 May 2025 06:26:31 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 10/12] media: ti: j721e-csi2rx: add multistream support Date: Wed, 14 May 2025 16:55:25 +0530 Message-ID: <20250514112527.1983068-11-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Jai Luthra Each CSI2 stream can be multiplexed into 4 independent streams, each identified by its virtual channel number. To capture this multiplexed stream, the application needs to tell the driver how it wants to route the data. It needs to specify which context should process which stream. This is done via the new routing APIs. Add ioctls to accept routing information from the application and save that in the driver. This can be used when starting streaming on a context to determine which route and consequently which virtual channel it should process. Support the new enable_stream()/disable_stream() APIs in the subdev instead of s_stream() hook. De-assert the pixel interface reset on first start_streaming() and assert it on the last stop_streaming(). Co-developed-by: Pratyush Yadav Signed-off-by: Pratyush Yadav Signed-off-by: Jai Luthra Co-developed-by: Rishikesh Donadkar Signed-off-by: Rishikesh Donadkar --- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 191 +++++++++++++----- 1 file changed, 135 insertions(+), 56 deletions(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 9f05d16ef8c1d..7986f96c5e11b 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -139,17 +139,6 @@ static inline struct ti_csi2rx_dev *to_csi2rx_dev(struct v4l2_subdev *sd) return container_of(sd, struct ti_csi2rx_dev, subdev); } -static const struct v4l2_mbus_framefmt ti_csi2rx_default_fmt = { - .width = 640, - .height = 480, - .code = MEDIA_BUS_FMT_UYVY8_1X16, - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, - .ycbcr_enc = V4L2_YCBCR_ENC_601, - .quantization = V4L2_QUANTIZATION_LIM_RANGE, - .xfer_func = V4L2_XFER_FUNC_SRGB, -}; - static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { { .fourcc = V4L2_PIX_FMT_YUYV, @@ -556,8 +545,10 @@ static void ti_csi2rx_setup_shim(struct ti_csi2rx_ctx *ctx) fmt = find_format_by_fourcc(ctx->v_fmt.fmt.pix.pixelformat); /* De-assert the pixel interface reset. */ - reg = SHIM_CNTL_PIX_RST; - writel(reg, csi->shim + SHIM_CNTL); + if (!csi->enable_count) { + reg = SHIM_CNTL_PIX_RST; + writel(reg, csi->shim + SHIM_CNTL); + } reg = SHIM_DMACNTX_EN; reg |= FIELD_PREP(SHIM_DMACNTX_FMT, fmt->csi_dt); @@ -1002,7 +993,10 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) dma->state = TI_CSI2RX_DMA_ACTIVE; spin_unlock_irqrestore(&dma->lock, flags); - ret = v4l2_subdev_call(&csi->subdev, video, s_stream, 1); + /* Start stream 0, we don't allow multiple streams on the source pad */ + ret = v4l2_subdev_enable_streams(&csi->subdev, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + BIT(0)); if (ret) goto err_dma; @@ -1025,16 +1019,20 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) struct ti_csi2rx_dev *csi = ctx->csi; int ret; - video_device_pipeline_stop(&ctx->vdev); + /* assert pixel reset to prevent stale data */ + if (csi->enable_count == 1) { + writel(0, csi->shim + SHIM_CNTL); - writel(0, csi->shim + SHIM_CNTL); - writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); + mutex_lock(&csi->mutex); + csi->vc_cached = false; + mutex_unlock(&csi->mutex); + } - mutex_lock(&csi->mutex); - csi->vc_cached = false; - mutex_unlock(&csi->mutex); + video_device_pipeline_stop(&ctx->vdev); - ret = v4l2_subdev_call(&csi->subdev, video, s_stream, 0); + ret = v4l2_subdev_disable_streams(&csi->subdev, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + BIT(0)); if (ret) dev_err(csi->dev, "Failed to stop subdev stream\n"); @@ -1080,57 +1078,140 @@ static int ti_csi2rx_sd_set_fmt(struct v4l2_subdev *sd, fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); *fmt = format->format; - fmt = v4l2_subdev_state_get_format(state, TI_CSI2RX_PAD_FIRST_SOURCE, - format->stream); + fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, + format->stream); + if (!fmt) + return -EINVAL; + *fmt = format->format; return 0; } -static int ti_csi2rx_sd_init_state(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +static int _ti_csi2rx_sd_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_krouting *routing) { - struct v4l2_mbus_framefmt *fmt; + int ret; - fmt = v4l2_subdev_state_get_format(state, TI_CSI2RX_PAD_SINK); - *fmt = ti_csi2rx_default_fmt; + const struct v4l2_mbus_framefmt format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }; - fmt = v4l2_subdev_state_get_format(state, TI_CSI2RX_PAD_FIRST_SOURCE); - *fmt = ti_csi2rx_default_fmt; + ret = v4l2_subdev_routing_validate(sd, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | + V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING); - return 0; + if (ret) + return ret; + + /* Only stream ID 0 allowed on source pads */ + for (unsigned int i = 0; i < routing->num_routes; ++i) { + const struct v4l2_subdev_route *route = &routing->routes[i]; + + if (route->source_stream != 0) + return -EINVAL; + } + + ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format); + + return ret; +} + +static int ti_csi2rx_sd_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd); + + if (csi->enable_count > 0) + return -EBUSY; + + return _ti_csi2rx_sd_set_routing(sd, state, routing); +} + +static int ti_csi2rx_sd_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { { + .sink_pad = 0, + .sink_stream = 0, + .source_pad = TI_CSI2RX_PAD_FIRST_SOURCE, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + } }; + + struct v4l2_subdev_krouting routing = { + .num_routes = 1, + .routes = routes, + }; + + /* Initialize routing to single route to the fist source pad */ + return _ti_csi2rx_sd_set_routing(sd, state, &routing); } -static int ti_csi2rx_sd_s_stream(struct v4l2_subdev *sd, int enable) +static int ti_csi2rx_sd_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) { struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd); + struct media_pad *remote_pad; + u64 sink_streams; int ret = 0; - mutex_lock(&csi->mutex); + remote_pad = media_entity_remote_source_pad_unique(&csi->subdev.entity); + if (!remote_pad) + return -ENODEV; + sink_streams = v4l2_subdev_state_xlate_streams(state, pad, + TI_CSI2RX_PAD_SINK, + &streams_mask); - if (enable) { - if (csi->enable_count > 0) { - csi->enable_count++; - goto out; - } + ret = v4l2_subdev_enable_streams(csi->source, remote_pad->index, + sink_streams); + if (ret) + return ret; - ret = v4l2_subdev_call(csi->source, video, s_stream, 1); - if (ret) - goto out; + mutex_lock(&csi->mutex); + csi->enable_count++; + mutex_unlock(&csi->mutex); - csi->enable_count++; - } else { - if (csi->enable_count == 0) { - ret = -EINVAL; - goto out; - } + return 0; +} + +static int ti_csi2rx_sd_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd); + struct media_pad *remote_pad; + u64 sink_streams; + int ret = 0; - if (--csi->enable_count > 0) - goto out; + remote_pad = media_entity_remote_source_pad_unique(&csi->subdev.entity); + if (!remote_pad) + return -ENODEV; + sink_streams = v4l2_subdev_state_xlate_streams(state, pad, + TI_CSI2RX_PAD_SINK, + &streams_mask); - ret = v4l2_subdev_call(csi->source, video, s_stream, 0); + mutex_lock(&csi->mutex); + if (csi->enable_count == 0) { + ret = -EINVAL; + goto out; } + ret = v4l2_subdev_disable_streams(csi->source, remote_pad->index, + sink_streams); + if (!ret) + --csi->enable_count; out: mutex_unlock(&csi->mutex); return ret; @@ -1138,16 +1219,14 @@ static int ti_csi2rx_sd_s_stream(struct v4l2_subdev *sd, int enable) static const struct v4l2_subdev_pad_ops ti_csi2rx_subdev_pad_ops = { .enum_mbus_code = ti_csi2rx_enum_mbus_code, + .set_routing = ti_csi2rx_sd_set_routing, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ti_csi2rx_sd_set_fmt, -}; - -static const struct v4l2_subdev_video_ops ti_csi2rx_subdev_video_ops = { - .s_stream = ti_csi2rx_sd_s_stream, + .enable_streams = ti_csi2rx_sd_enable_streams, + .disable_streams = ti_csi2rx_sd_disable_streams, }; static const struct v4l2_subdev_ops ti_csi2rx_subdev_ops = { - .video = &ti_csi2rx_subdev_video_ops, .pad = &ti_csi2rx_subdev_pad_ops, }; @@ -1329,7 +1408,7 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) v4l2_subdev_init(sd, &ti_csi2rx_subdev_ops); sd->internal_ops = &ti_csi2rx_internal_ops; sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; strscpy(sd->name, dev_name(csi->dev), sizeof(sd->name)); sd->dev = csi->dev; sd->entity.ops = &ti_csi2rx_subdev_entity_ops; From patchwork Wed May 14 11:25:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890465 Received: from fllvem-ot03.ext.ti.com (fllvem-ot03.ext.ti.com [198.47.19.245]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8227D27C150; Wed, 14 May 2025 11:26:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.19.245 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222018; cv=none; b=A/2A+W5EjRTZFPLRv9PwYn4kKNkg8Uzty3+mj+SGnfL5UhDDydEOsxeJKzIxKe9qT72Bisc4dSXCPBjOa4jhBoaVqhJrxZ0MyIU93TjaghkaP+T6GHqcNw3nxiEh5RR4Qo5leL/maIhB25kSO5xuotf+Y+mjQi+iAR0AoZkHjlw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222018; c=relaxed/simple; bh=eFB71THz0S9xFlBe7elWcUNFyjPLGWo2yxmK4oBB1UY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ORSTUcRm+7yXzuSdI59JF/qsrf3U6aPjGBH2T6k+DCWVBf0iPotiwv4W8FUJIgdzZa6PrncqIIYcdsEXwKfN0QxwQWyHgeL4nSCRfMxXOyYVfL5nxVZJ5WBmKzGfjRYIDuCWIgHOdzmxtEvPk341LK5xnwY/kPfB1eSUbyrSttM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=OxpBQzQv; arc=none smtp.client-ip=198.47.19.245 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="OxpBQzQv" Received: from lelv0266.itg.ti.com ([10.180.67.225]) by fllvem-ot03.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQirI2575278 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:26:44 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747222004; bh=V7c5TvZGitC52h6wjdjcFBIn9opBlON5J7xgJbZ07L0=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=OxpBQzQv8fXnxB1W4rOb33k8xXXnv5uVMPS570eBjfmZIyFZ3d1ATJobSlimatYTo h2cchlEVegWj7Jrto1qZjpsgg5K5IsUqK/ykO8itjpYN0lcFuWTe4VB3jac77zJ7qs t3brafR4cl6jVZJOMRLNK2VSLrAbfpV4e48uqjMs= Received: from DFLE108.ent.ti.com (dfle108.ent.ti.com [10.64.6.29]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQicC052570 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:26:44 -0500 Received: from DFLE108.ent.ti.com (10.64.6.29) by DFLE108.ent.ti.com (10.64.6.29) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:26:44 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DFLE108.ent.ti.com (10.64.6.29) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:26:44 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVH107507; Wed, 14 May 2025 06:26:38 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 11/12] media: ti: j721e-csi2rx: Submit all available buffers Date: Wed, 14 May 2025 16:55:26 +0530 Message-ID: <20250514112527.1983068-12-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea From: Jai Luthra We already make sure to submit all available buffers to DMA in each DMA completion callback. Move that logic in a separate function, and use it during stream start as well, as most application queue all their buffers before stream on. Signed-off-by: Jai Luthra Reviewed-by: Tomi Valkeinen Signed-off-by: Rishikesh Donadkar --- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 7986f96c5e11b..ba2a30bfed37d 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -651,6 +651,27 @@ static int ti_csi2rx_drain_dma(struct ti_csi2rx_ctx *ctx) return ret; } +static int ti_csi2rx_dma_submit_pending(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dma *dma = &ctx->dma; + struct ti_csi2rx_buffer *buf; + int ret = 0; + + /* If there are more buffers to process then start their transfer. */ + while (!list_empty(&dma->queue)) { + buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); + ret = ti_csi2rx_start_dma(ctx, buf); + if (ret) { + dev_err(ctx->csi->dev, + "Failed to queue the next buffer for DMA\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + break; + } + list_move_tail(&buf->list, &dma->submitted); + } + return ret; +} + static void ti_csi2rx_dma_callback(void *param) { struct ti_csi2rx_buffer *buf = param; @@ -671,18 +692,7 @@ static void ti_csi2rx_dma_callback(void *param) vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); list_del(&buf->list); - /* If there are more buffers to process then start their transfer. */ - while (!list_empty(&dma->queue)) { - buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); - - if (ti_csi2rx_start_dma(ctx, buf)) { - dev_err(ctx->csi->dev, - "Failed to queue the next buffer for DMA\n"); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - } else { - list_move_tail(&buf->list, &dma->submitted); - } - } + ti_csi2rx_dma_submit_pending(ctx); if (list_empty(&dma->submitted)) dma->state = TI_CSI2RX_DMA_IDLE; @@ -941,7 +951,6 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vq); struct ti_csi2rx_dev *csi = ctx->csi; struct ti_csi2rx_dma *dma = &ctx->dma; - struct ti_csi2rx_buffer *buf; unsigned long flags; int ret = 0; @@ -980,16 +989,13 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) ctx->sequence = 0; spin_lock_irqsave(&dma->lock, flags); - buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); - ret = ti_csi2rx_start_dma(ctx, buf); + ret = ti_csi2rx_dma_submit_pending(ctx); if (ret) { - dev_err(csi->dev, "Failed to start DMA: %d\n", ret); spin_unlock_irqrestore(&dma->lock, flags); - goto err_pipeline; + goto err_dma; } - list_move_tail(&buf->list, &dma->submitted); dma->state = TI_CSI2RX_DMA_ACTIVE; spin_unlock_irqrestore(&dma->lock, flags); @@ -1004,7 +1010,6 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) err_dma: ti_csi2rx_stop_dma(ctx); -err_pipeline: video_device_pipeline_stop(&ctx->vdev); writel(0, csi->shim + SHIM_CNTL); writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); From patchwork Wed May 14 11:25:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rishikesh Donadkar X-Patchwork-Id: 890074 Received: from fllvem-ot04.ext.ti.com (fllvem-ot04.ext.ti.com [198.47.19.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E7CA276053; Wed, 14 May 2025 11:27:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.19.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222024; cv=none; b=ioKnL3FFG2sH7aK+NmRRsrpINrRIOCVERkb1kjE8YaeD/dyHGWeyKF+rscJgSEzAeR8NoRE9v50Utzx8nq2z7J1TZ+gmRgxYoehOykCSfWB4iQ65n3ba9WLvwnI12fa+KtWQhcCjy0/KfK32K4JN9kHo0IGCVDI9HaIKXufVXek= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747222024; c=relaxed/simple; bh=OpIz8hToTsa12D3dl29WGsxu3kAJVZb1M4NVtWM4qwE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dczXn+6AFYdjZ3fBq4VdX0IXDR7E8/LjbNREWHULlG4y9fnnN/TzqFEYzxNaVC4yyXI5v877hRadNSMiUEpGqXla7yGpnU/hRalBOP++c0PNu7TAJEVsfcMuMYnbqnp+HmAMXiBk3cWihNvrY/UB9/YmoqaQYPYN03EBxDV4Jy4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=yZ4fBlsp; arc=none smtp.client-ip=198.47.19.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="yZ4fBlsp" Received: from fllv0034.itg.ti.com ([10.64.40.246]) by fllvem-ot04.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQpF33126881 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 May 2025 06:26:51 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1747222011; bh=NSVMFkYXwf8uF4rEPRU6EjL/j3hreF33Qtnl3skMvwc=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=yZ4fBlspfcI42EkS16g2RnfwXwfDFAk9RtNdKpMxmiKf7QINSIrqIagXUXFQ1hoqM YHE/uQQxWs1jTGYNR8YezTGW0HVH/wZwH93MZ3IA6QJ3IS8qah1j9HrXK1zVxGJASI XTtBFW9/JwXiF+d2w/UXf1zxR/7gswaICbRpAD2Y= Received: from DFLE103.ent.ti.com (dfle103.ent.ti.com [10.64.6.24]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 54EBQp47085433 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 14 May 2025 06:26:51 -0500 Received: from DFLE111.ent.ti.com (10.64.6.32) by DFLE103.ent.ti.com (10.64.6.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 14 May 2025 06:26:51 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DFLE111.ent.ti.com (10.64.6.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 14 May 2025 06:26:50 -0500 Received: from ws.dhcp.ti.com (ws.dhcp.ti.com [10.24.69.232]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 54EBPSVI107507; Wed, 14 May 2025 06:26:44 -0500 From: Rishikesh Donadkar To: , , CC: , , , , , , , , , , , , , , , , , , Subject: [PATCH v4 12/12] media: ti: j721e-csi2rx: Change the drain architecture for multistream Date: Wed, 14 May 2025 16:55:27 +0530 Message-ID: <20250514112527.1983068-13-r-donadkar@ti.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250514112527.1983068-1-r-donadkar@ti.com> References: <20250514112527.1983068-1-r-donadkar@ti.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea On buffer starvation the DMA is marked IDLE, and the stale data in the internal FIFOs gets drained only on the next VIDIOC_QBUF call from the userspace. This approach works fine for a single stream case. But in multistream scenarios, buffer starvation for one stream i.e. one virtual channel, can block the shared HW FIFO of the CSI2RX IP. This can stall the pipeline for all other virtual channels, even if buffers are available for them. This patch introduces a new architecture, that continuously drains data from the shared HW FIFO into a small (32KiB) buffer if no buffers are made available to the driver from the userspace. This ensures independence between different streams, where a slower downstream element for one camera does not block streaming for other cameras. Signed-off-by: Rishikesh Donadkar --- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 96 +++++++------------ 1 file changed, 33 insertions(+), 63 deletions(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index ba2a30bfed37d..3b046d3cf7e5a 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -57,7 +57,6 @@ #define TI_CSI2RX_MAX_SOURCE_PADS TI_CSI2RX_MAX_CTX #define TI_CSI2RX_MAX_PADS (1 + TI_CSI2RX_MAX_SOURCE_PADS) -#define DRAIN_TIMEOUT_MS 50 #define DRAIN_BUFFER_SIZE SZ_32K struct ti_csi2rx_fmt { @@ -77,7 +76,6 @@ struct ti_csi2rx_buffer { enum ti_csi2rx_dma_state { TI_CSI2RX_DMA_STOPPED, /* Streaming not started yet. */ - TI_CSI2RX_DMA_IDLE, /* Streaming but no pending DMA operation. */ TI_CSI2RX_DMA_ACTIVE, /* Streaming and pending DMA operation. */ }; @@ -245,6 +243,10 @@ static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { static int ti_csi2rx_start_dma(struct ti_csi2rx_ctx *ctx, struct ti_csi2rx_buffer *buf); +/* Forward declarations needed by ti_csi2rx_drain_callback. */ +static int ti_csi2rx_drain_dma(struct ti_csi2rx_ctx *ctx); +static int ti_csi2rx_dma_submit_pending(struct ti_csi2rx_ctx *ctx); + static const struct ti_csi2rx_fmt *find_format_by_fourcc(u32 pixelformat) { unsigned int i; @@ -596,9 +598,28 @@ static void ti_csi2rx_setup_shim(struct ti_csi2rx_ctx *ctx) static void ti_csi2rx_drain_callback(void *param) { - struct completion *drain_complete = param; + struct ti_csi2rx_ctx *ctx = param; + struct ti_csi2rx_dma *dma = &ctx->dma; + unsigned long flags; + + spin_lock_irqsave(&dma->lock, flags); - complete(drain_complete); + if (dma->state == TI_CSI2RX_DMA_STOPPED) { + spin_unlock_irqrestore(&dma->lock, flags); + return; + } + + /* + * If dma->queue is empty, it signals no buffer has arrived from + * user space, so, queue more transaction to drain dma + */ + if (list_empty(&dma->queue)) { + if (ti_csi2rx_drain_dma(ctx)) + dev_warn(ctx->csi->dev, "DMA drain failed\n"); + } else { + ti_csi2rx_dma_submit_pending(ctx); + } + spin_unlock_irqrestore(&dma->lock, flags); } /* @@ -616,12 +637,9 @@ static int ti_csi2rx_drain_dma(struct ti_csi2rx_ctx *ctx) { struct ti_csi2rx_dev *csi = ctx->csi; struct dma_async_tx_descriptor *desc; - struct completion drain_complete; dma_cookie_t cookie; int ret; - init_completion(&drain_complete); - desc = dmaengine_prep_slave_single(ctx->dma.chan, csi->drain.paddr, csi->drain.len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -631,7 +649,7 @@ static int ti_csi2rx_drain_dma(struct ti_csi2rx_ctx *ctx) } desc->callback = ti_csi2rx_drain_callback; - desc->callback_param = &drain_complete; + desc->callback_param = ctx; cookie = dmaengine_submit(desc); ret = dma_submit_error(cookie); @@ -640,13 +658,6 @@ static int ti_csi2rx_drain_dma(struct ti_csi2rx_ctx *ctx) dma_async_issue_pending(ctx->dma.chan); - if (!wait_for_completion_timeout(&drain_complete, - msecs_to_jiffies(DRAIN_TIMEOUT_MS))) { - dmaengine_terminate_sync(ctx->dma.chan); - dev_dbg(csi->dev, "DMA transfer timed out for drain buffer\n"); - ret = -ETIMEDOUT; - goto out; - } out: return ret; } @@ -694,9 +705,11 @@ static void ti_csi2rx_dma_callback(void *param) ti_csi2rx_dma_submit_pending(ctx); - if (list_empty(&dma->submitted)) - dma->state = TI_CSI2RX_DMA_IDLE; - + if (list_empty(&dma->submitted)) { + if (ti_csi2rx_drain_dma(ctx)) + dev_warn(ctx->csi->dev, + "DMA drain failed on one of the transactions\n"); + } spin_unlock_irqrestore(&dma->lock, flags); } @@ -749,7 +762,7 @@ static void ti_csi2rx_stop_dma(struct ti_csi2rx_ctx *ctx) * enforced before terminating DMA. */ ret = ti_csi2rx_drain_dma(ctx); - if (ret && ret != -ETIMEDOUT) + if (ret) dev_warn(ctx->csi->dev, "Failed to drain DMA. Next frame might be bogus\n"); } @@ -816,57 +829,14 @@ static void ti_csi2rx_buffer_queue(struct vb2_buffer *vb) struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct ti_csi2rx_buffer *buf; struct ti_csi2rx_dma *dma = &ctx->dma; - bool restart_dma = false; unsigned long flags = 0; - int ret; buf = container_of(vb, struct ti_csi2rx_buffer, vb.vb2_buf); buf->ctx = ctx; spin_lock_irqsave(&dma->lock, flags); - /* - * Usually the DMA callback takes care of queueing the pending buffers. - * But if DMA has stalled due to lack of buffers, restart it now. - */ - if (dma->state == TI_CSI2RX_DMA_IDLE) { - /* - * Do not restart DMA with the lock held because - * ti_csi2rx_drain_dma() might block for completion. - * There won't be a race on queueing DMA anyway since the - * callback is not being fired. - */ - restart_dma = true; - dma->state = TI_CSI2RX_DMA_ACTIVE; - } else { - list_add_tail(&buf->list, &dma->queue); - } + list_add_tail(&buf->list, &dma->queue); spin_unlock_irqrestore(&dma->lock, flags); - - if (restart_dma) { - /* - * Once frames start dropping, some data gets stuck in the DMA - * pipeline somewhere. So the first DMA transfer after frame - * drops gives a partial frame. This is obviously not useful to - * the application and will only confuse it. Issue a DMA - * transaction to drain that up. - */ - ret = ti_csi2rx_drain_dma(ctx); - if (ret && ret != -ETIMEDOUT) - dev_warn(ctx->csi->dev, - "Failed to drain DMA. Next frame might be bogus\n"); - - spin_lock_irqsave(&dma->lock, flags); - ret = ti_csi2rx_start_dma(ctx, buf); - if (ret) { - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - dma->state = TI_CSI2RX_DMA_IDLE; - spin_unlock_irqrestore(&dma->lock, flags); - dev_err(ctx->csi->dev, "Failed to start DMA: %d\n", ret); - } else { - list_add_tail(&buf->list, &dma->submitted); - spin_unlock_irqrestore(&dma->lock, flags); - } - } } static int ti_csi2rx_get_route(struct ti_csi2rx_ctx *ctx)